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
.awt
.Color
;
12 import java
.time
.LocalDateTime
;
13 import java
.util
.ArrayList
;
14 import java
.util
.Arrays
;
15 import java
.util
.Collections
;
16 import java
.util
.HashMap
;
17 import java
.util
.HashSet
;
18 import java
.util
.List
;
21 import java
.util
.UUID
;
22 import java
.util
.stream
.Collectors
;
24 import org
.apache
.commons
.lang3
.StringUtils
;
25 import org
.apache
.logging
.log4j
.LogManager
;
26 import org
.apache
.logging
.log4j
.Logger
;
27 import org
.joda
.time
.DateTime
;
29 import com
.fasterxml
.jackson
.core
.JsonProcessingException
;
31 import eu
.etaxonomy
.cdm
.api
.application
.ICdmRepository
;
32 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.AnnotatableDto
;
33 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.AnnotationDto
;
34 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.CdmBaseDto
;
35 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.CommonNameDto
;
36 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.ContainerDto
;
37 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.DistributionDto
;
38 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.DistributionInfoDto
;
39 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.DistributionTreeDto
;
40 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.FactDto
;
41 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.FactDtoBase
;
42 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.FeatureDto
;
43 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.IFactDto
;
44 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.IndividualsAssociationDto
;
45 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.MarkerDto
;
46 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.MessagesDto
;
47 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.NamedAreaDto
;
48 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.SingleSourcedDto
;
49 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.SourceDto
;
50 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.SourcedDto
;
51 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonBaseDto
;
52 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonBaseDto
.TaxonNameDto
;
53 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonInteractionDto
;
54 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
;
55 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.ConceptRelationDTO
;
56 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.HomotypicGroupDTO
;
57 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.KeyDTO
;
58 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.MediaDTO
;
59 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.MediaRepresentationDTO
;
60 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.NameRelationDTO
;
61 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.SpecimenDTO
;
62 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.TaxonNodeAgentsRelDTO
;
63 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.TaxonNodeDTO
;
64 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.config
.DistributionInfoConfiguration
;
65 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.config
.TaxonPageDtoConfiguration
;
66 import eu
.etaxonomy
.cdm
.api
.service
.geo
.DistributionServiceUtilities
;
67 import eu
.etaxonomy
.cdm
.api
.service
.geo
.IDistributionService
;
68 import eu
.etaxonomy
.cdm
.api
.service
.l10n
.LocaleContext
;
69 import eu
.etaxonomy
.cdm
.api
.service
.name
.TypeDesignationSetContainer
;
70 import eu
.etaxonomy
.cdm
.api
.service
.name
.TypeDesignationSetFormatter
;
71 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
72 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
73 import eu
.etaxonomy
.cdm
.common
.TreeNode
;
74 import eu
.etaxonomy
.cdm
.compare
.taxon
.TaxonComparator
;
75 import eu
.etaxonomy
.cdm
.format
.common
.TypedLabel
;
76 import eu
.etaxonomy
.cdm
.format
.description
.CategoricalDataFormatter
;
77 import eu
.etaxonomy
.cdm
.format
.description
.QuantitativeDataFormatter
;
78 import eu
.etaxonomy
.cdm
.format
.description
.distribution
.CondensedDistributionConfiguration
;
79 import eu
.etaxonomy
.cdm
.format
.reference
.OriginalSourceFormatter
;
80 import eu
.etaxonomy
.cdm
.format
.taxon
.TaxonRelationshipFormatter
;
81 import eu
.etaxonomy
.cdm
.model
.common
.AnnotatableEntity
;
82 import eu
.etaxonomy
.cdm
.model
.common
.Annotation
;
83 import eu
.etaxonomy
.cdm
.model
.common
.AnnotationType
;
84 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
85 import eu
.etaxonomy
.cdm
.model
.common
.ICdmBase
;
86 import eu
.etaxonomy
.cdm
.model
.common
.IPublishable
;
87 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
88 import eu
.etaxonomy
.cdm
.model
.common
.LanguageString
;
89 import eu
.etaxonomy
.cdm
.model
.common
.Marker
;
90 import eu
.etaxonomy
.cdm
.model
.common
.MarkerType
;
91 import eu
.etaxonomy
.cdm
.model
.common
.MultilanguageTextHelper
;
92 import eu
.etaxonomy
.cdm
.model
.common
.SingleSourcedEntityBase
;
93 import eu
.etaxonomy
.cdm
.model
.common
.VersionableEntity
;
94 import eu
.etaxonomy
.cdm
.model
.description
.CategoricalData
;
95 import eu
.etaxonomy
.cdm
.model
.description
.CommonTaxonName
;
96 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
97 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
98 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementSource
;
99 import eu
.etaxonomy
.cdm
.model
.description
.Distribution
;
100 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
101 import eu
.etaxonomy
.cdm
.model
.description
.IDescribable
;
102 import eu
.etaxonomy
.cdm
.model
.description
.IndividualsAssociation
;
103 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKey
;
104 import eu
.etaxonomy
.cdm
.model
.description
.PresenceAbsenceTerm
;
105 import eu
.etaxonomy
.cdm
.model
.description
.QuantitativeData
;
106 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
107 import eu
.etaxonomy
.cdm
.model
.description
.TaxonInteraction
;
108 import eu
.etaxonomy
.cdm
.model
.description
.TemporalData
;
109 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
110 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
111 import eu
.etaxonomy
.cdm
.model
.media
.ExternalLink
;
112 import eu
.etaxonomy
.cdm
.model
.media
.ImageFile
;
113 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
114 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
115 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentationPart
;
116 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
117 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationship
;
118 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationshipType
;
119 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalSource
;
120 import eu
.etaxonomy
.cdm
.model
.name
.SpecimenTypeDesignation
;
121 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
122 import eu
.etaxonomy
.cdm
.model
.name
.TypeDesignationBase
;
123 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
124 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
125 import eu
.etaxonomy
.cdm
.model
.reference
.ISourceable
;
126 import eu
.etaxonomy
.cdm
.model
.reference
.NamedSource
;
127 import eu
.etaxonomy
.cdm
.model
.reference
.NamedSourceBase
;
128 import eu
.etaxonomy
.cdm
.model
.reference
.OriginalSourceBase
;
129 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
130 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
131 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
132 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
133 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
134 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
135 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNodeAgentRelation
;
136 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNodeStatus
;
137 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
138 import eu
.etaxonomy
.cdm
.model
.term
.Representation
;
139 import eu
.etaxonomy
.cdm
.model
.term
.TermBase
;
140 import eu
.etaxonomy
.cdm
.model
.term
.TermNode
;
141 import eu
.etaxonomy
.cdm
.model
.term
.TermTree
;
142 import eu
.etaxonomy
.cdm
.strategy
.cache
.TaggedCacheHelper
;
143 import eu
.etaxonomy
.cdm
.strategy
.cache
.TaggedText
;
144 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.INameCacheStrategy
;
145 import eu
.etaxonomy
.cdm
.strategy
.cache
.taxon
.TaxonBaseDefaultCacheStrategy
;
148 * Loads the portal dto from a taxon instance.
149 * Maybe later also supports loading from persistence.
154 public class PortalDtoLoader
{
156 private static final Logger logger
= LogManager
.getLogger();
158 private ICdmRepository repository
;
160 public PortalDtoLoader(ICdmRepository repository
) {
161 this.repository
= repository
;
164 public TaxonPageDto
load(Taxon taxon
, TaxonPageDtoConfiguration config
) {
165 TaxonPageDto result
= new TaxonPageDto();
167 loadAcceptedTaxon(taxon
, config
, result
);
169 loadTaxonNodes(taxon
, result
, config
);
170 loadSynonyms(taxon
, result
, config
);
171 loadConceptRelations(taxon
, result
, config
);
172 loadFacts(taxon
, result
, config
);
173 loadMedia(taxon
, result
, config
);
174 loadSpecimens(taxon
, result
, config
);
175 loadKeys(taxon
, result
, config
);
180 private void loadAcceptedTaxon(Taxon taxon
, TaxonPageDtoConfiguration config
, TaxonPageDto result
) {
182 TaxonName name
= taxon
.getName();
185 //TODO supplementalData for name
186 loadBaseData(taxon
, result
);
187 result
.setLastUpdated(getLastUpdated(null, taxon
));
188 result
.setLabel(CdmUtils
.Nz(taxon
.getTitleCache()));
189 // result.setTypedTaxonLabel(getTypedTaxonLabel(taxon, config));
190 result
.setTaggedLabel(getTaggedTaxon(taxon
, config
));
192 handleName(config
, result
, name
, result
);
194 if (taxon
.getSec() != null) {
195 result
.setSecTitleCache(taxon
.getSec().getTitleCache());
197 } catch (Exception e
) {
198 //e.printStackTrace();
199 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading accepted name data.", e
));
203 private void handleName(TaxonPageDtoConfiguration config
, TaxonBaseDto taxonDto
, TaxonName name
, TaxonPageDto pageDto
) {
204 TaxonNameDto nameDto
= taxonDto
.new TaxonNameDto();
205 loadBaseData(name
, nameDto
);
207 INameCacheStrategy formatter
= name
.cacheStrategy();
208 formatter
.setEtAlPosition(config
.getEtAlPosition());
210 taxonDto
.setName(nameDto
);
211 taxonDto
.setNameLabel(formatter
.getTitleCache(name
));
212 handleRelatedNames(name
, taxonDto
, config
);
213 loadProtologues(name
, taxonDto
);
214 taxonDto
.setNameUuid(name
.getUuid());
215 taxonDto
.setNameType(name
.getNameType().toString());
216 loadNameFacts(name
, taxonDto
, config
, pageDto
);
217 nameDto
.setTaggedName(formatter
.getTaggedFullTitle(name
));
220 private List
<TaggedText
> getTaggedTaxon(TaxonBase
<?
> taxon
, TaxonPageDtoConfiguration config
) {
221 // List<TypedLabel> result = new ArrayList<>();
222 TaxonBaseDefaultCacheStrategy
<TaxonBase
<?
>> formatter
= new TaxonBaseDefaultCacheStrategy
<>();
223 List
<TaggedText
> tags
= formatter
.getTaggedTitle(taxon
);
227 private void loadKeys(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
229 ContainerDto
<KeyDTO
> container
= new ContainerDto
<>();
231 //TODO other key types, but type must not be null, otherwise NPE
232 Pager
<PolytomousKey
> keys
= repository
.getIdentificationKeyService().findKeysConvering(taxon
, PolytomousKey
.class, null, null, null);
233 for (PolytomousKey key
: keys
.getRecords()) {
234 KeyDTO dto
= new KeyDTO();
235 loadBaseData(key
, dto
);
236 dto
.setLabel(key
.getTitleCache());
237 dto
.setKeyClass(key
.getClass().getSimpleName());
238 container
.addItem(dto
);
240 if (container
.getCount() > 0) {
241 result
.setKeys(container
);
243 } catch (Exception e
) {
244 //e.printStackTrace();
245 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading identification key data.", e
));
249 private void loadSpecimens(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
250 //TODO load specimen from multiple places
253 ContainerDto
<SpecimenDTO
> container
= new ContainerDto
<>();
255 List
<SpecimenOrObservationBase
<?
>> specimens
= new ArrayList
<>();
256 for (TaxonDescription taxonDescription
: taxon
.getDescriptions()) {
257 if (taxonDescription
.isImageGallery()) {
260 for (DescriptionElementBase el
: taxonDescription
.getElements()) {
261 if (el
.isInstanceOf(IndividualsAssociation
.class)) {
262 IndividualsAssociation indAss
= CdmBase
.deproxy(el
, IndividualsAssociation
.class);
263 SpecimenOrObservationBase
<?
> specimen
= indAss
.getAssociatedSpecimenOrObservation();
264 specimens
.add(specimen
);
268 List
<SpecimenOrObservationBase
<?
>> typeSpecimens
= loadTypeSpecimen(taxon
.getName(), config
);
269 specimens
.addAll(typeSpecimens
);
270 for (TaxonName syn
: taxon
.getSynonymNames()) {
271 typeSpecimens
= loadTypeSpecimen(syn
, config
);
272 specimens
.addAll(typeSpecimens
);
275 //TODO maybe still need to check full derivate path #4484, #8424, #9559
276 for (SpecimenOrObservationBase
<?
> specimen
: filterPublished(specimens
)) {
277 SpecimenDTO dto
= new SpecimenDTO();
278 loadBaseData(specimen
, dto
);
279 dto
.setLabel(specimen
.getTitleCache());
280 container
.addItem(dto
);
282 if (container
.getCount() > 0 ) {
283 result
.setSpecimens(container
);
285 } catch (Exception e
) {
286 //e.printStackTrace();
287 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading specimen data.", e
));
291 private List
<SpecimenOrObservationBase
<?
>> loadTypeSpecimen(TaxonName name
, TaxonPageDtoConfiguration config
) {
292 List
<SpecimenOrObservationBase
<?
>> result
= new ArrayList
<>();
293 for (SpecimenTypeDesignation desig
: name
.getSpecimenTypeDesignations()){
294 DerivedUnit specimen
= desig
.getTypeSpecimen();
295 if (specimen
!= null) {
296 result
.add(specimen
);
302 private void loadMedia(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
305 ContainerDto
<MediaDTO
> container
= new ContainerDto
<TaxonPageDto
.MediaDTO
>();
307 List
<Media
> medias
= new ArrayList
<>();
308 for (TaxonDescription taxonDescription
: taxon
.getDescriptions()) {
309 if (!taxonDescription
.isImageGallery()) {
313 List
<Media
> newMedia
= taxonDescription
.getElements().stream()
314 .filter(el
->el
.isInstanceOf(TextData
.class))
315 .map(el
->CdmBase
.deproxy(el
, TextData
.class))
317 .flatMap(td
->td
.getMedia().stream())
318 .collect(Collectors
.toList())
320 medias
.addAll(newMedia
);
322 //TODO collect media from elsewhere
323 for (Media media
: medias
) {
324 MediaDTO dto
= new TaxonPageDto
.MediaDTO();
325 loadBaseData(media
, dto
);
326 dto
.setLabel(media
.getTitleCache());
327 ContainerDto
<MediaRepresentationDTO
> representations
= new ContainerDto
<>();
328 for (MediaRepresentation rep
: media
.getRepresentations()) {
329 MediaRepresentationDTO repDto
= new MediaRepresentationDTO();
330 loadBaseData(rep
, dto
);
331 repDto
.setMimeType(rep
.getMimeType());
332 repDto
.setSuffix(rep
.getSuffix());
333 if (!rep
.getParts().isEmpty()) {
334 //TODO handle message if n(parts) > 1
335 MediaRepresentationPart part
= rep
.getParts().get(0);
336 repDto
.setUri(part
.getUri());
337 repDto
.setClazz(part
.getClass());
338 repDto
.setSize(part
.getSize());
339 if (part
.isInstanceOf(ImageFile
.class)) {
340 ImageFile image
= CdmBase
.deproxy(part
, ImageFile
.class);
341 repDto
.setHeight(image
.getHeight());
342 repDto
.setWidth(image
.getWidth());
344 //TODO AudioFile etc.
346 representations
.addItem(repDto
);
348 if (representations
.getCount() > 0) {
349 dto
.setRepresentations(representations
);
351 //TODO load representation data
352 container
.addItem(dto
);
355 if (container
.getCount() > 0) {
356 result
.setMedia(container
);
358 } catch (Exception e
) {
359 //e.printStackTrace();
360 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading media data.", e
));
364 private void loadTaxonNodes(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
366 ContainerDto
<TaxonNodeDTO
> container
= new ContainerDto
<TaxonPageDto
.TaxonNodeDTO
>();
367 for (TaxonNode node
: taxon
.getTaxonNodes()) {
368 TaxonNodeDTO dto
= new TaxonNodeDTO();
369 loadBaseData(node
, dto
);
371 Classification classification
= node
.getClassification();
372 if (classification
!= null) {
373 dto
.setClassificationUuid(node
.getClassification().getUuid());
374 dto
.setClassificationLabel(classification
.getName().getText());
377 Language language
= Language
.DEFAULT();
380 TaxonNodeStatus status
= node
.getStatus();
381 if (status
!= null) {
382 dto
.setStatus(status
.getLabel(language
));
385 Map
<Language
, LanguageString
> statusNote
= node
.getStatusNote();
386 if (statusNote
!= null) {
387 //TODO handle fallback lang
388 LanguageString statusNoteStr
= statusNote
.get(language
);
389 if (statusNoteStr
== null && statusNote
.size() > 0) {
390 statusNoteStr
= statusNote
.entrySet().iterator().next().getValue();
392 if (statusNoteStr
!= null) {
393 dto
.setStatusNote(statusNoteStr
.getText());
397 Set
<TaxonNodeAgentRelation
> agents
= node
.getAgentRelations();
398 if (!agents
.isEmpty()) {
399 for (TaxonNodeAgentRelation rel
: agents
) {
400 TaxonNodeAgentsRelDTO agentDto
= new TaxonNodeAgentsRelDTO();
401 loadBaseData(rel
, agentDto
);
404 if (rel
.getAgent() != null) {
405 agentDto
.setAgent(rel
.getAgent().getFullTitle());
406 agentDto
.setAgentUuid(rel
.getAgent().getUuid());
407 //TODO compute preferred external link
408 agentDto
.setAgentLink(null);
410 if (rel
.getType() != null) {
411 agentDto
.setType(rel
.getType().getTitleCache());
412 agentDto
.setTypeUuid(rel
.getType().getUuid());
414 dto
.addAgent(agentDto
);
417 container
.addItem(dto
);
419 if (container
.getCount() > 0) {
420 result
.setTaxonNodes(container
);
422 } catch (Exception e
) {
423 // e.printStackTrace();
424 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading taxon node data.", e
));
428 private void loadSynonyms(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
431 // List<HomotypicalGroup> homotypicGroups = taxon.getHomotypicSynonymyGroups();
433 TaxonComparator comparator
= new TaxonComparator();
435 TaxonName name
= taxon
.getName();
437 //TODO depending on config add/remove accepted name
440 List
<Synonym
> homotypicSynonmys
= filterPublished(taxon
.getHomotypicSynonymsByHomotypicGroup(comparator
));
442 TaxonPageDto
.HomotypicGroupDTO homotypicGroupDto
= new TaxonPageDto
.HomotypicGroupDTO();
443 if (homotypicSynonmys
!= null && !homotypicSynonmys
.isEmpty()) {
444 loadBaseData(name
.getHomotypicalGroup(), homotypicGroupDto
);
446 for (Synonym syn
: homotypicSynonmys
) {
447 loadSynonymsInGroup(homotypicGroupDto
, syn
, config
, result
);
451 handleTypification(name
.getHomotypicalGroup(), homotypicGroupDto
, result
, config
);
453 result
.setHomotypicSynonyms(homotypicGroupDto
);
455 //heterotypic synonyms
456 List
<HomotypicalGroup
> heteroGroups
= taxon
.getHeterotypicSynonymyGroups();
457 if (heteroGroups
.isEmpty()) {
460 ContainerDto
<HomotypicGroupDTO
> heteroContainer
= new ContainerDto
<>();
461 result
.setHeterotypicSynonymGroups(heteroContainer
);
463 for (HomotypicalGroup hg
: heteroGroups
) {
464 TaxonPageDto
.HomotypicGroupDTO hgDto
= new TaxonPageDto
.HomotypicGroupDTO();
465 loadBaseData(taxon
.getName().getHomotypicalGroup(), hgDto
);
466 heteroContainer
.addItem(hgDto
);
468 List
<Synonym
> heteroSyns
= filterPublished(taxon
.getSynonymsInGroup(hg
, comparator
));
469 for (Synonym syn
: heteroSyns
) {
470 loadSynonymsInGroup(hgDto
, syn
, config
, result
);
472 handleTypification(hg
, hgDto
, result
, config
);
474 } catch (Exception e
) {
475 //e.printStackTrace();
476 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading synonym data.", e
));
480 private <P
extends IPublishable
> List
<P
> filterPublished(List
<P
> listToPublish
) {
481 if (listToPublish
== null) {
484 return listToPublish
.stream().filter(s
->s
.isPublish()).collect(Collectors
.toList());
487 private <P
extends IPublishable
> Set
<P
> filterPublished(Set
<P
> setToPublish
) {
488 if (setToPublish
== null) {
491 return setToPublish
.stream().filter(s
->s
.isPublish()).collect(Collectors
.toSet());
495 private void handleTypification(HomotypicalGroup homotypicalGroup
, HomotypicGroupDTO hgDto
,
496 TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
498 boolean withCitation
= true;
499 boolean withStartingTypeLabel
= true;
500 boolean withNameIfAvailable
= false;
501 TypeDesignationSetFormatter formatter
= new TypeDesignationSetFormatter(
502 withCitation
, withStartingTypeLabel
, withNameIfAvailable
);
503 Set
<TypeDesignationBase
<?
>> desigs
= homotypicalGroup
.getTypeDesignations();
505 TypeDesignationSetContainer manager
= TypeDesignationSetContainer
.NewDefaultInstance((Set
)desigs
);
506 List
<TaggedText
> tags
= formatter
.toTaggedText(manager
);
507 String label
= TaggedCacheHelper
.createString(tags
);
508 hgDto
.setTypes(label
);
509 hgDto
.setTaggedTypes(tags
);
510 // hgDto.setTypedTypes(null);
512 } catch (Exception e
) {
513 // e.printStackTrace();
514 result
.addMessage(MessagesDto
.NewErrorInstance("Error when creating type designation information", e
));
518 private void loadConceptRelations(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
522 ContainerDto
<ConceptRelationDTO
> conceptRelContainer
= new ContainerDto
<>();
523 TaxonRelationshipFormatter taxRelFormatter
= TaxonRelationshipFormatter
.INSTANCE();
526 Set
<TaxonRelationship
> misappliedRels
= taxon
.getMisappliedNameRelations();
527 for (TaxonRelationship rel
: misappliedRels
) {
528 boolean inverse
= true;
529 boolean withoutName
= false;
530 loadConceptRelation(taxRelFormatter
, rel
, conceptRelContainer
, inverse
, withoutName
);
533 //... pro parte Synonyms
534 Set
<TaxonRelationship
> proParteRels
= taxon
.getProParteAndPartialSynonymRelations();
535 for (TaxonRelationship rel
: proParteRels
) {
536 boolean inverse
= true;
537 boolean withoutName
= false;
538 loadConceptRelation(taxRelFormatter
, rel
, conceptRelContainer
, inverse
, withoutName
);
541 //TODO MAN and pp from this taxon
544 Set
<TaxonRelationship
> toRels
= taxon
.getRelationsToThisTaxon();
545 toRels
.removeAll(misappliedRels
);
546 toRels
.removeAll(proParteRels
);
547 for (TaxonRelationship rel
: toRels
) {
548 boolean inverse
= true;
549 boolean withoutName
= false;
550 loadConceptRelation(taxRelFormatter
, rel
, conceptRelContainer
, inverse
, withoutName
);
554 Set
<TaxonRelationship
> fromRels
= taxon
.getRelationsFromThisTaxon();
555 for (TaxonRelationship rel
: fromRels
) {
556 boolean inverse
= false;
557 boolean withoutName
= false;
558 loadConceptRelation(taxRelFormatter
, rel
, conceptRelContainer
, inverse
, withoutName
);
561 if (conceptRelContainer
.getCount() > 0) {
562 result
.setConceptRelations(conceptRelContainer
);
564 } catch (Exception e
) {
565 //e.printStackTrace();
566 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading concept relation data.", e
));
570 private void loadConceptRelation(TaxonRelationshipFormatter taxRelFormatter
, TaxonRelationship rel
, ContainerDto
<ConceptRelationDTO
> conceptRelContainer
, boolean inverse
,
571 boolean withoutName
) {
572 List
<Language
> languages
= Arrays
.asList(new Language
[] {Language
.DEFAULT()}); // TODO config.locales;
573 List
<TaggedText
> tags
= taxRelFormatter
.getTaggedText(rel
, inverse
, languages
, withoutName
);
574 String relLabel
= TaggedCacheHelper
.createString(tags
);
575 ConceptRelationDTO dto
= new TaxonPageDto
.ConceptRelationDTO();
576 loadBaseData(rel
, dto
);
577 Taxon relTaxon
= inverse ? rel
.getFromTaxon() : rel
.getToTaxon();
578 dto
.setRelTaxonId(relTaxon
.getId());
579 dto
.setRelTaxonUuid(relTaxon
.getUuid());
580 dto
.setRelTaxonLabel(relTaxon
.getTitleCache());
581 dto
.setLabel(relLabel
);
582 dto
.setTaggedLabel(tags
);
583 dto
.setNameUuid(relTaxon
.getName() != null ? relTaxon
.getName().getUuid() : null);
585 if (rel
.getType() != null) {
586 dto
.setRelTypeUuid(rel
.getType().getUuid());
588 for (TaxonNode node
: relTaxon
.getTaxonNodes()) {
589 Classification classification
= node
.getClassification();
590 if (classification
!= null) {
591 dto
.addClassificationUuids(classification
.getUuid());
594 conceptRelContainer
.addItem(dto
);
597 private void loadSynonymsInGroup(TaxonPageDto
.HomotypicGroupDTO hgDto
, Synonym syn
,
598 TaxonPageDtoConfiguration config
, TaxonPageDto pageDto
) {
600 TaxonBaseDto synDto
= new TaxonBaseDto();
601 loadBaseData(syn
, synDto
);
602 synDto
.setLabel(syn
.getTitleCache());
603 synDto
.setTaggedLabel(getTaggedTaxon(syn
, config
));
605 if (syn
.getName() != null) {
606 handleName(config
, synDto
, syn
.getName(), pageDto
);
610 hgDto
.addSynonym(synDto
);
613 private void loadProtologues(TaxonName name
, TaxonBaseDto taxonBaseDto
) {
614 NomenclaturalSource nomSource
= name
.getNomenclaturalSource();
615 if (nomSource
!= null) {
616 Set
<ExternalLink
> links
= nomSource
.getLinks();
617 for (ExternalLink link
: links
) {
618 if (link
.getUri() != null) {
619 taxonBaseDto
.addProtologue(link
.getUri());
625 private void handleRelatedNames(TaxonName name
, TaxonBaseDto taxonDto
, TaxonPageDtoConfiguration config
) {
626 //exclusions TODO handle via config
627 Set
<UUID
> excludedTypes
= new HashSet
<>(); //both directions
628 excludedTypes
.add(NameRelationshipType
.uuidBasionym
);
629 excludedTypes
.add(NameRelationshipType
.uuidReplacedSynonym
);
630 Set
<UUID
> excludedFromTypes
= new HashSet
<>(excludedTypes
);
631 Set
<UUID
> excludedToTypes
= new HashSet
<>(excludedTypes
);
634 //TODO config.getLocales();
635 Language locale
= Language
.DEFAULT();
637 for (NameRelationship rel
: name
.getRelationsFromThisName()) {
638 TaxonName relatedName
= rel
.getToName();
639 if (relatedName
== null || rel
.getType() == null || excludedFromTypes
.contains(rel
.getType().getUuid())) {
642 NameRelationDTO dto
= new NameRelationDTO();
643 loadBaseData(rel
, dto
);
645 dto
.setNameUuid(relatedName
.getUuid());
646 dto
.setNameLabel(relatedName
.getTaggedName());
648 dto
.setRelTypeUuid(rel
.getType().getUuid());
649 Representation rep
= rel
.getType().getPreferredRepresentation(locale
);
650 dto
.setRelType(rep
== null ? rel
.getType().toString() : rep
.getLabel());
652 dto
.setInverse(false);
654 dto
.setRuleConsidered(rel
.getRuleConsidered());
655 taxonDto
.addRelatedName(dto
);
659 for (NameRelationship rel
: name
.getRelationsToThisName()) {
660 TaxonName relatedName
= rel
.getFromName();
661 if (relatedName
== null || rel
.getType() == null || excludedFromTypes
.contains(rel
.getType().getUuid())) {
664 NameRelationDTO dto
= new NameRelationDTO();
665 loadBaseData(rel
, dto
);
667 dto
.setNameUuid(relatedName
.getUuid());
668 dto
.setNameLabel(relatedName
.getTaggedName());
670 dto
.setRelTypeUuid(rel
.getType().getUuid());
671 Representation rep
= rel
.getType().getPreferredInverseRepresentation(Arrays
.asList(new Language
[] {locale
}));
672 dto
.setRelType(rep
== null ? rel
.getType().toString() : rep
.getLabel());
674 dto
.setInverse(true);
675 taxonDto
.addRelatedName(dto
);
679 private void loadFacts(Taxon taxon
, TaxonPageDto taxonPageDto
, TaxonPageDtoConfiguration config
) {
682 //compute the features that do exist for this taxon
683 Map
<UUID
, Feature
> existingFeatureUuids
= getExistingFeatureUuids(taxon
);
685 //filter, sort and structure according to feature tree
686 TreeNode
<Feature
, UUID
> filteredRootNode
;
687 if (config
.getFeatureTree() != null) {
689 @SuppressWarnings({ "unchecked"})
690 TermTree
<Feature
> featureTree
= repository
.getTermTreeService().find(config
.getFeatureTree());
691 filteredRootNode
= filterFeatureNode(featureTree
.getRoot(), existingFeatureUuids
.keySet());
693 filteredRootNode
= createDefaultFeatureNode(taxon
);
696 //load facts per feature
697 Map
<UUID
,Set
<DescriptionElementBase
>> featureMap
= loadFeatureMap(taxon
);
700 if (filteredRootNode
!= null && !filteredRootNode
.getChildren().isEmpty()) {
701 ContainerDto
<FeatureDto
> features
= new ContainerDto
<>();
702 for (TreeNode
<Feature
,UUID
> node
: filteredRootNode
.getChildren()) {
703 handleFeatureNode(config
, featureMap
, features
, node
, taxonPageDto
);
705 taxonPageDto
.setTaxonFacts(features
);
707 } catch (Exception e
) {
708 //e.printStackTrace();
709 taxonPageDto
.addMessage(MessagesDto
.NewErrorInstance("Error when loading factual data.", e
));
713 //TODO merge with loadFacts, it is almost the same, see //DIFFERENT
714 private void loadNameFacts(TaxonName name
, TaxonBaseDto nameDto
, TaxonPageDtoConfiguration config
, TaxonPageDto pageDto
) {
717 //compute the features that do exist for this taxon
718 Map
<UUID
, Feature
> existingFeatureUuids
= getExistingFeatureUuids(name
);
720 //filter, sort and structure according to feature tree
721 TreeNode
<Feature
, UUID
> filteredRootNode
;
723 // if (config.getFeatureTree() != null) {
725 // @SuppressWarnings({ "unchecked"})
726 // TermTree<Feature> featureTree = repository.getTermTreeService().find(config.getFeatureTree());
727 // filteredRootNode = filterFeatureNode(featureTree.getRoot(), existingFeatureUuids.keySet());
729 filteredRootNode
= createDefaultFeatureNode(name
);
732 //load facts per feature
733 Map
<UUID
,Set
<DescriptionElementBase
>> featureMap
= loadFeatureMap(name
);
736 if (!filteredRootNode
.getChildren().isEmpty()) {
737 ContainerDto
<FeatureDto
> features
= new ContainerDto
<>();
738 for (TreeNode
<Feature
,UUID
> node
: filteredRootNode
.getChildren()) {
739 handleFeatureNode(config
, featureMap
, features
, node
, pageDto
);
742 nameDto
.setNameFacts(features
);
744 } catch (Exception e
) {
745 //e.printStackTrace();
747 pageDto
.addMessage(MessagesDto
.NewErrorInstance("Error when loading factual data.", e
));
751 private void handleFeatureNode(TaxonPageDtoConfiguration config
,
752 Map
<UUID
, Set
<DescriptionElementBase
>> featureMap
, ContainerDto
<FeatureDto
> features
,
753 TreeNode
<Feature
, UUID
> node
, TaxonPageDto pageDto
) {
755 Feature feature
= node
.getData();
757 FeatureDto featureDto
= new FeatureDto(feature
.getUuid(), feature
.getId(), feature
.getLabel());
758 features
.addItem(featureDto
);
760 List
<Distribution
> distributions
= new ArrayList
<>();
763 for (DescriptionElementBase fact
: featureMap
.get(feature
.getUuid())){
764 if (fact
.isInstanceOf(Distribution
.class)) {
765 distributions
.add(CdmBase
.deproxy(fact
, Distribution
.class));
767 //TODO how to handle CommonNames, do we also want to have a data structure
771 // a bit like for distribution??
772 handleFact(featureDto
, fact
, pageDto
);
776 handleDistributions(config
, featureDto
, distributions
, pageDto
);
777 //TODO really needed?
778 orderFacts(featureDto
);
781 ContainerDto
<FeatureDto
> childFeatures
= new ContainerDto
<>();
782 for (TreeNode
<Feature
,UUID
> child
: node
.getChildren()) {
783 handleFeatureNode(config
, featureMap
, childFeatures
, child
, pageDto
);
785 if (childFeatures
.getCount() > 0) {
786 featureDto
.setSubFeatures(childFeatures
);
790 //TODO not really used yet, only for distinguishing fact classes,
791 //needs discussion if needed and how to implement.
792 //we could also move compareTo methods to DTO classes but with this
793 //remove from having only data in the DTO, no logic
794 private void orderFacts(FeatureDto featureDto
) {
795 List
<IFactDto
> list
= featureDto
.getFacts().getItems();
796 Collections
.sort(list
, (f1
,f2
)->{
797 if (!f1
.getClass().equals(f2
.getClass())) {
798 return f1
.getClass().getSimpleName().compareTo(f2
.getClass().getSimpleName());
800 if (f1
instanceof FactDto
) {
801 FactDto fact1
= (FactDto
)f1
;
802 FactDto fact2
= (FactDto
)f2
;
804 // return fact1.getTypedLabel().toString().compareTo(fact2.getTypedLabel().toString());
806 } else if (f1
instanceof CommonNameDto
) {
808 CommonNameDto fact1
= (CommonNameDto
)f1
;
809 CommonNameDto fact2
= (CommonNameDto
)f2
;
818 private Map
<UUID
, Set
<DescriptionElementBase
>> loadFeatureMap(IDescribable
<?
> describable
) {
819 Map
<UUID
, Set
<DescriptionElementBase
>> featureMap
= new HashMap
<>();
822 for (DescriptionBase
<?
> description
: filterPublished(describable
.getDescriptions())) {
823 if (description
.isImageGallery()) {
826 for (DescriptionElementBase deb
: description
.getElements()) {
827 Feature feature
= deb
.getFeature();
828 if (featureMap
.get(feature
.getUuid()) == null) {
829 featureMap
.put(feature
.getUuid(), new HashSet
<>());
831 featureMap
.get(feature
.getUuid()).add(deb
);
837 private TreeNode
<Feature
, UUID
> createDefaultFeatureNode(IDescribable
<?
> describable
) {
838 TreeNode
<Feature
, UUID
> root
= new TreeNode
<>();
839 Set
<Feature
> requiredFeatures
= new HashSet
<>();
841 for (DescriptionBase
<?
> description
: describable
.getDescriptions()) {
842 if (description
.isImageGallery()) {
845 for (DescriptionElementBase deb
: description
.getElements()) {
846 Feature feature
= deb
.getFeature();
847 if (feature
!= null) { //null should not happen
848 requiredFeatures
.add(feature
);
852 List
<Feature
> sortedChildren
= new ArrayList
<>(requiredFeatures
);
853 Collections
.sort(sortedChildren
, (f1
,f2
) -> f1
.getTitleCache().compareTo(f2
.getTitleCache()));
854 sortedChildren
.stream().forEachOrdered(f
->root
.addChild(new TreeNode
<>(f
.getUuid(), f
)));
859 * Recursive call to a feature tree's feature node in order to creates a tree structure
860 * ordered in the same way as the according feature tree but only containing features
861 * that do really exist for the given taxon. If only a child node is required the parent
862 * node/feature is also considered to be required.<BR>
864 private TreeNode
<Feature
, UUID
> filterFeatureNode(TermNode
<Feature
> featureNode
,
865 Set
<UUID
> existingFeatureUuids
) {
867 //first filter children
868 List
<TreeNode
<Feature
, UUID
>> requiredChildNodes
= new ArrayList
<>();
869 for (TermNode
<Feature
> childNode
: featureNode
.getChildNodes()) {
870 TreeNode
<Feature
, UUID
> child
= filterFeatureNode(childNode
, existingFeatureUuids
);
872 requiredChildNodes
.add(child
);
876 //if any child is required or this node is required ....
877 if (!requiredChildNodes
.isEmpty() ||
878 featureNode
.getTerm() != null && existingFeatureUuids
.contains(featureNode
.getTerm().getUuid())) {
880 TreeNode
<Feature
,UUID
> result
= new TreeNode
<>();
881 //add this nodes data
882 Feature feature
= featureNode
.getTerm() == null ?
null : featureNode
.getTerm();
883 if (feature
!= null) {
884 result
.setNodeId(feature
.getUuid());
885 result
.setData(feature
);
888 requiredChildNodes
.stream().forEachOrdered(c
->result
.addChild(c
));
896 * Computes the (unsorted) set of features for which facts exist
897 * for the given taxon.
899 private Map
<UUID
, Feature
> getExistingFeatureUuids(IDescribable
<?
> describable
) {
900 Map
<UUID
, Feature
> result
= new HashMap
<>();
901 for (DescriptionBase
<?
> description
: filterPublished(describable
.getDescriptions())) {
902 if (description
.isImageGallery()) {
905 for (DescriptionElementBase deb
: description
.getElements()) {
906 Feature feature
= deb
.getFeature();
907 if (feature
!= null) { //null should not happen
908 result
.put(feature
.getUuid(), feature
);
915 private void handleDistributions(TaxonPageDtoConfiguration config
, FeatureDto featureDto
,
916 List
<Distribution
> distributions
, TaxonPageDto pageDto
) {
918 if (distributions
.isEmpty()) {
921 IDistributionService distributionService
= repository
.getDistributionService();
924 DistributionInfoConfiguration distributionConfig
= config
.getDistributionInfoConfiguration();
925 CondensedDistributionConfiguration condensedConfig
= distributionConfig
.getCondensedDistrConfig();
927 String statusColorsString
= distributionConfig
.getStatusColorsString();
930 //copied from DescriptionListController
932 boolean ignoreDistributionStatusUndefined
= true; //workaround until #9500 is fully implemented
933 distributionConfig
.setIgnoreDistributionStatusUndefined(ignoreDistributionStatusUndefined
);
934 boolean fallbackAsParent
= true; //may become a service parameter in future
936 DistributionInfoDto dto
;
938 //hiddenArea markers include markers for fully hidden areas and fallback areas. The later
939 //are hidden markers on areas that have non-hidden subareas (#4408)
940 Set
<MarkerType
> hiddenAreaMarkerTypes
= distributionConfig
.getHiddenAreaMarkerTypeList();
941 if(!CdmUtils
.isNullSafeEmpty(hiddenAreaMarkerTypes
)){
942 condensedConfig
.hiddenAndFallbackAreaMarkers
= hiddenAreaMarkerTypes
.stream().map(mt
->mt
.getUuid()).collect(Collectors
.toSet());
945 List
<String
> initStrategy
= null;
947 Map
<PresenceAbsenceTerm
, Color
> distributionStatusColors
;
949 distributionStatusColors
= DistributionServiceUtilities
.buildStatusColorMap(
950 statusColorsString
, repository
.getTermService(), repository
.getVocabularyService());
951 } catch (JsonProcessingException e
) {
952 pageDto
.addMessage(MessagesDto
.NewErrorInstance("JsonProcessingException when reading distribution status colors", e
));
953 //TODO is null allowed?
954 distributionStatusColors
= null;
957 dto
= distributionService
.composeDistributionInfoFor(distributionConfig
, distributions
,
959 distributionStatusColors
, LocaleContext
.getLanguages());
961 if (distributionConfig
.isUseTreeDto() && dto
.getTree() != null) {
962 DistributionTreeDto tree
= (DistributionTreeDto
)dto
.getTree();
963 TreeNode
<Set
<DistributionDto
>, NamedAreaDto
> root
= tree
.getRootElement();
964 //fill uuid->distribution map
965 Map
<UUID
,Distribution
> distributionMap
= new HashMap
<>();
966 distributions
.stream().forEach(d
->distributionMap
.put(d
.getUuid(), d
));
967 handleDistributionDtoNode(distributionMap
, root
);
970 featureDto
.addFact(dto
);
973 private void handleDistributionDtoNode(Map
<UUID
, Distribution
> map
,
974 TreeNode
<Set
<DistributionDto
>, NamedAreaDto
> root
) {
975 if (root
.getData() != null) {
976 root
.getData().stream().forEach(d
->{
977 Distribution distr
= map
.get(d
.getUuid());
978 loadBaseData(distr
, d
);
979 d
.setTimeperiod(distr
.getTimeperiod() == null ?
null : distr
.getTimeperiod().toString());
984 if (root
.getChildren() != null) {
985 root
.getChildren().stream().forEach(c
->handleDistributionDtoNode(map
, c
));
989 private FactDtoBase
handleFact(FeatureDto featureDto
, DescriptionElementBase fact
, TaxonPageDto pageDto
) {
991 Language localeLang
= null;
994 if (fact
.isInstanceOf(TextData
.class)) {
995 TextData td
= CdmBase
.deproxy(fact
, TextData
.class);
996 LanguageString ls
= td
.getPreferredLanguageString(localeLang
);
997 String text
= ls
== null ?
"" : CdmUtils
.Nz(ls
.getText());
999 FactDto factDto
= new FactDto();
1000 featureDto
.addFact(factDto
);
1001 //TODO do we really need type information for textdata here?
1002 TypedLabel typedLabel
= new TypedLabel(text
);
1003 typedLabel
.setClassAndId(td
);
1004 factDto
.getTypedLabel().add(typedLabel
);
1005 loadBaseData(td
, factDto
);
1008 }else if (fact
.isInstanceOf(CommonTaxonName
.class)) {
1009 CommonTaxonName ctn
= CdmBase
.deproxy(fact
, CommonTaxonName
.class);
1010 CommonNameDto dto
= new CommonNameDto();
1011 featureDto
.addFact(dto
);
1013 Language lang
= ctn
.getLanguage();
1015 String langLabel
= getTermLabel(lang
, localeLang
);
1016 dto
.setLanguage(langLabel
);
1017 dto
.setLanguageUuid(lang
.getUuid());
1020 dto
.setLanguage("-");
1023 NamedArea area
= ctn
.getArea();
1025 String areaLabel
= getTermLabel(area
, localeLang
);
1026 dto
.setArea(areaLabel
);
1027 dto
.setAreaUUID(area
.getUuid());
1029 dto
.setName(ctn
.getName());
1030 loadBaseData(ctn
, dto
);
1031 //TODO sort all common names (not urgent as this is done by portal code)
1033 } else if (fact
.isInstanceOf(IndividualsAssociation
.class)) {
1034 IndividualsAssociation ia
= CdmBase
.deproxy(fact
, IndividualsAssociation
.class);
1035 IndividualsAssociationDto dto
= new IndividualsAssociationDto ();
1037 LanguageString description
= MultilanguageTextHelper
.getPreferredLanguageString(ia
.getDescription(), Arrays
.asList(localeLang
));
1038 if (description
!= null) {
1039 dto
.setDescritpion(description
.getText());
1041 SpecimenOrObservationBase
<?
> specimen
= ia
.getAssociatedSpecimenOrObservation();
1042 if (specimen
!= null) {
1043 //TODO what to use here??
1044 dto
.setOccurrence(specimen
.getTitleCache());
1045 dto
.setOccurrenceUuid(specimen
.getUuid());
1048 featureDto
.addFact(dto
);
1049 loadBaseData(ia
, dto
);
1051 } else if (fact
.isInstanceOf(TaxonInteraction
.class)) {
1052 TaxonInteraction ti
= CdmBase
.deproxy(fact
, TaxonInteraction
.class);
1053 TaxonInteractionDto dto
= new TaxonInteractionDto ();
1055 LanguageString description
= MultilanguageTextHelper
.getPreferredLanguageString(
1056 ti
.getDescription(), Arrays
.asList(localeLang
));
1057 if (description
!= null) {
1058 dto
.setDescritpion(description
.getText());
1060 Taxon taxon
= ti
.getTaxon2();
1061 if (taxon
!= null) {
1062 //TODO what to use here??
1063 dto
.setTaxon(taxon
.cacheStrategy().getTaggedTitle(taxon
));
1064 dto
.setTaxonUuid(taxon
.getUuid());
1066 featureDto
.addFact(dto
);
1067 loadBaseData(ti
, dto
);
1069 }else if (fact
.isInstanceOf(CategoricalData
.class)) {
1070 CategoricalData cd
= CdmBase
.deproxy(fact
, CategoricalData
.class);
1071 FactDto factDto
= new FactDto();
1072 featureDto
.addFact(factDto
);
1073 //TODO do we really need type information for textdata here?
1074 String label
= CategoricalDataFormatter
.NewInstance(null).format(cd
, localeLang
);
1075 TypedLabel typedLabel
= new TypedLabel(label
);
1076 typedLabel
.setClassAndId(cd
);
1077 factDto
.getTypedLabel().add(typedLabel
);
1079 loadBaseData(cd
, factDto
);
1081 }else if (fact
.isInstanceOf(QuantitativeData
.class)) {
1082 QuantitativeData qd
= CdmBase
.deproxy(fact
, QuantitativeData
.class);
1083 FactDto factDto
= new FactDto();
1084 featureDto
.addFact(factDto
);
1085 //TODO do we really need type information for textdata here?
1086 String label
= QuantitativeDataFormatter
.NewInstance(null).format(qd
, localeLang
);
1087 TypedLabel typedLabel
= new TypedLabel(label
);
1088 typedLabel
.setClassAndId(qd
);
1089 factDto
.getTypedLabel().add(typedLabel
);
1091 loadBaseData(qd
, factDto
);
1093 }else if (fact
.isInstanceOf(TemporalData
.class)) {
1094 TemporalData td
= CdmBase
.deproxy(fact
, TemporalData
.class);
1095 FactDto factDto
= new FactDto();
1096 featureDto
.addFact(factDto
);
1097 //TODO do we really need type information for textdata here?
1098 String label
= td
.toString();
1099 TypedLabel typedLabel
= new TypedLabel(label
);
1100 typedLabel
.setClassAndId(td
);
1101 factDto
.getTypedLabel().add(typedLabel
);
1103 loadBaseData(td
, factDto
);
1106 pageDto
.addMessage(MessagesDto
.NewWarnInstance("DescriptionElement type not yet handled: " + fact
.getClass().getSimpleName()));
1109 result
.setTimeperiod(fact
.getTimeperiod() == null ?
null : fact
.getTimeperiod().toString());
1113 private String
getTermLabel(TermBase term
, Language localeLang
) {
1117 Representation rep
= term
.getPreferredRepresentation(localeLang
);
1118 String label
= rep
== null ?
null : rep
.getLabel();
1119 label
= label
== null ? term
.getLabel() : label
;
1124 * Compares an existing last date and the last date of an entity
1125 * and returns the resulting last date.
1127 private LocalDateTime
getLastUpdated(LocalDateTime existingLastDate
, VersionableEntity dateToAddEntity
) {
1129 DateTime dateToAdd
= dateToAddEntity
.getUpdated() != null ? dateToAddEntity
.getUpdated() : dateToAddEntity
.getCreated();
1131 LocalDateTime javaLocalDateTimeOfEntity
= dateToAdd
== null ?
null:
1132 LocalDateTime
.of(dateToAdd
.getYear(), dateToAdd
.getMonthOfYear(),
1133 dateToAdd
.getDayOfMonth(), dateToAdd
.getHourOfDay(),
1134 dateToAdd
.getMinuteOfHour(), dateToAdd
.getSecondOfMinute());
1136 if (existingLastDate
== null) {
1137 return javaLocalDateTimeOfEntity
;
1138 }else if (javaLocalDateTimeOfEntity
== null || javaLocalDateTimeOfEntity
.compareTo(existingLastDate
) < 0) {
1139 return existingLastDate
;
1141 return javaLocalDateTimeOfEntity
;
1145 private void loadBaseData(CdmBase cdmBase
, CdmBaseDto dto
) {
1146 dto
.setId(cdmBase
.getId());
1147 dto
.setUuid(cdmBase
.getUuid());
1149 loadAnnotatable(cdmBase
, dto
);
1150 loadSources(cdmBase
, dto
);
1151 //loadIdentifiable(cdmBase, dto);
1154 private void loadSources(CdmBase cdmBase
, CdmBaseDto dto
) {
1155 if (dto
instanceof SingleSourcedDto
&& cdmBase
.isInstanceOf(SingleSourcedEntityBase
.class)) {
1156 //TODO other sourced
1157 SingleSourcedEntityBase sourced
= CdmBase
.deproxy(cdmBase
, SingleSourcedEntityBase
.class);
1158 SingleSourcedDto sourcedDto
= (SingleSourcedDto
)dto
;
1159 NamedSource source
= sourced
.getSource();
1160 if (source
!= null) { //TODO && !source.isEmpty() - does not exist yet
1161 SourceDto sourceDto
= new SourceDto();
1162 loadSource(source
, sourceDto
);
1163 sourcedDto
.setSource(sourceDto
);
1165 } else if (dto
instanceof SourcedDto
&& cdmBase
instanceof ISourceable
) {
1166 @SuppressWarnings("unchecked")
1167 ISourceable
<OriginalSourceBase
> sourced
= (ISourceable
<OriginalSourceBase
>)cdmBase
;
1168 SourcedDto sourcedDto
= (SourcedDto
)dto
;
1169 for (OriginalSourceBase source
: sourced
.getSources()) {
1170 SourceDto sourceDto
= new SourceDto();
1171 loadSource(source
, sourceDto
);
1172 sourcedDto
.addSource(sourceDto
);
1175 //load description sources for facts
1176 if (cdmBase
.isInstanceOf(DescriptionElementBase
.class)){
1177 DescriptionBase
<?
> db
= CdmBase
.deproxy(cdmBase
, DescriptionElementBase
.class).getInDescription();
1178 SourcedDto sourcedDto
= (SourcedDto
)dto
;
1179 for (OriginalSourceBase source
: db
.getSources()) {
1180 SourceDto sourceDto
= new SourceDto();
1181 loadSource(source
, sourceDto
);
1182 sourcedDto
.addSource(sourceDto
);
1187 private void loadSource(OriginalSourceBase source
, SourceDto sourceDto
) {
1189 source
= CdmBase
.deproxy(source
);
1191 loadBaseData(source
, sourceDto
);
1193 ICdmBase linkedObject
= source
.getCitation();
1194 if (linkedObject
== null) {
1196 linkedObject
= source
.getCdmSource();
1199 //citation doi & uri & links
1200 Reference ref
= source
.getCitation();
1202 sourceDto
.setDoi(ref
.getDoiString());
1203 sourceDto
.setUri(ref
.getUri());
1204 Set
<ExternalLink
> links
= ref
.getLinks();
1205 for (ExternalLink link
: links
) {
1206 if (link
.getUri() != null) {
1207 sourceDto
.addLink(link
.getUri());
1213 //TODO this probably does not use specimen or cdmSource if necessary,
1214 // also long citation is still preliminary
1215 String label
= OriginalSourceFormatter
.INSTANCE_LONG_CITATION
.format(source
);
1216 TypedLabel typedLabel
= new TypedLabel(source
, label
);
1217 sourceDto
.addLabel(typedLabel
);
1218 sourceDto
.setType(source
.getType() != null ? source
.getType().toString() : null);
1220 if (source
.isInstanceOf(NamedSourceBase
.class)) {
1221 NamedSourceBase ns
= CdmBase
.deproxy(source
, NamedSourceBase
.class);
1224 TaxonName name
= ns
.getNameUsedInSource();
1226 List
<TaggedText
> taggedName
= name
.cacheStrategy().getTaggedTitle(name
);
1228 sourceDto
.setNameInSource(taggedName
);
1229 sourceDto
.setNameInSourceUuid(name
.getUuid());
1233 if (source
.isInstanceOf(DescriptionElementSource
.class)) {
1234 DescriptionElementSource des
= CdmBase
.deproxy(source
, DescriptionElementSource
.class);
1235 if (linkedObject
== null) {
1236 linkedObject
= des
.getSpecimen();
1241 sourceDto
.setLinkedUuid(getUuid(linkedObject
));
1242 String linkedObjectStr
= linkedObject
== null ?
null : CdmBase
.deproxy(linkedObject
).getClass().getSimpleName();
1243 sourceDto
.setLinkedClass(linkedObjectStr
);
1246 private UUID
getUuid(ICdmBase cdmBase
) {
1247 return cdmBase
== null ?
null : cdmBase
.getUuid();
1250 private void loadAnnotatable(CdmBase cdmBase
, CdmBaseDto dto
) {
1251 if (dto
instanceof AnnotatableDto
&& cdmBase
.isInstanceOf(AnnotatableEntity
.class)) {
1252 AnnotatableEntity annotatable
= CdmBase
.deproxy(cdmBase
, AnnotatableEntity
.class);
1253 AnnotatableDto annotatableDto
= (AnnotatableDto
)dto
;
1255 for (Annotation annotation
: annotatable
.getAnnotations()) {
1256 if (annotation
.getAnnotationType() != null
1257 //TODO annotation type filter
1258 && annotation
.getAnnotationType().getUuid().equals(AnnotationType
.uuidEditorial
)
1259 && StringUtils
.isNotBlank(annotation
.getText())) {
1261 AnnotationDto annotationDto
= new AnnotationDto();
1262 annotatableDto
.addAnnotation(annotationDto
);
1263 //TODO id needed? but need to adapt dto and container then
1264 loadBaseData(annotation
, annotationDto
);
1265 annotationDto
.setText(annotation
.getText());
1266 UUID uuidAnnotationType
= annotation
.getAnnotationType() == null ?
null :annotation
.getAnnotationType().getUuid();
1267 annotationDto
.setTypeUuid(uuidAnnotationType
);
1268 //language etc. currently not yet used
1273 for (Marker marker
: annotatable
.getMarkers()) {
1274 if (marker
.getMarkerType() != null
1275 //TODO markertype filter
1276 // && marker.getMarkerType().getUuid().equals(AnnotationType.uuidEditorial)
1279 MarkerDto markerDto
= new MarkerDto();
1280 annotatableDto
.addMarker(markerDto
);
1281 //TODO id needed? but need to adapt dto and container then
1282 loadBaseData(marker
, markerDto
);
1283 if (marker
.getMarkerType() != null) {
1284 markerDto
.setTypeUuid(marker
.getMarkerType().getUuid());
1286 markerDto
.setType(marker
.getMarkerType().getTitleCache());
1288 markerDto
.setValue(marker
.getValue());