2 * Copyright (C) 2021 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
.format
;
11 import java
.lang
.reflect
.InvocationTargetException
;
12 import java
.lang
.reflect
.Method
;
15 import org
.apache
.commons
.lang3
.StringUtils
;
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
;
75 public class ReferencingObjectFormatter
{
77 public static String
format(CdmBase element
, Language defaultLanguage
) {
78 return format(element
, null, defaultLanguage
);
81 public static String
format(CdmBase element
, String target
, Language defaultLanguage
) {
83 String resultString
= 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
93 String sourceObjectTitle
= "sourced object data not available (#5743)";
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
;
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
);
144 // TODO write return texts for HomotypicalGroup, etc.
145 resultString
= element
.toString();
148 if (resultString
== null){
149 resultString
= element
.toString();
154 private static String
getCache(DescriptionElementSource source
, Language defaultLanguage
) {
155 DescriptionElementBase sourcedElement
= source
.getSourcedElement();
157 if (sourcedElement
== null){
158 return "Source orphaned, not attached to a fact";
160 String superLabel
= getDescribedObjectLabel(sourcedElement
.getInDescription());
161 String result
= CdmUtils
.concat(": ", DescriptionElementFormatter
.format(sourcedElement
, defaultLanguage
), superLabel
);
165 private static String
getDescribedObjectLabel(DescriptionBase
<?
> inDescription
) {
166 IDescribable
<?
> entity
= inDescription
.describedEntity();
168 return entity
.getTitleCache();
170 return inDescription
.getTitleCache();
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();
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
);
201 String typeLabel
= null;
203 Representation typeRepr
= type
.getPreferredRepresentation(defaultLanguage
);
204 if (typeRepr
!= null){
205 typeLabel
= typeRepr
.getAbbreviatedLabel();
207 if (isBlank(typeLabel
) && typeRepr
!= null){
208 typeLabel
= typeRepr
.getLabel();
210 if (isBlank(typeLabel
) ){
211 typeLabel
= type
.getSymbol();
213 if (isBlank(typeLabel
)){
214 typeLabel
= type
.getTitleCache();
217 if (isBlank(typeLabel
)){
220 String result
= CdmUtils
.concat(" ", new String
[]{from
== null ?
null : from
.getTitleCache(),
221 typeLabel
, to
== null?
null : to
.getTitleCache()});
225 private static String
getCache(GatheringEvent gatheringEvent
){
226 String ALTITUDE_PREFIX
= "alt. ";
227 final String METER
= "m";
232 AgentBase
<?
> collector
= CdmBase
.deproxy(gatheringEvent
.getCollector());
233 String collectorStr
= collector
== null?
null : collector
.getTitleCache();
234 result
= CdmUtils
.concat(", ", result
, collectorStr
);
237 TimePeriod gatheringPeriod
= gatheringEvent
.getTimeperiod();
238 result
= CdmUtils
.concat(", ", result
, (gatheringPeriod
== null?
null : gatheringPeriod
.toString()));
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
);
248 LanguageString locality
= gatheringEvent
.getLocality();
249 if (locality
!= null) {
250 result
= CdmUtils
.concat(", ", result
, locality
.getText());
255 if (isNotBlank(gatheringEvent
.getAbsoluteElevationText())){
256 elevationStr
= gatheringEvent
.getAbsoluteElevationText();
258 String text
= gatheringEvent
.getAbsoluteElevationText();
259 Integer min
= gatheringEvent
.getAbsoluteElevation();
260 Integer max
= gatheringEvent
.getAbsoluteElevationMax();
261 elevationStr
= DistanceStringFormatter
.distanceString(min
, max
, text
, METER
);
263 if (isNotBlank(elevationStr
)){
264 result
= CdmUtils
.concat(", " , result
, ALTITUDE_PREFIX
);
265 result
+= elevationStr
;
269 if (gatheringEvent
.getExactLocation() != null){
270 String exactLocation
= gatheringEvent
.getExactLocation().toSexagesimalString(false, false);
271 result
= CdmUtils
.concat(", ", result
, exactLocation
);
277 private static String
getCache(DeterminationEvent detEvent
) {
279 String taxonStr
= null;
280 TaxonName taxonName
= detEvent
.getTaxonName();
281 TaxonBase
<?
> taxon
= detEvent
.getTaxon();
282 if (taxonName
!= null){
283 taxonStr
= taxonName
.getTitleCache();
285 if (isBlank(taxonStr
) && taxon
!= null){
286 taxonStr
= taxon
.getTitleCache();
288 if (isBlank(taxonStr
)){
289 taxonStr
= "no or unlabled taxon";
293 SpecimenOrObservationBase
<?
> unit
= detEvent
.getIdentifiedUnit();
296 unitStr
= unit
.getTitleCache();
297 if (isBlank(unitStr
)){
298 unitStr
= "Unlabled unit";
304 String result
= CdmUtils
.concat(" determined as ", unitStr
, taxonStr
);
309 private static String
getCache(TaxonNode taxonNode
) {
311 Taxon taxon
= taxonNode
.getTaxon();
313 result
= taxon
.getName() != null ? taxon
.getName().getTitleCache() : taxon
.getTitleCache();
316 final String invisible
= "Invisible root of ";
318 TaxonNode parentNode
= taxonNode
.getParent();
319 if (parentNode
== null){
320 parentStr
= invisible
;
322 Taxon parentTaxon
= parentNode
.getTaxon();
323 if (parentTaxon
== null){
324 parentStr
= " (root of ";
326 TaxonName parentName
= parentTaxon
.getName();
327 if (parentName
== null){
328 parentStr
= " (child of " + parentTaxon
.getTitleCache();
330 parentStr
= " (child of " + parentName
.getTitleCache();
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();
345 classificationStr
= "-no classification-"; //should not happen
348 result
= CdmUtils
.concat("", parentStr
, classificationStr
, parentStr
== invisible?
"" : ")");
353 private static String
getCache(TypeDesignationBase
<?
> designation
, Language defaultLanguage
) {
354 designation
= CdmBase
.deproxy(designation
);
356 String fromString
= null;
357 Set
<TaxonName
> from
= designation
.getTypifiedNames();
359 for (TaxonName name
: from
){
360 fromString
= CdmUtils
.concat(",", fromString
, name
.getTitleCache());
364 IdentifiableEntity
<?
> to
= null;
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
);
373 throw new RuntimeException("Type Designation class not supported: " + designation
.getClass().getName());
375 toStr
= to
== null? toStr
: to
.getTitleCache();
377 String typeLabel
= null;
378 TypeDesignationStatusBase
<?
> status
= designation
.getTypeStatus();
380 Representation typeRepr
= status
.getPreferredRepresentation(defaultLanguage
);
381 if (typeRepr
!= null){
382 typeLabel
= typeRepr
.getAbbreviatedLabel();
384 if (isBlank(typeLabel
) && typeRepr
!= null){
385 typeLabel
= typeRepr
.getLabel();
387 if (isBlank(typeLabel
) ){
388 typeLabel
= status
.getSymbol();
390 if (isBlank(typeLabel
)){
391 typeLabel
= status
.getTitleCache();
394 if (isBlank(typeLabel
)){
398 String result
= CdmUtils
.concat(" ", new String
[]{fromString
, typeLabel
, toStr
});
402 private static String
getCache(HomotypicalGroup hg
) {
404 for (TaxonName tnb
: hg
.getTypifiedNames()){
405 result
= CdmUtils
.concat(", ", result
, tnb
.getTitleCache());
407 if (isBlank(result
)){
408 result
= "No typified names";
413 private static String
getCache(KeyStatement ks
) {
415 LanguageString ls
= ks
.getPreferredLanguageString(Language
.DEFAULT());
416 if (ls
!= null && CdmUtils
.isNotBlank(ls
.getText())){
417 result
= ls
.getText();
419 result
= ks
.toString();
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());
429 result
= CdmUtils
.concat(": ", rep
.getAbbreviatedLabel(), result
);
436 private static boolean isNotBlank(String str
){
437 return StringUtils
.isNotBlank(str
);
440 private static boolean isBlank(String str
){
441 return StringUtils
.isBlank(str
);
444 //from taxeditor DescriptionHelper
445 private static String
getCache(DescriptionElementBase element
,
446 Language defaultLanguage
) {
448 String mainElementLabel
= null;
449 DescriptionBase
<?
> descr
= element
.getInDescription();
450 descr
= CdmBase
.deproxy(descr
);
453 if (descr
.isInstanceOf(TaxonDescription
.class)){
454 Taxon taxon
= CdmBase
.deproxy(descr
, TaxonDescription
.class).getTaxon();
456 mainElementLabel
= taxon
.getTitleCache();
458 }else if (descr
.isInstanceOf(SpecimenDescription
.class)){
459 SpecimenOrObservationBase
<?
> specimen
= CdmBase
.deproxy(descr
, SpecimenDescription
.class).getDescribedSpecimenOrObservation();
460 if (specimen
!= null){
461 mainElementLabel
= specimen
.getTitleCache();
463 }else if (descr
.isInstanceOf(TaxonNameDescription
.class)){
464 TaxonName name
= CdmBase
.deproxy(descr
, TaxonNameDescription
.class).getTaxonName();
466 mainElementLabel
= name
.getTitleCache();
472 if (element
instanceof TextData
) {
473 //cache = ((TextData) element).getText(language);
476 if (element
instanceof CommonTaxonName
) {
477 cache
= ((CommonTaxonName
) element
).getName();
479 if (element
instanceof TaxonInteraction
) {
480 Taxon taxon2
= ((TaxonInteraction
) element
).getTaxon2();
481 if(taxon2
!= null && taxon2
.getName() != null){
482 cache
= taxon2
.getName().getTitleCache();
484 cache
= "No taxon chosen";
487 if (element
instanceof Distribution
) {
488 Distribution distribution
= (Distribution
) element
;
490 NamedArea area
= distribution
.getArea();
492 cache
= area
.getLabel();
494 PresenceAbsenceTerm status
= distribution
.getStatus();
496 cache
+= ", no status";
498 cache
+= ", " + status
.getLabel();
502 String result
= cache
== null ?
"" : cache
;
503 if (isNotBlank(mainElementLabel
)){
504 result
= CdmUtils
.concat(" ", result
, "(" + mainElementLabel
+ ")");