ref #10322 add year to name relationship dto (cont.)
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / portal / PortalDtoLoader.java
1 /**
2 * Copyright (C) 2023 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
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.
8 */
9 package eu.etaxonomy.cdm.api.service.portal;
10
11 import java.time.LocalDateTime;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.EnumSet;
15 import java.util.HashSet;
16 import java.util.List;
17 import java.util.Set;
18 import java.util.UUID;
19 import java.util.stream.Collectors;
20
21 import org.apache.logging.log4j.LogManager;
22 import org.apache.logging.log4j.Logger;
23 import org.joda.time.DateTime;
24
25 import eu.etaxonomy.cdm.api.application.ICdmRepository;
26 import eu.etaxonomy.cdm.api.dto.SpecimenOrObservationBaseDTO;
27 import eu.etaxonomy.cdm.api.dto.portal.ContainerDto;
28 import eu.etaxonomy.cdm.api.dto.portal.MessagesDto;
29 import eu.etaxonomy.cdm.api.dto.portal.OccurrenceInfoDto;
30 import eu.etaxonomy.cdm.api.dto.portal.TaxonBaseDto;
31 import eu.etaxonomy.cdm.api.dto.portal.TaxonBaseDto.TaxonNameDto;
32 import eu.etaxonomy.cdm.api.dto.portal.TaxonPageDto;
33 import eu.etaxonomy.cdm.api.dto.portal.TaxonPageDto.ConceptRelationDTO;
34 import eu.etaxonomy.cdm.api.dto.portal.TaxonPageDto.HomotypicGroupDTO;
35 import eu.etaxonomy.cdm.api.dto.portal.TaxonPageDto.KeyDTO;
36 import eu.etaxonomy.cdm.api.dto.portal.TaxonPageDto.MediaDTO;
37 import eu.etaxonomy.cdm.api.dto.portal.TaxonPageDto.MediaRepresentationDTO;
38 import eu.etaxonomy.cdm.api.dto.portal.TaxonPageDto.NameRelationDTO;
39 import eu.etaxonomy.cdm.api.dto.portal.TaxonPageDto.SpecimenDTO;
40 import eu.etaxonomy.cdm.api.dto.portal.TaxonPageDto.TaxonNodeAgentsRelDTO;
41 import eu.etaxonomy.cdm.api.dto.portal.TaxonPageDto.TaxonNodeDTO;
42 import eu.etaxonomy.cdm.api.dto.portal.config.TaxonPageDtoConfiguration;
43 import eu.etaxonomy.cdm.api.filter.TaxonOccurrenceRelationType;
44 import eu.etaxonomy.cdm.api.service.dto.DtoUtil;
45 import eu.etaxonomy.cdm.api.service.geo.IGeoServiceAreaMapping;
46 import eu.etaxonomy.cdm.api.service.name.TypeDesignationSetContainer;
47 import eu.etaxonomy.cdm.api.service.name.TypeDesignationSetFormatter;
48 import eu.etaxonomy.cdm.api.service.pager.Pager;
49 import eu.etaxonomy.cdm.common.CdmUtils;
50 import eu.etaxonomy.cdm.compare.taxon.TaxonComparator;
51 import eu.etaxonomy.cdm.format.taxon.TaxonRelationshipFormatter;
52 import eu.etaxonomy.cdm.model.common.CdmBase;
53 import eu.etaxonomy.cdm.model.common.Language;
54 import eu.etaxonomy.cdm.model.common.VersionableEntity;
55 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
56 import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
57 import eu.etaxonomy.cdm.model.description.PolytomousKey;
58 import eu.etaxonomy.cdm.model.description.TaxonDescription;
59 import eu.etaxonomy.cdm.model.description.TextData;
60 import eu.etaxonomy.cdm.model.media.ExternalLink;
61 import eu.etaxonomy.cdm.model.media.ImageFile;
62 import eu.etaxonomy.cdm.model.media.Media;
63 import eu.etaxonomy.cdm.model.media.MediaRepresentation;
64 import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
65 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
66 import eu.etaxonomy.cdm.model.name.NameRelationship;
67 import eu.etaxonomy.cdm.model.name.NameRelationshipType;
68 import eu.etaxonomy.cdm.model.name.NomenclaturalSource;
69 import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
70 import eu.etaxonomy.cdm.model.name.TaxonName;
71 import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
72 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
73 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
74 import eu.etaxonomy.cdm.model.taxon.Classification;
75 import eu.etaxonomy.cdm.model.taxon.Synonym;
76 import eu.etaxonomy.cdm.model.taxon.Taxon;
77 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
78 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
79 import eu.etaxonomy.cdm.model.taxon.TaxonNodeAgentRelation;
80 import eu.etaxonomy.cdm.model.taxon.TaxonNodeStatus;
81 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
82 import eu.etaxonomy.cdm.model.term.Representation;
83 import eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao;
84 import eu.etaxonomy.cdm.strategy.cache.TaggedText;
85 import eu.etaxonomy.cdm.strategy.cache.TaggedTextFormatter;
86 import eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy;
87 import eu.etaxonomy.cdm.strategy.cache.taxon.TaxonBaseDefaultCacheStrategy;
88
89 /**
90 * Loads the portal dto from a taxon instance.
91 * Maybe later also supports loading from persistence.
92 *
93 * @author a.mueller
94 * @date 09.01.2023
95 */
96 public class PortalDtoLoader extends PortalDtoLoaderBase {
97
98 @SuppressWarnings("unused")
99 private static final Logger logger = LogManager.getLogger();
100
101 private PortalDtoFactLoader_Old factLoader;
102
103 public PortalDtoLoader(ICdmRepository repository, ICdmGenericDao dao, IGeoServiceAreaMapping areaMapping) {
104 super(repository, dao);
105 this.factLoader = new PortalDtoFactLoader_Old(repository, dao, areaMapping);
106 }
107
108 //TODO can we handle the area mapping better?
109 public TaxonPageDto load(Taxon taxon, TaxonPageDtoConfiguration config) {
110 TaxonPageDto result = new TaxonPageDto();
111
112 loadAcceptedTaxon(taxon, config, result);
113
114 loadTaxonNodes(taxon, result, config);
115 loadSynonyms(taxon, result, config);
116 loadConceptRelations(taxon, result, config);
117 loadFacts(taxon, result, config);
118 loadMedia(taxon, result, config);
119 loadSpecimens(taxon, result, config);
120 loadKeys(taxon, result, config);
121
122 return result;
123 }
124
125 private void loadAcceptedTaxon(Taxon taxon, TaxonPageDtoConfiguration config, TaxonPageDto result) {
126 try {
127 TaxonName name = taxon.getName();
128
129 //load 1:1
130 //TODO supplementalData for name
131 loadBaseData(taxon, result);
132 result.setLastUpdated(getLastUpdated(null, taxon));
133 result.setLabel(CdmUtils.Nz(taxon.getTitleCache()));
134 // result.setTypedTaxonLabel(getTypedTaxonLabel(taxon, config));
135 result.setTaggedLabel(getTaggedTaxon(taxon, config));
136 if (name != null) {
137 handleName(config, result, name, result);
138 }
139 if (taxon.getSec() != null) {
140 result.setSecTitleCache(taxon.getSec().getTitleCache());
141 }
142 } catch (Exception e) {
143 //e.printStackTrace();
144 result.addMessage(MessagesDto.NewErrorInstance("Error when loading accepted name data.", e));
145 }
146 }
147
148 private void handleName(TaxonPageDtoConfiguration config, TaxonBaseDto taxonDto, TaxonName name, TaxonPageDto pageDto) {
149 TaxonNameDto nameDto = taxonDto.new TaxonNameDto();
150 loadBaseData(name, nameDto);
151
152 INameCacheStrategy formatter = name.cacheStrategy();
153 formatter.setEtAlPosition(config.getEtAlPosition());
154
155 taxonDto.setName(nameDto);
156 taxonDto.setNameLabel(formatter.getTitleCache(name));
157 handleRelatedNames(name, taxonDto, config);
158 loadProtologues(name, taxonDto);
159 taxonDto.setNameUuid(name.getUuid());
160 taxonDto.setNameType(name.getNameType().toString());
161 loadNameFacts(name, taxonDto, config, pageDto);
162 nameDto.setTaggedName(formatter.getTaggedFullTitle(name));
163 }
164
165 private List<TaggedText> getTaggedTaxon(TaxonBase<?> taxon, TaxonPageDtoConfiguration config) {
166 // List<TypedLabel> result = new ArrayList<>();
167 TaxonBaseDefaultCacheStrategy<TaxonBase<?>> formatter = new TaxonBaseDefaultCacheStrategy<>();
168 List<TaggedText> tags = formatter.getTaggedTitle(taxon);
169 return tags;
170 }
171
172 private void loadKeys(Taxon taxon, TaxonPageDto result, TaxonPageDtoConfiguration config) {
173 if (!config.isWithKeys()){
174 return;
175 }
176 try {
177 ContainerDto<KeyDTO> container = new ContainerDto<>();
178
179 //TODO other key types, but type must not be null, otherwise NPE
180 Pager<PolytomousKey> keys = repository.getIdentificationKeyService().findKeysConvering(taxon, PolytomousKey.class, null, null, null);
181 for (PolytomousKey key : keys.getRecords()) {
182 KeyDTO dto = new KeyDTO();
183 loadBaseData(key, dto);
184 dto.setLabel(key.getTitleCache());
185 dto.setKeyClass(key.getClass().getSimpleName());
186 container.addItem(dto);
187 }
188 if (container.getCount() > 0) {
189 result.setKeys(container);
190 }
191 } catch (Exception e) {
192 //e.printStackTrace();
193 result.addMessage(MessagesDto.NewErrorInstance("Error when loading identification key data.", e));
194 }
195 }
196
197 private void loadSpecimens(Taxon taxon, TaxonPageDto result, TaxonPageDtoConfiguration config) {
198 if (!config.isWithSpecimens()){
199 return;
200 }
201 loadRootSpecimens(taxon, result, config);
202
203 //once fully switching to newSpecimens the tansient annotation on the getter should be removed
204 //in the TaxonPageDto
205 boolean newSpecimensImplemented = false;
206 if (newSpecimensImplemented) {
207 loadNewRootSpecimens(taxon, result, config);
208 }
209 }
210
211 /**
212 * Not really implemented yet
213 */
214 private void loadNewRootSpecimens(Taxon taxon, TaxonPageDto result, TaxonPageDtoConfiguration config) {
215 //TODO load specimen from multiple places
216
217 //TODO use filter
218 EnumSet<TaxonOccurrenceRelationType> specimenFilter = config.getSpecimenAssociationFilter();
219
220 //TODO maybe use OccurrenceService.listRootUnitDTOsByAssociatedTaxon
221 // or OccurrenceService.listRootUnitsByAssociatedTaxon()
222
223 try {
224 ContainerDto<SpecimenDTO> container = new ContainerDto<>();
225
226 List<SpecimenOrObservationBase<?>> specimens = new ArrayList<>();
227 for (TaxonDescription taxonDescription : taxon.getDescriptions()) {
228 if (taxonDescription.isImageGallery()) {
229 continue;
230 }
231 for (DescriptionElementBase el : taxonDescription.getElements()) {
232 if (el.isInstanceOf(IndividualsAssociation.class)) {
233 IndividualsAssociation indAss = CdmBase.deproxy(el, IndividualsAssociation.class);
234 SpecimenOrObservationBase<?> specimen = indAss.getAssociatedSpecimenOrObservation();
235 specimens.add(specimen);
236 }
237 }
238 }
239 List<SpecimenOrObservationBase<?>> typeSpecimens = loadTypeSpecimen(taxon.getName(), config);
240 specimens.addAll(typeSpecimens);
241 for (TaxonName syn : taxon.getSynonymNames()) {
242 typeSpecimens = loadTypeSpecimen(syn, config);
243 specimens.addAll(typeSpecimens);
244 }
245
246 //TODO maybe still need to check full derivate path #4484, #8424, #9559
247 for (SpecimenOrObservationBase<?> specimen : filterPublished(specimens)) {
248 SpecimenDTO dto = new SpecimenDTO();
249 loadBaseData(specimen, dto);
250 dto.setLabel(specimen.getTitleCache());
251 container.addItem(dto);
252 }
253 if (container.getCount() > 0 ) {
254 result.setSpecimens(container);
255 }
256 } catch (Exception e) {
257 //e.printStackTrace();
258 result.addMessage(MessagesDto.NewErrorInstance("Error when loading specimen data.", e));
259 }
260 }
261
262 /**
263 * Loads specimens the "old" way.
264 */
265 private void loadRootSpecimens(Taxon taxon, TaxonPageDto result, TaxonPageDtoConfiguration config) {
266 List<SpecimenOrObservationBaseDTO> rootSpecimens = this.repository.getOccurrenceService().listRootUnitDTOsByAssociatedTaxon(
267 taxon.getUuid(), null, config.isIncludeUnpublished(),
268 config.getSpecimenAssociationFilter(), null);
269
270 if (result.getOccurrenceInfo() == null) {
271 OccurrenceInfoDto oid = new OccurrenceInfoDto();
272 result.setOccurrenceInfo(oid);
273 }
274 result.getOccurrenceInfo().setRootSpecimens(rootSpecimens);
275 }
276
277 private List<SpecimenOrObservationBase<?>> loadTypeSpecimen(TaxonName name, TaxonPageDtoConfiguration config) {
278 List<SpecimenOrObservationBase<?>> result = new ArrayList<>();
279 for (SpecimenTypeDesignation desig: name.getSpecimenTypeDesignations()){
280 DerivedUnit specimen = desig.getTypeSpecimen();
281 if (specimen != null) {
282 result.add(specimen);
283 }
284 }
285 return result;
286 }
287
288 private void loadMedia(Taxon taxon, TaxonPageDto result, TaxonPageDtoConfiguration config) {
289 if (!config.isWithMedia()){
290 return;
291 }
292 try {
293 ContainerDto<MediaDTO> container = new ContainerDto<TaxonPageDto.MediaDTO>();
294
295 List<Media> medias = new ArrayList<>();
296 for (TaxonDescription taxonDescription : taxon.getDescriptions()) {
297 if (!taxonDescription.isImageGallery()) {
298 continue;
299 }
300
301 List<Media> newMedia = taxonDescription.getElements().stream()
302 .filter(el->el.isInstanceOf(TextData.class))
303 .map(el->CdmBase.deproxy(el, TextData.class))
304 .filter(td->true)
305 .flatMap(td->td.getMedia().stream())
306 .collect(Collectors.toList())
307 ;
308 medias.addAll(newMedia);
309 }
310 //TODO collect media from elsewhere
311 for (Media media : medias) {
312 MediaDTO dto = new TaxonPageDto.MediaDTO();
313 loadBaseData(media, dto);
314 dto.setLabel(media.getTitleCache());
315 ContainerDto<MediaRepresentationDTO> representations = new ContainerDto<>();
316 for (MediaRepresentation rep : media.getRepresentations()) {
317 MediaRepresentationDTO repDto = new MediaRepresentationDTO();
318 loadBaseData(rep, dto);
319 repDto.setMimeType(rep.getMimeType());
320 repDto.setSuffix(rep.getSuffix());
321 if (!rep.getParts().isEmpty()) {
322 //TODO handle message if n(parts) > 1
323 MediaRepresentationPart part = rep.getParts().get(0);
324 repDto.setUri(part.getUri());
325 repDto.setClazz(part.getClass());
326 repDto.setSize(part.getSize());
327 if (part.isInstanceOf(ImageFile.class)) {
328 ImageFile image = CdmBase.deproxy(part, ImageFile.class);
329 repDto.setHeight(image.getHeight());
330 repDto.setWidth(image.getWidth());
331 }
332 //TODO AudioFile etc.
333 }
334 representations.addItem(repDto);
335 }
336 if (representations.getCount() > 0) {
337 dto.setRepresentations(representations);
338 }
339 //TODO load representation data
340 container.addItem(dto);
341 }
342
343 if (container.getCount() > 0) {
344 result.setMedia(container);
345 }
346 } catch (Exception e) {
347 //e.printStackTrace();
348 result.addMessage(MessagesDto.NewErrorInstance("Error when loading media data.", e));
349 }
350 }
351
352 private void loadTaxonNodes(Taxon taxon, TaxonPageDto result, TaxonPageDtoConfiguration config) {
353 if (!config.isWithTaxonNodes()){
354 return;
355 }
356 try {
357 ContainerDto<TaxonNodeDTO> container = new ContainerDto<TaxonPageDto.TaxonNodeDTO>();
358 for (TaxonNode node : taxon.getTaxonNodes()) {
359 TaxonNodeDTO dto = new TaxonNodeDTO();
360 loadBaseData(node, dto);
361 //classification
362 Classification classification = node.getClassification();
363 if (classification != null) {
364 dto.setClassificationUuid(node.getClassification().getUuid());
365 dto.setClassificationLabel(classification.getName().getText());
366 }
367 //TODO lang/locale
368 Language language = Language.DEFAULT();
369
370 //status
371 TaxonNodeStatus status = node.getStatus();
372 if (status != null) {
373 dto.setStatus(status.getLabel(language));
374 }
375 //statusNote
376 dto.setStatusNote(node.preferredStatusNote(language));
377
378 //agent relations
379 Set<TaxonNodeAgentRelation> agents = node.getAgentRelations();
380 if (!agents.isEmpty()) {
381 for (TaxonNodeAgentRelation rel : agents) {
382 TaxonNodeAgentsRelDTO agentDto = new TaxonNodeAgentsRelDTO();
383 loadBaseData(rel, agentDto);
384
385 //TODO laod
386 if (rel.getAgent() != null) {
387 agentDto.setAgent(rel.getAgent().getFullTitle());
388 agentDto.setAgentUuid(rel.getAgent().getUuid());
389 //TODO compute preferred external link
390 agentDto.setAgentLink(null);
391 }
392 if (rel.getType() != null) {
393 agentDto.setType(rel.getType().getTitleCache());
394 agentDto.setTypeUuid(rel.getType().getUuid());
395 }
396 dto.addAgent(agentDto);
397 }
398 }
399 container.addItem(dto);
400 }
401 if (container.getCount() > 0) {
402 result.setTaxonNodes(container);
403 }
404 } catch (Exception e) {
405 // e.printStackTrace();
406 result.addMessage(MessagesDto.NewErrorInstance("Error when loading taxon node data.", e));
407 }
408 }
409
410 private void loadSynonyms(Taxon taxon, TaxonPageDto result, TaxonPageDtoConfiguration config) {
411
412 if (!config.isWithSynonyms()) {
413 return;
414 }
415
416 try {
417 // List<HomotypicalGroup> homotypicGroups = taxon.getHomotypicSynonymyGroups();
418
419 TaxonComparator comparator = new TaxonComparator();
420
421 TaxonName name = taxon.getName();
422
423 //TODO depending on config add/remove accepted name
424
425 //homotypic synonyms
426 List<Synonym> homotypicSynonmys = filterPublished(taxon.getHomotypicSynonymsByHomotypicGroup(comparator));
427
428 TaxonPageDto.HomotypicGroupDTO homotypicGroupDto = new TaxonPageDto.HomotypicGroupDTO();
429 if (homotypicSynonmys != null && !homotypicSynonmys.isEmpty()) {
430 loadBaseData(name.getHomotypicalGroup(), homotypicGroupDto);
431
432 for (Synonym syn : homotypicSynonmys) {
433 loadSynonymsInGroup(homotypicGroupDto, syn, config, result);
434 }
435 }
436 if (name != null) {
437 handleTypification(name.getHomotypicalGroup(), homotypicGroupDto, result, config);
438 }
439 result.setHomotypicSynonyms(homotypicGroupDto);
440
441 //heterotypic synonyms
442 List<HomotypicalGroup> heteroGroups = taxon.getHeterotypicSynonymyGroups();
443 if (heteroGroups.isEmpty()) {
444 return;
445 }
446 ContainerDto<HomotypicGroupDTO> heteroContainer = new ContainerDto<>();
447 result.setHeterotypicSynonymGroups(heteroContainer);
448
449 for (HomotypicalGroup hg : heteroGroups) {
450 TaxonPageDto.HomotypicGroupDTO hgDto = new TaxonPageDto.HomotypicGroupDTO();
451 loadBaseData(taxon.getName().getHomotypicalGroup(), hgDto);
452 heteroContainer.addItem(hgDto);
453
454 List<Synonym> heteroSyns = filterPublished(taxon.getSynonymsInGroup(hg, comparator));
455 for (Synonym syn : heteroSyns) {
456 loadSynonymsInGroup(hgDto, syn, config, result);
457 }
458 handleTypification(hg, hgDto, result, config);
459 }
460 } catch (Exception e) {
461 //e.printStackTrace();
462 result.addMessage(MessagesDto.NewErrorInstance("Error when loading synonym data.", e));
463 }
464 }
465
466 private void handleTypification(HomotypicalGroup homotypicalGroup, HomotypicGroupDTO hgDto,
467 TaxonPageDto result, TaxonPageDtoConfiguration config) {
468
469 TypeDesignationSetFormatter formatter = new TypeDesignationSetFormatter();
470 Set<TypeDesignationBase<?>> designations = homotypicalGroup.getTypeDesignations();
471 try {
472 TypeDesignationSetContainer manager = TypeDesignationSetContainer.NewDefaultInstance((Set)designations);
473 List<TaggedText> tags = formatter.toTaggedText(manager);
474 String label = TaggedTextFormatter.createString(tags);
475 hgDto.setTypes(label);
476 hgDto.setTaggedTypes(tags);
477 // hgDto.setTypedTypes(null);
478
479 } catch (Exception e) {
480 // e.printStackTrace();
481 result.addMessage(MessagesDto.NewErrorInstance("Error when creating type designation information", e));
482 }
483 }
484
485 private void loadConceptRelations(Taxon taxon, TaxonPageDto result, TaxonPageDtoConfiguration config) {
486 if (!config.isWithTaxonRelationships()){
487 return;
488 }
489 try {
490 //concept relations
491 ContainerDto<ConceptRelationDTO> conceptRelContainer = new ContainerDto<>();
492 TaxonRelationshipFormatter taxRelFormatter = TaxonRelationshipFormatter.INSTANCE();
493
494 //... MAN
495 Set<TaxonRelationship> misappliedRels = taxon.getMisappliedNameRelations();
496 for (TaxonRelationship rel : misappliedRels) {
497 boolean inverse = true;
498 boolean withoutName = false;
499 loadConceptRelation(taxRelFormatter, rel, conceptRelContainer, inverse, withoutName);
500 }
501
502 //... pro parte Synonyms
503 Set<TaxonRelationship> proParteRels = taxon.getProParteAndPartialSynonymRelations();
504 for (TaxonRelationship rel : proParteRels) {
505 boolean inverse = true;
506 boolean withoutName = false;
507 loadConceptRelation(taxRelFormatter, rel, conceptRelContainer, inverse, withoutName);
508 }
509
510 //TODO MAN and pp from this taxon
511
512 //... to-relations
513 Set<TaxonRelationship> toRels = taxon.getRelationsToThisTaxon();
514 toRels.removeAll(misappliedRels);
515 toRels.removeAll(proParteRels);
516 for (TaxonRelationship rel : toRels) {
517 boolean inverse = true;
518 boolean withoutName = false;
519 loadConceptRelation(taxRelFormatter, rel, conceptRelContainer, inverse, withoutName);
520 }
521
522 //... from-relations
523 Set<TaxonRelationship> fromRels = taxon.getRelationsFromThisTaxon();
524 for (TaxonRelationship rel : fromRels) {
525 boolean inverse = false;
526 boolean withoutName = false;
527 loadConceptRelation(taxRelFormatter, rel, conceptRelContainer, inverse, withoutName);
528 }
529
530 if (conceptRelContainer.getCount() > 0) {
531 result.setConceptRelations(conceptRelContainer);
532 }
533 } catch (Exception e) {
534 //e.printStackTrace();
535 result.addMessage(MessagesDto.NewErrorInstance("Error when loading concept relation data.", e));
536 }
537 }
538
539 private void loadConceptRelation(TaxonRelationshipFormatter taxRelFormatter, TaxonRelationship rel, ContainerDto<ConceptRelationDTO> conceptRelContainer, boolean inverse,
540 boolean withoutName) {
541
542 List<Language> languages = Arrays.asList(new Language[] {Language.DEFAULT()}); // TODO config.locales;
543 List<TaggedText> tags = taxRelFormatter.getTaggedText(rel, inverse, languages, withoutName);
544 String relLabel = TaggedTextFormatter.createString(tags);
545 ConceptRelationDTO dto = new TaxonPageDto.ConceptRelationDTO();
546 loadBaseData(rel, dto);
547 dto.setRelSource(makeSource(rel.getSource()));
548 Taxon relTaxon = inverse ? rel.getFromTaxon() : rel.getToTaxon();
549 dto.setRelTaxonId(relTaxon.getId());
550 dto.setRelTaxonUuid(relTaxon.getUuid());
551 dto.setRelTaxonLabel(relTaxon.getTitleCache());
552 dto.setSecSource(makeSource(relTaxon.getSecSource()));
553 dto.setLabel(relLabel);
554 dto.setTaggedLabel(tags);
555 dto.setNameUuid(relTaxon.getName() != null ? relTaxon.getName().getUuid() : null);
556
557 if (rel.getType() != null) {
558 dto.setRelTypeUuid(rel.getType().getUuid());
559 }
560 for (TaxonNode node : relTaxon.getTaxonNodes()) {
561 Classification classification = node.getClassification();
562 if (classification != null) {
563 dto.addClassificationUuids(classification.getUuid());
564 }
565 }
566 conceptRelContainer.addItem(dto);
567 }
568
569 private void loadSynonymsInGroup(TaxonPageDto.HomotypicGroupDTO hgDto, Synonym syn,
570 TaxonPageDtoConfiguration config, TaxonPageDto pageDto) {
571
572 TaxonBaseDto synDto = new TaxonBaseDto();
573 loadBaseData(syn, synDto);
574 synDto.setLabel(syn.getTitleCache());
575 synDto.setTaggedLabel(getTaggedTaxon(syn, config));
576
577 if (syn.getName() != null) {
578 handleName(config, synDto, syn.getName(), pageDto);
579 }
580
581 //TODO
582 hgDto.addSynonym(synDto);
583 }
584
585 private void loadProtologues(TaxonName name, TaxonBaseDto taxonBaseDto) {
586 //TODO maybe also load reference DOI/URL if no source external link exists
587 NomenclaturalSource nomSource = name.getNomenclaturalSource();
588 if (nomSource != null) {
589 Set<ExternalLink> links = nomSource.getLinks();
590 for (ExternalLink link : links) {
591 if (link.getUri() != null) {
592 taxonBaseDto.addProtologue(link.getUri());
593 }
594 }
595 }
596 }
597
598 private void handleRelatedNames(TaxonName name, TaxonBaseDto taxonDto, TaxonPageDtoConfiguration config) {
599 //exclusions TODO handle via config
600 Set<UUID> excludedTypes = new HashSet<>(); //both directions
601 excludedTypes.add(NameRelationshipType.uuidBasionym);
602 excludedTypes.add(NameRelationshipType.uuidReplacedSynonym);
603 Set<UUID> excludedFromTypes = new HashSet<>(excludedTypes);
604 Set<UUID> excludedToTypes = new HashSet<>(excludedTypes);
605 //TODO non-types
606
607 //TODO config.getLocales();
608 Language locale = Language.DEFAULT();
609
610 for (NameRelationship rel : name.getRelationsFromThisName()) {
611 TaxonName relatedName = rel.getToName();
612 if (relatedName == null || rel.getType() == null || excludedFromTypes.contains(rel.getType().getUuid())) {
613 continue;
614 }
615 NameRelationDTO dto = new NameRelationDTO();
616 loadBaseData(rel, dto);
617 //name
618 dto.setNameUuid(relatedName.getUuid());
619 dto.setNameLabel(relatedName.getTaggedName());
620 //type
621 dto.setRelTypeUuid(rel.getType().getUuid());
622 Representation rep = rel.getType().getPreferredRepresentation(locale);
623 dto.setRelType(rep == null ? rel.getType().toString() : rep.getLabel());
624 //inverse
625 dto.setInverse(false);
626 //ruleConsidered
627 dto.setRuleConsidered(rel.getRuleConsidered());
628 //year
629 dto.setYear(relatedName.getReferenceYear());
630 taxonDto.addRelatedName(dto);
631 }
632
633 //to relations
634 for (NameRelationship rel : name.getRelationsToThisName()) {
635 TaxonName relatedName = rel.getFromName();
636 if (relatedName == null || rel.getType() == null || excludedFromTypes.contains(rel.getType().getUuid())) {
637 continue;
638 }
639 NameRelationDTO dto = new NameRelationDTO();
640 loadBaseData(rel, dto);
641 //name
642 dto.setNameUuid(relatedName.getUuid());
643 dto.setNameLabel(relatedName.getTaggedName());
644 //type
645 dto.setRelTypeUuid(rel.getType().getUuid());
646 Representation rep = rel.getType().getPreferredInverseRepresentation(Arrays.asList(new Language[] {locale}));
647 dto.setRelType(rep == null ? rel.getType().toString() : rep.getLabel());
648 //inverse
649 dto.setInverse(true);
650 //year
651 dto.setYear(relatedName.getReferenceYear());
652 taxonDto.addRelatedName(dto);
653 }
654 }
655
656 private void loadFacts(Taxon taxon, TaxonPageDto taxonPageDto, TaxonPageDtoConfiguration config) {
657 factLoader.loadTaxonFacts(taxon, taxonPageDto, config);
658 }
659
660 private void loadNameFacts(TaxonName name, TaxonBaseDto nameDto, TaxonPageDtoConfiguration config, TaxonPageDto pageDto) {
661 factLoader.loadNameFacts(name, nameDto, config, pageDto);
662 }
663
664 /**
665 * Compares an existing last date and the last date of an entity
666 * and returns the resulting last date.
667 */
668 private LocalDateTime getLastUpdated(LocalDateTime existingLastDate, VersionableEntity dateToAddEntity) {
669
670 DateTime dateToAdd = dateToAddEntity.getUpdated() != null ? dateToAddEntity.getUpdated() : dateToAddEntity.getCreated();
671
672 LocalDateTime javaLocalDateTimeOfEntity = DtoUtil.fromDateTime(dateToAdd);
673
674 if (existingLastDate == null) {
675 return javaLocalDateTimeOfEntity;
676 }else if (javaLocalDateTimeOfEntity == null || javaLocalDateTimeOfEntity.compareTo(existingLastDate) < 0) {
677 return existingLastDate;
678 }else {
679 return javaLocalDateTimeOfEntity;
680 }
681 }
682 }