Use infrageneric epithet in cache strategies
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / strategy / cache / name / NonViralNameDefaultCacheStrategy.java
1 /**
2 * Copyright (C) 2007 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.strategy.cache.name;
10
11 import java.util.ArrayList;
12 import java.util.Iterator;
13 import java.util.List;
14 import java.util.Set;
15 import java.util.UUID;
16
17 import org.apache.commons.lang.StringUtils;
18 import org.apache.log4j.Logger;
19
20 import eu.etaxonomy.cdm.common.CdmUtils;
21 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
22 import eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor;
23 import eu.etaxonomy.cdm.model.agent.Team;
24 import eu.etaxonomy.cdm.model.common.Language;
25 import eu.etaxonomy.cdm.model.common.Representation;
26 import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
27 import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
28 import eu.etaxonomy.cdm.model.name.NonViralName;
29 import eu.etaxonomy.cdm.model.name.Rank;
30 import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
31 import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
32
33
34 /**
35 * This class is a default implementation for the INonViralNameCacheStrategy<T extends NonViralName> interface.
36 * The method actually implements a cache strategy for botanical names so no method has to be overwritten by
37 * a subclass for botanic names.
38 * Where differing from this Default BotanicNameCacheStrategy other subclasses should overwrite the existing methods
39 * e.g. a CacheStrategy for zoological names should overwrite getAuthorAndExAuthor
40 * @author a.mueller
41 */
42 /**
43 * @author AM
44 *
45 * @param <T>
46 */
47 public class NonViralNameDefaultCacheStrategy<T extends NonViralName> extends NameCacheStrategyBase<T> implements INonViralNameCacheStrategy<T> {
48 private static final Logger logger = Logger.getLogger(NonViralNameDefaultCacheStrategy.class);
49
50 final static UUID uuid = UUID.fromString("1cdda0d1-d5bc-480f-bf08-40a510a2f223");
51
52 protected String NameAuthorSeperator = " ";
53 protected String BasionymStart = "(";
54 protected String BasionymEnd = ")";
55 protected String ExAuthorSeperator = " ex ";
56 protected CharSequence BasionymAuthorCombinationAuthorSeperator = " ";
57
58 @Override
59 public UUID getUuid(){
60 return uuid;
61 }
62
63
64 /**
65 * Factory method
66 * @return NonViralNameDefaultCacheStrategy A new instance of NonViralNameDefaultCacheStrategy
67 */
68 public static NonViralNameDefaultCacheStrategy NewInstance(){
69 return new NonViralNameDefaultCacheStrategy();
70 }
71
72 /**
73 * Constructor
74 */
75 protected NonViralNameDefaultCacheStrategy(){
76 super();
77 }
78
79 /* **************** GETTER / SETTER **************************************/
80
81 /**
82 * String that separates the NameCache part from the AuthorCache part
83 * @return
84 */
85 public String getNameAuthorSeperator() {
86 return NameAuthorSeperator;
87 }
88
89
90 public void setNameAuthorSeperator(String nameAuthorSeperator) {
91 NameAuthorSeperator = nameAuthorSeperator;
92 }
93
94
95 /**
96 * String the basionym author part starts with e.g. '('.
97 * This should correspond with the {@link NonViralNameDefaultCacheStrategy#getBasionymEnd() basionymEnd} attribute
98 * @return
99 */
100 public String getBasionymStart() {
101 return BasionymStart;
102 }
103
104
105 public void setBasionymStart(String basionymStart) {
106 BasionymStart = basionymStart;
107 }
108
109
110 /**
111 * String the basionym author part ends with e.g. ')'.
112 * This should correspond with the {@link NonViralNameDefaultCacheStrategy#getBasionymStart() basionymStart} attribute
113 * @return
114 */
115 public String getBasionymEnd() {
116 return BasionymEnd;
117 }
118
119
120 public void setBasionymEnd(String basionymEnd) {
121 BasionymEnd = basionymEnd;
122 }
123
124
125 /**
126 * String to seperate ex author from author.
127 * @return
128 */
129 public String getExAuthorSeperator() {
130 return ExAuthorSeperator;
131 }
132
133
134 public void setExAuthorSeperator(String exAuthorSeperator) {
135 ExAuthorSeperator = exAuthorSeperator;
136 }
137
138
139 /**
140 * String that seperates the basionym/original_combination author part from the combination author part
141 * @return
142 */
143 public CharSequence getBasionymAuthorCombinationAuthorSeperator() {
144 return BasionymAuthorCombinationAuthorSeperator;
145 }
146
147
148 public void setBasionymAuthorCombinationAuthorSeperator(
149 CharSequence basionymAuthorCombinationAuthorSeperator) {
150 BasionymAuthorCombinationAuthorSeperator = basionymAuthorCombinationAuthorSeperator;
151 }
152
153
154 //** *****************************************************************************************/
155
156
157 /* (non-Javadoc)
158 * @see eu.etaxonomy.cdm.strategy.INameCacheStrategy#getNameCache()
159 */
160 @Override
161 public String getTitleCache(T nonViralName) {
162 if (nonViralName == null){
163 return null;
164 }
165
166 if (nonViralName.isProtectedTitleCache()){
167 return nonViralName.getTitleCache();
168 }
169 String result = "";
170 //Autonym
171 if (isAutonym(nonViralName)){
172 result = handleAutonym(nonViralName);
173 }else{ //not Autonym
174 String nameCache = nonViralName.getNameCache(); //OLD: CdmUtils.Nz(getNameCache(nonViralName));
175 if (nameIncludesAuthorship(nonViralName)){
176 String authorCache = CdmUtils.Nz(getAuthorshipCache(nonViralName));
177 result = CdmUtils.concat(NameAuthorSeperator, nameCache, authorCache);
178 }else{
179 result = nameCache;
180 }
181 }
182 return result;
183 }
184
185
186 /**
187 * @param nonViralName
188 * @param speciesPart
189 * @return
190 */
191 private String handleAutonym(T nonViralName) {
192 String result;
193 String speciesPart = getSpeciesNameCache(nonViralName);
194 //TODO should this include basionym authors and ex authors
195 INomenclaturalAuthor author = nonViralName.getCombinationAuthorTeam();
196 String authorPart = "";
197 if (author != null){
198 authorPart = CdmUtils.Nz(author.getNomenclaturalTitle());
199 }
200 INomenclaturalAuthor basAuthor = nonViralName.getBasionymAuthorTeam();
201 String basAuthorPart = "";
202 if (basAuthor != null){
203 basAuthorPart = CdmUtils.Nz(basAuthor.getNomenclaturalTitle());
204 }
205 if (! "".equals(basAuthorPart)){
206 authorPart = "("+ basAuthorPart +")" + authorPart;
207 }
208 String infraSpeciesPart = (CdmUtils.Nz(nonViralName.getInfraSpecificEpithet()));
209
210 String infraSpeciesSeparator = "";
211 if (nonViralName.getRank() == null || !nonViralName.getRank().isInfraSpecific()){
212 //TODO handle exception
213 logger.warn("Rank for autonym does not exist or is not lower than species !!");
214 }else{
215 infraSpeciesSeparator = nonViralName.getRank().getAbbreviation();
216 }
217
218 result = CdmUtils.concat(" ", new String[]{speciesPart, authorPart, infraSpeciesSeparator, infraSpeciesPart});
219 result = result.trim().replace("null", "");
220 return result;
221 }
222
223 protected boolean nameIncludesAuthorship(NonViralName nonViralName){
224 Rank rank = nonViralName.getRank();
225 if (rank != null && rank.isSpeciesAggregate()){
226 return false;
227 }else{
228 return true;
229 }
230 }
231
232
233
234
235
236 @Override
237 public String getFullTitleCache(T nonViralName) {
238 //null
239 if (nonViralName == null){
240 return null;
241 }
242 //full title cache
243 if (nonViralName.isProtectedFullTitleCache() == true) {
244 return nonViralName.getFullTitleCache();
245 }
246
247 String result = "";
248 //title cache
249 String titleCache = nonViralName.getTitleCache(); // OLD: getTitleCache(nonViralName);
250
251 String microReference = nonViralName.getNomenclaturalMicroReference();
252 INomenclaturalReference ref = nonViralName.getNomenclaturalReference();
253 String referenceBaseCache = null;
254 if (ref != null){
255 INomenclaturalReference nomenclaturalReference = HibernateProxyHelper.deproxy(ref, INomenclaturalReference.class);
256 nomenclaturalReference.setCacheStrategy(nomenclaturalReference.getType().getCacheStrategy());
257 referenceBaseCache = nomenclaturalReference.getNomenclaturalCitation(microReference);
258 }
259
260 //make nomenclatural status
261 String ncStatusCache = "";
262 Set<NomenclaturalStatus> ncStati = nonViralName.getStatus();
263 Iterator<NomenclaturalStatus> iterator = ncStati.iterator();
264 while (iterator.hasNext()) {
265 NomenclaturalStatus ncStatus = (NomenclaturalStatus)iterator.next();
266 // since the NewInstance method of nomencatural status allows null as parameter
267 // we have to check for null values here
268 String suffix = "not defined";
269 if(ncStatus.getType() != null){
270 NomenclaturalStatusType statusType = ncStatus.getType();
271 Language lang = Language.LATIN();
272 Representation repr = statusType.getRepresentation(lang);
273 if (repr != null){
274 suffix = repr.getAbbreviatedLabel();
275 }else{
276 String message = "No latin representation available for nom. status. " + statusType.getTitleCache();
277 logger.warn(message);
278 throw new IllegalStateException(message);
279 }
280 }else if(ncStatus.getRuleConsidered() != null && ! ncStatus.getRuleConsidered().equals("")){
281 suffix = ncStatus.getRuleConsidered();
282 }
283 ncStatusCache = ", " + suffix;
284 }
285 String refConcat = " ";
286 if (referenceBaseCache != null && ! referenceBaseCache.trim().startsWith("in ")){
287 refConcat = ", ";
288 }
289 result = CdmUtils.concat(refConcat, titleCache, referenceBaseCache);
290 result = CdmUtils.concat("", result, ncStatusCache);
291 return result;
292 }
293
294
295 /**
296 * Generates and returns the "name cache" (only scientific name without author teams and year).
297 * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy#getNameCache(eu.etaxonomy.cdm.model.name.TaxonNameBase)
298 */
299 public String getNameCache(T nonViralName) {
300 if (nonViralName == null){
301 return null;
302 }
303 String result;
304 Rank rank = nonViralName.getRank();
305
306 if (nonViralName.isProtectedNameCache()){
307 result = nonViralName.getNameCache();
308 }else if (rank == null){
309 result = getRanklessNameCache(nonViralName);
310 }else if (rank.isInfraSpecific()){
311 result = getInfraSpeciesNameCache(nonViralName);
312 }else if (rank.isSpecies()){
313 result = getSpeciesNameCache(nonViralName);
314 }else if (rank.isInfraGeneric()){
315 result = getInfraGenusNameCache(nonViralName);
316 }else if (rank.isGenus()){
317 result = getGenusOrUninomialNameCache(nonViralName);
318 }else if (rank.isSupraGeneric()){
319 result = getGenusOrUninomialNameCache(nonViralName);
320 }else{
321 logger.warn("Name Strategy for Name (UUID: " + nonViralName.getUuid() + ") not yet implemented");
322 result = "";
323 }
324 return result;
325 }
326
327
328 /* (non-Javadoc)
329 * @see eu.etaxonomy.cdm.strategy.cache.INonViralNameCacheStrategy#getAuthorCache(eu.etaxonomy.cdm.model.name.NonViralName)
330 */
331 public String getAuthorshipCache(T nonViralName) {
332 if (nonViralName == null){
333 return null;
334 }
335 //cache protected
336 if (nonViralName.isProtectedAuthorshipCache() == true) {
337 return nonViralName.getAuthorshipCache();
338 }
339 return getNonCacheAuthorshipCache(nonViralName);
340
341 }
342
343 /**
344 * Returns the authorshipcache string for the atomized authorship fields. Does not use the authorshipfield.
345 * @throws NullPointerException if nonViralName is null.
346 * @param nonViralName
347 * @return
348 */
349 protected String getNonCacheAuthorshipCache(T nonViralName){
350 String result = "";
351 INomenclaturalAuthor combinationAuthor = nonViralName.getCombinationAuthorTeam();
352 INomenclaturalAuthor exCombinationAuthor = nonViralName.getExCombinationAuthorTeam();
353 INomenclaturalAuthor basionymAuthor = nonViralName.getBasionymAuthorTeam();
354 INomenclaturalAuthor exBasionymAuthor = nonViralName.getExBasionymAuthorTeam();
355 String basionymPart = "";
356 String authorPart = "";
357 //basionym
358 if (basionymAuthor != null || exBasionymAuthor != null){
359 basionymPart = BasionymStart + getAuthorAndExAuthor(basionymAuthor, exBasionymAuthor) + BasionymEnd;
360 }
361 if (combinationAuthor != null || exCombinationAuthor != null){
362 authorPart = getAuthorAndExAuthor(combinationAuthor, exCombinationAuthor);
363 }
364 result = CdmUtils.concat(BasionymAuthorCombinationAuthorSeperator, basionymPart, authorPart);
365 return result;
366 }
367
368 /**
369 * Returns the AuthorCache part for a combination of an author and an ex author. This applies on combination authors
370 * as well as on basionym/orginal combination authors.
371 * @param author the author
372 * @param exAuthor the ex-author
373 * @return
374 */
375 protected String getAuthorAndExAuthor(INomenclaturalAuthor author, INomenclaturalAuthor exAuthor){
376 String result = "";
377 String authorString = "";
378 String exAuthorString = "";
379 if (author != null){
380 authorString = CdmUtils.Nz(author.getNomenclaturalTitle());
381 }
382 if (exAuthor != null){
383 exAuthorString = CdmUtils.Nz(exAuthor.getNomenclaturalTitle());
384 }
385 if (exAuthorString.length() > 0 ){
386 exAuthorString = exAuthorString + ExAuthorSeperator;
387 }
388 result = exAuthorString + authorString;
389 return result;
390
391 }
392
393
394 /* (non-Javadoc)
395 * @see eu.etaxonomy.cdm.strategy.INameCacheStrategy#getTaggedName(eu.etaxonomy.cdm.model.common.CdmBase)
396 */
397 @Override
398 public List<Object> getTaggedName(T nonViralName) {
399 List<Object> tags = new ArrayList<Object>();
400
401 // Why does it make sense to add the nameCache in case of non existing genusOrUninomial?
402 // if (nonViralName.getGenusOrUninomial() == null){
403 // tags.add(nonViralName.getNameCache());
404 // }else{
405
406 if (nonViralName.getGenusOrUninomial() != null) {
407 tags.add(nonViralName.getGenusOrUninomial());
408 }
409 if (nonViralName.isSpecies() || nonViralName.isInfraSpecific()){
410 tags.add(nonViralName.getSpecificEpithet());
411 }
412
413 // No autonym
414 if (nonViralName.isInfraSpecific() && ! nonViralName.getSpecificEpithet().equals(nonViralName.getInfraSpecificEpithet())){
415 tags.add(nonViralName.getRank());
416 tags.add(nonViralName.getInfraSpecificEpithet());
417 }
418
419 if (nonViralName.isInfraGeneric()){
420 //TODO choose right strategy or generic approach?
421 // --- strategy 1 ---
422
423 if (nonViralName.getRank().isSpeciesAggregate()){
424 tags.add(getSpeciesAggregateEpithet(nonViralName));
425 }else{
426 tags.add(nonViralName.getRank());
427 tags.add(nonViralName.getInfraGenericEpithet());
428 }
429 // --- strategy 2 ---
430 // tags.add('('+nvn.getInfraGenericEpithet()+')');
431 }
432 Team authorTeam = Team.NewInstance();
433 authorTeam.setProtectedTitleCache(true);
434 authorTeam.setTitleCache(nonViralName.getAuthorshipCache(), true);
435 tags.add(authorTeam);
436
437 // Name is an autonym. Rank and infraspecific eitheton follow the author
438 if (nonViralName.isInfraSpecific() && nonViralName.getSpecificEpithet().equals(nonViralName.getInfraSpecificEpithet())){
439 tags.add(nonViralName.getRank());
440 tags.add(nonViralName.getInfraSpecificEpithet());
441 }
442
443 if(! "".equals(nonViralName.getAppendedPhrase())&& (nonViralName.getAppendedPhrase() != null)){
444 tags.add(nonViralName.getAppendedPhrase());
445 }
446
447 return tags;
448 }
449
450
451 //***************************** PRIVATES ***************************************/
452
453 protected String getRanklessNameCache(NonViralName nonViralName){
454 String result = "";
455 result = (result + (CdmUtils.Nz(nonViralName.getGenusOrUninomial()))).trim().replace("null", "");
456 result += " " + (CdmUtils.Nz(nonViralName.getSpecificEpithet())).trim();
457 result += " " + (CdmUtils.Nz(nonViralName.getInfraSpecificEpithet())).trim();
458 result = result.trim().replace("null", "");
459 //result += " (rankless)";
460 result = addAppendedPhrase(result, nonViralName);
461 return result;
462 }
463
464
465 protected String getGenusOrUninomialNameCache(NonViralName nonViralName){
466 String result;
467 result = CdmUtils.Nz(nonViralName.getGenusOrUninomial()).trim();
468 result = addAppendedPhrase(result, nonViralName).trim();
469 return result;
470 }
471
472 protected String getInfraGenusNameCache(NonViralName nonViralName){
473 String result;
474 Rank rank = nonViralName.getRank();
475 if (rank.isSpeciesAggregate()){
476 return getSpeciesAggregateCache(nonViralName);
477 }
478 String infraGenericMarker = "'unhandled infrageneric rank'";
479 if (rank != null){
480 try {
481 infraGenericMarker = rank.getInfraGenericMarker();
482 } catch (UnknownCdmTypeException e) {
483 infraGenericMarker = "'unhandled infrageneric rank'";
484 }
485 }
486 result = CdmUtils.Nz(nonViralName.getGenusOrUninomial()).trim();
487 result += " " + infraGenericMarker + " " + (CdmUtils.Nz(nonViralName.getInfraGenericEpithet())).trim().replace("null", "");
488 result = addAppendedPhrase(result, nonViralName).trim();
489 return result;
490 }
491
492 // aggr.|agg.|group
493 protected String getSpeciesAggregateCache(NonViralName nonViralName){
494 String result = getGenusAndSpeciesPart(nonViralName);
495
496 result += " " + getSpeciesAggregateEpithet(nonViralName);
497 result = addAppendedPhrase(result, nonViralName).trim();
498 return result;
499 }
500
501 private String getSpeciesAggregateEpithet(NonViralName nonViralName) {
502 String marker;
503 try {
504 marker = nonViralName.getRank().getInfraGenericMarker();
505 } catch (UnknownCdmTypeException e) {
506 marker = "'unknown aggregat type'";
507 }
508 return marker;
509 }
510
511 protected String getSpeciesNameCache(NonViralName nonViralName){
512 String result = getGenusAndSpeciesPart(nonViralName);
513 result = addAppendedPhrase(result, nonViralName).trim();
514 result = result.replace("\\s\\", " ");
515 return result;
516 }
517
518
519 protected String getInfraSpeciesNameCache(NonViralName nonViralName){
520 return getInfraSpeciesNameCache(nonViralName, true);
521 }
522
523 protected String getInfraSpeciesNameCache(NonViralName nonViralName, boolean includeMarker){
524 String result = getGenusAndSpeciesPart(nonViralName);
525 if (includeMarker){
526 result += " " + (nonViralName.getRank().getAbbreviation()).trim().replace("null", "");
527 }
528 result += " " + (CdmUtils.Nz(nonViralName.getInfraSpecificEpithet())).trim().replace("null", "");
529 result = addAppendedPhrase(result, nonViralName).trim();
530 return result;
531 }
532
533
534 private String getGenusAndSpeciesPart(NonViralName nonViralName) {
535 String result;
536 result = CdmUtils.Nz(nonViralName.getGenusOrUninomial()).trim();
537 if (StringUtils.isNotBlank(nonViralName.getInfraGenericEpithet()) ){
538 result += " (" + nonViralName.getInfraGenericEpithet().trim() + ")";
539 }
540 result += " " + (CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim()).replace("null", "");
541 return result;
542 }
543
544
545
546 /**
547 * @param name
548 * @return true, if name has Rank, Rank is below species and species epithet equals infraSpeciesEpithtet, else false
549 */
550 protected boolean isAutonym(NonViralName nonViralName){
551 if (nonViralName != null && nonViralName.getRank() != null && nonViralName.getSpecificEpithet() != null && nonViralName.getInfraSpecificEpithet() != null &&
552 nonViralName.getRank().isInfraSpecific() && nonViralName.getSpecificEpithet().trim().equals(nonViralName.getInfraSpecificEpithet().trim())){
553 return true;
554 }else{
555 return false;
556 }
557 }
558
559 protected String addAppendedPhrase(String resultString, NonViralName nonViralName){
560 String appendedPhrase = nonViralName ==null ? null : nonViralName.getAppendedPhrase();
561 if (resultString == null){
562 return appendedPhrase;
563 }else if(appendedPhrase == null || "".equals(appendedPhrase.trim())) {
564 return resultString;
565 }else if ("".equals(resultString)){
566 return resultString + appendedPhrase;
567 }else {
568 return resultString + " " + appendedPhrase;
569 }
570 }
571
572
573 public String getLastEpithet(T taxonNameBase) {
574 Rank rank = taxonNameBase.getRank();
575 if(rank.isGenus() || rank.isSupraGeneric()) {
576 return taxonNameBase.getGenusOrUninomial();
577 } else if(rank.isInfraGeneric()) {
578 return taxonNameBase.getInfraGenericEpithet();
579 } else if(rank.isSpecies()) {
580 return taxonNameBase.getSpecificEpithet();
581 } else {
582 return taxonNameBase.getInfraSpecificEpithet();
583 }
584 }
585 }