ref #10441: adapt property path also for Taxon-/DescriptionController
[cdmlib.git] / cdmlib-remote / src / main / java / eu / etaxonomy / cdm / remote / controller / TaxonPortalController.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.remote.controller;
10
11 import java.io.IOException;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.EnumSet;
15 import java.util.HashSet;
16 import java.util.Hashtable;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.UUID;
22 import java.util.stream.Collectors;
23
24 import javax.servlet.http.HttpServletRequest;
25 import javax.servlet.http.HttpServletResponse;
26
27 import org.apache.logging.log4j.LogManager;
28 import org.apache.logging.log4j.Logger;
29 import org.springframework.beans.factory.annotation.Autowired;
30 import org.springframework.stereotype.Controller;
31 import org.springframework.web.bind.WebDataBinder;
32 import org.springframework.web.bind.annotation.InitBinder;
33 import org.springframework.web.bind.annotation.PathVariable;
34 import org.springframework.web.bind.annotation.RequestMapping;
35 import org.springframework.web.bind.annotation.RequestMethod;
36 import org.springframework.web.bind.annotation.RequestParam;
37 import org.springframework.web.bind.annotation.ResponseBody;
38 import org.springframework.web.servlet.ModelAndView;
39
40 import eu.etaxonomy.cdm.api.dto.portal.DistributionInfoDto.InfoPart;
41 import eu.etaxonomy.cdm.api.dto.portal.TaxonPageDto;
42 import eu.etaxonomy.cdm.api.dto.portal.config.DistributionInfoConfiguration;
43 import eu.etaxonomy.cdm.api.dto.portal.config.DistributionOrder;
44 import eu.etaxonomy.cdm.api.dto.portal.config.TaxonPageDtoConfiguration;
45 import eu.etaxonomy.cdm.api.service.INameService;
46 import eu.etaxonomy.cdm.api.service.ITaxonNodeService;
47 import eu.etaxonomy.cdm.api.service.ITaxonService;
48 import eu.etaxonomy.cdm.api.service.ITermService;
49 import eu.etaxonomy.cdm.api.service.portal.IPortalDtoService;
50 import eu.etaxonomy.cdm.api.util.TaxonRelationshipEdge;
51 import eu.etaxonomy.cdm.common.CdmUtils;
52 import eu.etaxonomy.cdm.database.UpdatableRoutingDataSource;
53 import eu.etaxonomy.cdm.format.description.distribution.CondensedDistributionConfiguration;
54 import eu.etaxonomy.cdm.format.description.distribution.CondensedDistributionRecipe;
55 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
56 import eu.etaxonomy.cdm.model.common.CdmBase;
57 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
58 import eu.etaxonomy.cdm.model.common.MarkerType;
59 import eu.etaxonomy.cdm.model.common.RelationshipBase.Direction;
60 import eu.etaxonomy.cdm.model.description.Feature;
61 import eu.etaxonomy.cdm.model.location.NamedArea;
62 import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
63 import eu.etaxonomy.cdm.model.media.Media;
64 import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
65 import eu.etaxonomy.cdm.model.name.NameRelationship;
66 import eu.etaxonomy.cdm.model.taxon.Synonym;
67 import eu.etaxonomy.cdm.model.taxon.Taxon;
68 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
69 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
70 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
71 import eu.etaxonomy.cdm.persistence.dao.initializer.EntityInitStrategy;
72 import eu.etaxonomy.cdm.persistence.query.MatchMode;
73 import eu.etaxonomy.cdm.remote.controller.util.ControllerUtils;
74 import eu.etaxonomy.cdm.remote.controller.util.IMediaToolbox;
75 import eu.etaxonomy.cdm.remote.editor.CdmTypePropertyEditor;
76 import eu.etaxonomy.cdm.remote.editor.DefinedTermBaseList;
77 import eu.etaxonomy.cdm.remote.editor.MatchModePropertyEditor;
78 import eu.etaxonomy.cdm.remote.editor.NamedAreaPropertyEditor;
79 import eu.etaxonomy.cdm.remote.editor.TermBaseListPropertyEditor;
80 import eu.etaxonomy.cdm.remote.editor.UUIDListPropertyEditor;
81 import eu.etaxonomy.cdm.remote.editor.UuidList;
82 import io.swagger.annotations.Api;
83
84 /**
85 * The TaxonPortalController class is a Spring MVC Controller.
86 * <p>
87 * The syntax of the mapped service URIs contains the the {datasource-name} path element.
88 * The available {datasource-name}s are defined in a configuration file which
89 * is loaded by the {@link UpdatableRoutingDataSource}. If the
90 * UpdatableRoutingDataSource is not being used in the actual application
91 * context any arbitrary {datasource-name} may be used.
92 * <p>
93 * Methods mapped at type level, inherited from super classes ({@link BaseController}):
94 * <blockquote>
95 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}</b>
96 *
97 * Get the {@link TaxonBase} instance identified by the <code>{taxon-uuid}</code>.
98 * The returned Taxon is initialized by
99 * the following strategy {@link #TAXON_INIT_STRATEGY}
100 * </blockquote>
101 *
102 * @author a.kohlbecker
103 * @since 20.07.2009
104 */
105 @Controller
106 @Api("portal_taxon")
107 @RequestMapping(value = {"/portal/taxon/{uuid}"})
108 public class TaxonPortalController extends TaxonController{
109
110 private static final Logger logger = LogManager.getLogger();
111
112 @Autowired
113 private INameService nameService;
114
115 @Autowired
116 private ITaxonNodeService taxonNodeService;
117
118 @Autowired
119 private ITaxonService taxonService;
120
121 @Autowired
122 private ITermService termService;
123
124 @Autowired
125 private IMediaToolbox mediaToolbox;
126
127 @Autowired
128 private IPortalDtoService portalDtoService;
129
130
131 public static final EntityInitStrategy TAXON_INIT_STRATEGY = new EntityInitStrategy(Arrays.asList(new String []{
132 "$",
133 "sources",
134 "statusNote",
135 "relationsFromThisTaxon.toTaxon.secSource.citation.authorship",
136 "relationsFromThisTaxon.toTaxon.secSource.citation.inReference.authorship",
137 "relationsToThisTaxon.fromTaxon.secSource.citation.authorship",
138 "relationsToThisTaxon.fromTaxon.secSource.citation.inReference.authorship",
139 // the name
140 "name.$",
141 "name.nomenclaturalSource.citation.authorship",
142 "name.nomenclaturalSource.citation.inReference.authorship",
143 "name.rank.representations",
144 "name.status.type.representations",
145 "name.status.source.citation",
146 "secSource.nameUsedInSource.$",
147 "secSource.nameUsedInSource.nomenclaturalSource.citation.authorship",
148 "secSource.nameUsedInSource.nomenclaturalSource.citation.inReference.authorship",
149 "secSource.citation.authorship.$",
150 "secSource.citation.inReference.authorship.$",
151 "annotations.$",
152 "annotations.type.includes.$"
153 // "descriptions" // TODO remove
154
155 }));
156
157 public static final EntityInitStrategy TAXON_WITH_CHILDNODES_INIT_STRATEGY = new EntityInitStrategy(Arrays.asList(new String []{
158 "taxonNodes.$",
159 "taxonNodes.classification.$",
160 "taxonNodes.childNodes.$"
161 }));
162
163 public static final EntityInitStrategy SIMPLE_TAXON_INIT_STRATEGY = new EntityInitStrategy(Arrays.asList(new String []{
164 "$",
165 // the name
166 "name.$",
167 "name.rank.representations",
168 "name.status.type.representations",
169 "name.status.source.citation",
170 "name.nomenclaturalSource.citation.authorship",
171 "name.nomenclaturalSource.citation.inReference.authorship",
172 "taxonNodes.classification",
173 "secSource.nameUsedInSource.$",
174 "secSource.citation.authorship.$",
175 "secSource.citation.inReference.authorship.$"
176 }));
177
178 public static final EntityInitStrategy SYNONYMY_INIT_STRATEGY = new EntityInitStrategy(Arrays.asList(new String []{
179 // initialize homotypical and heterotypical groups; needs synonyms
180 "synonyms.$",
181 "synonyms.name.status.type.representations",
182 "synonyms.name.status.source.citation",
183 "synonyms.name.nomenclaturalSource.citation.authorship",
184 "synonyms.name.nomenclaturalSource.citation.inReference.authorship",
185 // "synonyms.name.homotypicalGroup.typifiedNames.$",
186 // "synonyms.name.homotypicalGroup.typifiedNames.taxonBases.$",
187 "synonyms.name.combinationAuthorship.$",
188 "synonyms.secSource.citation.authorship.$",
189 "synonyms.secSource.citation.inReference.authorship.$",
190 "synonyms.secSource.nameUsedInSource.$",
191 "name.typeDesignations",
192
193 "name.homotypicalGroup.$",
194 "name.homotypicalGroup.typifiedNames.$",
195 "name.homotypicalGroup.typifiedNames.nomenclaturalSource.citation.authorship",
196 "name.homotypicalGroup.typifiedNames.nomenclaturalSource.citation.inReference.authorship",
197 // "name.homotypicalGroup.typifiedNames.taxonBases.$"
198 }));
199
200
201 private static final EntityInitStrategy TAXONRELATIONSHIP_INIT_STRATEGY = new EntityInitStrategy(Arrays.asList(new String []{
202 "$",
203 "type.inverseRepresentations",
204 "fromTaxon.sec",
205 "fromTaxon.name",
206 "toTaxon.sec",
207 "toTaxon.name"
208 }));
209
210 public static final EntityInitStrategy NAMERELATIONSHIP_INIT_STRATEGY = new EntityInitStrategy(Arrays.asList(new String []{
211 "$",
212 "type.inverseRepresentations",
213 "source.citation",
214 "toName.$",
215 "toName.nomenclaturalSource.citation.authorship",
216 "toName.nomenclaturalSource.citation.inReference.authorship",
217 "fromName.$",
218 "fromName.nomenclaturalSource.citation.authorship",
219 "fromName.nomenclaturalSource.citation.inReference.authorship",
220
221 }));
222
223 protected static final EntityInitStrategy TAXONDESCRIPTION_INIT_STRATEGY = DescriptionPortalController.DESCRIPTION_INIT_STRATEGY;
224
225 protected static final EntityInitStrategy DESCRIPTION_ELEMENT_INIT_STRATEGY = new EntityInitStrategy(Arrays.asList(new String []{
226 "$",
227 "sources.citation.authorship",
228 "sources.citation.inReference.authorship",
229 "sources.nameUsedInSource",
230 "multilanguageText",
231 "media",
232 }));
233
234
235 // private static final List<String> NAMEDESCRIPTION_INIT_STRATEGY = Arrays.asList(new String []{
236 // "uuid",
237 // "feature",
238 // "elements.$",
239 // "elements.multilanguageText",
240 // "elements.media",
241 // });
242
243 protected static final EntityInitStrategy TAXONDESCRIPTION_MEDIA_INIT_STRATEGY = new EntityInitStrategy(Arrays.asList(new String []{
244 "elements.media"
245
246 }));
247
248 private static final EntityInitStrategy TYPEDESIGNATION_INIT_STRATEGY = new EntityInitStrategy(Arrays.asList(new String []{
249 "typeSpecimen.$",
250 "citation.authorship.$",
251 "typeName",
252 "typeStatus"
253 }));
254
255 protected static final EntityInitStrategy TAXONNODE_WITH_CHILDNODES_INIT_STRATEGY = new EntityInitStrategy(Arrays.asList(new String []{
256 "childNodes.taxon",
257 }));
258
259 protected static final EntityInitStrategy TAXONNODE_INIT_STRATEGY = new EntityInitStrategy(Arrays.asList(new String []{
260 "taxonNodes.classification",
261 "taxonNodes.parent",
262 "taxonNodes.statusNote.*",
263 "taxonNodes.taxon.name",
264 "taxonNodes.taxon.secSource.citation",
265 "taxonNodes.taxon.secSource.nameUsedInSource.$",
266 "taxonNodes.taxon.secSource.citation.authorship.$",
267 "taxonNodes.taxon.secSource.citation.inReference.authorship.$",
268 "taxonNodes.source.citation.authorship",
269 "taxonNodes.source.citation.inReference.authorship",
270 "acceptedTaxon.taxonNodes.classification",
271 "secSource.nameUsedInSource"
272
273 }));
274
275 @Override
276 protected <CDM_BASE extends CdmBase> List<String> complementInitStrategy(Class<CDM_BASE> clazz,
277 List<String> pathProperties) {
278
279 if(pathProperties != null) {
280 List<String> complemented = new ArrayList<>(pathProperties);
281 if(pathProperties.contains("name")) {
282 // pathProperties for web service request for portal/taxon/{uuid}/name
283 complemented.add("name.nomenclaturalSource.citation.authorship");
284 complemented.add("name.nomenclaturalSource.citation.inReference.authorship");
285 return complemented;
286 }
287 }
288 return pathProperties;
289 }
290
291 public TaxonPortalController(){
292 super();
293 setInitializationStrategy(TAXON_INIT_STRATEGY.getPropertyPaths());
294 }
295
296 @Autowired
297 @Override
298 public void setService(ITaxonService service) {
299 this.service = service;
300 }
301
302 @InitBinder
303 @Override
304 public void initBinder(WebDataBinder binder) {
305 super.initBinder(binder);
306 binder.registerCustomEditor(NamedArea.class, new NamedAreaPropertyEditor());
307 binder.registerCustomEditor(MatchMode.class, new MatchModePropertyEditor());
308 binder.registerCustomEditor(Class.class, new CdmTypePropertyEditor());
309 binder.registerCustomEditor(UuidList.class, new UUIDListPropertyEditor());
310 binder.registerCustomEditor(DefinedTermBaseList.class, new TermBaseListPropertyEditor<>(termService));
311 }
312
313 /**
314 * TODO documentation
315 *
316 * @param taxonUuid the taxon uuid
317 * @param subtreeUuid the taxon node subtree filter
318 * @throws IOException
319 */
320 @RequestMapping(
321 value = {"page"},
322 method = RequestMethod.GET)
323 @ResponseBody
324 public TaxonPageDto doGetTaxonPage(@PathVariable("uuid") UUID taxonUuid,
325 @RequestParam(value = "subtree", required = false) UUID subtreeUuid,
326 @RequestParam(value = "featureTree", required = false) UUID featureTreeUuid,
327 @RequestParam(value = "nameRelationsDirect", required = false) Set<UUID> directNameRelations,
328 @RequestParam(value = "nameRelationsInverse", required = false) Set<UUID> inverseNameRelations,
329 @RequestParam(value = "etAlPos", required = false) Integer etAlPosition,
330 @RequestParam(value = "doSynonyms", required = false) boolean doSynonyms,
331 @RequestParam(value = "doFacts", required = false) boolean doFacts,
332 @RequestParam(value = "doSpecimens", required = false) boolean doSpecimens,
333 @RequestParam(value = "doKeys", required = false) boolean doKeys,
334 @RequestParam(value = "doMedia", required = false) boolean doMedia,
335 @RequestParam(value = "doTaxonNodes", required = false) boolean doTaxonNodes,
336 @RequestParam(value = "doTaxonRelations", required = false) boolean doTaxonRelations,
337 //TODO annotation type filter
338
339 //distributionInfoConfig
340 @RequestParam(value = "part", required = false) Set<InfoPart> partSet,
341 @RequestParam(value = "subAreaPreference", required = false) boolean preferSubAreas,
342 @RequestParam(value = "statusOrderPreference", required = false) boolean statusOrderPreference,
343 @RequestParam(value = "fallbackAreaMarkerType", required = false) DefinedTermBaseList<MarkerType> fallbackAreaMarkerTypeList,
344 @RequestParam(value = "alternativeRootAreaMarkerType", required = false) DefinedTermBaseList<MarkerType> alternativeRootAreaMarkerTypeList,
345 @RequestParam(value = "areaTree", required = false ) UUID areaTreeUuid,
346 //TODO still needs to be used
347 @RequestParam(value = "statusTree", required = false ) UUID statusTreeUuid,
348 @RequestParam(value = "omitLevels", required = false) Set<NamedAreaLevel> omitLevels,
349 @RequestParam(value = "statusColors", required = false) String statusColorsString,
350 @RequestParam(value = "distributionOrder", required = false, defaultValue="LABEL") DistributionOrder distributionOrder,
351 @RequestParam(value = "recipe", required = false, defaultValue="EuroPlusMed") CondensedDistributionRecipe recipe,
352
353 //TODO configuration data
354 HttpServletRequest request,
355 HttpServletResponse response) throws IOException {
356
357 boolean includeUnpublished = !INCLUDE_UNPUBLISHED;
358 if(request != null){
359 logger.info("doGetTaxonPage() " + requestPathAndQuery(request));
360 }
361
362 //TODO for now hardcoded
363 alternativeRootAreaMarkerTypeList = new DefinedTermBaseList<>();
364 UUID alternativeRootAreaMarkerTypeUuid = MarkerType.uuidAlternativeRootArea;
365 MarkerType defaultAlternativeRootAreaMarkerType = (MarkerType)termService.find(alternativeRootAreaMarkerTypeUuid);
366 if (defaultAlternativeRootAreaMarkerType != null) {
367 alternativeRootAreaMarkerTypeList.add(defaultAlternativeRootAreaMarkerType);
368 }
369
370
371 //TODO is this current state of art?
372 // ModelAndView mv = new ModelAndView();
373
374 //check taxon exists and not filtered
375 Taxon taxon = getCdmBaseInstance(Taxon.class, taxonUuid, response, getTaxonNodeInitStrategy().getPropertyPaths());
376 TaxonNode subtree = getSubtreeOrError(subtreeUuid, taxonNodeService, response);
377 taxon = checkExistsSubtreeAndAccess(taxon, subtree, NO_UNPUBLISHED, response);
378
379 if (partSet == null) {
380 partSet = EnumSet.of(InfoPart.condensedDistribution, InfoPart.mapUriParams, InfoPart.tree);
381 }
382 partSet.remove(InfoPart.elements); // we do not want to return model instances here at all
383
384 // //TODO is this performant?
385 // IVocabularyService vocabularyService = null;
386 // Map<PresenceAbsenceTerm, Color> distributionStatusColors = DistributionServiceUtilities.buildStatusColorMap(
387 // statusColorsString, termService, vocabularyService);
388
389 TaxonPageDtoConfiguration config = new TaxonPageDtoConfiguration();
390
391 config.setTaxonUuid(taxonUuid);
392 config.setFeatureTree(featureTreeUuid);
393 config.setEtAlPosition(etAlPosition);
394 config.setWithFacts(doFacts);
395 config.setWithKeys(doKeys);
396 config.setWithMedia(doMedia);
397 config.setWithSpecimens(doSpecimens);
398 config.setWithSynonyms(doSynonyms);
399 config.setWithTaxonNodes(doTaxonNodes);
400 config.setWithTaxonRelationships(doTaxonRelations);
401 config.setIncludeUnpublished(includeUnpublished);
402
403 Set<MarkerType> fallbackAreaMarkerTypes = new HashSet<>();
404 if(!CdmUtils.isNullSafeEmpty(fallbackAreaMarkerTypeList)){
405 fallbackAreaMarkerTypes = fallbackAreaMarkerTypeList.asSet();
406 }
407 Set<MarkerType> alternativeRootAreaMarkerTypes = new HashSet<>();
408 if(!CdmUtils.isNullSafeEmpty(alternativeRootAreaMarkerTypeList)){
409 alternativeRootAreaMarkerTypes = alternativeRootAreaMarkerTypeList.asSet();
410 }
411
412 //default distribution info config
413 DistributionInfoConfiguration distributionConfig = config.getDistributionInfoConfiguration();
414 distributionConfig.setUseTreeDto(true);
415 distributionConfig.setInfoParts(EnumSet.copyOf(partSet));
416 distributionConfig.setPreferSubAreas(preferSubAreas);
417 distributionConfig.setStatusOrderPreference(statusOrderPreference);
418 distributionConfig.setAreaTree(areaTreeUuid);
419 distributionConfig.setOmitLevels(omitLevels);
420 distributionConfig.setStatusColorsString(statusColorsString);
421 distributionConfig.setDistributionOrder(distributionOrder);
422 if (recipe != null) {
423 CondensedDistributionConfiguration condensedConfig = recipe.toConfiguration();
424 condensedConfig.alternativeRootAreaMarkers = getUuids(alternativeRootAreaMarkerTypes);
425 distributionConfig.setCondensedDistributionConfiguration(condensedConfig);
426 }
427 distributionConfig.setFallbackAreaMarkerTypeList(fallbackAreaMarkerTypes); //was (remove if current implementation works): fallbackAreaMarkerTypes.stream().map(mt->mt.getUuid()).collect(Collectors.toSet());
428 distributionConfig.setAlternativeRootAreaMarkerTypes(alternativeRootAreaMarkerTypes);
429
430 //iucn distribution info config
431 DistributionInfoConfiguration iucnDistributionConfig = new DistributionInfoConfiguration();
432 config.putDistributionInfoConfiguration(Feature.uuidIucnStatus, iucnDistributionConfig);
433 iucnDistributionConfig.setUseTreeDto(true);
434 EnumSet<InfoPart> iucnPartSet = EnumSet.of(InfoPart.condensedDistribution);
435 iucnDistributionConfig.setInfoParts(iucnPartSet);
436
437 iucnDistributionConfig.setPreferSubAreas(preferSubAreas);
438 iucnDistributionConfig.setStatusOrderPreference(statusOrderPreference);
439 iucnDistributionConfig.setAreaTree(areaTreeUuid);
440 iucnDistributionConfig.setOmitLevels(omitLevels);
441 // distributionConfig.setStatusColorsString(statusColorsString);
442 iucnDistributionConfig.setDistributionOrder(distributionOrder);
443 CondensedDistributionRecipe iucnRecipe = CondensedDistributionRecipe.IUCN;
444 if (iucnRecipe != null) {
445 CondensedDistributionConfiguration condensedConfig = iucnRecipe.toConfiguration();
446 condensedConfig.alternativeRootAreaMarkers = getUuids(alternativeRootAreaMarkerTypes);
447 iucnDistributionConfig.setCondensedDistributionConfiguration(condensedConfig);
448 }
449 iucnDistributionConfig.setFallbackAreaMarkerTypeList(fallbackAreaMarkerTypes);
450 iucnDistributionConfig.setAlternativeRootAreaMarkerTypes(alternativeRootAreaMarkerTypes);
451
452 TaxonPageDto dto = portalDtoService.taxonPageDto(config);
453 return dto;
454 }
455
456 private Set<UUID> getUuids(Set<? extends CdmBase> entities) {
457 return entities.stream().map(e->e.getUuid()).collect(Collectors.toSet());
458 }
459
460 /**
461 * Get the synonymy for a taxon identified by the <code>{taxon-uuid}</code>.
462 * The synonymy consists
463 * of two parts: The group of homotypic synonyms of the taxon and the
464 * heterotypic synonymy groups of the taxon. The synonymy is ordered
465 * historically by the type designations and by the publication date of the
466 * nomenclatural reference
467 * <p>
468 * URI:
469 * <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}&#x002F;synonymy</b>
470 *
471 *
472 * @param request
473 * @param response
474 * @return a Map with two entries which are mapped by the following keys:
475 * "homotypicSynonymsByHomotypicGroup", "heterotypicSynonymyGroups",
476 * containing lists of {@link Synonym}s which // TODO Auto-generated catch block
477 e.printStackTrace();are initialized using the
478 * following initialization strategy: {@link #SYNONYMY_INIT_STRATEGY}
479 *
480 * @throws IOException
481 */
482 @RequestMapping(
483 value = {"synonymy"},
484 method = RequestMethod.GET)
485 public ModelAndView doGetSynonymy(@PathVariable("uuid") UUID taxonUuid,
486 @RequestParam(value = "subtree", required = false) UUID subtreeUuid,
487 HttpServletRequest request,
488 HttpServletResponse response)throws IOException {
489
490 boolean includeUnpublished = NO_UNPUBLISHED;
491 if(request != null){
492 logger.info("doGetSynonymy() " + requestPathAndQuery(request));
493 }
494 ModelAndView mv = new ModelAndView();
495
496 Taxon taxon = getCdmBaseInstance(Taxon.class, taxonUuid, response, getTaxonNodeInitStrategy().getPropertyPaths());
497 TaxonNode subtree = getSubtreeOrError(subtreeUuid, taxonNodeService, response);
498 taxon = checkExistsSubtreeAndAccess(taxon, subtree, NO_UNPUBLISHED, response);
499
500 Map<String, List<?>> synonymy = new Hashtable<>();
501
502 //new
503 List<List<Synonym>> synonymyGroups = service.getSynonymsByHomotypicGroup(taxon, SYNONYMY_INIT_STRATEGY.getPropertyPaths());
504 if(!includeUnpublished){
505 synonymyGroups = removeUnpublishedSynonyms(synonymyGroups);
506 }
507
508 synonymy.put("homotypicSynonymsByHomotypicGroup", synonymyGroups.get(0));
509 synonymyGroups.remove(0);
510 synonymy.put("heterotypicSynonymyGroups", synonymyGroups);
511
512 //old
513 // synonymy.put("homotypicSynonymsByHomotypicGroup", service.getHomotypicSynonymsByHomotypicGroup(taxon, SYNONYMY_INIT_STRATEGY));
514 // synonymy.put("heterotypicSynonymyGroups", service.getHeterotypicSynonymyGroups(taxon, SYNONYMY_INIT_STRATEGY));
515
516 mv.addObject(synonymy);
517 return mv;
518 }
519
520
521 /**
522 * @param synonymyGroups
523 */
524 private List<List<Synonym>> removeUnpublishedSynonyms(List<List<Synonym>> synonymyGroups) {
525 List<List<Synonym>> result = new ArrayList<>();
526 boolean isHomotypicToAccepted = true;
527
528 for (List<Synonym> oldList : synonymyGroups){
529 List<Synonym> newList = new ArrayList<>();
530 for (Synonym oldSyn : oldList){
531 if (oldSyn.isPublish()){
532 newList.add(oldSyn);
533 }
534 }
535 if (isHomotypicToAccepted || !newList.isEmpty()){
536 result.add(newList);
537 }
538 isHomotypicToAccepted = false;
539 }
540 return result;
541 }
542
543 /**
544 * {@inheritDoc}
545 */
546 @Override
547 protected List<String> getTaxonDescriptionInitStrategy() {
548 return TAXONDESCRIPTION_INIT_STRATEGY.getPropertyPaths();
549 }
550
551 @Override
552 protected List<String> getTaxonDescriptionElementInitStrategy() {
553 return DESCRIPTION_ELEMENT_INIT_STRATEGY.getPropertyPaths();
554 }
555
556 @Override
557 protected EntityInitStrategy getTaxonNodeInitStrategy() {
558 return TAXONNODE_INIT_STRATEGY;
559 }
560
561 /**
562 * Get the list of {@link TaxonRelationship}s for the given
563 * {@link TaxonBase} instance identified by the <code>{taxon-uuid}</code>.
564 * <p>
565 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}&#x002F;taxonRelationships</b>
566 *
567 * @param request
568 * @param response
569 * @return a List of {@link TaxonRelationship} entities which are initialized
570 * using the following initialization strategy:
571 * {@link #TAXONRELATIONSHIP_INIT_STRATEGY}
572 * @throws IOException
573 */
574 @RequestMapping(
575 value = {"taxonRelationships"},
576 method = RequestMethod.GET)
577 public List<TaxonRelationship> doGetTaxonRelations(@PathVariable("uuid") UUID uuid,
578 HttpServletRequest request, HttpServletResponse response)throws IOException {
579
580 boolean includeUnpublished = NO_UNPUBLISHED;
581 logger.info("doGetTaxonRelations()" + requestPathAndQuery(request));
582 Taxon taxon = getCdmBaseInstance(Taxon.class, uuid, response, (List<String>)null);
583 taxon = checkExistsAndAccess(taxon, includeUnpublished, response);
584
585 List<TaxonRelationship> toRelationships = service.listToTaxonRelationships(taxon, null,
586 includeUnpublished, null, null, null, TAXONRELATIONSHIP_INIT_STRATEGY.getPropertyPaths());
587 List<TaxonRelationship> fromRelationships = service.listFromTaxonRelationships(taxon, null,
588 includeUnpublished, null, null, null, TAXONRELATIONSHIP_INIT_STRATEGY.getPropertyPaths());
589
590 List<TaxonRelationship> allRelationships = new ArrayList<>(toRelationships.size() + fromRelationships.size());
591 allRelationships.addAll(toRelationships);
592 allRelationships.addAll(fromRelationships);
593
594 return allRelationships;
595 }
596
597 /**
598 * Get the list of {@link NameRelationship}s of the Name associated with the
599 * {@link TaxonBase} instance identified by the <code>{taxon-uuid}</code>.
600 * <p>
601 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}&#x002F;nameRelationships</b>
602 *
603 * @param request
604 * @param response
605 * @return a List of {@link NameRelationship} entities which are initialized
606 * using the following initialization strategy:
607 * {@link #NAMERELATIONSHIP_INIT_STRATEGY}
608 * @throws IOException
609 */
610 @RequestMapping(
611 value = {"toNameRelationships"},
612 method = RequestMethod.GET)
613 public List<NameRelationship> doGetToNameRelations(@PathVariable("uuid") UUID uuid,
614 HttpServletRequest request, HttpServletResponse response)throws IOException {
615 logger.info("doGetNameRelations()" + request.getRequestURI());
616 boolean includeUnpublished = NO_UNPUBLISHED;
617
618 TaxonBase<?> taxonBase = getCdmBaseInstance(TaxonBase.class, uuid, response, (List<String>)null);
619 taxonBase = checkExistsAndAccess(taxonBase, includeUnpublished, response);
620
621 List<NameRelationship> list = nameService.listNameRelationships(taxonBase.getName(), Direction.relatedTo, null, null, 0, null, NAMERELATIONSHIP_INIT_STRATEGY.getPropertyPaths());
622 return list;
623 }
624
625 /**
626 * Get the list of {@link NameRelationship}s of the Name associated with the
627 * {@link TaxonBase} instance identified by the <code>{taxon-uuid}</code>.
628 * <p>
629 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}&#x002F;nameRelationships</b>
630 *
631 * @param request
632 * @param response
633 * @return a List of {@link NameRelationship} entities which are initialized
634 * using the following initialization strategy:
635 * {@link #NAMERELATIONSHIP_INIT_STRATEGY}
636 * @throws IOException
637 */
638 @RequestMapping(
639 value = {"fromNameRelationships"},
640 method = RequestMethod.GET)
641 public List<NameRelationship> doGetFromNameRelations(
642 @PathVariable("uuid") UUID uuid,
643 HttpServletRequest request,
644 HttpServletResponse response)throws IOException {
645 logger.info("doGetNameFromNameRelations()" + requestPathAndQuery(request));
646
647 boolean includeUnpublished = NO_UNPUBLISHED;
648
649 TaxonBase<?> taxonBase = getCdmBaseInstance(TaxonBase.class, uuid, response, SIMPLE_TAXON_INIT_STRATEGY.getPropertyPaths());
650 taxonBase = checkExistsAndAccess(taxonBase, includeUnpublished, response);
651
652 List<NameRelationship> list = nameService.listNameRelationships(taxonBase.getName(), Direction.relatedFrom, null, null, 0, null, NAMERELATIONSHIP_INIT_STRATEGY.getPropertyPaths());
653
654 return list;
655 }
656
657
658 // @RequestMapping(value = "specimens", method = RequestMethod.GET)
659 // public ModelAndView doGetSpecimens(
660 // @PathVariable("uuid") UUID uuid,
661 // HttpServletRequest request,
662 // HttpServletResponse response) throws IOException, ClassNotFoundException {
663 // logger.info("doGetSpecimens() - " + request.getRequestURI());
664 //
665 // ModelAndView mv = new ModelAndView();
666 //
667 // List<DerivedUnitFacade> derivedUnitFacadeList = new ArrayList<>();
668 //
669 // // find speciemens in the TaxonDescriptions
670 // List<TaxonDescription> taxonDescriptions = doGetDescriptions(uuid, request, response);
671 // if (taxonDescriptions != null) {
672 //
673 // for (TaxonDescription description : taxonDescriptions) {
674 // derivedUnitFacadeList.addAll( occurrenceService.listDerivedUnitFacades(description, null) );
675 // }
676 // }
677 // // TODO find specimens in the NameDescriptions ??
678 //
679 // // TODO also find type specimens
680 //
681 // mv.addObject(derivedUnitFacadeList);
682 //
683 // return mv;
684 // }
685
686 /**
687 * Get the {@link Media} attached to the {@link Taxon} instance
688 * identified by the <code>{taxon-uuid}</code>.
689 *
690 * Usage &#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-
691 * uuid}&#x002F;media&#x002F;{mime type
692 * list}&#x002F;{size}[,[widthOrDuration}][,{height}]&#x002F;
693 *
694 * Whereas
695 * <ul>
696 * <li><b>{mime type list}</b>: a comma separated list of mime types, in the
697 * order of preference. The forward slashes contained in the mime types must
698 * be replaced by a colon. Regular expressions can be used. Each media
699 * associated with this given taxon is being searched whereas the first
700 * matching mime type matching a representation always rules.</li>
701 * <li><b>{size},{widthOrDuration},{height}</b>: <i>not jet implemented</i>
702 * valid values are an integer or the asterisk '*' as a wildcard</li>
703 * </ul>
704 *
705 * @param request
706 * @param response
707 * @return a List of {@link Media} entities which are initialized
708 * using the following initialization strategy:
709 * {@link #TAXONDESCRIPTION_INIT_STRATEGY}
710 * @throws IOException
711 */
712 // @RequestMapping(
713 // value = {"media"},
714 // method = RequestMethod.GET)
715 // public List<Media> doGetMedia(
716 // @PathVariable("uuid") UUID uuid,
717 // @RequestParam(value = "type", required = false) Class<? extends MediaRepresentationPart> type,
718 // @RequestParam(value = "mimeTypes", required = false) String[] mimeTypes,
719 // @RequestParam(value = "relationships", required = false) UuidList relationshipUuids,
720 // @RequestParam(value = "relationshipsInvers", required = false) UuidList relationshipInversUuids,
721 // @RequestParam(value = "includeTaxonDescriptions", required = true) Boolean includeTaxonDescriptions,
722 // @RequestParam(value = "includeOccurrences", required = true) Boolean includeOccurrences,
723 // @RequestParam(value = "includeTaxonNameDescriptions", required = true) Boolean includeTaxonNameDescriptions,
724 // @RequestParam(value = "widthOrDuration", required = false) Integer widthOrDuration,
725 // @RequestParam(value = "height", required = false) Integer height,
726 // @RequestParam(value = "size", required = false) Integer size,
727 // HttpServletRequest request, HttpServletResponse response) throws IOException {
728 //
729 // logger.info("doGetMedia() " + requestPathAndQuery(request));
730 //
731 // List<String> initStrategy = null;
732 //
733 // EntityMediaContext<Taxon> taxonMediaContext = loadMediaForTaxonAndRelated(uuid, relationshipUuids,
734 // relationshipInversUuids, includeTaxonDescriptions, includeOccurrences, includeTaxonNameDescriptions,
735 // response, initStrategy, MediaPortalController.MEDIA_INIT_STRATEGY.getPropertyPaths());
736 //
737 // List<Media> mediafilteredForPreferredRepresentations = mediaToolbox.processAndFilterPreferredMediaRepresentations(type, mimeTypes, widthOrDuration, height, size,
738 // taxonMediaContext.media);
739 //
740 // return mediafilteredForPreferredRepresentations;
741 // }
742
743 @RequestMapping(
744 value = {"media"},
745 method = RequestMethod.GET)
746 public List<Media> doGetMedia(
747 @PathVariable("uuid") UUID uuid,
748 @RequestParam(value = "type", required = false) Class<? extends MediaRepresentationPart> type,
749 @RequestParam(value = "mimeTypes", required = false) String[] mimeTypes,
750 @RequestParam(value = "relationships", required = false) UuidList relationshipUuids,
751 @RequestParam(value = "relationshipsInvers", required = false) UuidList relationshipInversUuids,
752 @RequestParam(value = "includeTaxonDescriptions", required = true) Boolean includeTaxonDescriptions,
753 @RequestParam(value = "includeOccurrences", required = true) Boolean includeOccurrences,
754 @RequestParam(value = "includeOriginals", required = false) Boolean includeOriginals,
755 @RequestParam(value = "includeTaxonNameDescriptions", required = true) Boolean includeTaxonNameDescriptions,
756 @RequestParam(value = "widthOrDuration", required = false) Integer widthOrDuration,
757 @RequestParam(value = "height", required = false) Integer height,
758 @RequestParam(value = "size", required = false) Integer size,
759 HttpServletRequest request, HttpServletResponse response) throws IOException {
760
761 logger.info("doGetMedia() " + requestPathAndQuery(request));
762
763 List<String> initStrategy = null;
764
765 EntityMediaContext<Taxon> taxonMediaContext = loadMediaForTaxonAndRelated(uuid, relationshipUuids,
766 relationshipInversUuids, includeTaxonDescriptions, includeOccurrences, includeTaxonNameDescriptions,
767 response, initStrategy, MediaPortalController.MEDIA_INIT_STRATEGY.getPropertyPaths());
768
769 List<Media> mediafilteredForPreferredRepresentations = mediaToolbox.processAndFilterPreferredMediaRepresentations(
770 type, mimeTypes, widthOrDuration, height, size, taxonMediaContext.media);
771
772 return mediafilteredForPreferredRepresentations;
773 }
774
775 /**
776 * @Deprecated To be replaced by other loadMediaForTaxonAndRelated method
777 */
778 @Deprecated
779 public EntityMediaContext<Taxon> loadMediaForTaxonAndRelated(UUID uuid,
780 UuidList relationshipUuids, UuidList relationshipInversUuids,
781 Boolean includeTaxonDescriptions, Boolean includeOccurrences, Boolean includeTaxonNameDescriptions,
782 HttpServletResponse response,
783 List<String> taxonInitStrategy) throws IOException {
784 return loadMediaForTaxonAndRelated(uuid, relationshipUuids, relationshipInversUuids,
785 includeTaxonDescriptions, includeOccurrences, includeTaxonNameDescriptions, response, taxonInitStrategy, null);
786 }
787
788 public EntityMediaContext<Taxon> loadMediaForTaxonAndRelated(UUID taxonUuid,
789 UuidList relationshipUuids, UuidList relationshipInversUuids,
790 Boolean includeTaxonDescriptions, Boolean includeOccurrences, Boolean includeTaxonNameDescriptions,
791 HttpServletResponse response,
792 List<String> taxonInitStrategy, List<String> mediaInitStrategy) throws IOException {
793
794 return loadMediaForTaxonAndRelated(taxonUuid,
795 relationshipUuids, relationshipInversUuids,
796 includeTaxonDescriptions, includeOccurrences, false, includeTaxonNameDescriptions,
797 response, taxonInitStrategy, mediaInitStrategy);
798 }
799
800 public EntityMediaContext<Taxon> loadMediaForTaxonAndRelated(UUID taxonUuid,
801 UuidList relationshipUuids, UuidList relationshipInversUuids,
802 Boolean includeTaxonDescriptions, Boolean includeOccurrences, Boolean includeOriginals, Boolean includeTaxonNameDescriptions,
803 HttpServletResponse response,
804 List<String> taxonInitStrategy, List<String> mediaInitStrategy) throws IOException {
805
806 boolean includeUnpublished = NO_UNPUBLISHED;
807
808 Taxon taxon = getCdmBaseInstance(Taxon.class, taxonUuid, response, taxonInitStrategy);
809 taxon = checkExistsAndAccess(taxon, includeUnpublished, response);
810
811 Set<TaxonRelationshipEdge> includeRelationships = ControllerUtils.loadIncludeRelationships(relationshipUuids, relationshipInversUuids, termService);
812
813 List<Media> media = listMediaForTaxon(taxon, includeRelationships,
814 includeTaxonDescriptions, includeOccurrences, includeTaxonNameDescriptions, mediaInitStrategy);
815
816 EntityMediaContext<Taxon> entityMediaContext = new EntityMediaContext<>(taxon, media);
817
818 return entityMediaContext;
819 }
820
821 @RequestMapping(
822 value = {"subtree/media"},
823 method = RequestMethod.GET)
824 public List<Media> doGetSubtreeMedia(
825 @PathVariable("uuid") UUID uuid,
826 @RequestParam(value = "type", required = false) Class<? extends MediaRepresentationPart> type,
827 @RequestParam(value = "mimeTypes", required = false) String[] mimeTypes,
828 @RequestParam(value = "relationships", required = false) UuidList relationshipUuids,
829 @RequestParam(value = "relationshipsInvers", required = false) UuidList relationshipInversUuids,
830 @RequestParam(value = "includeTaxonDescriptions", required = true) Boolean includeTaxonDescriptions,
831 @RequestParam(value = "includeOccurrences", required = true) Boolean includeOccurrences,
832 @RequestParam(value = "includeTaxonNameDescriptions", required = true) Boolean includeTaxonNameDescriptions,
833 @RequestParam(value = "widthOrDuration", required = false) Integer widthOrDuration,
834 @RequestParam(value = "height", required = false) Integer height,
835 @RequestParam(value = "size", required = false) Integer size,
836 HttpServletRequest request, HttpServletResponse response)throws IOException {
837
838 boolean includeUnpublished = NO_UNPUBLISHED;
839
840 logger.info("doGetSubtreeMedia() " + requestPathAndQuery(request));
841
842 List<String> initStrategy = TAXON_WITH_CHILDNODES_INIT_STRATEGY.getPropertyPaths();
843
844 Taxon taxon = getCdmBaseInstance(Taxon.class, uuid, response, initStrategy);
845 taxon = checkExistsAndAccess(taxon, includeUnpublished, response);
846
847 Set<TaxonRelationshipEdge> includeRelationships = ControllerUtils.loadIncludeRelationships(relationshipUuids, relationshipInversUuids, termService);
848
849 List<Media> media = listMediaForTaxon(taxon, includeRelationships,
850 includeTaxonDescriptions, includeOccurrences, includeTaxonNameDescriptions, null);
851 media = addTaxonomicChildrenMedia(includeTaxonDescriptions, includeOccurrences, includeTaxonNameDescriptions, taxon,
852 includeRelationships, media);
853
854 List<Media> mediafilteredForPreferredRepresentations = mediaToolbox.processAndFilterPreferredMediaRepresentations(type, mimeTypes, widthOrDuration, height, size,
855 media);
856
857 return mediafilteredForPreferredRepresentations;
858 }
859
860 public List<Media> addTaxonomicChildrenMedia(Boolean includeTaxonDescriptions, Boolean includeOccurrences,
861 Boolean includeTaxonNameDescriptions, Taxon taxon, Set<TaxonRelationshipEdge> includeRelationships,
862 List<Media> media) {
863
864 //TODO use treeindex
865 //looking for all medias of direct children
866 TaxonNode node;
867 if (taxon.getTaxonNodes().size()>0){
868 Set<TaxonNode> nodes = taxon.getTaxonNodes();
869 Iterator<TaxonNode> iterator = nodes.iterator();
870 //TaxonNode holen
871 node = iterator.next();
872 //Check if TaxonNode belongs to the current tree
873
874 node = taxonNodeService.load(node.getUuid(), TAXONNODE_WITH_CHILDNODES_INIT_STRATEGY.getPropertyPaths());
875 List<TaxonNode> children = node.getChildNodes();
876 Taxon childTaxon;
877 for (TaxonNode child : children){
878 childTaxon = child.getTaxon();
879 if(childTaxon != null) {
880 childTaxon = (Taxon)taxonService.load(childTaxon.getUuid(), NO_UNPUBLISHED, null);
881 media.addAll(listMediaForTaxon(childTaxon, includeRelationships,
882 includeTaxonDescriptions, includeOccurrences, includeTaxonNameDescriptions, MediaPortalController.MEDIA_INIT_STRATEGY.getPropertyPaths()));
883 }
884 }
885 }
886 return media;
887 }
888
889 private List<Media> listMediaForTaxon(Taxon taxon, Set<TaxonRelationshipEdge> includeRelationships,
890 Boolean includeTaxonDescriptions, Boolean includeOccurrences, Boolean includeTaxonNameDescriptions, List<String> propertyPath) {
891
892 return listMediaForTaxon(taxon, includeRelationships, includeTaxonDescriptions, includeOccurrences, false, includeTaxonNameDescriptions, propertyPath);
893 }
894
895 private List<Media> listMediaForTaxon(Taxon taxon, Set<TaxonRelationshipEdge> includeRelationships,
896 Boolean includeTaxonDescriptions, Boolean includeOccurrences, Boolean includeOriginals, Boolean includeTaxonNameDescriptions, List<String> propertyPath) {
897
898 List<Media> media = service.listMedia(taxon, includeRelationships,
899 false, includeTaxonDescriptions, includeOccurrences, includeOriginals, includeTaxonNameDescriptions, propertyPath);
900
901 return media;
902 }
903
904
905 public class EntityMediaContext<T extends IdentifiableEntity> {
906
907 private T entity;
908 private List<Media> media;
909
910 public EntityMediaContext(T entity, List<Media> media) {
911 this.entity = HibernateProxyHelper.deproxy(entity);
912 this.media = media;
913 }
914
915 public T getEntity() {
916 return entity;
917 }
918 public List<Media> getMedia() {
919 return media;
920 }
921
922 /**
923 * @param addTaxonomicChildrenMedia
924 */
925 public void setMedia(List<Media> media) {
926 this.media = media;
927
928 }
929 }
930
931 // ---------------------- code snippet preserved for possible later use --------------------
932 // @RequestMapping(
933 // value = {"//*/portal/taxon/*/descriptions"}, // mapped as absolute path, see CdmAntPathMatcher
934 // method = RequestMethod.GET)
935 // public List<TaxonDescription> doGetDescriptionsbyFeatureTree(HttpServletRequest request, HttpServletResponse response)throws IOException {
936 // TaxonBase tb = getCdmBase(request, response, null, Taxon.class);
937 // if(tb instanceof Taxon){
938 // //T O D O this is a quick and dirty implementation -> generalize
939 // UUID featureTreeUuid = readValueUuid(request, termTreeUuidPattern);
940 //
941 // FeatureTree featureTree = descriptionService.getFeatureTreeByUuid(featureTreeUuid);
942 // Pager<TaxonDescription> p = descriptionService.getTaxonDescriptions((Taxon)tb, null, null, null, null, TAXONDESCRIPTION_INIT_STRATEGY);
943 // List<TaxonDescription> descriptions = p.getRecords();
944 //
945 // if(!featureTree.isDescriptionSeparated()){
946 //
947 // TaxonDescription superDescription = TaxonDescription.NewInstance();
948 // //put all descriptionElements in superDescription and make it invisible
949 // for(TaxonDescription description: descriptions){
950 // for(DescriptionElementBase element: description.getElements()){
951 // superDescription.addElement(element);
952 // }
953 // }
954 // List<TaxonDescription> separatedDescriptions = new ArrayList<TaxonDescription>(descriptions.size());
955 // separatedDescriptions.add(superDescription);
956 // return separatedDescriptions;
957 // }else{
958 // return descriptions;
959 // }
960 // } else {
961 // response.sendError(HttpServletResponse.SC_NOT_FOUND, "invalid type; Taxon expected but " + tb.getClass().getSimpleName() + " found.");
962 // return null;
963 // }
964 // }
965
966 }