cleanup
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / format / reference / NomenclaturalSourceFormatter.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.reference;
10
11 import java.io.Serializable;
12
13 import org.apache.logging.log4j.LogManager;
14 import org.apache.logging.log4j.Logger;
15
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;
29
30 /**
31 * @author a.mueller
32 * @since 03.05.2021
33 */
34 public class NomenclaturalSourceFormatter
35 extends CdmFormatterBase<NomenclaturalSource>
36 implements Serializable {
37
38 private static final long serialVersionUID = -6263443499465634548L;
39
40 private static final Logger logger = LogManager.getLogger();
41
42 private static final String EMPTY_TITLE = "-";
43 private static final String beforeMicroReference = ": ";
44 private static final String afterInRefAuthor = ", ";
45
46 private static NomenclaturalSourceFormatter instance;
47
48 public static final NomenclaturalSourceFormatter INSTANCE() {
49 if (instance == null){
50 instance = new NomenclaturalSourceFormatter();
51 }
52 return instance;
53 }
54
55 @Override
56 public String format(NomenclaturalSource source){
57 if (source == null){
58 return null;
59 }
60 Reference reference = source.getCitation();
61 String microReference = source.getCitationMicroReference();
62 if (reference == null && isBlank(microReference)){
63 return null;
64 }
65 return format(reference, microReference);
66 }
67
68 /**
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>
72 *
73 * @param reference
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()
82 */
83 public String format(Reference reference, String microReference){
84
85 if (isNotBlank(microReference)){
86 microReference = microReference.startsWith(":") ? microReference : getBeforeMicroReference() + microReference;
87 }else{
88 microReference = "";
89 }
90
91 if (reference == null){
92 return EMPTY_TITLE + microReference;
93 }
94
95 if (reference.isProtectedAbbrevTitleCache()){
96 String cache = reference.getAbbrevTitleCache();
97 return handleDetailAndYearForProtected(reference, cache, microReference);
98 }
99
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);
107 }
108
109 if (isNotBlank(microReference)){
110 microReference = getBeforeMicroReference() + microReference;
111 if (microReference.endsWith(".")){
112 microReference = microReference.substring(0, microReference.length() - 1);
113 }
114 }
115 if (result.startsWith(". ")){ //only year available, remove '. '
116 result = result.substring(2);
117 }
118 return result;
119 }
120
121 private String getBeforeMicroReference(){
122 return beforeMicroReference;
123 }
124
125 /**
126 * Returns the nomenclatural title with micro reference represented as token
127 * which can later be replaced by the real data.
128 * @param microReference
129 */
130 private String getTitelDetailAndYear(Reference ref, String microReference) {
131 if (ReferenceDefaultCacheStrategy.isRealInRef(ref)){
132 return getTokenizedNomenclaturalTitelInRef(ref, microReference);
133 }else{
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);
137 return result;
138 }
139 }
140
141 private String getDetailOnly(String microReference) {
142 if (isBlank(microReference)){
143 return "";
144 }else{
145 return EMPTY_TITLE + microReference;
146 }
147 }
148
149 private String handleDetailAndYearForProtected(Reference nomenclaturalReference, String cache, String microRef) {
150 if (cache == null){
151 logger.warn("Cache is null. This should never be the case.");
152 cache = "";
153 }
154 String result = cache + (cache.contains(microRef) ? "" : microRef);
155
156 String date = nomenclaturalReference.getDatePublishedString();
157 if (isNotBlank(date) && ! result.contains(date)){
158 result = result + ReferenceDefaultCacheStrategy.beforeYear + date;
159 }
160 return result;
161 }
162
163 private String getTokenizedNomenclaturalTitelInRef(Reference thisRef, String microReference) {
164 if (thisRef == null){
165 return null;
166 }
167
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);
173 }
174
175 String result;
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
180
181 if (isNotBlank(thisRef.getVolume())){
182 result = result + " " + thisRef.getVolume();
183 }
184 //TODO series / edition
185
186 //end added
187 result += microReference;
188 result = addYear(result, thisRef, true);
189 }else{
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);
194 // }
195 }
196 //FIXME: vol. etc., https://dev.e-taxonomy.eu/redmine/issues/2862
197
198 result = getInRefAuthorPart(thisRef.getInReference(), afterInRefAuthor) + result;
199 result = "in " + result;
200 return result;
201 }
202
203
204 /**
205 * For handling in-in-Ref case.
206 * Must only be called if a reference has inRef and inInRef
207 * @param section
208 * @return
209 */
210 private String getTokenizedNomenclaturalTitelInInRef(Reference ref, String microReference) {
211 String result;
212
213 Reference inRef = CdmBase.deproxy(ref.getInReference());
214 Reference inInRef = CdmBase.deproxy(inRef.getInReference());
215
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())
223 }else{
224 result = getTitleWithoutYearAndAuthor(inRef, true, true);
225 }
226 }else{
227 result = getTitleWithoutYearAndAuthor(inInRef, true, true);
228 }
229 result += microReference;
230
231 Reference dataReference = (ref.hasDatePublished() ? ref : inRef.hasDatePublished() ? inRef : inInRef);
232
233 result = addYear(result, dataReference, true);
234
235 result = getInRefAuthorPart(inInRef, afterInRefAuthor) + result;
236 if (! result.startsWith("in ")){
237 result = "in " + result;
238 }
239 return result;
240 }
241
242 /**
243 * See https://dev.e-taxonomy.eu/redmine/issues/8881
244 */
245 private String getInRefAuthorPart(Reference book, String seperator){
246 if (book == null){
247 return "";
248 }
249
250 TeamOrPersonBase<?> author = book.getAuthorship();
251 String result;
252 if (author == null){
253 result = "";
254 }else if(author.isInstanceOf(Person.class)){
255 Person person = CdmBase.deproxy(author, Person.class);
256 result = getInRefPerson(person);
257 }else{
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();
268 }else{
269 result = TeamDefaultCacheStrategy.INSTANCE_ET_AL_3().getFamilyTitle(team);
270 }
271 }
272
273 result = Nz(result);
274 if (! result.trim().equals("")){
275 result = result + seperator;
276 }
277 return result;
278 }
279
280 private String getInRefPerson(Person person) {
281 String result;
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
286 }else{
287 result = person.getTitleCache(); //maybe remove everything behind a ","
288 }
289 return result;
290 }
291
292 /**
293 * @see ReferenceDefaultCacheStrategy#addYear(String, Reference, boolean)
294 */
295 private String addYear(String yearStr, Reference ref, boolean useFullDatePublished) {
296 return ReferenceDefaultCacheStrategy.addYear(yearStr, ref, useFullDatePublished);
297 }
298 private String getTitleWithoutYearAndAuthorGeneric(Reference ref, boolean isAbbrev){
299 return TitleWithoutYearAndAuthorHelper.getTitleWithoutYearAndAuthorGeneric(ref, isAbbrev);
300 }
301 private String getTitleWithoutYearAndAuthor(Reference ref, boolean isAbbrev, boolean isNomRef){
302 return TitleWithoutYearAndAuthorHelper.getTitleWithoutYearAndAuthor(ref, isAbbrev, isNomRef);
303 }
304 }