2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
9 package eu
.etaxonomy
.cdm
.remote
.controller
;
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
;
21 import java
.util
.UUID
;
22 import java
.util
.stream
.Collectors
;
24 import javax
.servlet
.http
.HttpServletRequest
;
25 import javax
.servlet
.http
.HttpServletResponse
;
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
;
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
;
85 * The TaxonPortalController class is a Spring MVC Controller.
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.
93 * Methods mapped at type level, inherited from super classes ({@link BaseController}):
95 * URI: <b>/{datasource-name}/portal/taxon/{taxon-uuid}</b>
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}
102 * @author a.kohlbecker
107 @RequestMapping(value
= {"/portal/taxon/{uuid}"})
108 public class TaxonPortalController
extends TaxonController
{
110 private static final Logger logger
= LogManager
.getLogger();
113 private INameService nameService
;
116 private ITaxonNodeService taxonNodeService
;
119 private ITaxonService taxonService
;
122 private ITermService termService
;
125 private IMediaToolbox mediaToolbox
;
128 private IPortalDtoService portalDtoService
;
131 public static final EntityInitStrategy TAXON_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
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",
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.$",
152 "annotations.type.includes.$"
153 // "descriptions" // TODO remove
157 public static final EntityInitStrategy TAXON_WITH_CHILDNODES_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
159 "taxonNodes.classification.$",
160 "taxonNodes.childNodes.$"
163 public static final EntityInitStrategy SIMPLE_TAXON_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
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.$"
178 public static final EntityInitStrategy SYNONYMY_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
179 // initialize homotypical and heterotypical groups; needs 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",
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.$"
201 private static final EntityInitStrategy TAXONRELATIONSHIP_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
203 "type.inverseRepresentations",
210 public static final EntityInitStrategy NAMERELATIONSHIP_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
212 "type.inverseRepresentations",
215 "toName.nomenclaturalSource.citation.authorship",
216 "toName.nomenclaturalSource.citation.inReference.authorship",
218 "fromName.nomenclaturalSource.citation.authorship",
219 "fromName.nomenclaturalSource.citation.inReference.authorship",
223 protected static final EntityInitStrategy TAXONDESCRIPTION_INIT_STRATEGY
= DescriptionPortalController
.DESCRIPTION_INIT_STRATEGY
;
225 protected static final EntityInitStrategy DESCRIPTION_ELEMENT_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
227 "sources.citation.authorship",
228 "sources.citation.inReference.authorship",
229 "sources.nameUsedInSource",
235 // private static final List<String> NAMEDESCRIPTION_INIT_STRATEGY = Arrays.asList(new String []{
239 // "elements.multilanguageText",
243 protected static final EntityInitStrategy TAXONDESCRIPTION_MEDIA_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
248 private static final EntityInitStrategy TYPEDESIGNATION_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
250 "citation.authorship.$",
255 protected static final EntityInitStrategy TAXONNODE_WITH_CHILDNODES_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
259 protected static final EntityInitStrategy TAXONNODE_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
260 "taxonNodes.classification",
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"
276 protected <CDM_BASE
extends CdmBase
> List
<String
> complementInitStrategy(Class
<CDM_BASE
> clazz
,
277 List
<String
> pathProperties
) {
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");
288 return pathProperties
;
291 public TaxonPortalController(){
293 setInitializationStrategy(TAXON_INIT_STRATEGY
.getPropertyPaths());
298 public void setService(ITaxonService service
) {
299 this.service
= service
;
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
));
316 * @param taxonUuid the taxon uuid
317 * @param subtreeUuid the taxon node subtree filter
318 * @throws IOException
322 method
= RequestMethod
.GET
)
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
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
,
353 //TODO configuration data
354 HttpServletRequest request
,
355 HttpServletResponse response
) throws IOException
{
357 boolean includeUnpublished
= !INCLUDE_UNPUBLISHED
;
359 logger
.info("doGetTaxonPage() " + requestPathAndQuery(request
));
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
);
371 //TODO is this current state of art?
372 // ModelAndView mv = new ModelAndView();
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
);
379 if (partSet
== null) {
380 partSet
= EnumSet
.of(InfoPart
.condensedDistribution
, InfoPart
.mapUriParams
, InfoPart
.tree
);
382 partSet
.remove(InfoPart
.elements
); // we do not want to return model instances here at all
384 // //TODO is this performant?
385 // IVocabularyService vocabularyService = null;
386 // Map<PresenceAbsenceTerm, Color> distributionStatusColors = DistributionServiceUtilities.buildStatusColorMap(
387 // statusColorsString, termService, vocabularyService);
389 TaxonPageDtoConfiguration config
= new TaxonPageDtoConfiguration();
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
);
403 Set
<MarkerType
> fallbackAreaMarkerTypes
= new HashSet
<>();
404 if(!CdmUtils
.isNullSafeEmpty(fallbackAreaMarkerTypeList
)){
405 fallbackAreaMarkerTypes
= fallbackAreaMarkerTypeList
.asSet();
407 Set
<MarkerType
> alternativeRootAreaMarkerTypes
= new HashSet
<>();
408 if(!CdmUtils
.isNullSafeEmpty(alternativeRootAreaMarkerTypeList
)){
409 alternativeRootAreaMarkerTypes
= alternativeRootAreaMarkerTypeList
.asSet();
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
);
427 distributionConfig
.setFallbackAreaMarkerTypeList(fallbackAreaMarkerTypes
); //was (remove if current implementation works): fallbackAreaMarkerTypes.stream().map(mt->mt.getUuid()).collect(Collectors.toSet());
428 distributionConfig
.setAlternativeRootAreaMarkerTypes(alternativeRootAreaMarkerTypes
);
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
);
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
);
449 iucnDistributionConfig
.setFallbackAreaMarkerTypeList(fallbackAreaMarkerTypes
);
450 iucnDistributionConfig
.setAlternativeRootAreaMarkerTypes(alternativeRootAreaMarkerTypes
);
452 TaxonPageDto dto
= portalDtoService
.taxonPageDto(config
);
456 private Set
<UUID
> getUuids(Set
<?
extends CdmBase
> entities
) {
457 return entities
.stream().map(e
->e
.getUuid()).collect(Collectors
.toSet());
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
469 * <b>/{datasource-name}/portal/taxon/{taxon-uuid}/synonymy</b>
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}
480 * @throws IOException
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
{
490 boolean includeUnpublished
= NO_UNPUBLISHED
;
492 logger
.info("doGetSynonymy() " + requestPathAndQuery(request
));
494 ModelAndView mv
= new ModelAndView();
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
);
500 Map
<String
, List
<?
>> synonymy
= new Hashtable
<>();
503 List
<List
<Synonym
>> synonymyGroups
= service
.getSynonymsByHomotypicGroup(taxon
, SYNONYMY_INIT_STRATEGY
.getPropertyPaths());
504 if(!includeUnpublished
){
505 synonymyGroups
= removeUnpublishedSynonyms(synonymyGroups
);
508 synonymy
.put("homotypicSynonymsByHomotypicGroup", synonymyGroups
.get(0));
509 synonymyGroups
.remove(0);
510 synonymy
.put("heterotypicSynonymyGroups", synonymyGroups
);
513 // synonymy.put("homotypicSynonymsByHomotypicGroup", service.getHomotypicSynonymsByHomotypicGroup(taxon, SYNONYMY_INIT_STRATEGY));
514 // synonymy.put("heterotypicSynonymyGroups", service.getHeterotypicSynonymyGroups(taxon, SYNONYMY_INIT_STRATEGY));
516 mv
.addObject(synonymy
);
522 * @param synonymyGroups
524 private List
<List
<Synonym
>> removeUnpublishedSynonyms(List
<List
<Synonym
>> synonymyGroups
) {
525 List
<List
<Synonym
>> result
= new ArrayList
<>();
526 boolean isHomotypicToAccepted
= true;
528 for (List
<Synonym
> oldList
: synonymyGroups
){
529 List
<Synonym
> newList
= new ArrayList
<>();
530 for (Synonym oldSyn
: oldList
){
531 if (oldSyn
.isPublish()){
535 if (isHomotypicToAccepted
|| !newList
.isEmpty()){
538 isHomotypicToAccepted
= false;
547 protected List
<String
> getTaxonDescriptionInitStrategy() {
548 return TAXONDESCRIPTION_INIT_STRATEGY
.getPropertyPaths();
552 protected List
<String
> getTaxonDescriptionElementInitStrategy() {
553 return DESCRIPTION_ELEMENT_INIT_STRATEGY
.getPropertyPaths();
557 protected EntityInitStrategy
getTaxonNodeInitStrategy() {
558 return TAXONNODE_INIT_STRATEGY
;
562 * Get the list of {@link TaxonRelationship}s for the given
563 * {@link TaxonBase} instance identified by the <code>{taxon-uuid}</code>.
565 * URI: <b>/{datasource-name}/portal/taxon/{taxon-uuid}/taxonRelationships</b>
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
575 value
= {"taxonRelationships"},
576 method
= RequestMethod
.GET
)
577 public List
<TaxonRelationship
> doGetTaxonRelations(@PathVariable("uuid") UUID uuid
,
578 HttpServletRequest request
, HttpServletResponse response
)throws IOException
{
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
);
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());
590 List
<TaxonRelationship
> allRelationships
= new ArrayList
<>(toRelationships
.size() + fromRelationships
.size());
591 allRelationships
.addAll(toRelationships
);
592 allRelationships
.addAll(fromRelationships
);
594 return allRelationships
;
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>.
601 * URI: <b>/{datasource-name}/portal/taxon/{taxon-uuid}/nameRelationships</b>
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
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
;
618 TaxonBase
<?
> taxonBase
= getCdmBaseInstance(TaxonBase
.class, uuid
, response
, (List
<String
>)null);
619 taxonBase
= checkExistsAndAccess(taxonBase
, includeUnpublished
, response
);
621 List
<NameRelationship
> list
= nameService
.listNameRelationships(taxonBase
.getName(), Direction
.relatedTo
, null, null, 0, null, NAMERELATIONSHIP_INIT_STRATEGY
.getPropertyPaths());
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>.
629 * URI: <b>/{datasource-name}/portal/taxon/{taxon-uuid}/nameRelationships</b>
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
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
));
647 boolean includeUnpublished
= NO_UNPUBLISHED
;
649 TaxonBase
<?
> taxonBase
= getCdmBaseInstance(TaxonBase
.class, uuid
, response
, SIMPLE_TAXON_INIT_STRATEGY
.getPropertyPaths());
650 taxonBase
= checkExistsAndAccess(taxonBase
, includeUnpublished
, response
);
652 List
<NameRelationship
> list
= nameService
.listNameRelationships(taxonBase
.getName(), Direction
.relatedFrom
, null, null, 0, null, NAMERELATIONSHIP_INIT_STRATEGY
.getPropertyPaths());
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());
665 // ModelAndView mv = new ModelAndView();
667 // List<DerivedUnitFacade> derivedUnitFacadeList = new ArrayList<>();
669 // // find speciemens in the TaxonDescriptions
670 // List<TaxonDescription> taxonDescriptions = doGetDescriptions(uuid, request, response);
671 // if (taxonDescriptions != null) {
673 // for (TaxonDescription description : taxonDescriptions) {
674 // derivedUnitFacadeList.addAll( occurrenceService.listDerivedUnitFacades(description, null) );
677 // // TODO find specimens in the NameDescriptions ??
679 // // TODO also find type specimens
681 // mv.addObject(derivedUnitFacadeList);
687 * Get the {@link Media} attached to the {@link Taxon} instance
688 * identified by the <code>{taxon-uuid}</code>.
690 * Usage /{datasource-name}/portal/taxon/{taxon-
691 * uuid}/media/{mime type
692 * list}/{size}[,[widthOrDuration}][,{height}]/
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>
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
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 {
729 // logger.info("doGetMedia() " + requestPathAndQuery(request));
731 // List<String> initStrategy = null;
733 // EntityMediaContext<Taxon> taxonMediaContext = loadMediaForTaxonAndRelated(uuid, relationshipUuids,
734 // relationshipInversUuids, includeTaxonDescriptions, includeOccurrences, includeTaxonNameDescriptions,
735 // response, initStrategy, MediaPortalController.MEDIA_INIT_STRATEGY.getPropertyPaths());
737 // List<Media> mediafilteredForPreferredRepresentations = mediaToolbox.processAndFilterPreferredMediaRepresentations(type, mimeTypes, widthOrDuration, height, size,
738 // taxonMediaContext.media);
740 // return mediafilteredForPreferredRepresentations;
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
{
761 logger
.info("doGetMedia() " + requestPathAndQuery(request
));
763 List
<String
> initStrategy
= null;
765 EntityMediaContext
<Taxon
> taxonMediaContext
= loadMediaForTaxonAndRelated(uuid
, relationshipUuids
,
766 relationshipInversUuids
, includeTaxonDescriptions
, includeOccurrences
, includeTaxonNameDescriptions
,
767 response
, initStrategy
, MediaPortalController
.MEDIA_INIT_STRATEGY
.getPropertyPaths());
769 List
<Media
> mediafilteredForPreferredRepresentations
= mediaToolbox
.processAndFilterPreferredMediaRepresentations(
770 type
, mimeTypes
, widthOrDuration
, height
, size
, taxonMediaContext
.media
);
772 return mediafilteredForPreferredRepresentations
;
776 * @Deprecated To be replaced by other loadMediaForTaxonAndRelated method
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);
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
{
794 return loadMediaForTaxonAndRelated(taxonUuid
,
795 relationshipUuids
, relationshipInversUuids
,
796 includeTaxonDescriptions
, includeOccurrences
, false, includeTaxonNameDescriptions
,
797 response
, taxonInitStrategy
, mediaInitStrategy
);
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
{
806 boolean includeUnpublished
= NO_UNPUBLISHED
;
808 Taxon taxon
= getCdmBaseInstance(Taxon
.class, taxonUuid
, response
, taxonInitStrategy
);
809 taxon
= checkExistsAndAccess(taxon
, includeUnpublished
, response
);
811 Set
<TaxonRelationshipEdge
> includeRelationships
= ControllerUtils
.loadIncludeRelationships(relationshipUuids
, relationshipInversUuids
, termService
);
813 List
<Media
> media
= listMediaForTaxon(taxon
, includeRelationships
,
814 includeTaxonDescriptions
, includeOccurrences
, includeTaxonNameDescriptions
, mediaInitStrategy
);
816 EntityMediaContext
<Taxon
> entityMediaContext
= new EntityMediaContext
<>(taxon
, media
);
818 return entityMediaContext
;
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
{
838 boolean includeUnpublished
= NO_UNPUBLISHED
;
840 logger
.info("doGetSubtreeMedia() " + requestPathAndQuery(request
));
842 List
<String
> initStrategy
= TAXON_WITH_CHILDNODES_INIT_STRATEGY
.getPropertyPaths();
844 Taxon taxon
= getCdmBaseInstance(Taxon
.class, uuid
, response
, initStrategy
);
845 taxon
= checkExistsAndAccess(taxon
, includeUnpublished
, response
);
847 Set
<TaxonRelationshipEdge
> includeRelationships
= ControllerUtils
.loadIncludeRelationships(relationshipUuids
, relationshipInversUuids
, termService
);
849 List
<Media
> media
= listMediaForTaxon(taxon
, includeRelationships
,
850 includeTaxonDescriptions
, includeOccurrences
, includeTaxonNameDescriptions
, null);
851 media
= addTaxonomicChildrenMedia(includeTaxonDescriptions
, includeOccurrences
, includeTaxonNameDescriptions
, taxon
,
852 includeRelationships
, media
);
854 List
<Media
> mediafilteredForPreferredRepresentations
= mediaToolbox
.processAndFilterPreferredMediaRepresentations(type
, mimeTypes
, widthOrDuration
, height
, size
,
857 return mediafilteredForPreferredRepresentations
;
860 public List
<Media
> addTaxonomicChildrenMedia(Boolean includeTaxonDescriptions
, Boolean includeOccurrences
,
861 Boolean includeTaxonNameDescriptions
, Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
,
865 //looking for all medias of direct children
867 if (taxon
.getTaxonNodes().size()>0){
868 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
869 Iterator
<TaxonNode
> iterator
= nodes
.iterator();
871 node
= iterator
.next();
872 //Check if TaxonNode belongs to the current tree
874 node
= taxonNodeService
.load(node
.getUuid(), TAXONNODE_WITH_CHILDNODES_INIT_STRATEGY
.getPropertyPaths());
875 List
<TaxonNode
> children
= node
.getChildNodes();
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()));
889 private List
<Media
> listMediaForTaxon(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
,
890 Boolean includeTaxonDescriptions
, Boolean includeOccurrences
, Boolean includeTaxonNameDescriptions
, List
<String
> propertyPath
) {
892 return listMediaForTaxon(taxon
, includeRelationships
, includeTaxonDescriptions
, includeOccurrences
, false, includeTaxonNameDescriptions
, propertyPath
);
895 private List
<Media
> listMediaForTaxon(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
,
896 Boolean includeTaxonDescriptions
, Boolean includeOccurrences
, Boolean includeOriginals
, Boolean includeTaxonNameDescriptions
, List
<String
> propertyPath
) {
898 List
<Media
> media
= service
.listMedia(taxon
, includeRelationships
,
899 false, includeTaxonDescriptions
, includeOccurrences
, includeOriginals
, includeTaxonNameDescriptions
, propertyPath
);
905 public class EntityMediaContext
<T
extends IdentifiableEntity
> {
908 private List
<Media
> media
;
910 public EntityMediaContext(T entity
, List
<Media
> media
) {
911 this.entity
= HibernateProxyHelper
.deproxy(entity
);
915 public T
getEntity() {
918 public List
<Media
> getMedia() {
923 * @param addTaxonomicChildrenMedia
925 public void setMedia(List
<Media
> media
) {
931 // ---------------------- code snippet preserved for possible later use --------------------
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);
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();
945 // if(!featureTree.isDescriptionSeparated()){
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);
954 // List<TaxonDescription> separatedDescriptions = new ArrayList<TaxonDescription>(descriptions.size());
955 // separatedDescriptions.add(superDescription);
956 // return separatedDescriptions;
958 // return descriptions;
961 // response.sendError(HttpServletResponse.SC_NOT_FOUND, "invalid type; Taxon expected but " + tb.getClass().getSimpleName() + " found.");