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.annotationType.$",
153 "annotations.annotationType.includes.$"
154 // "descriptions" // TODO remove
158 public static final EntityInitStrategy TAXON_WITH_CHILDNODES_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
160 "taxonNodes.classification.$",
161 "taxonNodes.childNodes.$"
164 public static final EntityInitStrategy SIMPLE_TAXON_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
168 "name.rank.representations",
169 "name.status.type.representations",
170 "name.status.source.citation",
171 "name.nomenclaturalSource.citation.authorship",
172 "name.nomenclaturalSource.citation.inReference.authorship",
173 "taxonNodes.classification",
174 "secSource.nameUsedInSource.$",
175 "secSource.citation.authorship.$",
176 "secSource.citation.inReference.authorship.$"
179 public static final EntityInitStrategy SYNONYMY_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
180 // initialize homotypical and heterotypical groups; needs synonyms
182 "synonyms.name.status.type.representations",
183 "synonyms.name.status.source.citation",
184 "synonyms.name.nomenclaturalSource.citation.authorship",
185 "synonyms.name.nomenclaturalSource.citation.inReference.authorship",
186 // "synonyms.name.homotypicalGroup.typifiedNames.$",
187 // "synonyms.name.homotypicalGroup.typifiedNames.taxonBases.$",
188 "synonyms.name.combinationAuthorship.$",
189 "synonyms.secSource.citation.authorship.$",
190 "synonyms.secSource.citation.inReference.authorship.$",
191 "synonyms.secSource.nameUsedInSource.$",
192 "name.typeDesignations",
194 "name.homotypicalGroup.$",
195 "name.homotypicalGroup.typifiedNames.$",
196 "name.homotypicalGroup.typifiedNames.nomenclaturalSource.citation.authorship",
197 "name.homotypicalGroup.typifiedNames.nomenclaturalSource.citation.inReference.authorship",
198 "synonyms.annotations.$",
199 "synonyms.annotations.annotationType.$",
200 "synonyms.annotations.annotationType.includes.$"
202 // "name.homotypicalGroup.typifiedNames.taxonBases.$"
206 private static final EntityInitStrategy TAXONRELATIONSHIP_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
208 "type.inverseRepresentations",
215 public static final EntityInitStrategy NAMERELATIONSHIP_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
217 "type.inverseRepresentations",
220 "toName.nomenclaturalSource.citation.authorship",
221 "toName.nomenclaturalSource.citation.inReference.authorship",
223 "fromName.nomenclaturalSource.citation.authorship",
224 "fromName.nomenclaturalSource.citation.inReference.authorship",
228 protected static final EntityInitStrategy TAXONDESCRIPTION_INIT_STRATEGY
= DescriptionPortalController
.DESCRIPTION_INIT_STRATEGY
;
230 protected static final EntityInitStrategy DESCRIPTION_ELEMENT_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
232 "sources.citation.authorship",
233 "sources.citation.inReference.authorship",
234 "sources.nameUsedInSource",
240 // private static final List<String> NAMEDESCRIPTION_INIT_STRATEGY = Arrays.asList(new String []{
244 // "elements.multilanguageText",
248 protected static final EntityInitStrategy TAXONDESCRIPTION_MEDIA_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
253 private static final EntityInitStrategy TYPEDESIGNATION_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
255 "citation.authorship.$",
260 protected static final EntityInitStrategy TAXONNODE_WITH_CHILDNODES_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
264 protected static final EntityInitStrategy TAXONNODE_INIT_STRATEGY
= new EntityInitStrategy(Arrays
.asList(new String
[]{
265 "taxonNodes.classification",
267 "taxonNodes.statusNote.*",
268 "taxonNodes.taxon.name",
269 "taxonNodes.taxon.secSource.citation",
270 "taxonNodes.taxon.secSource.nameUsedInSource.$",
271 "taxonNodes.taxon.secSource.citation.authorship.$",
272 "taxonNodes.taxon.secSource.citation.inReference.authorship.$",
273 "taxonNodes.source.citation.authorship",
274 "taxonNodes.source.citation.inReference.authorship",
275 "acceptedTaxon.taxonNodes.classification",
276 "secSource.nameUsedInSource"
281 protected <CDM_BASE
extends CdmBase
> List
<String
> complementInitStrategy(Class
<CDM_BASE
> clazz
,
282 List
<String
> pathProperties
) {
284 if(pathProperties
!= null) {
285 List
<String
> complemented
= new ArrayList
<>(pathProperties
);
286 if(pathProperties
.contains("name")) {
287 // pathProperties for web service request for portal/taxon/{uuid}/name
288 complemented
.add("name.nomenclaturalSource.citation.authorship");
289 complemented
.add("name.nomenclaturalSource.citation.inReference.authorship");
293 return pathProperties
;
296 public TaxonPortalController(){
298 setInitializationStrategy(TAXON_INIT_STRATEGY
.getPropertyPaths());
303 public void setService(ITaxonService service
) {
304 this.service
= service
;
309 public void initBinder(WebDataBinder binder
) {
310 super.initBinder(binder
);
311 binder
.registerCustomEditor(NamedArea
.class, new NamedAreaPropertyEditor());
312 binder
.registerCustomEditor(MatchMode
.class, new MatchModePropertyEditor());
313 binder
.registerCustomEditor(Class
.class, new CdmTypePropertyEditor());
314 binder
.registerCustomEditor(UuidList
.class, new UUIDListPropertyEditor());
315 binder
.registerCustomEditor(DefinedTermBaseList
.class, new TermBaseListPropertyEditor
<>(termService
));
321 * @param taxonUuid the taxon uuid
322 * @param subtreeUuid the taxon node subtree filter
323 * @throws IOException
327 method
= RequestMethod
.GET
)
329 public TaxonPageDto
doGetTaxonPage(@PathVariable("uuid") UUID taxonUuid
,
330 @RequestParam(value
= "subtree", required
= false) UUID subtreeUuid
,
331 @RequestParam(value
= "featureTree", required
= false) UUID featureTreeUuid
,
332 @RequestParam(value
= "nameRelationsDirect", required
= false) Set
<UUID
> directNameRelations
,
333 @RequestParam(value
= "nameRelationsInverse", required
= false) Set
<UUID
> inverseNameRelations
,
334 @RequestParam(value
= "etAlPos", required
= false) Integer etAlPosition
,
335 @RequestParam(value
= "doSynonyms", required
= false) boolean doSynonyms
,
336 @RequestParam(value
= "doFacts", required
= false) boolean doFacts
,
337 @RequestParam(value
= "doSpecimens", required
= false) boolean doSpecimens
,
338 @RequestParam(value
= "doKeys", required
= false) boolean doKeys
,
339 @RequestParam(value
= "doMedia", required
= false) boolean doMedia
,
340 @RequestParam(value
= "doTaxonNodes", required
= false) boolean doTaxonNodes
,
341 @RequestParam(value
= "doTaxonRelations", required
= false) boolean doTaxonRelations
,
342 //TODO annotation type filter
344 //distributionInfoConfig
345 @RequestParam(value
= "part", required
= false) Set
<InfoPart
> partSet
,
346 @RequestParam(value
= "subAreaPreference", required
= false) boolean preferSubAreas
,
347 @RequestParam(value
= "statusOrderPreference", required
= false) boolean statusOrderPreference
,
348 @RequestParam(value
= "fallbackAreaMarkerType", required
= false) DefinedTermBaseList
<MarkerType
> fallbackAreaMarkerTypeList
,
349 @RequestParam(value
= "alternativeRootAreaMarkerType", required
= false) DefinedTermBaseList
<MarkerType
> alternativeRootAreaMarkerTypeList
,
350 @RequestParam(value
= "areaTree", required
= false ) UUID areaTreeUuid
,
351 //TODO still needs to be used
352 @RequestParam(value
= "statusTree", required
= false ) UUID statusTreeUuid
,
353 @RequestParam(value
= "omitLevels", required
= false) Set
<NamedAreaLevel
> omitLevels
,
354 @RequestParam(value
= "statusColors", required
= false) String statusColorsString
,
355 @RequestParam(value
= "distributionOrder", required
= false, defaultValue
="LABEL") DistributionOrder distributionOrder
,
356 @RequestParam(value
= "recipe", required
= false, defaultValue
="EuroPlusMed") CondensedDistributionRecipe recipe
,
358 //TODO configuration data
359 HttpServletRequest request
,
360 HttpServletResponse response
) throws IOException
{
362 boolean includeUnpublished
= NO_UNPUBLISHED
;
364 logger
.info("doGetTaxonPage() " + requestPathAndQuery(request
));
367 //TODO for now hardcoded
368 alternativeRootAreaMarkerTypeList
= new DefinedTermBaseList
<>();
369 UUID alternativeRootAreaMarkerTypeUuid
= MarkerType
.uuidAlternativeRootArea
;
370 MarkerType defaultAlternativeRootAreaMarkerType
= (MarkerType
)termService
.find(alternativeRootAreaMarkerTypeUuid
);
371 if (defaultAlternativeRootAreaMarkerType
!= null) {
372 alternativeRootAreaMarkerTypeList
.add(defaultAlternativeRootAreaMarkerType
);
376 //TODO is this current state of art?
377 // ModelAndView mv = new ModelAndView();
379 //check taxon exists and not filtered
380 Taxon taxon
= getCdmBaseInstance(Taxon
.class, taxonUuid
, response
, getTaxonNodeInitStrategy().getPropertyPaths());
381 TaxonNode subtree
= getSubtreeOrError(subtreeUuid
, taxonNodeService
, response
);
382 taxon
= checkExistsSubtreeAndAccess(taxon
, subtree
, NO_UNPUBLISHED
, response
);
384 if (partSet
== null) {
385 partSet
= EnumSet
.of(InfoPart
.condensedDistribution
, InfoPart
.mapUriParams
, InfoPart
.tree
);
387 partSet
.remove(InfoPart
.elements
); // we do not want to return model instances here at all
389 // //TODO is this performant?
390 // IVocabularyService vocabularyService = null;
391 // Map<PresenceAbsenceTerm, Color> distributionStatusColors = DistributionServiceUtilities.buildStatusColorMap(
392 // statusColorsString, termService, vocabularyService);
394 TaxonPageDtoConfiguration config
= new TaxonPageDtoConfiguration();
396 config
.setTaxonUuid(taxonUuid
);
397 config
.setFeatureTree(featureTreeUuid
);
398 config
.setEtAlPosition(etAlPosition
);
399 config
.setWithFacts(doFacts
);
400 config
.setWithKeys(doKeys
);
401 config
.setWithMedia(doMedia
);
402 config
.setWithSpecimens(doSpecimens
);
403 config
.setWithSynonyms(doSynonyms
);
404 config
.setWithTaxonNodes(doTaxonNodes
);
405 config
.setWithTaxonRelationships(doTaxonRelations
);
406 config
.setIncludeUnpublished(includeUnpublished
);
408 Set
<MarkerType
> fallbackAreaMarkerTypes
= new HashSet
<>();
409 if(!CdmUtils
.isNullSafeEmpty(fallbackAreaMarkerTypeList
)){
410 fallbackAreaMarkerTypes
= fallbackAreaMarkerTypeList
.asSet();
412 Set
<MarkerType
> alternativeRootAreaMarkerTypes
= new HashSet
<>();
413 if(!CdmUtils
.isNullSafeEmpty(alternativeRootAreaMarkerTypeList
)){
414 alternativeRootAreaMarkerTypes
= alternativeRootAreaMarkerTypeList
.asSet();
417 //default distribution info config
418 DistributionInfoConfiguration distributionConfig
= config
.getDistributionInfoConfiguration();
419 distributionConfig
.setIncludeUnpublished(includeUnpublished
);
420 distributionConfig
.setUseTreeDto(true);
421 distributionConfig
.setInfoParts(EnumSet
.copyOf(partSet
));
422 distributionConfig
.setPreferSubAreas(preferSubAreas
);
423 distributionConfig
.setStatusOrderPreference(statusOrderPreference
);
424 distributionConfig
.setAreaTree(areaTreeUuid
);
425 distributionConfig
.setStatusTree(statusTreeUuid
);
426 distributionConfig
.setOmitLevels(omitLevels
);
427 distributionConfig
.setStatusColorsString(statusColorsString
);
428 distributionConfig
.setDistributionOrder(distributionOrder
);
429 if (recipe
!= null) {
430 CondensedDistributionConfiguration condensedConfig
= recipe
.toConfiguration();
431 condensedConfig
.alternativeRootAreaMarkers
= getUuids(alternativeRootAreaMarkerTypes
);
432 distributionConfig
.setCondensedDistributionConfiguration(condensedConfig
);
434 distributionConfig
.setFallbackAreaMarkerTypeList(fallbackAreaMarkerTypes
); //was (remove if current implementation works): fallbackAreaMarkerTypes.stream().map(mt->mt.getUuid()).collect(Collectors.toSet());
435 distributionConfig
.setAlternativeRootAreaMarkerTypes(alternativeRootAreaMarkerTypes
);
437 //iucn distribution info config
438 DistributionInfoConfiguration iucnDistributionConfig
= new DistributionInfoConfiguration();
439 iucnDistributionConfig
.setIncludeUnpublished(includeUnpublished
);
440 config
.putDistributionInfoConfiguration(Feature
.uuidIucnStatus
, iucnDistributionConfig
);
441 iucnDistributionConfig
.setUseTreeDto(true);
442 EnumSet
<InfoPart
> iucnPartSet
= EnumSet
.of(InfoPart
.condensedDistribution
);
443 iucnDistributionConfig
.setInfoParts(iucnPartSet
);
445 iucnDistributionConfig
.setPreferSubAreas(preferSubAreas
);
446 iucnDistributionConfig
.setStatusOrderPreference(statusOrderPreference
);
447 iucnDistributionConfig
.setAreaTree(areaTreeUuid
);
448 //TODO IUCN status tree?
449 iucnDistributionConfig
.setOmitLevels(omitLevels
);
450 // distributionConfig.setStatusColorsString(statusColorsString);
451 iucnDistributionConfig
.setDistributionOrder(distributionOrder
);
452 CondensedDistributionRecipe iucnRecipe
= CondensedDistributionRecipe
.IUCN
;
453 if (iucnRecipe
!= null) {
454 CondensedDistributionConfiguration condensedConfig
= iucnRecipe
.toConfiguration();
455 condensedConfig
.alternativeRootAreaMarkers
= getUuids(alternativeRootAreaMarkerTypes
);
456 iucnDistributionConfig
.setCondensedDistributionConfiguration(condensedConfig
);
458 iucnDistributionConfig
.setFallbackAreaMarkerTypeList(fallbackAreaMarkerTypes
);
459 iucnDistributionConfig
.setAlternativeRootAreaMarkerTypes(alternativeRootAreaMarkerTypes
);
461 TaxonPageDto dto
= portalDtoService
.taxonPageDto(config
);
465 private Set
<UUID
> getUuids(Set
<?
extends CdmBase
> entities
) {
466 return entities
.stream().map(e
->e
.getUuid()).collect(Collectors
.toSet());
470 * Get the synonymy for a taxon identified by the <code>{taxon-uuid}</code>.
471 * The synonymy consists
472 * of two parts: The group of homotypic synonyms of the taxon and the
473 * heterotypic synonymy groups of the taxon. The synonymy is ordered
474 * historically by the type designations and by the publication date of the
475 * nomenclatural reference
478 * <b>/{datasource-name}/portal/taxon/{taxon-uuid}/synonymy</b>
483 * @return a Map with two entries which are mapped by the following keys:
484 * "homotypicSynonymsByHomotypicGroup", "heterotypicSynonymyGroups",
485 * containing lists of {@link Synonym}s which // TODO Auto-generated catch block
486 e.printStackTrace();are initialized using the
487 * following initialization strategy: {@link #SYNONYMY_INIT_STRATEGY}
489 * @throws IOException
492 value
= {"synonymy"},
493 method
= RequestMethod
.GET
)
494 public ModelAndView
doGetSynonymy(@PathVariable("uuid") UUID taxonUuid
,
495 @RequestParam(value
= "subtree", required
= false) UUID subtreeUuid
,
496 HttpServletRequest request
,
497 HttpServletResponse response
)throws IOException
{
499 boolean includeUnpublished
= NO_UNPUBLISHED
;
501 logger
.info("doGetSynonymy() " + requestPathAndQuery(request
));
503 ModelAndView mv
= new ModelAndView();
505 Taxon taxon
= getCdmBaseInstance(Taxon
.class, taxonUuid
, response
, getTaxonNodeInitStrategy().getPropertyPaths());
506 TaxonNode subtree
= getSubtreeOrError(subtreeUuid
, taxonNodeService
, response
);
507 taxon
= checkExistsSubtreeAndAccess(taxon
, subtree
, NO_UNPUBLISHED
, response
);
509 Map
<String
, List
<?
>> synonymy
= new Hashtable
<>();
512 List
<List
<Synonym
>> synonymyGroups
= service
.getSynonymsByHomotypicGroup(taxon
, SYNONYMY_INIT_STRATEGY
.getPropertyPaths());
513 if(!includeUnpublished
){
514 synonymyGroups
= removeUnpublishedSynonyms(synonymyGroups
);
517 synonymy
.put("homotypicSynonymsByHomotypicGroup", synonymyGroups
.get(0));
518 synonymyGroups
.remove(0);
519 synonymy
.put("heterotypicSynonymyGroups", synonymyGroups
);
522 // synonymy.put("homotypicSynonymsByHomotypicGroup", service.getHomotypicSynonymsByHomotypicGroup(taxon, SYNONYMY_INIT_STRATEGY));
523 // synonymy.put("heterotypicSynonymyGroups", service.getHeterotypicSynonymyGroups(taxon, SYNONYMY_INIT_STRATEGY));
525 mv
.addObject(synonymy
);
531 * @param synonymyGroups
533 private List
<List
<Synonym
>> removeUnpublishedSynonyms(List
<List
<Synonym
>> synonymyGroups
) {
534 List
<List
<Synonym
>> result
= new ArrayList
<>();
535 boolean isHomotypicToAccepted
= true;
537 for (List
<Synonym
> oldList
: synonymyGroups
){
538 List
<Synonym
> newList
= new ArrayList
<>();
539 for (Synonym oldSyn
: oldList
){
540 if (oldSyn
.isPublish()){
544 if (isHomotypicToAccepted
|| !newList
.isEmpty()){
547 isHomotypicToAccepted
= false;
556 protected List
<String
> getTaxonDescriptionInitStrategy() {
557 return TAXONDESCRIPTION_INIT_STRATEGY
.getPropertyPaths();
561 protected List
<String
> getTaxonDescriptionElementInitStrategy() {
562 return DESCRIPTION_ELEMENT_INIT_STRATEGY
.getPropertyPaths();
566 protected EntityInitStrategy
getTaxonNodeInitStrategy() {
567 return TAXONNODE_INIT_STRATEGY
;
571 * Get the list of {@link TaxonRelationship}s for the given
572 * {@link TaxonBase} instance identified by the <code>{taxon-uuid}</code>.
574 * URI: <b>/{datasource-name}/portal/taxon/{taxon-uuid}/taxonRelationships</b>
578 * @return a List of {@link TaxonRelationship} entities which are initialized
579 * using the following initialization strategy:
580 * {@link #TAXONRELATIONSHIP_INIT_STRATEGY}
581 * @throws IOException
584 value
= {"taxonRelationships"},
585 method
= RequestMethod
.GET
)
586 public List
<TaxonRelationship
> doGetTaxonRelations(@PathVariable("uuid") UUID uuid
,
587 HttpServletRequest request
, HttpServletResponse response
)throws IOException
{
589 boolean includeUnpublished
= NO_UNPUBLISHED
;
590 logger
.info("doGetTaxonRelations()" + requestPathAndQuery(request
));
591 Taxon taxon
= getCdmBaseInstance(Taxon
.class, uuid
, response
, (List
<String
>)null);
592 taxon
= checkExistsAndAccess(taxon
, includeUnpublished
, response
);
594 List
<TaxonRelationship
> toRelationships
= service
.listToTaxonRelationships(taxon
, null,
595 includeUnpublished
, null, null, null, TAXONRELATIONSHIP_INIT_STRATEGY
.getPropertyPaths());
596 List
<TaxonRelationship
> fromRelationships
= service
.listFromTaxonRelationships(taxon
, null,
597 includeUnpublished
, null, null, null, TAXONRELATIONSHIP_INIT_STRATEGY
.getPropertyPaths());
599 List
<TaxonRelationship
> allRelationships
= new ArrayList
<>(toRelationships
.size() + fromRelationships
.size());
600 allRelationships
.addAll(toRelationships
);
601 allRelationships
.addAll(fromRelationships
);
603 return allRelationships
;
607 * Get the list of {@link NameRelationship}s of the Name associated with the
608 * {@link TaxonBase} instance identified by the <code>{taxon-uuid}</code>.
610 * URI: <b>/{datasource-name}/portal/taxon/{taxon-uuid}/nameRelationships</b>
614 * @return a List of {@link NameRelationship} entities which are initialized
615 * using the following initialization strategy:
616 * {@link #NAMERELATIONSHIP_INIT_STRATEGY}
617 * @throws IOException
620 value
= {"toNameRelationships"},
621 method
= RequestMethod
.GET
)
622 public List
<NameRelationship
> doGetToNameRelations(@PathVariable("uuid") UUID uuid
,
623 HttpServletRequest request
, HttpServletResponse response
)throws IOException
{
624 logger
.info("doGetNameRelations()" + request
.getRequestURI());
625 boolean includeUnpublished
= NO_UNPUBLISHED
;
627 TaxonBase
<?
> taxonBase
= getCdmBaseInstance(TaxonBase
.class, uuid
, response
, (List
<String
>)null);
628 taxonBase
= checkExistsAndAccess(taxonBase
, includeUnpublished
, response
);
630 List
<NameRelationship
> list
= nameService
.listNameRelationships(taxonBase
.getName(), Direction
.relatedTo
, null, null, 0, null, NAMERELATIONSHIP_INIT_STRATEGY
.getPropertyPaths());
635 * Get the list of {@link NameRelationship}s of the Name associated with the
636 * {@link TaxonBase} instance identified by the <code>{taxon-uuid}</code>.
638 * URI: <b>/{datasource-name}/portal/taxon/{taxon-uuid}/nameRelationships</b>
642 * @return a List of {@link NameRelationship} entities which are initialized
643 * using the following initialization strategy:
644 * {@link #NAMERELATIONSHIP_INIT_STRATEGY}
645 * @throws IOException
648 value
= {"fromNameRelationships"},
649 method
= RequestMethod
.GET
)
650 public List
<NameRelationship
> doGetFromNameRelations(
651 @PathVariable("uuid") UUID uuid
,
652 HttpServletRequest request
,
653 HttpServletResponse response
)throws IOException
{
654 logger
.info("doGetNameFromNameRelations()" + requestPathAndQuery(request
));
656 boolean includeUnpublished
= NO_UNPUBLISHED
;
658 TaxonBase
<?
> taxonBase
= getCdmBaseInstance(TaxonBase
.class, uuid
, response
, SIMPLE_TAXON_INIT_STRATEGY
.getPropertyPaths());
659 taxonBase
= checkExistsAndAccess(taxonBase
, includeUnpublished
, response
);
661 List
<NameRelationship
> list
= nameService
.listNameRelationships(taxonBase
.getName(), Direction
.relatedFrom
, null, null, 0, null, NAMERELATIONSHIP_INIT_STRATEGY
.getPropertyPaths());
667 // @RequestMapping(value = "specimens", method = RequestMethod.GET)
668 // public ModelAndView doGetSpecimens(
669 // @PathVariable("uuid") UUID uuid,
670 // HttpServletRequest request,
671 // HttpServletResponse response) throws IOException, ClassNotFoundException {
672 // logger.info("doGetSpecimens() - " + request.getRequestURI());
674 // ModelAndView mv = new ModelAndView();
676 // List<DerivedUnitFacade> derivedUnitFacadeList = new ArrayList<>();
678 // // find speciemens in the TaxonDescriptions
679 // List<TaxonDescription> taxonDescriptions = doGetDescriptions(uuid, request, response);
680 // if (taxonDescriptions != null) {
682 // for (TaxonDescription description : taxonDescriptions) {
683 // derivedUnitFacadeList.addAll( occurrenceService.listDerivedUnitFacades(description, null) );
686 // // TODO find specimens in the NameDescriptions ??
688 // // TODO also find type specimens
690 // mv.addObject(derivedUnitFacadeList);
696 * Get the {@link Media} attached to the {@link Taxon} instance
697 * identified by the <code>{taxon-uuid}</code>.
699 * Usage /{datasource-name}/portal/taxon/{taxon-
700 * uuid}/media/{mime type
701 * list}/{size}[,[widthOrDuration}][,{height}]/
705 * <li><b>{mime type list}</b>: a comma separated list of mime types, in the
706 * order of preference. The forward slashes contained in the mime types must
707 * be replaced by a colon. Regular expressions can be used. Each media
708 * associated with this given taxon is being searched whereas the first
709 * matching mime type matching a representation always rules.</li>
710 * <li><b>{size},{widthOrDuration},{height}</b>: <i>not jet implemented</i>
711 * valid values are an integer or the asterisk '*' as a wildcard</li>
716 * @return a List of {@link Media} entities which are initialized
717 * using the following initialization strategy:
718 * {@link #TAXONDESCRIPTION_INIT_STRATEGY}
719 * @throws IOException
722 // value = {"media"},
723 // method = RequestMethod.GET)
724 // public List<Media> doGetMedia(
725 // @PathVariable("uuid") UUID uuid,
726 // @RequestParam(value = "type", required = false) Class<? extends MediaRepresentationPart> type,
727 // @RequestParam(value = "mimeTypes", required = false) String[] mimeTypes,
728 // @RequestParam(value = "relationships", required = false) UuidList relationshipUuids,
729 // @RequestParam(value = "relationshipsInvers", required = false) UuidList relationshipInversUuids,
730 // @RequestParam(value = "includeTaxonDescriptions", required = true) Boolean includeTaxonDescriptions,
731 // @RequestParam(value = "includeOccurrences", required = true) Boolean includeOccurrences,
732 // @RequestParam(value = "includeTaxonNameDescriptions", required = true) Boolean includeTaxonNameDescriptions,
733 // @RequestParam(value = "widthOrDuration", required = false) Integer widthOrDuration,
734 // @RequestParam(value = "height", required = false) Integer height,
735 // @RequestParam(value = "size", required = false) Integer size,
736 // HttpServletRequest request, HttpServletResponse response) throws IOException {
738 // logger.info("doGetMedia() " + requestPathAndQuery(request));
740 // List<String> initStrategy = null;
742 // EntityMediaContext<Taxon> taxonMediaContext = loadMediaForTaxonAndRelated(uuid, relationshipUuids,
743 // relationshipInversUuids, includeTaxonDescriptions, includeOccurrences, includeTaxonNameDescriptions,
744 // response, initStrategy, MediaPortalController.MEDIA_INIT_STRATEGY.getPropertyPaths());
746 // List<Media> mediafilteredForPreferredRepresentations = mediaToolbox.processAndFilterPreferredMediaRepresentations(type, mimeTypes, widthOrDuration, height, size,
747 // taxonMediaContext.media);
749 // return mediafilteredForPreferredRepresentations;
754 method
= RequestMethod
.GET
)
755 public List
<Media
> doGetMedia(
756 @PathVariable("uuid") UUID uuid
,
757 @RequestParam(value
= "type", required
= false) Class
<?
extends MediaRepresentationPart
> type
,
758 @RequestParam(value
= "mimeTypes", required
= false) String
[] mimeTypes
,
759 @RequestParam(value
= "relationships", required
= false) UuidList relationshipUuids
,
760 @RequestParam(value
= "relationshipsInvers", required
= false) UuidList relationshipInversUuids
,
761 @RequestParam(value
= "includeTaxonDescriptions", required
= true) Boolean includeTaxonDescriptions
,
762 @RequestParam(value
= "includeOccurrences", required
= true) Boolean includeOccurrences
,
763 @RequestParam(value
= "includeOriginals", required
= false) Boolean includeOriginals
,
764 @RequestParam(value
= "includeTaxonNameDescriptions", required
= true) Boolean includeTaxonNameDescriptions
,
765 @RequestParam(value
= "widthOrDuration", required
= false) Integer widthOrDuration
,
766 @RequestParam(value
= "height", required
= false) Integer height
,
767 @RequestParam(value
= "size", required
= false) Integer size
,
768 HttpServletRequest request
, HttpServletResponse response
) throws IOException
{
770 logger
.info("doGetMedia() " + requestPathAndQuery(request
));
772 List
<String
> initStrategy
= null;
774 EntityMediaContext
<Taxon
> taxonMediaContext
= loadMediaForTaxonAndRelated(uuid
, relationshipUuids
,
775 relationshipInversUuids
, includeTaxonDescriptions
, includeOccurrences
, includeTaxonNameDescriptions
,
776 response
, initStrategy
, MediaPortalController
.MEDIA_INIT_STRATEGY
.getPropertyPaths());
778 List
<Media
> mediafilteredForPreferredRepresentations
= mediaToolbox
.processAndFilterPreferredMediaRepresentations(
779 type
, mimeTypes
, widthOrDuration
, height
, size
, taxonMediaContext
.media
);
781 return mediafilteredForPreferredRepresentations
;
785 * @Deprecated To be replaced by other loadMediaForTaxonAndRelated method
788 public EntityMediaContext
<Taxon
> loadMediaForTaxonAndRelated(UUID uuid
,
789 UuidList relationshipUuids
, UuidList relationshipInversUuids
,
790 Boolean includeTaxonDescriptions
, Boolean includeOccurrences
, Boolean includeTaxonNameDescriptions
,
791 HttpServletResponse response
,
792 List
<String
> taxonInitStrategy
) throws IOException
{
793 return loadMediaForTaxonAndRelated(uuid
, relationshipUuids
, relationshipInversUuids
,
794 includeTaxonDescriptions
, includeOccurrences
, includeTaxonNameDescriptions
, response
, taxonInitStrategy
, null);
797 public EntityMediaContext
<Taxon
> loadMediaForTaxonAndRelated(UUID taxonUuid
,
798 UuidList relationshipUuids
, UuidList relationshipInversUuids
,
799 Boolean includeTaxonDescriptions
, Boolean includeOccurrences
, Boolean includeTaxonNameDescriptions
,
800 HttpServletResponse response
,
801 List
<String
> taxonInitStrategy
, List
<String
> mediaInitStrategy
) throws IOException
{
803 return loadMediaForTaxonAndRelated(taxonUuid
,
804 relationshipUuids
, relationshipInversUuids
,
805 includeTaxonDescriptions
, includeOccurrences
, false, includeTaxonNameDescriptions
,
806 response
, taxonInitStrategy
, mediaInitStrategy
);
809 public EntityMediaContext
<Taxon
> loadMediaForTaxonAndRelated(UUID taxonUuid
,
810 UuidList relationshipUuids
, UuidList relationshipInversUuids
,
811 Boolean includeTaxonDescriptions
, Boolean includeOccurrences
, Boolean includeOriginals
, Boolean includeTaxonNameDescriptions
,
812 HttpServletResponse response
,
813 List
<String
> taxonInitStrategy
, List
<String
> mediaInitStrategy
) throws IOException
{
815 boolean includeUnpublished
= NO_UNPUBLISHED
;
817 Taxon taxon
= getCdmBaseInstance(Taxon
.class, taxonUuid
, response
, taxonInitStrategy
);
818 taxon
= checkExistsAndAccess(taxon
, includeUnpublished
, response
);
820 Set
<TaxonRelationshipEdge
> includeRelationships
= ControllerUtils
.loadIncludeRelationships(relationshipUuids
, relationshipInversUuids
, termService
);
822 List
<Media
> media
= listMediaForTaxon(taxon
, includeRelationships
,
823 includeTaxonDescriptions
, includeOccurrences
, includeOriginals
, includeTaxonNameDescriptions
, includeUnpublished
, mediaInitStrategy
);
825 EntityMediaContext
<Taxon
> entityMediaContext
= new EntityMediaContext
<>(taxon
, media
);
827 return entityMediaContext
;
831 value
= {"subtree/media"},
832 method
= RequestMethod
.GET
)
833 public List
<Media
> doGetSubtreeMedia(
834 @PathVariable("uuid") UUID uuid
,
835 @RequestParam(value
= "type", required
= false) Class
<?
extends MediaRepresentationPart
> type
,
836 @RequestParam(value
= "mimeTypes", required
= false) String
[] mimeTypes
,
837 @RequestParam(value
= "relationships", required
= false) UuidList relationshipUuids
,
838 @RequestParam(value
= "relationshipsInvers", required
= false) UuidList relationshipInversUuids
,
839 @RequestParam(value
= "includeTaxonDescriptions", required
= true) Boolean includeTaxonDescriptions
,
840 @RequestParam(value
= "includeOccurrences", required
= true) Boolean includeOccurrences
,
841 @RequestParam(value
= "includeTaxonNameDescriptions", required
= true) Boolean includeTaxonNameDescriptions
,
842 @RequestParam(value
= "widthOrDuration", required
= false) Integer widthOrDuration
,
843 @RequestParam(value
= "height", required
= false) Integer height
,
844 @RequestParam(value
= "size", required
= false) Integer size
,
845 HttpServletRequest request
, HttpServletResponse response
)throws IOException
{
847 boolean includeUnpublished
= NO_UNPUBLISHED
;
849 logger
.info("doGetSubtreeMedia() " + requestPathAndQuery(request
));
851 List
<String
> initStrategy
= TAXON_WITH_CHILDNODES_INIT_STRATEGY
.getPropertyPaths();
853 Taxon taxon
= getCdmBaseInstance(Taxon
.class, uuid
, response
, initStrategy
);
854 taxon
= checkExistsAndAccess(taxon
, includeUnpublished
, response
);
856 Set
<TaxonRelationshipEdge
> includeRelationships
= ControllerUtils
.loadIncludeRelationships(relationshipUuids
, relationshipInversUuids
, termService
);
858 boolean includeOriginals
= false; //or when unifying methods, do we want this as webservice parameter, too?
859 List
<Media
> media
= listMediaForTaxon(taxon
, includeRelationships
,
860 includeTaxonDescriptions
, includeOccurrences
, includeOriginals
, includeTaxonNameDescriptions
, includeUnpublished
, null);
861 media
= addTaxonomicChildrenMedia(includeTaxonDescriptions
, includeOccurrences
, includeOriginals
,
862 includeTaxonNameDescriptions
, taxon
,
863 includeRelationships
, media
, includeUnpublished
);
865 List
<Media
> mediafilteredForPreferredRepresentations
= mediaToolbox
.processAndFilterPreferredMediaRepresentations(type
, mimeTypes
, widthOrDuration
, height
, size
,
868 return mediafilteredForPreferredRepresentations
;
871 public List
<Media
> addTaxonomicChildrenMedia(Boolean includeTaxonDescriptions
, Boolean includeOccurrences
,
872 boolean includeOriginals
, Boolean includeTaxonNameDescriptions
, Taxon taxon
,
873 Set
<TaxonRelationshipEdge
> includeRelationships
, List
<Media
> media
, boolean includeUnpublished
) {
876 //looking for all medias of direct children
878 if (taxon
.getTaxonNodes().size()>0){
879 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
880 Iterator
<TaxonNode
> iterator
= nodes
.iterator();
882 node
= iterator
.next();
883 //Check if TaxonNode belongs to the current tree
885 node
= taxonNodeService
.load(node
.getUuid(), TAXONNODE_WITH_CHILDNODES_INIT_STRATEGY
.getPropertyPaths());
886 List
<TaxonNode
> children
= node
.getChildNodes();
888 for (TaxonNode child
: children
){
889 childTaxon
= child
.getTaxon();
890 if(childTaxon
!= null) {
891 childTaxon
= (Taxon
)taxonService
.load(childTaxon
.getUuid(), NO_UNPUBLISHED
, null);
892 media
.addAll(listMediaForTaxon(childTaxon
, includeRelationships
,
893 includeTaxonDescriptions
, includeOccurrences
, includeOriginals
,
894 includeTaxonNameDescriptions
, includeUnpublished
, MediaPortalController
.MEDIA_INIT_STRATEGY
.getPropertyPaths()));
901 private List
<Media
> listMediaForTaxon(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
,
902 Boolean includeTaxonDescriptions
, Boolean includeOccurrences
, Boolean includeOriginals
,
903 Boolean includeTaxonNameDescriptions
, boolean includeUnpublished
, List
<String
> propertyPath
) {
905 List
<Media
> media
= service
.listMedia(taxon
, includeRelationships
,
906 false, includeTaxonDescriptions
, includeOccurrences
, includeOriginals
,
907 includeTaxonNameDescriptions
, includeUnpublished
, propertyPath
);
912 public class EntityMediaContext
<T
extends IdentifiableEntity
> {
915 private List
<Media
> media
;
917 public EntityMediaContext(T entity
, List
<Media
> media
) {
918 this.entity
= HibernateProxyHelper
.deproxy(entity
);
922 public T
getEntity() {
925 public List
<Media
> getMedia() {
930 * @param addTaxonomicChildrenMedia
932 public void setMedia(List
<Media
> media
) {
938 // ---------------------- code snippet preserved for possible later use --------------------
940 // value = {"//*/portal/taxon/*/descriptions"}, // mapped as absolute path, see CdmAntPathMatcher
941 // method = RequestMethod.GET)
942 // public List<TaxonDescription> doGetDescriptionsbyFeatureTree(HttpServletRequest request, HttpServletResponse response)throws IOException {
943 // TaxonBase tb = getCdmBase(request, response, null, Taxon.class);
944 // if(tb instanceof Taxon){
945 // //T O D O this is a quick and dirty implementation -> generalize
946 // UUID featureTreeUuid = readValueUuid(request, termTreeUuidPattern);
948 // FeatureTree featureTree = descriptionService.getFeatureTreeByUuid(featureTreeUuid);
949 // Pager<TaxonDescription> p = descriptionService.getTaxonDescriptions((Taxon)tb, null, null, null, null, TAXONDESCRIPTION_INIT_STRATEGY);
950 // List<TaxonDescription> descriptions = p.getRecords();
952 // if(!featureTree.isDescriptionSeparated()){
954 // TaxonDescription superDescription = TaxonDescription.NewInstance();
955 // //put all descriptionElements in superDescription and make it invisible
956 // for(TaxonDescription description: descriptions){
957 // for(DescriptionElementBase element: description.getElements()){
958 // superDescription.addElement(element);
961 // List<TaxonDescription> separatedDescriptions = new ArrayList<TaxonDescription>(descriptions.size());
962 // separatedDescriptions.add(superDescription);
963 // return separatedDescriptions;
965 // return descriptions;
968 // response.sendError(HttpServletResponse.SC_NOT_FOUND, "invalid type; Taxon expected but " + tb.getClass().getSimpleName() + " found.");