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
.reference
;
11 import java
.io
.Serializable
;
13 import org
.apache
.logging
.log4j
.LogManager
;
14 import org
.apache
.logging
.log4j
.Logger
;
16 import eu
.etaxonomy
.cdm
.format
.CdmFormatterBase
;
17 import eu
.etaxonomy
.cdm
.model
.agent
.Person
;
18 import eu
.etaxonomy
.cdm
.model
.agent
.Team
;
19 import eu
.etaxonomy
.cdm
.model
.agent
.TeamOrPersonBase
;
20 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
21 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalSource
;
22 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
23 import eu
.etaxonomy
.cdm
.model
.reference
.INomenclaturalReference
;
24 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
25 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceType
;
26 import eu
.etaxonomy
.cdm
.strategy
.cache
.agent
.TeamDefaultCacheStrategy
;
27 import eu
.etaxonomy
.cdm
.strategy
.cache
.reference
.ReferenceDefaultCacheStrategy
;
28 import eu
.etaxonomy
.cdm
.strategy
.cache
.reference
.TitleWithoutYearAndAuthorHelper
;
34 public class NomenclaturalSourceFormatter
35 extends CdmFormatterBase
<NomenclaturalSource
>
36 implements Serializable
{
38 private static final long serialVersionUID
= -6263443499465634548L;
40 private static final Logger logger
= LogManager
.getLogger();
42 private static final String EMPTY_TITLE
= "-";
43 private static final String beforeMicroReference
= ": ";
44 private static final String afterInRefAuthor
= ", ";
46 private static NomenclaturalSourceFormatter instance
;
48 public static final NomenclaturalSourceFormatter
INSTANCE() {
49 if (instance
== null){
50 instance
= new NomenclaturalSourceFormatter();
56 public String
format(NomenclaturalSource source
){
60 Reference reference
= source
.getCitation();
61 String microReference
= source
.getCitationMicroReference();
62 if (reference
== null && isBlank(microReference
)){
65 return format(reference
, microReference
);
69 * Returns a formatted string containing the entire citation used for
70 * nomenclatural purposes based on the {@link Reference reference} supplied - including
71 * (abbreviated) title but not authors - and on the given details.<BR>
74 * the nomenclatural reference
75 * @param microReference the string with the details (generally pages)
76 * corresponding to the nomenclatural reference supplied
77 * as the first argument
78 * @return the formatted string representing the
79 * nomenclatural citation
80 * @see INomenclaturalReference#getNomenclaturalCitation(String)
81 * @see TaxonName#getNomenclaturalReference()
83 public String
format(Reference reference
, String microReference
){
85 if (isNotBlank(microReference
)){
86 microReference
= microReference
.startsWith(":") ? microReference
: getBeforeMicroReference() + microReference
;
91 if (reference
== null){
92 return EMPTY_TITLE
+ microReference
;
95 if (reference
.isProtectedAbbrevTitleCache()){
96 String cache
= reference
.getAbbrevTitleCache();
97 return handleDetailAndYearForProtected(reference
, cache
, microReference
);
100 String result
= getTitelDetailAndYear(reference
, microReference
);
101 //if no data is available and only titleCache is protected take the protected title
102 //this is to avoid empty cache if someone forgets to set also the abbrevTitleCache
103 //we need to think about handling protected not separate for abbrevTitleCache and titleCache
104 if (result
.equals(getDetailOnly(microReference
)) && reference
.isProtectedTitleCache() ){
105 String cache
= reference
.getTitleCache();
106 return handleDetailAndYearForProtected(reference
, cache
, microReference
);
109 if (isNotBlank(microReference
)){
110 microReference
= getBeforeMicroReference() + microReference
;
111 if (microReference
.endsWith(".")){
112 microReference
= microReference
.substring(0, microReference
.length() - 1);
115 if (result
.startsWith(". ")){ //only year available, remove '. '
116 result
= result
.substring(2);
121 private String
getBeforeMicroReference(){
122 return beforeMicroReference
;
126 * Returns the nomenclatural title with micro reference represented as token
127 * which can later be replaced by the real data.
128 * @param microReference
130 private String
getTitelDetailAndYear(Reference ref
, String microReference
) {
131 if (ReferenceDefaultCacheStrategy
.isRealInRef(ref
)){
132 return getTokenizedNomenclaturalTitelInRef(ref
, microReference
);
134 String result
= getTitleWithoutYearAndAuthor(ref
, true, true);
135 result
= isBlank(result
) ?
getDetailOnly(microReference
): isBlank(microReference
)? result
: isBlank(microReference
)? result
: result
+ microReference
;
136 result
= addYear(result
, ref
, true);
141 private String
getDetailOnly(String microReference
) {
142 if (isBlank(microReference
)){
145 return EMPTY_TITLE
+ microReference
;
149 private String
handleDetailAndYearForProtected(Reference nomenclaturalReference
, String cache
, String microRef
) {
151 logger
.warn("Cache is null. This should never be the case.");
154 String result
= cache
+ (cache
.contains(microRef
) ?
"" : microRef
);
156 String date
= nomenclaturalReference
.getDatePublishedString();
157 if (isNotBlank(date
) && ! result
.contains(date
)){
158 result
= result
+ ReferenceDefaultCacheStrategy
.beforeYear
+ date
;
163 private String
getTokenizedNomenclaturalTitelInRef(Reference thisRef
, String microReference
) {
164 if (thisRef
== null){
168 Reference inRef
= CdmBase
.deproxy(thisRef
.getInReference());
169 if (inRef
!= null && inRef
.getInReference() != null && thisRef
.getType() == ReferenceType
.Section
){
170 //this is a reference of type Section which has an in-in-Ref
171 //TODO maybe we do not need to restrict to type=Section only
172 return this.getTokenizedNomenclaturalTitelInInRef(thisRef
, microReference
);
176 //use generics's publication date if it exists
177 if (inRef
== null || (thisRef
.hasDatePublished() ) ){
178 result
= inRef
== null ?
"" : getTitleWithoutYearAndAuthorGeneric(inRef
, true);
179 //added //TODO unify with non-inRef references formatting
181 if (isNotBlank(thisRef
.getVolume())){
182 result
= result
+ " " + thisRef
.getVolume();
184 //TODO series / edition
187 result
+= microReference
;
188 result
= addYear(result
, thisRef
, true);
190 //else use inRefs's publication date
191 result
= format(inRef
, microReference
); // inRef.getNomenclaturalCitation(INomenclaturalReference.MICRO_REFERENCE_TOKEN);
192 // if (result != null){
193 // result = result.replace(beforeMicroReference + INomenclaturalReference.MICRO_REFERENCE_TOKEN, INomenclaturalReference.MICRO_REFERENCE_TOKEN);
196 //FIXME: vol. etc., https://dev.e-taxonomy.eu/redmine/issues/2862
198 result
= getInRefAuthorPart(thisRef
.getInReference(), afterInRefAuthor
) + result
;
199 result
= "in " + result
;
205 * For handling in-in-Ref case.
206 * Must only be called if a reference has inRef and inInRef
210 private String
getTokenizedNomenclaturalTitelInInRef(Reference ref
, String microReference
) {
213 Reference inRef
= CdmBase
.deproxy(ref
.getInReference());
214 Reference inInRef
= CdmBase
.deproxy(inRef
.getInReference());
216 if (! ReferenceDefaultCacheStrategy
.isNomRef(inInRef
.getType())){
217 if (! ReferenceDefaultCacheStrategy
.isNomRef(inRef
.getType())){
218 logger
.warn("Neither inReference nor inInReference is a "
219 + " nomenclatural reference. This is not correct or not handled yet."
220 + " Generic titleWithoutYearAndAuthor used instead");
221 result
= getTitleWithoutYearAndAuthorGeneric(inInRef
, true);
222 //FIXME: vol. etc., https://dev.e-taxonomy.eu/redmine/issues/2862 (comment taken from super.getTokenizedNomenclaturalTitel())
224 result
= getTitleWithoutYearAndAuthor(inRef
, true, true);
227 result
= getTitleWithoutYearAndAuthor(inInRef
, true, true);
229 result
+= microReference
;
231 Reference dataReference
= (ref
.hasDatePublished() ? ref
: inRef
.hasDatePublished() ? inRef
: inInRef
);
233 result
= addYear(result
, dataReference
, true);
235 result
= getInRefAuthorPart(inInRef
, afterInRefAuthor
) + result
;
236 if (! result
.startsWith("in ")){
237 result
= "in " + result
;
243 * See https://dev.e-taxonomy.eu/redmine/issues/8881
245 private String
getInRefAuthorPart(Reference book
, String seperator
){
250 TeamOrPersonBase
<?
> author
= book
.getAuthorship();
254 }else if(author
.isInstanceOf(Person
.class)){
255 Person person
= CdmBase
.deproxy(author
, Person
.class);
256 result
= getInRefPerson(person
);
258 Team team
= CdmBase
.deproxy(author
, Team
.class);
259 if (team
.isProtectedNomenclaturalTitleCache()){
260 //not yet finally discussed may change in future
261 result
= team
.getNomenclaturalTitleCache();
262 }else if (team
.isProtectedTitleCache()){
263 //not yet finally discussed may change in future
264 result
= team
.getTitleCache();
265 }else if (team
.getTeamMembers().isEmpty()){
266 //not yet finally discussed may change in future
267 result
= team
.getTitleCache();
269 result
= TeamDefaultCacheStrategy
.INSTANCE_ET_AL_3().getFamilyTitle(team
);
274 if (! result
.trim().equals("")){
275 result
= result
+ seperator
;
280 private String
getInRefPerson(Person person
) {
282 if (isNotBlank(person
.getFamilyName())){
283 result
= person
.getFamilyName();
284 }else if (isNotBlank(person
.getNomenclaturalTitleCache())){
285 result
= person
.getNomenclaturalTitleCache(); //TODO discuss if nomTitle is really better here then titleCache
287 result
= person
.getTitleCache(); //maybe remove everything behind a ","
293 * @see ReferenceDefaultCacheStrategy#addYear(String, Reference, boolean)
295 private String
addYear(String yearStr
, Reference ref
, boolean useFullDatePublished
) {
296 return ReferenceDefaultCacheStrategy
.addYear(yearStr
, ref
, useFullDatePublished
);
298 private String
getTitleWithoutYearAndAuthorGeneric(Reference ref
, boolean isAbbrev
){
299 return TitleWithoutYearAndAuthorHelper
.getTitleWithoutYearAndAuthorGeneric(ref
, isAbbrev
);
301 private String
getTitleWithoutYearAndAuthor(Reference ref
, boolean isAbbrev
, boolean isNomRef
){
302 return TitleWithoutYearAndAuthorHelper
.getTitleWithoutYearAndAuthor(ref
, isAbbrev
, isNomRef
);