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
.TaxonInteractionDto
;
53 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
;
54 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.ConceptRelationDTO
;
55 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.HomotypicGroupDTO
;
56 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.KeyDTO
;
57 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.MediaDTO
;
58 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.MediaRepresentationDTO
;
59 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.NameRelationDTO
;
60 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.SpecimenDTO
;
61 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.TaxonNodeAgentsRelDTO
;
62 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.TaxonPageDto
.TaxonNodeDTO
;
63 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.config
.DistributionInfoConfiguration
;
64 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.config
.TaxonPageDtoConfiguration
;
65 import eu
.etaxonomy
.cdm
.api
.service
.geo
.DistributionServiceUtilities
;
66 import eu
.etaxonomy
.cdm
.api
.service
.geo
.IDistributionService
;
67 import eu
.etaxonomy
.cdm
.api
.service
.l10n
.LocaleContext
;
68 import eu
.etaxonomy
.cdm
.api
.service
.name
.TypeDesignationSetContainer
;
69 import eu
.etaxonomy
.cdm
.api
.service
.name
.TypeDesignationSetFormatter
;
70 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
71 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
72 import eu
.etaxonomy
.cdm
.common
.TreeNode
;
73 import eu
.etaxonomy
.cdm
.compare
.taxon
.TaxonComparator
;
74 import eu
.etaxonomy
.cdm
.format
.common
.TypedLabel
;
75 import eu
.etaxonomy
.cdm
.format
.description
.CategoricalDataFormatter
;
76 import eu
.etaxonomy
.cdm
.format
.description
.QuantitativeDataFormatter
;
77 import eu
.etaxonomy
.cdm
.format
.description
.distribution
.CondensedDistributionConfiguration
;
78 import eu
.etaxonomy
.cdm
.format
.reference
.OriginalSourceFormatter
;
79 import eu
.etaxonomy
.cdm
.format
.taxon
.TaxonRelationshipFormatter
;
80 import eu
.etaxonomy
.cdm
.model
.common
.AnnotatableEntity
;
81 import eu
.etaxonomy
.cdm
.model
.common
.Annotation
;
82 import eu
.etaxonomy
.cdm
.model
.common
.AnnotationType
;
83 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
84 import eu
.etaxonomy
.cdm
.model
.common
.ICdmBase
;
85 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
86 import eu
.etaxonomy
.cdm
.model
.common
.LanguageString
;
87 import eu
.etaxonomy
.cdm
.model
.common
.Marker
;
88 import eu
.etaxonomy
.cdm
.model
.common
.MarkerType
;
89 import eu
.etaxonomy
.cdm
.model
.common
.MultilanguageTextHelper
;
90 import eu
.etaxonomy
.cdm
.model
.common
.SingleSourcedEntityBase
;
91 import eu
.etaxonomy
.cdm
.model
.common
.VersionableEntity
;
92 import eu
.etaxonomy
.cdm
.model
.description
.CategoricalData
;
93 import eu
.etaxonomy
.cdm
.model
.description
.CommonTaxonName
;
94 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
95 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
96 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementSource
;
97 import eu
.etaxonomy
.cdm
.model
.description
.Distribution
;
98 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
99 import eu
.etaxonomy
.cdm
.model
.description
.IDescribable
;
100 import eu
.etaxonomy
.cdm
.model
.description
.IndividualsAssociation
;
101 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKey
;
102 import eu
.etaxonomy
.cdm
.model
.description
.PresenceAbsenceTerm
;
103 import eu
.etaxonomy
.cdm
.model
.description
.QuantitativeData
;
104 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
105 import eu
.etaxonomy
.cdm
.model
.description
.TaxonInteraction
;
106 import eu
.etaxonomy
.cdm
.model
.description
.TemporalData
;
107 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
108 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
109 import eu
.etaxonomy
.cdm
.model
.media
.ExternalLink
;
110 import eu
.etaxonomy
.cdm
.model
.media
.ImageFile
;
111 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
112 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
113 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentationPart
;
114 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
115 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationship
;
116 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationshipType
;
117 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalSource
;
118 import eu
.etaxonomy
.cdm
.model
.name
.SpecimenTypeDesignation
;
119 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
120 import eu
.etaxonomy
.cdm
.model
.name
.TypeDesignationBase
;
121 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
122 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
123 import eu
.etaxonomy
.cdm
.model
.reference
.ISourceable
;
124 import eu
.etaxonomy
.cdm
.model
.reference
.NamedSource
;
125 import eu
.etaxonomy
.cdm
.model
.reference
.NamedSourceBase
;
126 import eu
.etaxonomy
.cdm
.model
.reference
.OriginalSourceBase
;
127 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
128 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
129 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
130 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
131 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
132 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNodeAgentRelation
;
133 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNodeStatus
;
134 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
135 import eu
.etaxonomy
.cdm
.model
.term
.Representation
;
136 import eu
.etaxonomy
.cdm
.model
.term
.TermBase
;
137 import eu
.etaxonomy
.cdm
.model
.term
.TermNode
;
138 import eu
.etaxonomy
.cdm
.model
.term
.TermTree
;
139 import eu
.etaxonomy
.cdm
.strategy
.cache
.TaggedCacheHelper
;
140 import eu
.etaxonomy
.cdm
.strategy
.cache
.TaggedText
;
141 import eu
.etaxonomy
.cdm
.strategy
.cache
.taxon
.TaxonBaseDefaultCacheStrategy
;
144 * Loads the portal dto from a taxon instance.
145 * Maybe later also supports loading from persistence.
150 public class PortalDtoLoader
{
152 private static final Logger logger
= LogManager
.getLogger();
154 private ICdmRepository repository
;
156 public PortalDtoLoader(ICdmRepository repository
) {
157 this.repository
= repository
;
160 public TaxonPageDto
load(Taxon taxon
, TaxonPageDtoConfiguration config
) {
161 TaxonPageDto result
= new TaxonPageDto();
163 loadAcceptedTaxon(taxon
, config
, result
);
165 loadTaxonNodes(taxon
, result
, config
);
166 loadSynonyms(taxon
, result
, config
);
167 loadConceptRelations(taxon
, result
, config
);
168 loadFacts(taxon
, result
, config
);
169 loadMedia(taxon
, result
, config
);
170 loadSpecimens(taxon
, result
, config
);
171 loadKeys(taxon
, result
, config
);
176 private void loadAcceptedTaxon(Taxon taxon
, TaxonPageDtoConfiguration config
, TaxonPageDto result
) {
178 TaxonName name
= taxon
.getName();
181 //TODO supplementalData for name
182 loadBaseData(taxon
, result
);
183 result
.setLastUpdated(getLastUpdated(null, taxon
));
184 result
.setLabel(CdmUtils
.Nz(taxon
.getTitleCache()));
185 // result.setTypedTaxonLabel(getTypedTaxonLabel(taxon, config));
186 result
.setTaggedLabel(getTaggedTaxon(taxon
, config
));
188 handleName(config
, result
, name
, result
);
190 } catch (Exception e
) {
191 //e.printStackTrace();
192 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading accepted name data.", e
));
196 private void handleName(TaxonPageDtoConfiguration config
, TaxonBaseDto nameDto
, TaxonName name
, TaxonPageDto pageDto
) {
197 nameDto
.setNameLabel(name
.getTitleCache());
198 handleRelatedNames(name
, nameDto
, config
);
199 loadProtologues(name
, nameDto
);
200 nameDto
.setNameUuid(name
.getUuid());
201 nameDto
.setNameType(name
.getNameType().toString());
202 loadNameFacts(name
, nameDto
, config
, pageDto
);
203 nameDto
.setTaggedName(name
.getTaggedFullTitle());
206 private List
<TaggedText
> getTaggedTaxon(TaxonBase
<?
> taxon
, TaxonPageDtoConfiguration config
) {
207 // List<TypedLabel> result = new ArrayList<>();
208 TaxonBaseDefaultCacheStrategy
<TaxonBase
<?
>> formatter
= new TaxonBaseDefaultCacheStrategy
<>();
209 List
<TaggedText
> tags
= formatter
.getTaggedTitle(taxon
);
213 private void loadKeys(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
215 ContainerDto
<KeyDTO
> container
= new ContainerDto
<>();
217 //TODO other key types, but type must not be null, otherwise NPE
218 Pager
<PolytomousKey
> keys
= repository
.getIdentificationKeyService().findKeysConvering(taxon
, PolytomousKey
.class, null, null, null);
219 for (PolytomousKey key
: keys
.getRecords()) {
220 KeyDTO dto
= new KeyDTO();
221 loadBaseData(key
, dto
);
222 dto
.setLabel(key
.getTitleCache());
223 dto
.setKeyClass(key
.getClass().getSimpleName());
224 container
.addItem(dto
);
226 if (container
.getCount() > 0) {
227 result
.setKeys(container
);
229 } catch (Exception e
) {
230 //e.printStackTrace();
231 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading identification key data.", e
));
235 private void loadSpecimens(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
236 //TODO load specimen from multiple places
239 ContainerDto
<SpecimenDTO
> container
= new ContainerDto
<>();
241 List
<SpecimenOrObservationBase
<?
>> specimens
= new ArrayList
<>();
242 for (TaxonDescription taxonDescription
: taxon
.getDescriptions()) {
243 if (taxonDescription
.isImageGallery()) {
246 for (DescriptionElementBase el
: taxonDescription
.getElements()) {
247 if (el
.isInstanceOf(IndividualsAssociation
.class)) {
248 IndividualsAssociation indAss
= CdmBase
.deproxy(el
, IndividualsAssociation
.class);
249 SpecimenOrObservationBase
<?
> specimen
= indAss
.getAssociatedSpecimenOrObservation();
250 specimens
.add(specimen
);
254 List
<SpecimenOrObservationBase
<?
>> typeSpecimens
= loadTypeSpecimen(taxon
.getName(), config
);
255 specimens
.addAll(typeSpecimens
);
256 for (TaxonName syn
: taxon
.getSynonymNames()) {
257 typeSpecimens
= loadTypeSpecimen(syn
, config
);
258 specimens
.addAll(typeSpecimens
);
261 for (SpecimenOrObservationBase
<?
> specimen
: specimens
) {
262 SpecimenDTO dto
= new SpecimenDTO();
263 loadBaseData(specimen
, dto
);
264 dto
.setLabel(specimen
.getTitleCache());
265 container
.addItem(dto
);
267 if (container
.getCount() > 0 ) {
268 result
.setSpecimens(container
);
270 } catch (Exception e
) {
271 //e.printStackTrace();
272 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading specimen data.", e
));
276 private List
<SpecimenOrObservationBase
<?
>> loadTypeSpecimen(TaxonName name
, TaxonPageDtoConfiguration config
) {
277 List
<SpecimenOrObservationBase
<?
>> result
= new ArrayList
<>();
278 for (SpecimenTypeDesignation desig
: name
.getSpecimenTypeDesignations()){
279 DerivedUnit specimen
= desig
.getTypeSpecimen();
280 if (specimen
!= null) {
281 result
.add(specimen
);
287 private void loadMedia(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
290 ContainerDto
<MediaDTO
> container
= new ContainerDto
<TaxonPageDto
.MediaDTO
>();
292 List
<Media
> medias
= new ArrayList
<>();
293 for (TaxonDescription taxonDescription
: taxon
.getDescriptions()) {
294 if (!taxonDescription
.isImageGallery()) {
298 List
<Media
> newMedia
= taxonDescription
.getElements().stream()
299 .filter(el
->el
.isInstanceOf(TextData
.class))
300 .map(el
->CdmBase
.deproxy(el
, TextData
.class))
302 .flatMap(td
->td
.getMedia().stream())
303 .collect(Collectors
.toList())
305 medias
.addAll(newMedia
);
307 //TODO collect media from elsewhere
308 for (Media media
: medias
) {
309 MediaDTO dto
= new TaxonPageDto
.MediaDTO();
310 loadBaseData(media
, dto
);
311 dto
.setLabel(media
.getTitleCache());
312 ContainerDto
<MediaRepresentationDTO
> representations
= new ContainerDto
<>();
313 for (MediaRepresentation rep
: media
.getRepresentations()) {
314 MediaRepresentationDTO repDto
= new MediaRepresentationDTO();
315 loadBaseData(rep
, dto
);
316 repDto
.setMimeType(rep
.getMimeType());
317 repDto
.setSuffix(rep
.getSuffix());
318 if (!rep
.getParts().isEmpty()) {
319 //TODO handle message if n(parts) > 1
320 MediaRepresentationPart part
= rep
.getParts().get(0);
321 repDto
.setUri(part
.getUri());
322 repDto
.setClazz(part
.getClass());
323 repDto
.setSize(part
.getSize());
324 if (part
.isInstanceOf(ImageFile
.class)) {
325 ImageFile image
= CdmBase
.deproxy(part
, ImageFile
.class);
326 repDto
.setHeight(image
.getHeight());
327 repDto
.setWidth(image
.getWidth());
329 //TODO AudioFile etc.
331 representations
.addItem(repDto
);
333 if (representations
.getCount() > 0) {
334 dto
.setRepresentations(representations
);
336 //TODO load representation data
337 container
.addItem(dto
);
340 if (container
.getCount() > 0) {
341 result
.setMedia(container
);
343 } catch (Exception e
) {
344 //e.printStackTrace();
345 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading media data.", e
));
349 private void loadTaxonNodes(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
351 ContainerDto
<TaxonNodeDTO
> container
= new ContainerDto
<TaxonPageDto
.TaxonNodeDTO
>();
352 for (TaxonNode node
: taxon
.getTaxonNodes()) {
353 TaxonNodeDTO dto
= new TaxonNodeDTO();
354 loadBaseData(node
, dto
);
356 Classification classification
= node
.getClassification();
357 if (classification
!= null) {
358 dto
.setClassificationUuid(node
.getClassification().getUuid());
359 dto
.setClassificationLabel(classification
.getName().getText());
362 Language language
= Language
.DEFAULT();
365 TaxonNodeStatus status
= node
.getStatus();
366 if (status
!= null) {
367 dto
.setStatus(status
.getLabel(language
));
370 Map
<Language
, LanguageString
> statusNote
= node
.getStatusNote();
371 if (statusNote
!= null) {
372 //TODO handle fallback lang
373 LanguageString statusNoteStr
= statusNote
.get(language
);
374 if (statusNoteStr
== null && statusNote
.size() > 0) {
375 statusNoteStr
= statusNote
.entrySet().iterator().next().getValue();
377 if (statusNoteStr
!= null) {
378 dto
.setStatusNote(statusNoteStr
.getText());
382 Set
<TaxonNodeAgentRelation
> agents
= node
.getAgentRelations();
383 if (!agents
.isEmpty()) {
384 for (TaxonNodeAgentRelation rel
: agents
) {
385 TaxonNodeAgentsRelDTO agentDto
= new TaxonNodeAgentsRelDTO();
386 loadBaseData(rel
, agentDto
);
389 if (rel
.getAgent() != null) {
390 agentDto
.setAgent(rel
.getAgent().getFullTitle());
391 agentDto
.setAgentUuid(rel
.getAgent().getUuid());
392 //TODO compute preferred external link
393 agentDto
.setAgentLink(null);
395 if (rel
.getType() != null) {
396 agentDto
.setType(rel
.getType().getTitleCache());
397 agentDto
.setTypeUuid(rel
.getType().getUuid());
399 dto
.addAgent(agentDto
);
402 container
.addItem(dto
);
404 if (container
.getCount() > 0) {
405 result
.setTaxonNodes(container
);
407 } catch (Exception e
) {
408 // e.printStackTrace();
409 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading taxon node data.", e
));
413 private void loadSynonyms(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
416 // List<HomotypicalGroup> homotypicGroups = taxon.getHomotypicSynonymyGroups();
418 TaxonComparator comparator
= new TaxonComparator();
420 TaxonName name
= taxon
.getName();
422 //TODO depending on config add/remove accepted name
424 //TODO check publish flag
427 List
<Synonym
> homotypicSynonmys
= 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
= 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 boolean withCitation
= true;
470 boolean withStartingTypeLabel
= true;
471 boolean withNameIfAvailable
= false;
472 TypeDesignationSetFormatter formatter
= new TypeDesignationSetFormatter(
473 withCitation
, withStartingTypeLabel
, withNameIfAvailable
);
474 Set
<TypeDesignationBase
<?
>> desigs
= homotypicalGroup
.getTypeDesignations();
476 TypeDesignationSetContainer manager
= TypeDesignationSetContainer
.NewDefaultInstance((Set
)desigs
);
477 List
<TaggedText
> tags
= formatter
.toTaggedText(manager
);
478 String label
= TaggedCacheHelper
.createString(tags
);
479 hgDto
.setTypes(label
);
480 hgDto
.setTaggedTypes(tags
);
481 // hgDto.setTypedTypes(null);
483 } catch (Exception e
) {
484 // e.printStackTrace();
485 result
.addMessage(MessagesDto
.NewErrorInstance("Error when creating type designation information", e
));
489 private void loadConceptRelations(Taxon taxon
, TaxonPageDto result
, TaxonPageDtoConfiguration config
) {
493 ContainerDto
<ConceptRelationDTO
> conceptRelContainer
= new ContainerDto
<>();
494 TaxonRelationshipFormatter taxRelFormatter
= TaxonRelationshipFormatter
.INSTANCE();
497 Set
<TaxonRelationship
> misappliedRels
= taxon
.getMisappliedNameRelations();
498 for (TaxonRelationship rel
: misappliedRels
) {
499 boolean inverse
= true;
500 boolean withoutName
= false;
501 loadConceptRelation(taxRelFormatter
, rel
, conceptRelContainer
, inverse
, withoutName
);
504 //... pro parte Synonyms
505 Set
<TaxonRelationship
> proParteRels
= taxon
.getProParteAndPartialSynonymRelations();
506 for (TaxonRelationship rel
: proParteRels
) {
507 boolean inverse
= true;
508 boolean withoutName
= false;
509 loadConceptRelation(taxRelFormatter
, rel
, conceptRelContainer
, inverse
, withoutName
);
512 //TODO MAN and pp from this taxon
515 Set
<TaxonRelationship
> toRels
= taxon
.getRelationsToThisTaxon();
516 toRels
.removeAll(misappliedRels
);
517 toRels
.removeAll(proParteRels
);
518 for (TaxonRelationship rel
: toRels
) {
519 boolean inverse
= true;
520 boolean withoutName
= false;
521 loadConceptRelation(taxRelFormatter
, rel
, conceptRelContainer
, inverse
, withoutName
);
525 Set
<TaxonRelationship
> fromRels
= taxon
.getRelationsFromThisTaxon();
526 for (TaxonRelationship rel
: fromRels
) {
527 boolean inverse
= false;
528 boolean withoutName
= false;
529 loadConceptRelation(taxRelFormatter
, rel
, conceptRelContainer
, inverse
, withoutName
);
532 if (conceptRelContainer
.getCount() > 0) {
533 result
.setConceptRelations(conceptRelContainer
);
535 } catch (Exception e
) {
536 //e.printStackTrace();
537 result
.addMessage(MessagesDto
.NewErrorInstance("Error when loading concept relation data.", e
));
541 private void loadConceptRelation(TaxonRelationshipFormatter taxRelFormatter
, TaxonRelationship rel
, ContainerDto
<ConceptRelationDTO
> conceptRelContainer
, boolean inverse
,
542 boolean withoutName
) {
543 List
<Language
> languages
= Arrays
.asList(new Language
[] {Language
.DEFAULT()}); // TODO config.locales;
544 List
<TaggedText
> tags
= taxRelFormatter
.getTaggedText(rel
, inverse
, languages
, withoutName
);
545 String relLabel
= TaggedCacheHelper
.createString(tags
);
546 ConceptRelationDTO dto
= new TaxonPageDto
.ConceptRelationDTO();
547 loadBaseData(rel
, dto
);
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
.setLabel(relLabel
);
553 if (rel
.getType() != null) {
554 dto
.setRelTypeUuid(rel
.getType().getUuid());
556 for (TaxonNode node
: relTaxon
.getTaxonNodes()) {
557 Classification classification
= node
.getClassification();
558 if (classification
!= null) {
559 dto
.addClassificationUuids(classification
.getUuid());
562 conceptRelContainer
.addItem(dto
);
565 private void loadSynonymsInGroup(TaxonPageDto
.HomotypicGroupDTO hgDto
, Synonym syn
,
566 TaxonPageDtoConfiguration config
, TaxonPageDto pageDto
) {
568 TaxonBaseDto synDto
= new TaxonBaseDto();
569 loadBaseData(syn
, synDto
);
570 synDto
.setLabel(syn
.getTitleCache());
571 synDto
.setTaggedLabel(getTaggedTaxon(syn
, config
));
573 if (syn
.getName() != null) {
574 handleName(config
, synDto
, syn
.getName(), pageDto
);
575 synDto
.setNameLabel(syn
.getName().getTitleCache());
576 handleRelatedNames(syn
.getName(), synDto
, config
);
577 loadProtologues(syn
.getName(), synDto
);
581 hgDto
.addSynonym(synDto
);
584 private void loadProtologues(TaxonName name
, TaxonBaseDto taxonBaseDto
) {
585 NomenclaturalSource nomSource
= name
.getNomenclaturalSource();
586 if (nomSource
!= null) {
587 Set
<ExternalLink
> links
= nomSource
.getLinks();
588 for (ExternalLink link
: links
) {
589 if (link
.getUri() != null) {
590 taxonBaseDto
.addProtologue(link
.getUri());
596 private void handleRelatedNames(TaxonName name
, TaxonBaseDto taxonDto
, TaxonPageDtoConfiguration config
) {
597 //exclusions TODO handle via config
598 Set
<UUID
> excludedTypes
= new HashSet
<>(); //both directions
599 excludedTypes
.add(NameRelationshipType
.uuidBasionym
);
600 excludedTypes
.add(NameRelationshipType
.uuidReplacedSynonym
);
601 Set
<UUID
> excludedFromTypes
= new HashSet
<>(excludedTypes
);
602 Set
<UUID
> excludedToTypes
= new HashSet
<>(excludedTypes
);
605 //TODO config.getLocales();
606 Language locale
= Language
.DEFAULT();
608 for (NameRelationship rel
: name
.getRelationsFromThisName()) {
609 TaxonName relatedName
= rel
.getToName();
610 if (relatedName
== null || rel
.getType() == null || excludedFromTypes
.contains(rel
.getType().getUuid())) {
613 NameRelationDTO dto
= new NameRelationDTO();
614 loadBaseData(rel
, dto
);
616 dto
.setNameUuid(relatedName
.getUuid());
617 dto
.setNameLabel(relatedName
.getTaggedName());
619 dto
.setRelTypeUuid(rel
.getType().getUuid());
620 Representation rep
= rel
.getType().getPreferredRepresentation(locale
);
621 dto
.setRelType(rep
== null ? rel
.getType().toString() : rep
.getLabel());
623 dto
.setInverse(false);
625 dto
.setRuleConsidered(rel
.getRuleConsidered());
626 taxonDto
.addRelatedName(dto
);
630 for (NameRelationship rel
: name
.getRelationsToThisName()) {
631 TaxonName relatedName
= rel
.getFromName();
632 if (relatedName
== null || rel
.getType() == null || excludedFromTypes
.contains(rel
.getType().getUuid())) {
635 NameRelationDTO dto
= new NameRelationDTO();
636 loadBaseData(rel
, dto
);
638 dto
.setNameUuid(relatedName
.getUuid());
639 dto
.setNameLabel(relatedName
.getTaggedName());
641 dto
.setRelTypeUuid(rel
.getType().getUuid());
642 Representation rep
= rel
.getType().getPreferredInverseRepresentation(Arrays
.asList(new Language
[] {locale
}));
643 dto
.setRelType(rep
== null ? rel
.getType().toString() : rep
.getLabel());
645 dto
.setInverse(true);
646 taxonDto
.addRelatedName(dto
);
650 private void loadFacts(Taxon taxon
, TaxonPageDto taxonPageDto
, TaxonPageDtoConfiguration config
) {
653 //compute the features that do exist for this taxon
654 Map
<UUID
, Feature
> existingFeatureUuids
= getExistingFeatureUuids(taxon
);
656 //filter, sort and structure according to feature tree
657 TreeNode
<Feature
, UUID
> filteredRootNode
;
658 if (config
.getFeatureTree() != null) {
661 TermTree
<Feature
> featureTree
= repository
.getTermTreeService().find(config
.getFeatureTree());
662 filteredRootNode
= filterFeatureNode(featureTree
.getRoot(), existingFeatureUuids
.keySet());
664 filteredRootNode
= createDefaultFeatureNode(taxon
);
667 //load facts per feature
668 Map
<UUID
,Set
<DescriptionElementBase
>> featureMap
= loadFeatureMap(taxon
);
671 if (!filteredRootNode
.getChildren().isEmpty()) {
672 ContainerDto
<FeatureDto
> features
= new ContainerDto
<>();
673 for (TreeNode
<Feature
,UUID
> node
: filteredRootNode
.getChildren()) {
674 handleFeatureNode(config
, featureMap
, features
, node
);
676 taxonPageDto
.setTaxonFacts(features
);
678 } catch (Exception e
) {
679 //e.printStackTrace();
680 taxonPageDto
.addMessage(MessagesDto
.NewErrorInstance("Error when loading factual data.", e
));
684 //TODO merge with loadFacts, it is almost the same, see //DIFFERENT
685 private void loadNameFacts(TaxonName name
, TaxonBaseDto nameDto
, TaxonPageDtoConfiguration config
, TaxonPageDto pageDto
) {
688 //compute the features that do exist for this taxon
689 Map
<UUID
, Feature
> existingFeatureUuids
= getExistingFeatureUuids(name
);
691 //filter, sort and structure according to feature tree
692 TreeNode
<Feature
, UUID
> filteredRootNode
;
693 if (config
.getFeatureTree() != null) {
696 TermTree
<Feature
> featureTree
= repository
.getTermTreeService().find(config
.getFeatureTree());
697 filteredRootNode
= filterFeatureNode(featureTree
.getRoot(), existingFeatureUuids
.keySet());
699 filteredRootNode
= createDefaultFeatureNode(name
);
702 //load facts per feature
703 Map
<UUID
,Set
<DescriptionElementBase
>> featureMap
= loadFeatureMap(name
);
706 if (!filteredRootNode
.getChildren().isEmpty()) {
707 ContainerDto
<FeatureDto
> features
= new ContainerDto
<>();
708 for (TreeNode
<Feature
,UUID
> node
: filteredRootNode
.getChildren()) {
709 handleFeatureNode(config
, featureMap
, features
, node
);
712 nameDto
.setNameFacts(features
);
714 } catch (Exception e
) {
715 //e.printStackTrace();
717 pageDto
.addMessage(MessagesDto
.NewErrorInstance("Error when loading factual data.", e
));
721 private void handleFeatureNode(TaxonPageDtoConfiguration config
,
722 Map
<UUID
, Set
<DescriptionElementBase
>> featureMap
, ContainerDto
<FeatureDto
> features
,
723 TreeNode
<Feature
, UUID
> node
) {
725 Feature feature
= node
.getData();
727 FeatureDto featureDto
= new FeatureDto(feature
.getUuid(), feature
.getId(), feature
.getLabel());
728 features
.addItem(featureDto
);
730 List
<Distribution
> distributions
= new ArrayList
<>();
733 for (DescriptionElementBase fact
: featureMap
.get(feature
.getUuid())){
734 if (fact
.isInstanceOf(Distribution
.class)) {
735 distributions
.add(CdmBase
.deproxy(fact
, Distribution
.class));
737 //TODO how to handle CommonNames, do we also want to have a data structure
741 // a bit like for distribution??
742 handleFact(featureDto
, fact
);
746 handleDistributions(config
, featureDto
, distributions
);
747 //TODO really needed?
748 orderFacts(featureDto
);
751 ContainerDto
<FeatureDto
> childFeatures
= new ContainerDto
<>();
752 for (TreeNode
<Feature
,UUID
> child
: node
.getChildren()) {
753 handleFeatureNode(config
, featureMap
, childFeatures
, child
);
755 if (childFeatures
.getCount() > 0) {
756 featureDto
.setSubFeatures(childFeatures
);
760 //TODO not really used yet, only for distinguishing fact classes,
761 //needs discussion if needed and how to implement.
762 //we could also move compareTo methods to DTO classes but with this
763 //remove from having only data in the DTO, no logic
764 private void orderFacts(FeatureDto featureDto
) {
765 List
<IFactDto
> list
= featureDto
.getFacts().getItems();
766 Collections
.sort(list
, (f1
,f2
)->{
767 if (!f1
.getClass().equals(f2
.getClass())) {
768 return f1
.getClass().getSimpleName().compareTo(f2
.getClass().getSimpleName());
770 if (f1
instanceof FactDto
) {
771 FactDto fact1
= (FactDto
)f1
;
772 FactDto fact2
= (FactDto
)f2
;
774 // return fact1.getTypedLabel().toString().compareTo(fact2.getTypedLabel().toString());
776 } else if (f1
instanceof CommonNameDto
) {
778 CommonNameDto fact1
= (CommonNameDto
)f1
;
779 CommonNameDto fact2
= (CommonNameDto
)f2
;
788 private Map
<UUID
, Set
<DescriptionElementBase
>> loadFeatureMap(IDescribable
<?
> describable
) {
789 Map
<UUID
, Set
<DescriptionElementBase
>> featureMap
= new HashMap
<>();
792 for (DescriptionBase
<?
> description
: describable
.getDescriptions()) {
793 if (description
.isImageGallery()) {
796 for (DescriptionElementBase deb
: description
.getElements()) {
797 Feature feature
= deb
.getFeature();
798 if (featureMap
.get(feature
.getUuid()) == null) {
799 featureMap
.put(feature
.getUuid(), new HashSet
<>());
801 featureMap
.get(feature
.getUuid()).add(deb
);
807 private TreeNode
<Feature
, UUID
> createDefaultFeatureNode(IDescribable
<?
> describable
) {
808 TreeNode
<Feature
, UUID
> root
= new TreeNode
<>();
809 Set
<Feature
> requiredFeatures
= new HashSet
<>();
811 for (DescriptionBase
<?
> description
: describable
.getDescriptions()) {
812 if (description
.isImageGallery()) {
815 for (DescriptionElementBase deb
: description
.getElements()) {
816 Feature feature
= deb
.getFeature();
817 if (feature
!= null) { //null should not happen
818 requiredFeatures
.add(feature
);
822 List
<Feature
> sortedChildren
= new ArrayList
<>(requiredFeatures
);
823 Collections
.sort(sortedChildren
, (f1
,f2
) -> f1
.getTitleCache().compareTo(f2
.getTitleCache()));
824 sortedChildren
.stream().forEachOrdered(f
->root
.addChild(new TreeNode
<>(f
.getUuid(), f
)));
829 * Recursive call to a feature tree's feature node in order to creates a tree structure
830 * ordered in the same way as the according feature tree but only containing features
831 * that do really exist for the given taxon. If only a child node is required the parent
832 * node/feature is also considered to be required.<BR>
834 private TreeNode
<Feature
, UUID
> filterFeatureNode(TermNode
<Feature
> featureNode
,
835 Set
<UUID
> existingFeatureUuids
) {
837 //first filter children
838 List
<TreeNode
<Feature
, UUID
>> requiredChildNodes
= new ArrayList
<>();
839 for (TermNode
<Feature
> childNode
: featureNode
.getChildNodes()) {
840 TreeNode
<Feature
, UUID
> child
= filterFeatureNode(childNode
, existingFeatureUuids
);
842 requiredChildNodes
.add(child
);
846 //if any child is required or this node is required ....
847 if (!requiredChildNodes
.isEmpty() ||
848 featureNode
.getTerm() != null && existingFeatureUuids
.contains(featureNode
.getTerm().getUuid())) {
849 TreeNode
<Feature
,UUID
> result
= new TreeNode
<>();
850 //add this nodes data
851 Feature feature
= featureNode
.getTerm() == null ?
null : featureNode
.getTerm();
852 if (feature
!= null) {
853 result
.setNodeId(feature
.getUuid());
854 result
.setData(feature
);
857 requiredChildNodes
.stream().forEachOrdered(c
->result
.addChild(c
));
865 * Computes the (unsorted) set of features for which facts exist
866 * for the given taxon.
868 private Map
<UUID
, Feature
> getExistingFeatureUuids(IDescribable
<?
> describable
) {
869 Map
<UUID
, Feature
> result
= new HashMap
<>();
870 for (DescriptionBase
<?
> description
: describable
.getDescriptions()) {
871 if (description
.isImageGallery()) {
874 for (DescriptionElementBase deb
: description
.getElements()) {
875 Feature feature
= deb
.getFeature();
876 if (feature
!= null) { //null should not happen
877 result
.put(feature
.getUuid(), feature
);
884 private void handleDistributions(TaxonPageDtoConfiguration config
, FeatureDto featureDto
,
885 List
<Distribution
> distributions
) {
887 if (distributions
.isEmpty()) {
890 IDistributionService distributionService
= repository
.getDistributionService();
893 DistributionInfoConfiguration distributionConfig
= config
.getDistributionInfoConfiguration();
894 CondensedDistributionConfiguration condensedConfig
= distributionConfig
.getCondensedDistrConfig();
896 String statusColorsString
= distributionConfig
.getStatusColorsString();
899 //copied from DescriptionListController
901 boolean ignoreDistributionStatusUndefined
= true; //workaround until #9500 is fully implemented
902 distributionConfig
.setIgnoreDistributionStatusUndefined(ignoreDistributionStatusUndefined
);
903 boolean fallbackAsParent
= true; //may become a service parameter in future
905 DistributionInfoDto dto
;
907 //hiddenArea markers include markers for fully hidden areas and fallback areas. The later
908 //are hidden markers on areas that have non-hidden subareas (#4408)
909 Set
<MarkerType
> hiddenAreaMarkerTypes
= distributionConfig
.getHiddenAreaMarkerTypeList();
910 if(hiddenAreaMarkerTypes
!= null && !hiddenAreaMarkerTypes
.isEmpty()){
911 condensedConfig
.hiddenAndFallbackAreaMarkers
= hiddenAreaMarkerTypes
.stream().map(mt
->mt
.getUuid()).collect(Collectors
.toSet());
914 List
<String
> initStrategy
= null;
916 Map
<PresenceAbsenceTerm
, Color
> distributionStatusColors
;
918 distributionStatusColors
= DistributionServiceUtilities
.buildStatusColorMap(
919 statusColorsString
, repository
.getTermService(), repository
.getVocabularyService());
920 } catch (JsonProcessingException e
) {
921 logger
.error("JsonProcessingException when reading distribution status colors");
922 //TODO is null allowed?
923 distributionStatusColors
= null;
926 dto
= distributionService
.composeDistributionInfoFor(distributionConfig
, distributions
,
928 distributionStatusColors
, LocaleContext
.getLanguages());
930 if (distributionConfig
.isUseTreeDto() && dto
.getTree() != null) {
931 DistributionTreeDto tree
= (DistributionTreeDto
)dto
.getTree();
932 TreeNode
<Set
<DistributionDto
>, NamedAreaDto
> root
= tree
.getRootElement();
933 //fill uuid->distribution map
934 Map
<UUID
,Distribution
> distributionMap
= new HashMap
<>();
935 distributions
.stream().forEach(d
->distributionMap
.put(d
.getUuid(), d
));
936 handleDistributionDtoNode(distributionMap
, root
);
939 featureDto
.addFact(dto
);
942 private void handleDistributionDtoNode(Map
<UUID
, Distribution
> map
,
943 TreeNode
<Set
<DistributionDto
>, NamedAreaDto
> root
) {
944 if (root
.getData() != null) {
945 root
.getData().stream().forEach(d
->{
946 Distribution distr
= map
.get(d
.getUuid());
947 loadBaseData(distr
, d
);
948 d
.setTimeperiod(distr
.getTimeperiod() == null ?
null : distr
.getTimeperiod().toString());
953 if (root
.getChildren() != null) {
954 root
.getChildren().stream().forEach(c
->handleDistributionDtoNode(map
, c
));
958 private FactDtoBase
handleFact(FeatureDto featureDto
, DescriptionElementBase fact
) {
960 Language localeLang
= null;
963 if (fact
.isInstanceOf(TextData
.class)) {
964 TextData td
= CdmBase
.deproxy(fact
, TextData
.class);
965 LanguageString ls
= td
.getPreferredLanguageString(localeLang
);
966 String text
= ls
== null ?
"" : CdmUtils
.Nz(ls
.getText());
968 FactDto factDto
= new FactDto();
969 featureDto
.addFact(factDto
);
970 //TODO do we really need type information for textdata here?
971 TypedLabel typedLabel
= new TypedLabel(text
);
972 typedLabel
.setClassAndId(td
);
973 factDto
.getTypedLabel().add(typedLabel
);
974 loadBaseData(td
, factDto
);
977 }else if (fact
.isInstanceOf(CommonTaxonName
.class)) {
978 CommonTaxonName ctn
= CdmBase
.deproxy(fact
, CommonTaxonName
.class);
979 CommonNameDto dto
= new CommonNameDto();
980 featureDto
.addFact(dto
);
982 Language lang
= ctn
.getLanguage();
984 String langLabel
= getTermLabel(lang
, localeLang
);
985 dto
.setLanguage(langLabel
);
986 dto
.setLanguageUuid(lang
.getUuid());
989 dto
.setLanguage("-");
992 NamedArea area
= ctn
.getArea();
994 String areaLabel
= getTermLabel(area
, localeLang
);
995 dto
.setArea(areaLabel
);
996 dto
.setAreaUUID(area
.getUuid());
998 dto
.setName(ctn
.getName());
999 loadBaseData(ctn
, dto
);
1000 //TODO sort all common names
1002 } else if (fact
.isInstanceOf(IndividualsAssociation
.class)) {
1003 IndividualsAssociation ia
= CdmBase
.deproxy(fact
, IndividualsAssociation
.class);
1004 IndividualsAssociationDto dto
= new IndividualsAssociationDto ();
1006 LanguageString description
= MultilanguageTextHelper
.getPreferredLanguageString(ia
.getDescription(), Arrays
.asList(localeLang
));
1007 if (description
!= null) {
1008 dto
.setDescritpion(description
.getText());
1010 SpecimenOrObservationBase
<?
> specimen
= ia
.getAssociatedSpecimenOrObservation();
1011 if (specimen
!= null) {
1012 //TODO what to use here??
1013 dto
.setOccurrence(specimen
.getTitleCache());
1014 dto
.setOccurrenceUuid(specimen
.getUuid());
1017 featureDto
.addFact(dto
);
1018 loadBaseData(ia
, dto
);
1020 } else if (fact
.isInstanceOf(TaxonInteraction
.class)) {
1021 TaxonInteraction ti
= CdmBase
.deproxy(fact
, TaxonInteraction
.class);
1022 TaxonInteractionDto dto
= new TaxonInteractionDto ();
1024 LanguageString description
= MultilanguageTextHelper
.getPreferredLanguageString(
1025 ti
.getDescription(), Arrays
.asList(localeLang
));
1026 if (description
!= null) {
1027 dto
.setDescritpion(description
.getText());
1029 Taxon taxon
= ti
.getTaxon2();
1030 if (taxon
!= null) {
1031 //TODO what to use here??
1032 dto
.setTaxon(taxon
.cacheStrategy().getTaggedTitle(taxon
));
1033 dto
.setTaxonUuid(taxon
.getUuid());
1035 featureDto
.addFact(dto
);
1036 loadBaseData(ti
, dto
);
1038 }else if (fact
.isInstanceOf(CategoricalData
.class)) {
1039 CategoricalData cd
= CdmBase
.deproxy(fact
, CategoricalData
.class);
1040 FactDto factDto
= new FactDto();
1041 featureDto
.addFact(factDto
);
1042 //TODO do we really need type information for textdata here?
1043 String label
= CategoricalDataFormatter
.NewInstance(null).format(cd
, localeLang
);
1044 TypedLabel typedLabel
= new TypedLabel(label
);
1045 typedLabel
.setClassAndId(cd
);
1046 factDto
.getTypedLabel().add(typedLabel
);
1048 loadBaseData(cd
, factDto
);
1050 }else if (fact
.isInstanceOf(QuantitativeData
.class)) {
1051 QuantitativeData qd
= CdmBase
.deproxy(fact
, QuantitativeData
.class);
1052 FactDto factDto
= new FactDto();
1053 featureDto
.addFact(factDto
);
1054 //TODO do we really need type information for textdata here?
1055 String label
= QuantitativeDataFormatter
.NewInstance(null).format(qd
, localeLang
);
1056 TypedLabel typedLabel
= new TypedLabel(label
);
1057 typedLabel
.setClassAndId(qd
);
1058 factDto
.getTypedLabel().add(typedLabel
);
1060 loadBaseData(qd
, factDto
);
1062 }else if (fact
.isInstanceOf(TemporalData
.class)) {
1063 TemporalData td
= CdmBase
.deproxy(fact
, TemporalData
.class);
1064 FactDto factDto
= new FactDto();
1065 featureDto
.addFact(factDto
);
1066 //TODO do we really need type information for textdata here?
1067 String label
= td
.toString();
1068 TypedLabel typedLabel
= new TypedLabel(label
);
1069 typedLabel
.setClassAndId(td
);
1070 factDto
.getTypedLabel().add(typedLabel
);
1072 loadBaseData(td
, factDto
);
1076 logger
.warn("DescriptionElement type not yet handled: " + fact
.getClass().getSimpleName());
1079 result
.setTimeperiod(fact
.getTimeperiod() == null ?
null : fact
.getTimeperiod().toString());
1083 private String
getTermLabel(TermBase term
, Language localeLang
) {
1087 Representation rep
= term
.getPreferredRepresentation(localeLang
);
1088 String label
= rep
== null ?
null : rep
.getLabel();
1089 label
= label
== null ? term
.getLabel() : label
;
1094 * Compares an existing last date and the last date of an entity
1095 * and returns the resulting last date.
1097 private LocalDateTime
getLastUpdated(LocalDateTime existingLastDate
, VersionableEntity dateToAddEntity
) {
1099 DateTime dateToAdd
= dateToAddEntity
.getUpdated() != null ? dateToAddEntity
.getUpdated() : dateToAddEntity
.getCreated();
1101 LocalDateTime javaLocalDateTimeOfEntity
= dateToAdd
== null ?
null:
1102 LocalDateTime
.of(dateToAdd
.getYear(), dateToAdd
.getMonthOfYear(),
1103 dateToAdd
.getDayOfMonth(), dateToAdd
.getHourOfDay(),
1104 dateToAdd
.getMinuteOfHour(), dateToAdd
.getSecondOfMinute());
1106 if (existingLastDate
== null) {
1107 return javaLocalDateTimeOfEntity
;
1108 }else if (javaLocalDateTimeOfEntity
== null || javaLocalDateTimeOfEntity
.compareTo(existingLastDate
) < 0) {
1109 return existingLastDate
;
1111 return javaLocalDateTimeOfEntity
;
1115 private void loadBaseData(CdmBase cdmBase
, CdmBaseDto dto
) {
1116 dto
.setId(cdmBase
.getId());
1117 dto
.setUuid(cdmBase
.getUuid());
1119 loadAnnotatable(cdmBase
, dto
);
1120 loadSources(cdmBase
, dto
);
1121 //loadIdentifiable(cdmBase, dto);
1124 private void loadSources(CdmBase cdmBase
, CdmBaseDto dto
) {
1125 if (dto
instanceof SingleSourcedDto
&& cdmBase
.isInstanceOf(SingleSourcedEntityBase
.class)) {
1126 //TODO other sourced
1127 SingleSourcedEntityBase sourced
= CdmBase
.deproxy(cdmBase
, SingleSourcedEntityBase
.class);
1128 SingleSourcedDto sourcedDto
= (SingleSourcedDto
)dto
;
1129 NamedSource source
= sourced
.getSource();
1130 if (source
!= null) { //TODO && !source.isEmpty() - does not exist yet
1131 SourceDto sourceDto
= new SourceDto();
1132 loadSource(source
, sourceDto
);
1133 sourcedDto
.setSource(sourceDto
);
1135 } else if (dto
instanceof SourcedDto
&& cdmBase
instanceof ISourceable
) {
1136 @SuppressWarnings("unchecked")
1137 ISourceable
<OriginalSourceBase
> sourced
= (ISourceable
<OriginalSourceBase
>)cdmBase
;
1138 SourcedDto sourcedDto
= (SourcedDto
)dto
;
1139 for (OriginalSourceBase source
: sourced
.getSources()) {
1140 SourceDto sourceDto
= new SourceDto();
1141 loadSource(source
, sourceDto
);
1142 sourcedDto
.addSource(sourceDto
);
1147 private void loadSource(OriginalSourceBase source
, SourceDto sourceDto
) {
1149 source
= CdmBase
.deproxy(source
);
1151 loadBaseData(source
, sourceDto
);
1153 ICdmBase linkedObject
= source
.getCitation();
1154 if (linkedObject
== null) {
1156 linkedObject
= source
.getCdmSource();
1159 //citation uuid & doi
1160 if (source
.getCitation()!= null) {
1161 sourceDto
.setDoi(source
.getCitation().getDoiString());
1165 //TODO this probably does not use specimen or cdmSource if necessary,
1166 // also long citation is still preliminary
1167 String label
= OriginalSourceFormatter
.INSTANCE_LONG_CITATION
.format(source
);
1168 TypedLabel typedLabel
= new TypedLabel(source
, label
);
1169 sourceDto
.addLabel(typedLabel
);
1170 sourceDto
.setType(source
.getType() != null ? source
.getType().toString() : null);
1172 if (source
.isInstanceOf(NamedSourceBase
.class)) {
1173 NamedSourceBase ns
= CdmBase
.deproxy(source
, NamedSourceBase
.class);
1176 TaxonName name
= ns
.getNameUsedInSource();
1178 List
<TaggedText
> taggedName
= name
.cacheStrategy().getTaggedTitle(name
);
1180 sourceDto
.setNameInSource(taggedName
);
1181 sourceDto
.setNameInSourceUuid(name
.getUuid());
1185 if (source
.isInstanceOf(DescriptionElementSource
.class)) {
1186 DescriptionElementSource des
= CdmBase
.deproxy(source
, DescriptionElementSource
.class);
1187 if (linkedObject
== null) {
1188 linkedObject
= des
.getSpecimen();
1193 sourceDto
.setLinkedUuid(getUuid(linkedObject
));
1194 String linkedObjectStr
= linkedObject
== null ?
null : CdmBase
.deproxy(linkedObject
).getClass().getSimpleName();
1195 sourceDto
.setLinkedClass(linkedObjectStr
);
1198 private UUID
getUuid(ICdmBase cdmBase
) {
1199 return cdmBase
== null ?
null : cdmBase
.getUuid();
1202 private void loadAnnotatable(CdmBase cdmBase
, CdmBaseDto dto
) {
1203 if (dto
instanceof AnnotatableDto
&& cdmBase
.isInstanceOf(AnnotatableEntity
.class)) {
1204 AnnotatableEntity annotatable
= CdmBase
.deproxy(cdmBase
, AnnotatableEntity
.class);
1205 AnnotatableDto annotatableDto
= (AnnotatableDto
)dto
;
1207 for (Annotation annotation
: annotatable
.getAnnotations()) {
1208 if (annotation
.getAnnotationType() != null
1209 //TODO annotation type filter
1210 && annotation
.getAnnotationType().getUuid().equals(AnnotationType
.uuidEditorial
)
1211 && StringUtils
.isNotBlank(annotation
.getText())) {
1213 AnnotationDto annotationDto
= new AnnotationDto();
1214 annotatableDto
.addAnnotation(annotationDto
);
1215 //TODO id needed? but need to adapt dto and container then
1216 loadBaseData(annotation
, annotationDto
);
1217 annotationDto
.setText(annotation
.getText());
1218 UUID uuidAnnotationType
= annotation
.getAnnotationType() == null ?
null :annotation
.getAnnotationType().getUuid();
1219 annotationDto
.setTypeUuid(uuidAnnotationType
);
1220 //language etc. currently not yet used
1225 for (Marker marker
: annotatable
.getMarkers()) {
1226 if (marker
.getMarkerType() != null
1227 //TODO markertype filter
1228 // && marker.getMarkerType().getUuid().equals(AnnotationType.uuidEditorial)
1231 MarkerDto markerDto
= new MarkerDto();
1232 annotatableDto
.addMarker(markerDto
);
1233 //TODO id needed? but need to adapt dto and container then
1234 loadBaseData(marker
, markerDto
);
1235 if (marker
.getMarkerType() != null) {
1236 markerDto
.setTypeUuid(marker
.getMarkerType().getUuid());
1238 markerDto
.setType(marker
.getMarkerType().getTitleCache());
1240 markerDto
.setValue(marker
.getValue());