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 org
.apache
.log4j
.Logger
;
13 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
14 import eu
.etaxonomy
.cdm
.format
.CdmFormatterBase
;
15 import eu
.etaxonomy
.cdm
.model
.agent
.Person
;
16 import eu
.etaxonomy
.cdm
.model
.agent
.Team
;
17 import eu
.etaxonomy
.cdm
.model
.agent
.TeamOrPersonBase
;
18 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
19 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalSource
;
20 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
21 import eu
.etaxonomy
.cdm
.model
.reference
.INomenclaturalReference
;
22 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
23 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceType
;
24 import eu
.etaxonomy
.cdm
.strategy
.cache
.agent
.TeamDefaultCacheStrategy
;
25 import eu
.etaxonomy
.cdm
.strategy
.cache
.reference
.ReferenceDefaultCacheStrategy
;
26 import eu
.etaxonomy
.cdm
.strategy
.cache
.reference
.TitleWithoutYearAndAuthorHelper
;
32 public class NomenclaturalSourceFormatter
extends CdmFormatterBase
<NomenclaturalSource
>{
34 private static final Logger logger
= Logger
.getLogger(NomenclaturalSourceFormatter
.class);
36 private static final String beforeMicroReference
= ": ";
37 private static final String afterInRefAuthor
= ", ";
39 private static NomenclaturalSourceFormatter instance
;
41 public static final NomenclaturalSourceFormatter
INSTANCE() {
42 if (instance
== null){
43 instance
= new NomenclaturalSourceFormatter();
49 public String
format(NomenclaturalSource source
){
53 Reference reference
= source
.getCitation();
54 String microReference
= source
.getCitationMicroReference();
55 if (reference
== null && isBlank(microReference
)){
58 return format(reference
, microReference
);
62 * Returns a formatted string containing the entire citation used for
63 * nomenclatural purposes based on the {@link Reference reference} supplied - including
64 * (abbreviated) title but not authors - and on the given details.<BR>
67 * the nomenclatural reference
68 * @param microReference the string with the details (generally pages)
69 * corresponding to the nomenclatural reference supplied
70 * as the first argument
71 * @return the formatted string representing the
72 * nomenclatural citation
73 * @see INomenclaturalReference#getNomenclaturalCitation(String)
74 * @see TaxonName#getNomenclaturalReference()
76 public String
format(Reference reference
, String microReference
){
77 if (reference
== null){
78 return CdmUtils
.concat(beforeMicroReference
, "-", microReference
);
81 if (reference
.isProtectedAbbrevTitleCache()){
82 String cache
= reference
.getAbbrevTitleCache();
83 return handleDetailAndYearForProtected(reference
, cache
, microReference
);
86 String result
= getTokenizedNomenclaturalTitel(reference
);
87 //if no data is available and only titleCache is protected take the protected title
88 //this is to avoid empty cache if someone forgets to set also the abbrevTitleCache
89 //we need to think about handling protected not separate for abbrevTitleCache and titleCache
90 if (result
.equals(INomenclaturalReference
.MICRO_REFERENCE_TOKEN
) && reference
.isProtectedTitleCache() ){
91 String cache
= reference
.getTitleCache();
92 return handleDetailAndYearForProtected(reference
, cache
, microReference
);
95 microReference
= Nz(microReference
);
96 if (isNotBlank(microReference
)){
97 microReference
= getBeforeMicroReference() + microReference
;
98 if (microReference
.endsWith(".") && result
.contains(INomenclaturalReference
.MICRO_REFERENCE_TOKEN
+ ".") ){
99 microReference
= microReference
.substring(0, microReference
.length() - 1);
102 result
= replaceMicroRefToken(microReference
, result
);
103 if (result
.startsWith(". ")){ //only year available, remove '. '
104 result
= result
.substring(2);
109 private String
getBeforeMicroReference(){
110 return beforeMicroReference
;
114 * Returns the nomenclatural title with micro reference represented as token
115 * which can later be replaced by the real data.
117 * @see INomenclaturalReference#MICRO_REFERENCE_TOKEN
119 private String
getTokenizedNomenclaturalTitel(Reference ref
) {
120 if (ReferenceDefaultCacheStrategy
.isRealInRef(ref
)){
121 return getTokenizedNomenclaturalTitelInRef(ref
);
123 String result
= getTitleWithoutYearAndAuthor(ref
, true, true);
124 result
+= INomenclaturalReference
.MICRO_REFERENCE_TOKEN
;
125 result
= addYear(result
, ref
, true);
130 private String
replaceMicroRefToken(String microReference
, String string
) {
131 int index
= string
.indexOf(INomenclaturalReference
.MICRO_REFERENCE_TOKEN
);
134 String before
= string
.substring(0, index
);
135 String after
= string
.substring(index
+ INomenclaturalReference
.MICRO_REFERENCE_TOKEN
.length() );
136 String localMicroReference
= microReference
.trim(); //needed ?
137 if (after
.length() > 0){
138 if ( ("".equals(localMicroReference
) && before
.endsWith(after
.substring(0,1)) || localMicroReference
.endsWith(after
.substring(0,1)))){
139 after
= after
.substring(1);
142 String result
= before
+ localMicroReference
+ after
;
149 private String
handleDetailAndYearForProtected(Reference nomenclaturalReference
, String cache
, String microReference
) {
150 String microRef
= isNotBlank(microReference
) ?
getBeforeMicroReference() + microReference
: "";
152 logger
.warn("Cache is null. This should never be the case.");
155 String result
= cache
+ (cache
.contains(microRef
) ?
"" : microRef
);
157 String date
= nomenclaturalReference
.getDatePublishedString();
158 if (isNotBlank(date
) && ! result
.contains(date
)){
159 result
= result
+ ReferenceDefaultCacheStrategy
.beforeYear
+ date
;
164 private String
getTokenizedNomenclaturalTitelInRef(Reference thisRef
) {
165 if (thisRef
== null){
169 Reference inRef
= CdmBase
.deproxy(thisRef
.getInReference(), Reference
.class);
170 if (inRef
!= null && inRef
.getInReference() != null && thisRef
.getType() == ReferenceType
.Section
){
171 //this is a reference of type Section which has a in-in-Ref
172 //TODO maybe we do not need to restrict to type=Section only
173 return this.getTokenizedNomenclaturalTitelInInRef(thisRef
);
177 //use generics's publication date if it exists
178 if (inRef
== null || (thisRef
.hasDatePublished() ) ){
179 result
= inRef
== null ?
"" : getTitleWithoutYearAndAuthorGeneric(inRef
, true);
180 //added //TODO unify with non-inRef references formatting
182 if (isNotBlank(thisRef
.getVolume())){
183 result
= result
+ " " + thisRef
.getVolume();
185 //TODO series / edition
188 result
+= INomenclaturalReference
.MICRO_REFERENCE_TOKEN
;
189 result
= addYear(result
, thisRef
, true);
191 //else use inRefs's publication date
192 result
= inRef
.getNomenclaturalCitation(INomenclaturalReference
.MICRO_REFERENCE_TOKEN
);
194 result
= result
.replace(beforeMicroReference
+ INomenclaturalReference
.MICRO_REFERENCE_TOKEN
, INomenclaturalReference
.MICRO_REFERENCE_TOKEN
);
197 //FIXME: vol. etc., https://dev.e-taxonomy.eu/redmine/issues/2862
199 result
= getInRefAuthorPart(thisRef
.getInReference(), afterInRefAuthor
) + result
;
200 result
= "in " + result
;
206 * For handling in-in-Ref case.
207 * Must only be called if a reference has inRef and inInRef
211 private String
getTokenizedNomenclaturalTitelInInRef(Reference ref
) {
214 Reference inRef
= CdmBase
.deproxy(ref
.getInReference(), Reference
.class);
215 Reference inInRef
= CdmBase
.deproxy(inRef
.getInReference(), Reference
.class);
217 if (! ReferenceDefaultCacheStrategy
.isNomRef(inInRef
.getType())){
218 if (! ReferenceDefaultCacheStrategy
.isNomRef(inRef
.getType())){
219 logger
.warn("Neither inReference nor inInReference is a "
220 + " nomenclatural reference. This is not correct or not handled yet."
221 + " Generic titleWithoutYearAndAuthor used instead");
222 result
= getTitleWithoutYearAndAuthorGeneric(inInRef
, true);
223 //FIXME: vol. etc., https://dev.e-taxonomy.eu/redmine/issues/2862 (comment taken from super.getTokenizedNomenclaturalTitel())
225 result
= getTitleWithoutYearAndAuthor(inRef
, true, true);
228 result
= getTitleWithoutYearAndAuthor(inInRef
, true, true);
230 result
+= INomenclaturalReference
.MICRO_REFERENCE_TOKEN
;
232 Reference dataReference
= (ref
.hasDatePublished() ? ref
: inRef
.hasDatePublished() ? inRef
: inInRef
);
234 result
= addYear(result
, dataReference
, true);
236 result
= getInRefAuthorPart(inInRef
, afterInRefAuthor
) + result
;
237 if (! result
.startsWith("in ")){
238 result
= "in " + result
;
244 * See https://dev.e-taxonomy.eu/redmine/issues/8881
246 private String
getInRefAuthorPart(Reference book
, String seperator
){
251 TeamOrPersonBase
<?
> author
= book
.getAuthorship();
255 }else if(author
.isInstanceOf(Person
.class)){
256 Person person
= CdmBase
.deproxy(author
, Person
.class);
257 result
= getInRefPerson(person
);
259 Team team
= CdmBase
.deproxy(author
, Team
.class);
260 if (team
.isProtectedNomenclaturalTitleCache()){
261 //not yet finally discussed may change in future
262 result
= team
.getNomenclaturalTitle();
263 }else if (team
.isProtectedTitleCache()){
264 //not yet finally discussed may change in future
265 result
= team
.getTitleCache();
266 }else if (team
.getTeamMembers().isEmpty()){
267 //not yet finally discussed may change in future
268 result
= team
.getTitleCache();
270 result
= TeamDefaultCacheStrategy
.INSTANCE_ET_AL_3().getFamilyTitle(team
);
275 if (! result
.trim().equals("")){
276 result
= result
+ seperator
;
281 private String
getInRefPerson(Person person
) {
283 if (isNotBlank(person
.getFamilyName())){
284 result
= person
.getFamilyName();
285 }else if (isNotBlank(person
.getNomenclaturalTitle())){
286 result
= person
.getNomenclaturalTitle(); //TODO discuss if nomTitle is really better here then titleCache
288 result
= person
.getTitleCache(); //maybe remove everything behind a ","
294 * @see ReferenceDefaultCacheStrategy#addYear(String, Reference, boolean)
296 private String
addYear(String yearStr
, Reference ref
, boolean useFullDatePublished
) {
297 return ReferenceDefaultCacheStrategy
.addYear(yearStr
, ref
, useFullDatePublished
);
299 private String
getTitleWithoutYearAndAuthorGeneric(Reference ref
, boolean isAbbrev
){
300 return TitleWithoutYearAndAuthorHelper
.getTitleWithoutYearAndAuthorGeneric(ref
, isAbbrev
);
302 private String
getTitleWithoutYearAndAuthor(Reference ref
, boolean isAbbrev
, boolean isNomRef
){
303 return TitleWithoutYearAndAuthorHelper
.getTitleWithoutYearAndAuthor(ref
, isAbbrev
, isNomRef
);