genusOrUninomial == NULL does not add the nameCache as part of the returned list...
[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
400 // Why does it make sense to add the nameCache in case of non existing genusOrUninomial?
401 // if (nonViralName.getGenusOrUninomial() == null){
402 // tags.add(nonViralName.getNameCache());
403 // }else{
404
405 if (nonViralName.getGenusOrUninomial() != null) {
406 tags.add(nonViralName.getGenusOrUninomial());
407 }
408 if (nonViralName.isSpecies() || nonViralName.isInfraSpecific()){
409 tags.add(nonViralName.getSpecificEpithet());
410 }
411
412 // No autonym
413 if (nonViralName.isInfraSpecific() && ! nonViralName.getSpecificEpithet().equals(nonViralName.getInfraSpecificEpithet())){
414 tags.add(nonViralName.getRank());
415 tags.add(nonViralName.getInfraSpecificEpithet());
416 }
417
418 if (nonViralName.isInfraGeneric()){
419 //TODO choose right strategy or generic approach?
420 // --- strategy 1 ---
421
422 if (nonViralName.getRank().isSpeciesAggregate()){
423 tags.add(getSpeciesAggregateEpithet(nonViralName));
424 }else{
425 tags.add(nonViralName.getRank());
426 tags.add(nonViralName.getInfraGenericEpithet());
427 }
428 // --- strategy 2 ---
429 // tags.add('('+nvn.getInfraGenericEpithet()+')');
430 }
431 Team authorTeam = Team.NewInstance();
432 authorTeam.setProtectedTitleCache(true);
433 authorTeam.setTitleCache(nonViralName.getAuthorshipCache(), true);
434 tags.add(authorTeam);
435
436 // Name is an autonym. Rank and infraspecific eitheton follow the author
437 if (nonViralName.isInfraSpecific() && nonViralName.getSpecificEpithet().equals(nonViralName.getInfraSpecificEpithet())){
438 tags.add(nonViralName.getRank());
439 tags.add(nonViralName.getInfraSpecificEpithet());
440 }
441
442 if(! "".equals(nonViralName.getAppendedPhrase())&& (nonViralName.getAppendedPhrase() != null)){
443 tags.add(nonViralName.getAppendedPhrase());
444 }
445
446 return tags;
447 }
448
449
450 //***************************** PRIVATES ***************************************/
451
452 protected String getRanklessNameCache(NonViralName nonViralName){
453 String result = "";
454 result = (result + (CdmUtils.Nz(nonViralName.getGenusOrUninomial()))).trim().replace("null", "");
455 result += " " + (CdmUtils.Nz(nonViralName.getSpecificEpithet())).trim();
456 result += " " + (CdmUtils.Nz(nonViralName.getInfraSpecificEpithet())).trim();
457 result = result.trim().replace("null", "");
458 //result += " (rankless)";
459 result = addAppendedPhrase(result, nonViralName);
460 return result;
461 }
462
463
464 protected String getGenusOrUninomialNameCache(NonViralName nonViralName){
465 String result;
466 result = CdmUtils.Nz(nonViralName.getGenusOrUninomial()).trim();
467 result = addAppendedPhrase(result, nonViralName).trim();
468 return result;
469 }
470
471 protected String getInfraGenusNameCache(NonViralName nonViralName){
472 String result;
473 Rank rank = nonViralName.getRank();
474 if (rank.isSpeciesAggregate()){
475 return getSpeciesAggregateCache(nonViralName);
476 }
477 String infraGenericMarker = "'unhandled infrageneric rank'";
478 if (rank != null){
479 try {
480 infraGenericMarker = rank.getInfraGenericMarker();
481 } catch (UnknownCdmTypeException e) {
482 infraGenericMarker = "'unhandled infrageneric rank'";
483 }
484 }
485 result = CdmUtils.Nz(nonViralName.getGenusOrUninomial()).trim();
486 result += " " + infraGenericMarker + " " + (CdmUtils.Nz(nonViralName.getInfraGenericEpithet())).trim().replace("null", "");
487 result = addAppendedPhrase(result, nonViralName).trim();
488 return result;
489 }
490
491 // aggr.|agg.|group
492 protected String getSpeciesAggregateCache(NonViralName nonViralName){
493 String result;
494 result = CdmUtils.Nz(nonViralName.getGenusOrUninomial()).trim();
495
496 result += " " + getSpeciesAggregateEpithet(nonViralName);
497 /*result += " " + CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim().replace("null", "");
498 String marker;
499 try {
500 marker = nonViralName.getRank().getInfraGenericMarker();
501 } catch (UnknownCdmTypeException e) {
502 marker = "'unknown aggregat type'";
503 }
504 result += " " + marker;*/
505 result = addAppendedPhrase(result, nonViralName).trim();
506 return result;
507 }
508
509 private String getSpeciesAggregateEpithet(NonViralName nonViralName) {
510 String result;
511
512 result = CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim().replace("null", "");
513 String marker;
514 try {
515 marker = nonViralName.getRank().getInfraGenericMarker();
516 } catch (UnknownCdmTypeException e) {
517 marker = "'unknown aggregat type'";
518 }
519 result += " " + marker;
520
521 return result;
522 }
523
524 protected String getSpeciesNameCache(NonViralName nonViralName){
525 String result;
526 result = CdmUtils.Nz(nonViralName.getGenusOrUninomial()).trim();
527 result += " " + CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim().replace("null", "");
528 result = addAppendedPhrase(result, nonViralName).trim();
529 result = result.replace("\\s\\", " ");
530 return result;
531 }
532
533
534 protected String getInfraSpeciesNameCache(NonViralName nonViralName){
535 return getInfraSpeciesNameCache(nonViralName, true);
536 }
537
538 protected String getInfraSpeciesNameCache(NonViralName nonViralName, boolean includeMarker){
539 String result;
540 result = CdmUtils.Nz(nonViralName.getGenusOrUninomial()).trim();
541 result += " " + (CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim()).replace("null", "");
542 if (includeMarker){
543 result += " " + (nonViralName.getRank().getAbbreviation()).trim().replace("null", "");
544 }
545 result += " " + (CdmUtils.Nz(nonViralName.getInfraSpecificEpithet())).trim().replace("null", "");
546 result = addAppendedPhrase(result, nonViralName).trim();
547 return result;
548 }
549
550
551
552 /**
553 * @param name
554 * @return true, if name has Rank, Rank is below species and species epithet equals infraSpeciesEpithtet, else false
555 */
556 protected boolean isAutonym(NonViralName nonViralName){
557 if (nonViralName != null && nonViralName.getRank() != null && nonViralName.getSpecificEpithet() != null && nonViralName.getInfraSpecificEpithet() != null &&
558 nonViralName.getRank().isInfraSpecific() && nonViralName.getSpecificEpithet().trim().equals(nonViralName.getInfraSpecificEpithet().trim())){
559 return true;
560 }else{
561 return false;
562 }
563 }
564
565 protected String addAppendedPhrase(String resultString, NonViralName nonViralName){
566 String appendedPhrase = nonViralName ==null ? null : nonViralName.getAppendedPhrase();
567 if (resultString == null){
568 return appendedPhrase;
569 }else if(appendedPhrase == null || "".equals(appendedPhrase.trim())) {
570 return resultString;
571 }else if ("".equals(resultString)){
572 return resultString + appendedPhrase;
573 }else {
574 return resultString + " " + appendedPhrase;
575 }
576 }
577
578
579 public String getLastEpithet(T taxonNameBase) {
580 Rank rank = taxonNameBase.getRank();
581 if(rank.isGenus() || rank.isSupraGeneric()) {
582 return taxonNameBase.getGenusOrUninomial();
583 } else if(rank.isInfraGeneric()) {
584 return taxonNameBase.getInfraGenericEpithet();
585 } else if(rank.isSpecies()) {
586 return taxonNameBase.getSpecificEpithet();
587 } else {
588 return taxonNameBase.getInfraSpecificEpithet();
589 }
590 }
591 }