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