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