2 * Copyright (C) 2023 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
.api
.service
.portal
;
11 import java
.time
.LocalDateTime
;
12 import java
.util
.ArrayList
;
13 import java
.util
.Arrays
;
14 import java
.util
.EnumSet
;
15 import java
.util
.HashSet
;
16 import java
.util
.List
;
18 import java
.util
.UUID
;
19 import java
.util
.stream
.Collectors
;
21 import org
.apache
.logging
.log4j
.LogManager
;
22 import org
.apache
.logging
.log4j
.Logger
;
23 import org
.joda
.time
.DateTime
;
25 import eu
.etaxonomy
.cdm
.api
.application
.ICdmRepository
;
26 import eu
.etaxonomy
.cdm
.api
.dto
.SpecimenOrObservationBaseDTO
;
27 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.ContainerDto
;
28 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.MessagesDto
;
29 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.OccurrenceInfoDto
;
30 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonBaseDto
;
31 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonBaseDto
.TaxonNameDto
;
32 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
;
33 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.ConceptRelationDTO
;
34 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.HomotypicGroupDTO
;
35 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.KeyDTO
;
36 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.MediaDTO
;
37 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.MediaRepresentationDTO
;
38 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.NameRelationDTO
;
39 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.SpecimenDTO
;
40 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.TaxonNodeAgentsRelDTO
;
41 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.TaxonNodeDTO
;
42 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.config
.TaxonPageDtoConfiguration
;
43 import eu
.etaxonomy
.cdm
.api
.filter
.TaxonOccurrenceRelationType
;
44 import eu
.etaxonomy
.cdm
.api
.service
.dto
.DtoUtil
;
45 import eu
.etaxonomy
.cdm
.api
.service
.geo
.IGeoServiceAreaMapping
;
46 import eu
.etaxonomy
.cdm
.api
.service
.name
.TypeDesignationSetContainer
;
47 import eu
.etaxonomy
.cdm
.api
.service
.name
.TypeDesignationSetFormatter
;
48 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
49 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
50 import eu
.etaxonomy
.cdm
.compare
.taxon
.TaxonComparator
;
51 import eu
.etaxonomy
.cdm
.format
.taxon
.TaxonRelationshipFormatter
;
52 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
53 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
54 import eu
.etaxonomy
.cdm
.model
.common
.VersionableEntity
;
55 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
56 import eu
.etaxonomy
.cdm
.model
.description
.IndividualsAssociation
;
57 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKey
;
58 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
59 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
60 import eu
.etaxonomy
.cdm
.model
.media
.ExternalLink
;
61 import eu
.etaxonomy
.cdm
.model
.media
.ImageFile
;
62 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
63 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
64 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentationPart
;
65 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
66 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationship
;
67 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationshipType
;
68 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalSource
;
69 import eu
.etaxonomy
.cdm
.model
.name
.SpecimenTypeDesignation
;
70 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
71 import eu
.etaxonomy
.cdm
.model
.name
.TypeDesignationBase
;
72 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
73 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
74 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
75 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
76 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
77 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
78 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
79 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNodeAgentRelation
;
80 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNodeStatus
;
81 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
82 import eu
.etaxonomy
.cdm
.model
.term
.Representation
;
83 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
84 import eu
.etaxonomy
.cdm
.strategy
.cache
.TaggedText
;
85 import eu
.etaxonomy
.cdm
.strategy
.cache
.TaggedTextFormatter
;
86 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.INameCacheStrategy
;
87 import eu
.etaxonomy
.cdm
.strategy
.cache
.taxon
.TaxonBaseDefaultCacheStrategy
;
90 * Loads the portal dto from a taxon instance.
91 * Maybe later also supports loading from persistence.
96 public class PortalDtoLoader
extends PortalDtoLoaderBase
{
98 @SuppressWarnings("unused")
99 private static final Logger logger
= LogManager
.getLogger();
101 private PortalDtoFactLoader_Old factLoader
;
103 public PortalDtoLoader(ICdmRepository repository
, ICdmGenericDao dao
, IGeoServiceAreaMapping areaMapping
) {
104 super(repository
, dao
);
105 this.factLoader
= new PortalDtoFactLoader_Old(repository
, dao
, areaMapping
);
108 //TODO can we handle the area mapping better?
109 public TaxonPageDto
load(Taxon taxon
, TaxonPageDtoConfiguration config
) {
110 TaxonPageDto result
= new TaxonPageDto();
112 loadAcceptedTaxon(taxon
, config
, result
);
114 loadTaxonNodes(taxon
, result
, config
);
115 loadSynonyms(taxon
, result
, config
);
116 loadConceptRelations(taxon
, result
, config
);
117 loadFacts(taxon
, result
, config
);
118 loadMedia(taxon
, result
, config
);
119 loadSpecimens(taxon
, result
, config
);
120 loadKeys(taxon
, result
, config
);
125 private void loadAcceptedTaxon(Taxon taxon
, TaxonPageDtoConfiguration config
, TaxonPageDto result
) {
127 TaxonName name
= taxon
.getName();
130 //TODO supplementalData for name
131 loadBaseData(taxon
, result
);
132 result
.setLastUpdated(getLastUpdated(null, taxon
));
133 result
.setLabel(CdmUtils
.Nz(taxon
.getTitleCache()));
134 // result.setTypedTaxonLabel(getTypedTaxonLabel(taxon, config));
135 result
.setTaggedLabel(getTaggedTaxon(taxon
, config
));
137 handleName(config
, result
, name
, result
);
139 if (taxon
.getSec() != null) {
140 result
.setSecTitleCache(taxon
.getSec().getTitleCache());
142 } catch (Exception e
) {
143 //e.printStackTrace();
144 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading accepted name data.", e
));
148 private void handleName(TaxonPageDtoConfiguration config
, TaxonBaseDto taxonDto
, TaxonName name
, TaxonPageDto pageDto
) {
149 TaxonNameDto nameDto
= taxonDto
.new TaxonNameDto();
150 loadBaseData(name
, nameDto
);
152 INameCacheStrategy formatter
= name
.cacheStrategy();
153 formatter
.setEtAlPosition(config
.getEtAlPosition());
155 taxonDto
.setName(nameDto
);
156 taxonDto
.setNameLabel(formatter
.getTitleCache(name
));
157 handleRelatedNames(name
, taxonDto
, config
);
158 loadProtologues(name
, taxonDto
);
159 taxonDto
.setNameUuid(name
.getUuid());
160 taxonDto
.setNameType(name
.getNameType().toString());
161 loadNameFacts(name
, taxonDto
, config
, pageDto
);
162 nameDto
.setTaggedName(formatter
.getTaggedFullTitle(name
));
165 private List
<TaggedText
> getTaggedTaxon(TaxonBase
<?
> taxon
, TaxonPageDtoConfiguration config
) {
166 // List<TypedLabel> result = new ArrayList<>();
167 TaxonBaseDefaultCacheStrategy
<TaxonBase
<?
>> formatter
= new TaxonBaseDefaultCacheStrategy
<>();
168 List
<TaggedText
> tags
= formatter
.getTaggedTitle(taxon
);
172 private void loadKeys(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
173 if (!config
.isWithKeys()){
177 ContainerDto
<KeyDTO
> container
= new ContainerDto
<>();
179 //TODO other key types, but type must not be null, otherwise NPE
180 Pager
<PolytomousKey
> keys
= repository
.getIdentificationKeyService().findKeysConvering(taxon
, PolytomousKey
.class, null, null, null);
181 for (PolytomousKey key
: keys
.getRecords()) {
182 KeyDTO dto
= new KeyDTO();
183 loadBaseData(key
, dto
);
184 dto
.setLabel(key
.getTitleCache());
185 dto
.setKeyClass(key
.getClass().getSimpleName());
186 container
.addItem(dto
);
188 if (container
.getCount() > 0) {
189 result
.setKeys(container
);
191 } catch (Exception e
) {
192 //e.printStackTrace();
193 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading identification key data.", e
));
197 private void loadSpecimens(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
198 if (!config
.isWithSpecimens()){
201 loadRootSpecimens(taxon
, result
, config
);
203 //once fully switching to newSpecimens the tansient annotation on the getter should be removed
204 //in the TaxonPageDto
205 boolean newSpecimensImplemented
= false;
206 if (newSpecimensImplemented
) {
207 loadNewRootSpecimens(taxon
, result
, config
);
212 * Not really implemented yet
214 private void loadNewRootSpecimens(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
215 //TODO load specimen from multiple places
218 EnumSet
<TaxonOccurrenceRelationType
> specimenFilter
= config
.getSpecimenAssociationFilter();
220 //TODO maybe use OccurrenceService.listRootUnitDTOsByAssociatedTaxon
221 // or OccurrenceService.listRootUnitsByAssociatedTaxon()
224 ContainerDto
<SpecimenDTO
> container
= new ContainerDto
<>();
226 List
<SpecimenOrObservationBase
<?
>> specimens
= new ArrayList
<>();
227 for (TaxonDescription taxonDescription
: taxon
.getDescriptions()) {
228 if (taxonDescription
.isImageGallery()) {
231 for (DescriptionElementBase el
: taxonDescription
.getElements()) {
232 if (el
.isInstanceOf(IndividualsAssociation
.class)) {
233 IndividualsAssociation indAss
= CdmBase
.deproxy(el
, IndividualsAssociation
.class);
234 SpecimenOrObservationBase
<?
> specimen
= indAss
.getAssociatedSpecimenOrObservation();
235 specimens
.add(specimen
);
239 List
<SpecimenOrObservationBase
<?
>> typeSpecimens
= loadTypeSpecimen(taxon
.getName(), config
);
240 specimens
.addAll(typeSpecimens
);
241 for (TaxonName syn
: taxon
.getSynonymNames()) {
242 typeSpecimens
= loadTypeSpecimen(syn
, config
);
243 specimens
.addAll(typeSpecimens
);
246 //TODO maybe still need to check full derivate path #4484, #8424, #9559
247 for (SpecimenOrObservationBase
<?
> specimen
: filterPublished(specimens
)) {
248 SpecimenDTO dto
= new SpecimenDTO();
249 loadBaseData(specimen
, dto
);
250 dto
.setLabel(specimen
.getTitleCache());
251 container
.addItem(dto
);
253 if (container
.getCount() > 0 ) {
254 result
.setSpecimens(container
);
256 } catch (Exception e
) {
257 //e.printStackTrace();
258 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading specimen data.", e
));
263 * Loads specimens the "old" way.
265 private void loadRootSpecimens(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
266 List
<SpecimenOrObservationBaseDTO
> rootSpecimens
= this.repository
.getOccurrenceService().listRootUnitDTOsByAssociatedTaxon(
267 taxon
.getUuid(), null, config
.isIncludeUnpublished(),
268 config
.getSpecimenAssociationFilter(), null);
270 if (result
.getOccurrenceInfo() == null) {
271 OccurrenceInfoDto oid
= new OccurrenceInfoDto();
272 result
.setOccurrenceInfo(oid
);
274 result
.getOccurrenceInfo().setRootSpecimens(rootSpecimens
);
277 private List
<SpecimenOrObservationBase
<?
>> loadTypeSpecimen(TaxonName name
, TaxonPageDtoConfiguration config
) {
278 List
<SpecimenOrObservationBase
<?
>> result
= new ArrayList
<>();
279 for (SpecimenTypeDesignation desig
: name
.getSpecimenTypeDesignations()){
280 DerivedUnit specimen
= desig
.getTypeSpecimen();
281 if (specimen
!= null) {
282 result
.add(specimen
);
288 private void loadMedia(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
289 if (!config
.isWithMedia()){
293 ContainerDto
<MediaDTO
> container
= new ContainerDto
<TaxonPageDto
.MediaDTO
>();
295 List
<Media
> medias
= new ArrayList
<>();
296 for (TaxonDescription taxonDescription
: taxon
.getDescriptions()) {
297 if (!taxonDescription
.isImageGallery()) {
301 List
<Media
> newMedia
= taxonDescription
.getElements().stream()
302 .filter(el
->el
.isInstanceOf(TextData
.class))
303 .map(el
->CdmBase
.deproxy(el
, TextData
.class))
305 .flatMap(td
->td
.getMedia().stream())
306 .collect(Collectors
.toList())
308 medias
.addAll(newMedia
);
310 //TODO collect media from elsewhere
311 for (Media media
: medias
) {
312 MediaDTO dto
= new TaxonPageDto
.MediaDTO();
313 loadBaseData(media
, dto
);
314 dto
.setLabel(media
.getTitleCache());
315 ContainerDto
<MediaRepresentationDTO
> representations
= new ContainerDto
<>();
316 for (MediaRepresentation rep
: media
.getRepresentations()) {
317 MediaRepresentationDTO repDto
= new MediaRepresentationDTO();
318 loadBaseData(rep
, dto
);
319 repDto
.setMimeType(rep
.getMimeType());
320 repDto
.setSuffix(rep
.getSuffix());
321 if (!rep
.getParts().isEmpty()) {
322 //TODO handle message if n(parts) > 1
323 MediaRepresentationPart part
= rep
.getParts().get(0);
324 repDto
.setUri(part
.getUri());
325 repDto
.setClazz(part
.getClass());
326 repDto
.setSize(part
.getSize());
327 if (part
.isInstanceOf(ImageFile
.class)) {
328 ImageFile image
= CdmBase
.deproxy(part
, ImageFile
.class);
329 repDto
.setHeight(image
.getHeight());
330 repDto
.setWidth(image
.getWidth());
332 //TODO AudioFile etc.
334 representations
.addItem(repDto
);
336 if (representations
.getCount() > 0) {
337 dto
.setRepresentations(representations
);
339 //TODO load representation data
340 container
.addItem(dto
);
343 if (container
.getCount() > 0) {
344 result
.setMedia(container
);
346 } catch (Exception e
) {
347 //e.printStackTrace();
348 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading media data.", e
));
352 private void loadTaxonNodes(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
353 if (!config
.isWithTaxonNodes()){
357 ContainerDto
<TaxonNodeDTO
> container
= new ContainerDto
<TaxonPageDto
.TaxonNodeDTO
>();
358 for (TaxonNode node
: taxon
.getTaxonNodes()) {
359 TaxonNodeDTO dto
= new TaxonNodeDTO();
360 loadBaseData(node
, dto
);
362 Classification classification
= node
.getClassification();
363 if (classification
!= null) {
364 dto
.setClassificationUuid(node
.getClassification().getUuid());
365 dto
.setClassificationLabel(classification
.getName().getText());
368 Language language
= Language
.DEFAULT();
371 TaxonNodeStatus status
= node
.getStatus();
372 if (status
!= null) {
373 dto
.setStatus(status
.getLabel(language
));
376 dto
.setStatusNote(node
.preferredStatusNote(language
));
379 Set
<TaxonNodeAgentRelation
> agents
= node
.getAgentRelations();
380 if (!agents
.isEmpty()) {
381 for (TaxonNodeAgentRelation rel
: agents
) {
382 TaxonNodeAgentsRelDTO agentDto
= new TaxonNodeAgentsRelDTO();
383 loadBaseData(rel
, agentDto
);
386 if (rel
.getAgent() != null) {
387 agentDto
.setAgent(rel
.getAgent().getFullTitle());
388 agentDto
.setAgentUuid(rel
.getAgent().getUuid());
389 //TODO compute preferred external link
390 agentDto
.setAgentLink(null);
392 if (rel
.getType() != null) {
393 agentDto
.setType(rel
.getType().getTitleCache());
394 agentDto
.setTypeUuid(rel
.getType().getUuid());
396 dto
.addAgent(agentDto
);
399 container
.addItem(dto
);
401 if (container
.getCount() > 0) {
402 result
.setTaxonNodes(container
);
404 } catch (Exception e
) {
405 // e.printStackTrace();
406 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading taxon node data.", e
));
410 private void loadSynonyms(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
412 if (!config
.isWithSynonyms()) {
417 // List<HomotypicalGroup> homotypicGroups = taxon.getHomotypicSynonymyGroups();
419 TaxonComparator comparator
= new TaxonComparator();
421 TaxonName name
= taxon
.getName();
423 //TODO depending on config add/remove accepted name
426 List
<Synonym
> homotypicSynonmys
= filterPublished(taxon
.getHomotypicSynonymsByHomotypicGroup(comparator
));
428 TaxonPageDto
.HomotypicGroupDTO homotypicGroupDto
= new TaxonPageDto
.HomotypicGroupDTO();
429 if (homotypicSynonmys
!= null && !homotypicSynonmys
.isEmpty()) {
430 loadBaseData(name
.getHomotypicalGroup(), homotypicGroupDto
);
432 for (Synonym syn
: homotypicSynonmys
) {
433 loadSynonymsInGroup(homotypicGroupDto
, syn
, config
, result
);
437 handleTypification(name
.getHomotypicalGroup(), homotypicGroupDto
, result
, config
);
439 result
.setHomotypicSynonyms(homotypicGroupDto
);
441 //heterotypic synonyms
442 List
<HomotypicalGroup
> heteroGroups
= taxon
.getHeterotypicSynonymyGroups();
443 if (heteroGroups
.isEmpty()) {
446 ContainerDto
<HomotypicGroupDTO
> heteroContainer
= new ContainerDto
<>();
447 result
.setHeterotypicSynonymGroups(heteroContainer
);
449 for (HomotypicalGroup hg
: heteroGroups
) {
450 TaxonPageDto
.HomotypicGroupDTO hgDto
= new TaxonPageDto
.HomotypicGroupDTO();
451 loadBaseData(taxon
.getName().getHomotypicalGroup(), hgDto
);
452 heteroContainer
.addItem(hgDto
);
454 List
<Synonym
> heteroSyns
= filterPublished(taxon
.getSynonymsInGroup(hg
, comparator
));
455 for (Synonym syn
: heteroSyns
) {
456 loadSynonymsInGroup(hgDto
, syn
, config
, result
);
458 handleTypification(hg
, hgDto
, result
, config
);
460 } catch (Exception e
) {
461 //e.printStackTrace();
462 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading synonym data.", e
));
466 private void handleTypification(HomotypicalGroup homotypicalGroup
, HomotypicGroupDTO hgDto
,
467 TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
469 TypeDesignationSetFormatter formatter
= new TypeDesignationSetFormatter();
470 Set
<TypeDesignationBase
<?
>> designations
= homotypicalGroup
.getTypeDesignations();
472 TypeDesignationSetContainer manager
= TypeDesignationSetContainer
.NewDefaultInstance((Set
)designations
);
473 List
<TaggedText
> tags
= formatter
.toTaggedText(manager
);
474 String label
= TaggedTextFormatter
.createString(tags
);
475 hgDto
.setTypes(label
);
476 hgDto
.setTaggedTypes(tags
);
477 // hgDto.setTypedTypes(null);
479 } catch (Exception e
) {
480 // e.printStackTrace();
481 result
.addMessage(MessagesDto
.NewErrorInstance("Error when creating type designation information", e
));
485 private void loadConceptRelations(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
486 if (!config
.isWithTaxonRelationships()){
491 ContainerDto
<ConceptRelationDTO
> conceptRelContainer
= new ContainerDto
<>();
492 TaxonRelationshipFormatter taxRelFormatter
= TaxonRelationshipFormatter
.INSTANCE();
495 Set
<TaxonRelationship
> misappliedRels
= taxon
.getMisappliedNameRelations();
496 for (TaxonRelationship rel
: misappliedRels
) {
497 boolean inverse
= true;
498 boolean withoutName
= false;
499 loadConceptRelation(taxRelFormatter
, rel
, conceptRelContainer
, inverse
, withoutName
);
502 //... pro parte Synonyms
503 Set
<TaxonRelationship
> proParteRels
= taxon
.getProParteAndPartialSynonymRelations();
504 for (TaxonRelationship rel
: proParteRels
) {
505 boolean inverse
= true;
506 boolean withoutName
= false;
507 loadConceptRelation(taxRelFormatter
, rel
, conceptRelContainer
, inverse
, withoutName
);
510 //TODO MAN and pp from this taxon
513 Set
<TaxonRelationship
> toRels
= taxon
.getRelationsToThisTaxon();
514 toRels
.removeAll(misappliedRels
);
515 toRels
.removeAll(proParteRels
);
516 for (TaxonRelationship rel
: toRels
) {
517 boolean inverse
= true;
518 boolean withoutName
= false;
519 loadConceptRelation(taxRelFormatter
, rel
, conceptRelContainer
, inverse
, withoutName
);
523 Set
<TaxonRelationship
> fromRels
= taxon
.getRelationsFromThisTaxon();
524 for (TaxonRelationship rel
: fromRels
) {
525 boolean inverse
= false;
526 boolean withoutName
= false;
527 loadConceptRelation(taxRelFormatter
, rel
, conceptRelContainer
, inverse
, withoutName
);
530 if (conceptRelContainer
.getCount() > 0) {
531 result
.setConceptRelations(conceptRelContainer
);
533 } catch (Exception e
) {
534 //e.printStackTrace();
535 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading concept relation data.", e
));
539 private void loadConceptRelation(TaxonRelationshipFormatter taxRelFormatter
, TaxonRelationship rel
, ContainerDto
<ConceptRelationDTO
> conceptRelContainer
, boolean inverse
,
540 boolean withoutName
) {
542 List
<Language
> languages
= Arrays
.asList(new Language
[] {Language
.DEFAULT()}); // TODO config.locales;
543 List
<TaggedText
> tags
= taxRelFormatter
.getTaggedText(rel
, inverse
, languages
, withoutName
);
544 String relLabel
= TaggedTextFormatter
.createString(tags
);
545 ConceptRelationDTO dto
= new TaxonPageDto
.ConceptRelationDTO();
546 loadBaseData(rel
, dto
);
547 dto
.setRelSource(makeSource(rel
.getSource()));
548 Taxon relTaxon
= inverse ? rel
.getFromTaxon() : rel
.getToTaxon();
549 dto
.setRelTaxonId(relTaxon
.getId());
550 dto
.setRelTaxonUuid(relTaxon
.getUuid());
551 dto
.setRelTaxonLabel(relTaxon
.getTitleCache());
552 dto
.setSecSource(makeSource(relTaxon
.getSecSource()));
553 dto
.setLabel(relLabel
);
554 dto
.setTaggedLabel(tags
);
555 dto
.setNameUuid(relTaxon
.getName() != null ? relTaxon
.getName().getUuid() : null);
557 if (rel
.getType() != null) {
558 dto
.setRelTypeUuid(rel
.getType().getUuid());
560 for (TaxonNode node
: relTaxon
.getTaxonNodes()) {
561 Classification classification
= node
.getClassification();
562 if (classification
!= null) {
563 dto
.addClassificationUuids(classification
.getUuid());
566 conceptRelContainer
.addItem(dto
);
569 private void loadSynonymsInGroup(TaxonPageDto
.HomotypicGroupDTO hgDto
, Synonym syn
,
570 TaxonPageDtoConfiguration config
, TaxonPageDto pageDto
) {
572 TaxonBaseDto synDto
= new TaxonBaseDto();
573 loadBaseData(syn
, synDto
);
574 synDto
.setLabel(syn
.getTitleCache());
575 synDto
.setTaggedLabel(getTaggedTaxon(syn
, config
));
577 if (syn
.getName() != null) {
578 handleName(config
, synDto
, syn
.getName(), pageDto
);
582 hgDto
.addSynonym(synDto
);
585 private void loadProtologues(TaxonName name
, TaxonBaseDto taxonBaseDto
) {
586 //TODO maybe also load reference DOI/URL if no source external link exists
587 NomenclaturalSource nomSource
= name
.getNomenclaturalSource();
588 if (nomSource
!= null) {
589 Set
<ExternalLink
> links
= nomSource
.getLinks();
590 for (ExternalLink link
: links
) {
591 if (link
.getUri() != null) {
592 taxonBaseDto
.addProtologue(link
.getUri());
598 private void handleRelatedNames(TaxonName name
, TaxonBaseDto taxonDto
, TaxonPageDtoConfiguration config
) {
599 //exclusions TODO handle via config
600 Set
<UUID
> excludedTypes
= new HashSet
<>(); //both directions
601 excludedTypes
.add(NameRelationshipType
.uuidBasionym
);
602 excludedTypes
.add(NameRelationshipType
.uuidReplacedSynonym
);
603 Set
<UUID
> excludedFromTypes
= new HashSet
<>(excludedTypes
);
604 Set
<UUID
> excludedToTypes
= new HashSet
<>(excludedTypes
);
607 //TODO config.getLocales();
608 Language locale
= Language
.DEFAULT();
610 for (NameRelationship rel
: name
.getRelationsFromThisName()) {
611 TaxonName relatedName
= rel
.getToName();
612 if (relatedName
== null || rel
.getType() == null || excludedFromTypes
.contains(rel
.getType().getUuid())) {
615 NameRelationDTO dto
= new NameRelationDTO();
616 loadBaseData(rel
, dto
);
618 dto
.setNameUuid(relatedName
.getUuid());
619 dto
.setNameLabel(relatedName
.getTaggedName());
621 dto
.setRelTypeUuid(rel
.getType().getUuid());
622 Representation rep
= rel
.getType().getPreferredRepresentation(locale
);
623 dto
.setRelType(rep
== null ? rel
.getType().toString() : rep
.getLabel());
625 dto
.setInverse(false);
627 dto
.setRuleConsidered(rel
.getRuleConsidered());
629 dto
.setYear(relatedName
.getReferenceYear());
630 taxonDto
.addRelatedName(dto
);
634 for (NameRelationship rel
: name
.getRelationsToThisName()) {
635 TaxonName relatedName
= rel
.getFromName();
636 if (relatedName
== null || rel
.getType() == null || excludedFromTypes
.contains(rel
.getType().getUuid())) {
639 NameRelationDTO dto
= new NameRelationDTO();
640 loadBaseData(rel
, dto
);
642 dto
.setNameUuid(relatedName
.getUuid());
643 dto
.setNameLabel(relatedName
.getTaggedName());
645 dto
.setRelTypeUuid(rel
.getType().getUuid());
646 Representation rep
= rel
.getType().getPreferredInverseRepresentation(Arrays
.asList(new Language
[] {locale
}));
647 dto
.setRelType(rep
== null ? rel
.getType().toString() : rep
.getLabel());
649 dto
.setInverse(true);
651 dto
.setYear(relatedName
.getReferenceYear());
652 taxonDto
.addRelatedName(dto
);
656 private void loadFacts(Taxon taxon
, TaxonPageDto taxonPageDto
, TaxonPageDtoConfiguration config
) {
657 factLoader
.loadTaxonFacts(taxon
, taxonPageDto
, config
);
660 private void loadNameFacts(TaxonName name
, TaxonBaseDto nameDto
, TaxonPageDtoConfiguration config
, TaxonPageDto pageDto
) {
661 factLoader
.loadNameFacts(name
, nameDto
, config
, pageDto
);
665 * Compares an existing last date and the last date of an entity
666 * and returns the resulting last date.
668 private LocalDateTime
getLastUpdated(LocalDateTime existingLastDate
, VersionableEntity dateToAddEntity
) {
670 DateTime dateToAdd
= dateToAddEntity
.getUpdated() != null ? dateToAddEntity
.getUpdated() : dateToAddEntity
.getCreated();
672 LocalDateTime javaLocalDateTimeOfEntity
= DtoUtil
.fromDateTime(dateToAdd
);
674 if (existingLastDate
== null) {
675 return javaLocalDateTimeOfEntity
;
676 }else if (javaLocalDateTimeOfEntity
== null || javaLocalDateTimeOfEntity
.compareTo(existingLastDate
) < 0) {
677 return existingLastDate
;
679 return javaLocalDateTimeOfEntity
;