include taxon name in taxon node referencing objects formatter
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / format / ReferencingObjectFormatter.java
1 /**
2 * Copyright (C) 2021 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.format;
10
11 import java.lang.reflect.InvocationTargetException;
12 import java.lang.reflect.Method;
13 import java.util.Set;
14
15 import org.apache.commons.lang3.StringUtils;
16
17 import eu.etaxonomy.cdm.common.CdmUtils;
18 import eu.etaxonomy.cdm.format.occurrences.DistanceStringFormatter;
19 import eu.etaxonomy.cdm.model.agent.AgentBase;
20 import eu.etaxonomy.cdm.model.common.CdmBase;
21 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
22 import eu.etaxonomy.cdm.model.common.IdentifiableSource;
23 import eu.etaxonomy.cdm.model.common.Language;
24 import eu.etaxonomy.cdm.model.common.LanguageString;
25 import eu.etaxonomy.cdm.model.common.LanguageStringBase;
26 import eu.etaxonomy.cdm.model.common.Marker;
27 import eu.etaxonomy.cdm.model.common.MarkerType;
28 import eu.etaxonomy.cdm.model.common.RelationshipBase;
29 import eu.etaxonomy.cdm.model.common.RelationshipTermBase;
30 import eu.etaxonomy.cdm.model.common.TimePeriod;
31 import eu.etaxonomy.cdm.model.description.CommonTaxonName;
32 import eu.etaxonomy.cdm.model.description.DescriptionBase;
33 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
34 import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
35 import eu.etaxonomy.cdm.model.description.Distribution;
36 import eu.etaxonomy.cdm.model.description.IDescribable;
37 import eu.etaxonomy.cdm.model.description.KeyStatement;
38 import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
39 import eu.etaxonomy.cdm.model.description.SpecimenDescription;
40 import eu.etaxonomy.cdm.model.description.TaxonDescription;
41 import eu.etaxonomy.cdm.model.description.TaxonInteraction;
42 import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
43 import eu.etaxonomy.cdm.model.description.TextData;
44 import eu.etaxonomy.cdm.model.location.NamedArea;
45 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
46 import eu.etaxonomy.cdm.model.name.HybridRelationship;
47 import eu.etaxonomy.cdm.model.name.NameRelationship;
48 import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
49 import eu.etaxonomy.cdm.model.name.NomenclaturalSource;
50 import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
51 import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
52 import eu.etaxonomy.cdm.model.name.TaxonName;
53 import eu.etaxonomy.cdm.model.name.TextualTypeDesignation;
54 import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
55 import eu.etaxonomy.cdm.model.name.TypeDesignationStatusBase;
56 import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent;
57 import eu.etaxonomy.cdm.model.occurrence.GatheringEvent;
58 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
59 import eu.etaxonomy.cdm.model.permission.Group;
60 import eu.etaxonomy.cdm.model.permission.User;
61 import eu.etaxonomy.cdm.model.reference.NamedSource;
62 import eu.etaxonomy.cdm.model.reference.OriginalSourceBase;
63 import eu.etaxonomy.cdm.model.taxon.Classification;
64 import eu.etaxonomy.cdm.model.taxon.SecundumSource;
65 import eu.etaxonomy.cdm.model.taxon.Taxon;
66 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
67 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
68 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
69 import eu.etaxonomy.cdm.model.term.Representation;
70
71 /**
72 * @author a.mueller
73 * @date 19.03.2021
74 */
75 public class ReferencingObjectFormatter {
76
77 public static String format(CdmBase element, Language defaultLanguage) {
78 return format(element, null, defaultLanguage);
79 }
80
81 public static String format(CdmBase element, String target, Language defaultLanguage) {
82
83 String resultString = null;
84 if (element == null){
85 return null;
86 }else if (element instanceof IdentifiableEntity) {
87 resultString = ((IdentifiableEntity<?>) element).getTitleCache();
88 }else if (element instanceof OriginalSourceBase) {
89 OriginalSourceBase originalSource = (OriginalSourceBase) element;
90 // ISourceable sourcedObject = originalSource.getSourcedObj();
91 //due to #5743 the bidirectionality for sourced object had to be removed
92
93 String sourceObjectTitle = "sourced object data not available (#5743)";
94
95 //it is now possible for NomenclaturalSource as they link to the sourced name
96 if (originalSource instanceof NomenclaturalSource){
97 TaxonName sourcedName = ((NomenclaturalSource)originalSource).getSourcedName();
98 sourceObjectTitle = sourcedName == null ? "Source orphaned, not attached to a name" :
99 "for " + sourcedName.getTitleCache();
100 }else if (originalSource instanceof SecundumSource){
101 TaxonBase<?> sourcedTaxon = ((SecundumSource)originalSource).getSourcedTaxon();
102 sourceObjectTitle = sourcedTaxon == null ? "Source orphaned, not attached to a taxon" :
103 "for " + sourcedTaxon.getTitleCache();
104 }else if (originalSource instanceof DescriptionElementSource){
105 sourceObjectTitle = getCache((DescriptionElementSource)originalSource, defaultLanguage);
106 }else if (originalSource instanceof IdentifiableSource && isNotBlank(target) ){
107 sourceObjectTitle = "for " + target;
108 }else if (originalSource instanceof NamedSource && isNotBlank(target) ){
109 sourceObjectTitle = "for " + target;
110 }
111 resultString = CdmUtils.concat("; ", new String[]{originalSource.getIdNamespace(), originalSource.getIdInSource(), sourceObjectTitle});
112 }else if (element instanceof LanguageStringBase) {
113 resultString = ((LanguageStringBase) element).getText();
114 }else if (element instanceof DescriptionElementBase) {
115 resultString = getCache((DescriptionElementBase) element, defaultLanguage);
116 }else if (element instanceof RelationshipBase<?, ?, ?>) {
117 resultString = getCache((RelationshipBase<?, ?, ?>) element, defaultLanguage);
118 }else if (element instanceof TypeDesignationBase<?>) {
119 resultString = getCache((TypeDesignationBase<?>) element, defaultLanguage);
120 }else if (element instanceof HomotypicalGroup) {
121 resultString = getCache((HomotypicalGroup) element);
122 }else if (element instanceof TaxonNode) {
123 resultString = getCache((TaxonNode) element);
124 }else if (element instanceof DeterminationEvent) {
125 resultString = getCache((DeterminationEvent) element);
126 }else if (element instanceof NomenclaturalStatus) {
127 resultString = getCache((NomenclaturalStatus) element);
128 }else if (element instanceof GatheringEvent){
129 resultString = getCache((GatheringEvent) element);
130 }else if (element instanceof Marker) {
131 Marker marker = (Marker) element;
132 MarkerType type = marker.getMarkerType();
133 resultString = (type == null ? "- no marker type -" : marker.getMarkerType().getLabel()) + " (" + marker.getFlag() + ")";
134 }else if (element instanceof User) {
135 User user = (User) element;
136 resultString = user.getUsername();
137 }else if (element instanceof Group) {
138 Group group = (Group) element;
139 resultString = group.getName();
140 }else if (element instanceof KeyStatement) {
141 KeyStatement keyStatement = (KeyStatement) element;
142 resultString = getCache(keyStatement);
143 }else{
144 // TODO write return texts for HomotypicalGroup, etc.
145 resultString = element.toString();
146 }
147
148 if (resultString == null){
149 resultString = element.toString();
150 }
151 return resultString;
152 }
153
154 private static String getCache(DescriptionElementSource source, Language defaultLanguage) {
155 DescriptionElementBase sourcedElement = source.getSourcedElement();
156
157 if (sourcedElement == null){
158 return "Source orphaned, not attached to a fact";
159 }
160 String superLabel = getDescribedObjectLabel(sourcedElement.getInDescription());
161 String result = CdmUtils.concat(": ", DescriptionElementFormatter.format(sourcedElement, defaultLanguage), superLabel);
162 return result;
163 }
164
165 private static String getDescribedObjectLabel(DescriptionBase<?> inDescription) {
166 IDescribable<?> entity = inDescription.describedEntity();
167 if (entity != null){
168 return entity.getTitleCache();
169 }else{
170 return inDescription.getTitleCache();
171 }
172 }
173
174 private static String getCache(RelationshipBase<?, ?, ?> rel, Language defaultLanguage) {
175 rel = CdmBase.deproxy(rel);
176 RelationshipTermBase<?> type = rel.getType();
177 IdentifiableEntity<?> from;
178 IdentifiableEntity<?> to;
179 if (rel.isInstanceOf(NameRelationship.class)){
180 from = ((NameRelationship)rel).getFromName();
181 to = ((NameRelationship)rel).getToName();
182 }else if (rel.isInstanceOf(HybridRelationship.class)){
183 from = ((HybridRelationship)rel).getParentName();
184 to = ((HybridRelationship)rel).getHybridName();
185 }else if (rel.isInstanceOf(TaxonRelationship.class)){
186 from = ((TaxonRelationship)rel).getFromTaxon();
187 to = ((TaxonRelationship)rel).getToTaxon();
188 }else{
189 try {
190 Method fromMethod = rel.getClass().getMethod("getRelatedFrom");
191 Method toMethod = rel.getClass().getMethod("getRelatedFrom");
192 fromMethod.setAccessible(true);
193 toMethod.setAccessible(true);
194 from = (IdentifiableEntity<?>)fromMethod.invoke(rel);
195 to = (IdentifiableEntity<?>)toMethod.invoke(rel);
196 } catch (NoSuchMethodException | SecurityException | IllegalAccessException
197 | IllegalArgumentException | InvocationTargetException e) {
198 throw new RuntimeException(e);
199 }
200 }
201 String typeLabel = null;
202 if (type != null){
203 Representation typeRepr = type.getPreferredRepresentation(defaultLanguage);
204 if (typeRepr != null){
205 typeLabel = typeRepr.getAbbreviatedLabel();
206 }
207 if (isBlank(typeLabel) && typeRepr != null){
208 typeLabel = typeRepr.getLabel();
209 }
210 if (isBlank(typeLabel) ){
211 typeLabel = type.getSymbol();
212 }
213 if (isBlank(typeLabel)){
214 typeLabel = type.getTitleCache();
215 }
216 }
217 if (isBlank(typeLabel)){
218 typeLabel = "->";
219 }
220 String result = CdmUtils.concat(" ", new String[]{from == null ? null : from.getTitleCache(),
221 typeLabel, to == null? null : to.getTitleCache()});
222 return result;
223 }
224
225 private static String getCache(GatheringEvent gatheringEvent){
226 String ALTITUDE_PREFIX = "alt. ";
227 final String METER = "m";
228
229 String result = "";
230
231 //collector
232 AgentBase<?> collector = CdmBase.deproxy(gatheringEvent.getCollector());
233 String collectorStr = collector == null? null : collector.getTitleCache();
234 result = CdmUtils.concat(", ", result, collectorStr);
235
236 //gathering period
237 TimePeriod gatheringPeriod = gatheringEvent.getTimeperiod();
238 result = CdmUtils.concat(", ", result, (gatheringPeriod == null? null : gatheringPeriod.toString()));
239
240 //country
241 String strCountry = null;
242 NamedArea country = gatheringEvent.getCountry();
243 Representation repCountry = country == null ? null : country.getRepresentation(Language.DEFAULT());
244 strCountry = repCountry == null ? null: repCountry.getLabel();
245 result = CdmUtils.concat(", ", result, strCountry);
246
247 //locality
248 LanguageString locality = gatheringEvent.getLocality();
249 if (locality != null) {
250 result = CdmUtils.concat(", ", result, locality.getText());
251 }
252
253 //elevation
254 String elevationStr;
255 if (isNotBlank(gatheringEvent.getAbsoluteElevationText())){
256 elevationStr = gatheringEvent.getAbsoluteElevationText();
257 }else{
258 String text = gatheringEvent.getAbsoluteElevationText();
259 Integer min = gatheringEvent.getAbsoluteElevation();
260 Integer max = gatheringEvent.getAbsoluteElevationMax();
261 elevationStr = DistanceStringFormatter.distanceString(min, max, text, METER);
262 }
263 if (isNotBlank(elevationStr)){
264 result = CdmUtils.concat(", " , result, ALTITUDE_PREFIX);
265 result += elevationStr;
266 }
267
268 //exact locality
269 if (gatheringEvent.getExactLocation() != null){
270 String exactLocation = gatheringEvent.getExactLocation().toSexagesimalString(false, false);
271 result = CdmUtils.concat(", ", result, exactLocation);
272 }
273
274 return result;
275 }
276
277 private static String getCache(DeterminationEvent detEvent) {
278 //taxon
279 String taxonStr = null;
280 TaxonName taxonName = detEvent.getTaxonName();
281 TaxonBase<?> taxon = detEvent.getTaxon();
282 if (taxonName != null){
283 taxonStr = taxonName.getTitleCache();
284 }
285 if (isBlank(taxonStr) && taxon != null){
286 taxonStr = taxon.getTitleCache();
287 }
288 if (isBlank(taxonStr)){
289 taxonStr = "no or unlabled taxon";
290 }
291
292 //unit
293 SpecimenOrObservationBase<?> unit = detEvent.getIdentifiedUnit();
294 String unitStr;
295 if (unit != null){
296 unitStr = unit.getTitleCache();
297 if (isBlank(unitStr)){
298 unitStr = "Unlabled unit";
299 }
300 }else{
301 unitStr = "no unit";
302 }
303
304 String result = CdmUtils.concat(" determined as ", unitStr, taxonStr);
305
306 return result;
307 }
308
309 private static String getCache(TaxonNode taxonNode) {
310 String result = "";
311 Taxon taxon = taxonNode.getTaxon();
312 if (taxon != null){
313 result = taxon.getName() != null ? taxon.getName().getTitleCache() : taxon.getTitleCache();
314 }
315
316 final String invisible = "Invisible root of ";
317 String parentStr;
318 TaxonNode parentNode = taxonNode.getParent();
319 if (parentNode == null){
320 parentStr = invisible;
321 }else{
322 Taxon parentTaxon = parentNode.getTaxon();
323 if (parentTaxon == null){
324 parentStr = " (root of ";
325 }else{
326 TaxonName parentName = parentTaxon.getName();
327 if (parentName == null){
328 parentStr = " (child of " + parentTaxon.getTitleCache();
329 }else{
330 parentStr = " (child of " + parentName.getTitleCache();
331 }
332 parentStr += " in ";
333 }
334 }
335
336 //classification
337 Classification classification = taxonNode.getClassification();
338 String classificationStr ;
339 if (classification != null){
340 classificationStr = classification.getName() == null ? "classification:"+classification.getId() : classification.getName().getText();
341 if (isBlank(classificationStr)){
342 classificationStr = classification.toString();
343 }
344 }else{
345 classificationStr = "-no classification-"; //should not happen
346 }
347
348 result = CdmUtils.concat("", parentStr, classificationStr, parentStr == invisible? "" : ")");
349
350 return result;
351 }
352
353 private static String getCache(TypeDesignationBase<?> designation, Language defaultLanguage) {
354 designation = CdmBase.deproxy(designation);
355 //from
356 String fromString = null;
357 Set<TaxonName> from = designation.getTypifiedNames();
358 if(from != null){
359 for (TaxonName name : from){
360 fromString = CdmUtils.concat(",", fromString, name.getTitleCache());
361 }
362 }
363 //to
364 IdentifiableEntity<?> to = null;
365 String toStr = "";
366 if (designation.isInstanceOf(SpecimenTypeDesignation.class)){
367 to = ((SpecimenTypeDesignation)designation).getTypeSpecimen();
368 }else if (designation.isInstanceOf(NameTypeDesignation.class)){
369 to = ((NameTypeDesignation)designation).getTypeName();
370 }else if (designation.isInstanceOf(TextualTypeDesignation.class)){
371 toStr = ((TextualTypeDesignation)designation).getPreferredText(defaultLanguage);
372 }else{
373 throw new RuntimeException("Type Designation class not supported: " + designation.getClass().getName());
374 }
375 toStr = to == null? toStr : to.getTitleCache();
376 //status
377 String typeLabel = null;
378 TypeDesignationStatusBase<?> status = designation.getTypeStatus();
379 if (status != null){
380 Representation typeRepr = status.getPreferredRepresentation(defaultLanguage);
381 if (typeRepr != null){
382 typeLabel = typeRepr.getAbbreviatedLabel();
383 }
384 if (isBlank(typeLabel) && typeRepr != null){
385 typeLabel = typeRepr.getLabel();
386 }
387 if (isBlank(typeLabel) ){
388 typeLabel = status.getSymbol();
389 }
390 if (isBlank(typeLabel)){
391 typeLabel = status.getTitleCache();
392 }
393 }
394 if (isBlank(typeLabel)){
395 typeLabel = "->";
396 }
397 //concat
398 String result = CdmUtils.concat(" ", new String[]{fromString, typeLabel, toStr});
399 return result;
400 }
401
402 private static String getCache(HomotypicalGroup hg) {
403 String result = "";
404 for (TaxonName tnb : hg.getTypifiedNames()){
405 result = CdmUtils.concat(", ", result, tnb.getTitleCache());
406 }
407 if (isBlank(result)){
408 result = "No typified names";
409 }
410 return result;
411 }
412
413 private static String getCache(KeyStatement ks) {
414 String result = "";
415 LanguageString ls = ks.getPreferredLanguageString(Language.DEFAULT());
416 if (ls != null && CdmUtils.isNotBlank(ls.getText())){
417 result = ls.getText();
418 }else{
419 result = ks.toString();
420 }
421 return result;
422 }
423
424 private static String getCache(NomenclaturalStatus nomStatus) {
425 String result = nomStatus.getName().getTitleCache();
426 if (nomStatus.getType()!= null){
427 Representation rep = nomStatus.getType().getPreferredRepresentation(Language.DEFAULT());
428 if (rep != null){
429 result = CdmUtils.concat(": ", rep.getAbbreviatedLabel(), result);
430 }
431 }
432 return result;
433 }
434
435
436 private static boolean isNotBlank(String str){
437 return StringUtils.isNotBlank(str);
438 }
439
440 private static boolean isBlank(String str){
441 return StringUtils.isBlank(str);
442 }
443
444 //from taxeditor DescriptionHelper
445 private static String getCache(DescriptionElementBase element,
446 Language defaultLanguage) {
447
448 String mainElementLabel= null;
449 DescriptionBase<?> descr = element.getInDescription();
450 descr = CdmBase.deproxy(descr);
451
452 if (descr != null){
453 if (descr.isInstanceOf(TaxonDescription.class)){
454 Taxon taxon = CdmBase.deproxy(descr, TaxonDescription.class).getTaxon();
455 if (taxon != null){
456 mainElementLabel = taxon.getTitleCache();
457 }
458 }else if (descr.isInstanceOf(SpecimenDescription.class)){
459 SpecimenOrObservationBase<?> specimen = CdmBase.deproxy(descr, SpecimenDescription.class).getDescribedSpecimenOrObservation();
460 if (specimen != null){
461 mainElementLabel = specimen.getTitleCache();
462 }
463 }else if (descr.isInstanceOf(TaxonNameDescription.class)){
464 TaxonName name = CdmBase.deproxy(descr, TaxonNameDescription.class).getTaxonName();
465 if (name != null){
466 mainElementLabel = name.getTitleCache();
467 }
468 }
469 }
470
471 String cache = null;
472 if (element instanceof TextData) {
473 //cache = ((TextData) element).getText(language);
474 cache = "Text Data";
475 }
476 if (element instanceof CommonTaxonName) {
477 cache = ((CommonTaxonName) element).getName();
478 }
479 if (element instanceof TaxonInteraction) {
480 Taxon taxon2 = ((TaxonInteraction) element).getTaxon2();
481 if(taxon2 != null && taxon2.getName() != null){
482 cache = taxon2.getName().getTitleCache();
483 }else{
484 cache = "No taxon chosen";
485 }
486 }
487 if (element instanceof Distribution) {
488 Distribution distribution = (Distribution) element;
489
490 NamedArea area = distribution.getArea();
491 if(area != null){
492 cache = area.getLabel();
493
494 PresenceAbsenceTerm status = distribution.getStatus();
495 if (status == null){
496 cache += ", no status";
497 }else {
498 cache += ", " + status.getLabel();
499 }
500 }
501 }
502 String result = cache == null ? "" : cache;
503 if (isNotBlank(mainElementLabel)){
504 result = CdmUtils.concat(" ", result, "(" + mainElementLabel + ")");
505 }
506 return result;
507 }
508
509 }