2 * Copyright (C) 2007 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
.strategy
.cache
.name
;
11 import java
.util
.ArrayList
;
12 import java
.util
.Iterator
;
13 import java
.util
.List
;
15 import java
.util
.UUID
;
17 import org
.apache
.log4j
.Logger
;
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
;
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
46 public class NonViralNameDefaultCacheStrategy
<T
extends NonViralName
> extends NameCacheStrategyBase
<T
> implements INonViralNameCacheStrategy
<T
> {
47 private static final Logger logger
= Logger
.getLogger(NonViralNameDefaultCacheStrategy
.class);
49 final static UUID uuid
= UUID
.fromString("1cdda0d1-d5bc-480f-bf08-40a510a2f223");
51 protected String NameAuthorSeperator
= " ";
52 protected String BasionymStart
= "(";
53 protected String BasionymEnd
= ")";
54 protected String ExAuthorSeperator
= " ex ";
55 protected CharSequence BasionymAuthorCombinationAuthorSeperator
= " ";
58 public UUID
getUuid(){
65 * @return NonViralNameDefaultCacheStrategy A new instance of NonViralNameDefaultCacheStrategy
67 public static NonViralNameDefaultCacheStrategy
NewInstance(){
68 return new NonViralNameDefaultCacheStrategy();
74 protected NonViralNameDefaultCacheStrategy(){
78 /* **************** GETTER / SETTER **************************************/
81 * String that separates the NameCache part from the AuthorCache part
84 public String
getNameAuthorSeperator() {
85 return NameAuthorSeperator
;
89 public void setNameAuthorSeperator(String nameAuthorSeperator
) {
90 NameAuthorSeperator
= nameAuthorSeperator
;
95 * String the basionym author part starts with e.g. '('.
96 * This should correspond with the {@link NonViralNameDefaultCacheStrategy#getBasionymEnd() basionymEnd} attribute
99 public String
getBasionymStart() {
100 return BasionymStart
;
104 public void setBasionymStart(String basionymStart
) {
105 BasionymStart
= basionymStart
;
110 * String the basionym author part ends with e.g. ')'.
111 * This should correspond with the {@link NonViralNameDefaultCacheStrategy#getBasionymStart() basionymStart} attribute
114 public String
getBasionymEnd() {
119 public void setBasionymEnd(String basionymEnd
) {
120 BasionymEnd
= basionymEnd
;
125 * String to seperate ex author from author.
128 public String
getExAuthorSeperator() {
129 return ExAuthorSeperator
;
133 public void setExAuthorSeperator(String exAuthorSeperator
) {
134 ExAuthorSeperator
= exAuthorSeperator
;
139 * String that seperates the basionym/original_combination author part from the combination author part
142 public CharSequence
getBasionymAuthorCombinationAuthorSeperator() {
143 return BasionymAuthorCombinationAuthorSeperator
;
147 public void setBasionymAuthorCombinationAuthorSeperator(
148 CharSequence basionymAuthorCombinationAuthorSeperator
) {
149 BasionymAuthorCombinationAuthorSeperator
= basionymAuthorCombinationAuthorSeperator
;
153 //** *****************************************************************************************/
157 * @see eu.etaxonomy.cdm.strategy.INameCacheStrategy#getNameCache()
160 public String
getTitleCache(T nonViralName
) {
161 if (nonViralName
== null){
165 if (nonViralName
.isProtectedTitleCache()){
166 return nonViralName
.getTitleCache();
170 if (isAutonym(nonViralName
)){
171 result
= handleAutonym(nonViralName
);
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
);
186 * @param nonViralName
190 private String
handleAutonym(T nonViralName
) {
192 String speciesPart
= getSpeciesNameCache(nonViralName
);
193 //TODO should this include basionym authors and ex authors
194 INomenclaturalAuthor author
= nonViralName
.getCombinationAuthorTeam();
195 String authorPart
= "";
197 authorPart
= CdmUtils
.Nz(author
.getNomenclaturalTitle());
199 INomenclaturalAuthor basAuthor
= nonViralName
.getBasionymAuthorTeam();
200 String basAuthorPart
= "";
201 if (basAuthor
!= null){
202 basAuthorPart
= CdmUtils
.Nz(basAuthor
.getNomenclaturalTitle());
204 if (! "".equals(basAuthorPart
)){
205 authorPart
= "("+ basAuthorPart
+")" + authorPart
;
207 String infraSpeciesPart
= (CdmUtils
.Nz(nonViralName
.getInfraSpecificEpithet()));
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 !!");
214 infraSpeciesSeparator
= nonViralName
.getRank().getAbbreviation();
217 result
= CdmUtils
.concat(" ", new String
[]{speciesPart
, authorPart
, infraSpeciesSeparator
, infraSpeciesPart
});
218 result
= result
.trim().replace("null", "");
222 protected boolean nameIncludesAuthorship(NonViralName nonViralName
){
223 Rank rank
= nonViralName
.getRank();
224 if (rank
!= null && rank
.isSpeciesAggregate()){
236 public String
getFullTitleCache(T nonViralName
) {
238 if (nonViralName
== null){
242 if (nonViralName
.isProtectedFullTitleCache() == true) {
243 return nonViralName
.getFullTitleCache();
248 String titleCache
= nonViralName
.getTitleCache(); // OLD: getTitleCache(nonViralName);
250 String microReference
= nonViralName
.getNomenclaturalMicroReference();
251 INomenclaturalReference ref
= nonViralName
.getNomenclaturalReference();
252 String referenceBaseCache
= null;
254 INomenclaturalReference nomenclaturalReference
= HibernateProxyHelper
.deproxy(ref
, INomenclaturalReference
.class);
255 nomenclaturalReference
.setCacheStrategy(nomenclaturalReference
.getType().getCacheStrategy());
256 referenceBaseCache
= nomenclaturalReference
.getNomenclaturalCitation(microReference
);
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
);
273 suffix
= repr
.getAbbreviatedLabel();
275 String message
= "No latin representation available for nom. status. " + statusType
.getTitleCache();
276 logger
.warn(message
);
277 throw new IllegalStateException(message
);
279 }else if(ncStatus
.getRuleConsidered() != null && ! ncStatus
.getRuleConsidered().equals("")){
280 suffix
= ncStatus
.getRuleConsidered();
282 ncStatusCache
= ", " + suffix
;
284 String refConcat
= " ";
285 if (referenceBaseCache
!= null && ! referenceBaseCache
.trim().startsWith("in ")){
288 result
= CdmUtils
.concat(refConcat
, titleCache
, referenceBaseCache
);
289 result
= CdmUtils
.concat("", result
, ncStatusCache
);
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)
298 public String
getNameCache(T nonViralName
) {
299 if (nonViralName
== null){
303 Rank rank
= nonViralName
.getRank();
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
);
320 logger
.warn("Name Strategy for Name (UUID: " + nonViralName
.getUuid() + ") not yet implemented");
328 * @see eu.etaxonomy.cdm.strategy.cache.INonViralNameCacheStrategy#getAuthorCache(eu.etaxonomy.cdm.model.name.NonViralName)
330 public String
getAuthorshipCache(T nonViralName
) {
331 if (nonViralName
== null){
335 if (nonViralName
.isProtectedAuthorshipCache() == true) {
336 return nonViralName
.getAuthorshipCache();
338 return getNonCacheAuthorshipCache(nonViralName
);
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
348 protected String
getNonCacheAuthorshipCache(T nonViralName
){
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
= "";
357 if (basionymAuthor
!= null || exBasionymAuthor
!= null){
358 basionymPart
= BasionymStart
+ getAuthorAndExAuthor(basionymAuthor
, exBasionymAuthor
) + BasionymEnd
;
360 if (combinationAuthor
!= null || exCombinationAuthor
!= null){
361 authorPart
= getAuthorAndExAuthor(combinationAuthor
, exCombinationAuthor
);
363 result
= CdmUtils
.concat(BasionymAuthorCombinationAuthorSeperator
, basionymPart
, authorPart
);
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
374 protected String
getAuthorAndExAuthor(INomenclaturalAuthor author
, INomenclaturalAuthor exAuthor
){
376 String authorString
= "";
377 String exAuthorString
= "";
379 authorString
= CdmUtils
.Nz(author
.getNomenclaturalTitle());
381 if (exAuthor
!= null){
382 exAuthorString
= CdmUtils
.Nz(exAuthor
.getNomenclaturalTitle());
384 if (exAuthorString
.length() > 0 ){
385 exAuthorString
= exAuthorString
+ ExAuthorSeperator
;
387 result
= exAuthorString
+ authorString
;
394 * @see eu.etaxonomy.cdm.strategy.INameCacheStrategy#getTaggedName(eu.etaxonomy.cdm.model.common.CdmBase)
397 public List
<Object
> getTaggedName(T nonViralName
) {
398 List
<Object
> tags
= new ArrayList
<Object
>();
399 if (nonViralName
.getGenusOrUninomial() == null){
400 tags
.add(nonViralName
.getNameCache());
402 tags
.add(nonViralName
.getGenusOrUninomial());
404 if (nonViralName
.isSpecies() || nonViralName
.isInfraSpecific()){
405 tags
.add(nonViralName
.getSpecificEpithet());
409 if (nonViralName
.isInfraSpecific() && ! nonViralName
.getSpecificEpithet().equals(nonViralName
.getInfraSpecificEpithet())){
410 tags
.add(nonViralName
.getRank());
411 tags
.add(nonViralName
.getInfraSpecificEpithet());
414 if (nonViralName
.isInfraGeneric()){
415 //TODO choose right strategy or generic approach?
416 // --- strategy 1 ---
418 if (nonViralName
.getRank().isSpeciesAggregate()){
419 tags
.add(getSpeciesAggregateEpithet(nonViralName
));
421 tags
.add(nonViralName
.getRank());
422 tags
.add(nonViralName
.getInfraGenericEpithet());
424 // --- strategy 2 ---
425 // tags.add('('+nvn.getInfraGenericEpithet()+')');
427 Team authorTeam
= Team
.NewInstance();
428 authorTeam
.setProtectedTitleCache(true);
429 authorTeam
.setTitleCache(nonViralName
.getAuthorshipCache(), true);
430 tags
.add(authorTeam
);
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());
438 if(! "".equals(nonViralName
.getAppendedPhrase())&& (nonViralName
.getAppendedPhrase() != null)){
439 tags
.add(nonViralName
.getAppendedPhrase());
446 //***************************** PRIVATES ***************************************/
448 protected String
getRanklessNameCache(NonViralName nonViralName
){
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
);
460 protected String
getGenusOrUninomialNameCache(NonViralName nonViralName
){
462 result
= CdmUtils
.Nz(nonViralName
.getGenusOrUninomial()).trim();
463 result
= addAppendedPhrase(result
, nonViralName
).trim();
467 protected String
getInfraGenusNameCache(NonViralName nonViralName
){
469 Rank rank
= nonViralName
.getRank();
470 if (rank
.isSpeciesAggregate()){
471 return getSpeciesAggregateCache(nonViralName
);
473 String infraGenericMarker
= "'unhandled infrageneric rank'";
476 infraGenericMarker
= rank
.getInfraGenericMarker();
477 } catch (UnknownCdmTypeException e
) {
478 infraGenericMarker
= "'unhandled infrageneric rank'";
481 result
= CdmUtils
.Nz(nonViralName
.getGenusOrUninomial()).trim();
482 result
+= " " + infraGenericMarker
+ " " + (CdmUtils
.Nz(nonViralName
.getInfraGenericEpithet())).trim().replace("null", "");
483 result
= addAppendedPhrase(result
, nonViralName
).trim();
488 protected String
getSpeciesAggregateCache(NonViralName nonViralName
){
490 result
= CdmUtils
.Nz(nonViralName
.getGenusOrUninomial()).trim();
492 result
+= " " + getSpeciesAggregateEpithet(nonViralName
);
493 /*result += " " + CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim().replace("null", "");
496 marker = nonViralName.getRank().getInfraGenericMarker();
497 } catch (UnknownCdmTypeException e) {
498 marker = "'unknown aggregat type'";
500 result += " " + marker;*/
501 result
= addAppendedPhrase(result
, nonViralName
).trim();
505 private String
getSpeciesAggregateEpithet(NonViralName nonViralName
) {
508 result
= CdmUtils
.Nz(nonViralName
.getSpecificEpithet()).trim().replace("null", "");
511 marker
= nonViralName
.getRank().getInfraGenericMarker();
512 } catch (UnknownCdmTypeException e
) {
513 marker
= "'unknown aggregat type'";
515 result
+= " " + marker
;
520 protected String
getSpeciesNameCache(NonViralName nonViralName
){
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\\", " ");
530 protected String
getInfraSpeciesNameCache(NonViralName nonViralName
){
531 return getInfraSpeciesNameCache(nonViralName
, true);
534 protected String
getInfraSpeciesNameCache(NonViralName nonViralName
, boolean includeMarker
){
536 result
= CdmUtils
.Nz(nonViralName
.getGenusOrUninomial()).trim();
537 result
+= " " + (CdmUtils
.Nz(nonViralName
.getSpecificEpithet()).trim()).replace("null", "");
539 result
+= " " + (nonViralName
.getRank().getAbbreviation()).trim().replace("null", "");
541 result
+= " " + (CdmUtils
.Nz(nonViralName
.getInfraSpecificEpithet())).trim().replace("null", "");
542 result
= addAppendedPhrase(result
, nonViralName
).trim();
550 * @return true, if name has Rank, Rank is below species and species epithet equals infraSpeciesEpithtet, else false
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())){
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())) {
567 }else if ("".equals(resultString
)){
568 return resultString
+ appendedPhrase
;
570 return resultString
+ " " + appendedPhrase
;
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();
584 return taxonNameBase
.getInfraSpecificEpithet();