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
.commons
.lang
.StringUtils
;
18 import org
.apache
.log4j
.Logger
;
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 import eu
.etaxonomy
.cdm
.strategy
.parser
.NonViralNameParserImplRegExBase
;
36 * This class is a default implementation for the INonViralNameCacheStrategy<T extends NonViralName> interface.
37 * The method actually implements a cache strategy for botanical names so no method has to be overwritten by
38 * a subclass for botanic names.
39 * Where differing from this Default BotanicNameCacheStrategy other subclasses should overwrite the existing methods
40 * e.g. a CacheStrategy for zoological names should overwrite getAuthorAndExAuthor
48 public class NonViralNameDefaultCacheStrategy
<T
extends NonViralName
> extends NameCacheStrategyBase
<T
> implements INonViralNameCacheStrategy
<T
> {
49 private static final Logger logger
= Logger
.getLogger(NonViralNameDefaultCacheStrategy
.class);
51 final static UUID uuid
= UUID
.fromString("1cdda0d1-d5bc-480f-bf08-40a510a2f223");
53 protected String NameAuthorSeperator
= " ";
54 protected String BasionymStart
= "(";
55 protected String BasionymEnd
= ")";
56 protected String ExAuthorSeperator
= " ex ";
57 protected CharSequence BasionymAuthorCombinationAuthorSeperator
= " ";
60 public UUID
getUuid(){
67 * @return NonViralNameDefaultCacheStrategy A new instance of NonViralNameDefaultCacheStrategy
69 public static NonViralNameDefaultCacheStrategy
NewInstance(){
70 return new NonViralNameDefaultCacheStrategy();
76 protected NonViralNameDefaultCacheStrategy(){
80 /* **************** GETTER / SETTER **************************************/
83 * String that separates the NameCache part from the AuthorCache part
86 public String
getNameAuthorSeperator() {
87 return NameAuthorSeperator
;
91 public void setNameAuthorSeperator(String nameAuthorSeperator
) {
92 NameAuthorSeperator
= nameAuthorSeperator
;
97 * String the basionym author part starts with e.g. '('.
98 * This should correspond with the {@link NonViralNameDefaultCacheStrategy#getBasionymEnd() basionymEnd} attribute
101 public String
getBasionymStart() {
102 return BasionymStart
;
106 public void setBasionymStart(String basionymStart
) {
107 BasionymStart
= basionymStart
;
112 * String the basionym author part ends with e.g. ')'.
113 * This should correspond with the {@link NonViralNameDefaultCacheStrategy#getBasionymStart() basionymStart} attribute
116 public String
getBasionymEnd() {
121 public void setBasionymEnd(String basionymEnd
) {
122 BasionymEnd
= basionymEnd
;
127 * String to seperate ex author from author.
130 public String
getExAuthorSeperator() {
131 return ExAuthorSeperator
;
135 public void setExAuthorSeperator(String exAuthorSeperator
) {
136 ExAuthorSeperator
= exAuthorSeperator
;
141 * String that seperates the basionym/original_combination author part from the combination author part
144 public CharSequence
getBasionymAuthorCombinationAuthorSeperator() {
145 return BasionymAuthorCombinationAuthorSeperator
;
149 public void setBasionymAuthorCombinationAuthorSeperator(
150 CharSequence basionymAuthorCombinationAuthorSeperator
) {
151 BasionymAuthorCombinationAuthorSeperator
= basionymAuthorCombinationAuthorSeperator
;
155 //** *****************************************************************************************/
159 * @see eu.etaxonomy.cdm.strategy.INameCacheStrategy#getNameCache()
162 public String
getTitleCache(T nonViralName
) {
163 if (nonViralName
== null){
167 if (nonViralName
.isProtectedTitleCache()){
168 return nonViralName
.getTitleCache();
172 if (nonViralName
.isAutonym()){
173 result
= handleAutonym(nonViralName
);
175 String nameCache
= nonViralName
.getNameCache(); //OLD: CdmUtils.Nz(getNameCache(nonViralName));
176 if (nameIncludesAuthorship(nonViralName
)){
177 String authorCache
= CdmUtils
.Nz(getAuthorshipCache(nonViralName
));
178 result
= CdmUtils
.concat(NameAuthorSeperator
, nameCache
, authorCache
);
188 * @param nonViralName
192 private String
handleAutonym(T nonViralName
) {
194 String speciesPart
= getSpeciesNameCache(nonViralName
);
195 //TODO should this include basionym authors and ex authors
196 INomenclaturalAuthor author
= nonViralName
.getCombinationAuthorTeam();
197 String authorPart
= "";
199 authorPart
= CdmUtils
.Nz(author
.getNomenclaturalTitle());
201 INomenclaturalAuthor basAuthor
= nonViralName
.getBasionymAuthorTeam();
202 String basAuthorPart
= "";
203 if (basAuthor
!= null){
204 basAuthorPart
= CdmUtils
.Nz(basAuthor
.getNomenclaturalTitle());
206 if (! "".equals(basAuthorPart
)){
207 authorPart
= "("+ basAuthorPart
+")" + authorPart
;
209 String infraSpeciesPart
= (CdmUtils
.Nz(nonViralName
.getInfraSpecificEpithet()));
211 String infraSpeciesSeparator
= "";
212 if (nonViralName
.getRank() == null || !nonViralName
.getRank().isInfraSpecific()){
213 //TODO handle exception
214 logger
.warn("Rank for autonym does not exist or is not lower than species !!");
216 infraSpeciesSeparator
= nonViralName
.getRank().getAbbreviation();
219 result
= CdmUtils
.concat(" ", new String
[]{speciesPart
, authorPart
, infraSpeciesSeparator
, infraSpeciesPart
});
220 result
= result
.trim().replace("null", "");
224 protected boolean nameIncludesAuthorship(NonViralName nonViralName
){
225 Rank rank
= nonViralName
.getRank();
226 if (rank
!= null && rank
.isSpeciesAggregate()){
238 public String
getFullTitleCache(T nonViralName
) {
240 if (nonViralName
== null){
244 if (nonViralName
.isProtectedFullTitleCache() == true) {
245 return nonViralName
.getFullTitleCache();
250 String titleCache
= nonViralName
.getTitleCache(); // OLD: getTitleCache(nonViralName);
252 String microReference
= nonViralName
.getNomenclaturalMicroReference();
253 INomenclaturalReference ref
= nonViralName
.getNomenclaturalReference();
254 String referenceBaseCache
= null;
256 INomenclaturalReference nomenclaturalReference
= HibernateProxyHelper
.deproxy(ref
, INomenclaturalReference
.class);
257 nomenclaturalReference
.setCacheStrategy(nomenclaturalReference
.getType().getCacheStrategy());
258 referenceBaseCache
= nomenclaturalReference
.getNomenclaturalCitation(microReference
);
261 //make nomenclatural status
262 String ncStatusCache
= "";
263 Set
<NomenclaturalStatus
> ncStati
= nonViralName
.getStatus();
264 Iterator
<NomenclaturalStatus
> iterator
= ncStati
.iterator();
265 while (iterator
.hasNext()) {
266 NomenclaturalStatus ncStatus
= (NomenclaturalStatus
)iterator
.next();
267 // since the NewInstance method of nomencatural status allows null as parameter
268 // we have to check for null values here
269 String suffix
= "not defined";
270 if(ncStatus
.getType() != null){
271 NomenclaturalStatusType statusType
= ncStatus
.getType();
272 Language lang
= Language
.LATIN();
273 Representation repr
= statusType
.getRepresentation(lang
);
275 suffix
= repr
.getAbbreviatedLabel();
277 String message
= "No latin representation available for nom. status. " + statusType
.getTitleCache();
278 logger
.warn(message
);
279 throw new IllegalStateException(message
);
281 }else if(ncStatus
.getRuleConsidered() != null && ! ncStatus
.getRuleConsidered().equals("")){
282 suffix
= ncStatus
.getRuleConsidered();
284 ncStatusCache
= ", " + suffix
;
286 String refConcat
= " ";
287 if (referenceBaseCache
!= null && ! referenceBaseCache
.trim().startsWith("in ")){
290 result
= CdmUtils
.concat(refConcat
, titleCache
, referenceBaseCache
);
291 result
= CdmUtils
.concat("", result
, ncStatusCache
);
297 * Generates and returns the "name cache" (only scientific name without author teams and year).
298 * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy#getNameCache(eu.etaxonomy.cdm.model.name.TaxonNameBase)
300 public String
getNameCache(T nonViralName
) {
301 if (nonViralName
== null){
305 Rank rank
= nonViralName
.getRank();
307 if (nonViralName
.isProtectedNameCache()){
308 result
= nonViralName
.getNameCache();
309 }else if (rank
== null){
310 result
= getRanklessNameCache(nonViralName
);
311 }else if (nonViralName
.isInfragenericUnranked()){
312 result
= getUnrankedInfragenericNameCache(nonViralName
);
313 }else if (rank
.isInfraSpecific()){
314 result
= getInfraSpeciesNameCache(nonViralName
);
315 }else if (rank
.isSpecies()){
316 result
= getSpeciesNameCache(nonViralName
);
317 }else if (rank
.isInfraGeneric()){
318 result
= getInfraGenusNameCache(nonViralName
);
319 }else if (rank
.isGenus()){
320 result
= getGenusOrUninomialNameCache(nonViralName
);
321 }else if (rank
.isSupraGeneric()){
322 result
= getGenusOrUninomialNameCache(nonViralName
);
324 logger
.warn("Name Strategy for Name (UUID: " + nonViralName
.getUuid() + ") not yet implemented");
332 // * @param nonViralName
335 // private boolean isInfragenericUnranked(T nonViralName) {
336 // Rank rank = nonViralName.getRank();
337 // if (rank == null || ! rank.equals(Rank.UNRANKED())){
340 // if (StringUtils.isBlank(nonViralName.getSpecificEpithet()) && StringUtils.isBlank(nonViralName.getInfraSpecificEpithet()) ){
348 private String
getUnrankedInfragenericNameCache(T nonViralName
) {
350 Rank rank
= nonViralName
.getRank();
351 if (rank
.isSpeciesAggregate()){
352 return getSpeciesAggregateCache(nonViralName
);
354 String infraGenericMarker
= rank
.getAbbreviation();
355 result
= CdmUtils
.Nz(nonViralName
.getGenusOrUninomial()).trim();
356 result
+= " " + infraGenericMarker
+ " " + (CdmUtils
.Nz(nonViralName
.getInfraGenericEpithet())).trim().replace("null", "");
357 result
= addAppendedPhrase(result
, nonViralName
).trim();
363 * @see eu.etaxonomy.cdm.strategy.cache.INonViralNameCacheStrategy#getAuthorCache(eu.etaxonomy.cdm.model.name.NonViralName)
365 public String
getAuthorshipCache(T nonViralName
) {
366 if (nonViralName
== null){
370 if (nonViralName
.isProtectedAuthorshipCache() == true) {
371 return nonViralName
.getAuthorshipCache();
373 return getNonCacheAuthorshipCache(nonViralName
);
378 * Returns the authorshipcache string for the atomized authorship fields. Does not use the authorshipfield.
379 * @throws NullPointerException if nonViralName is null.
380 * @param nonViralName
383 protected String
getNonCacheAuthorshipCache(T nonViralName
){
385 INomenclaturalAuthor combinationAuthor
= nonViralName
.getCombinationAuthorTeam();
386 INomenclaturalAuthor exCombinationAuthor
= nonViralName
.getExCombinationAuthorTeam();
387 INomenclaturalAuthor basionymAuthor
= nonViralName
.getBasionymAuthorTeam();
388 INomenclaturalAuthor exBasionymAuthor
= nonViralName
.getExBasionymAuthorTeam();
389 String basionymPart
= "";
390 String authorPart
= "";
392 if (basionymAuthor
!= null || exBasionymAuthor
!= null){
393 basionymPart
= BasionymStart
+ getAuthorAndExAuthor(basionymAuthor
, exBasionymAuthor
) + BasionymEnd
;
395 if (combinationAuthor
!= null || exCombinationAuthor
!= null){
396 authorPart
= getAuthorAndExAuthor(combinationAuthor
, exCombinationAuthor
);
398 result
= CdmUtils
.concat(BasionymAuthorCombinationAuthorSeperator
, basionymPart
, authorPart
);
403 * Returns the AuthorCache part for a combination of an author and an ex author. This applies on combination authors
404 * as well as on basionym/orginal combination authors.
405 * @param author the author
406 * @param exAuthor the ex-author
409 protected String
getAuthorAndExAuthor(INomenclaturalAuthor author
, INomenclaturalAuthor exAuthor
){
411 String authorString
= "";
412 String exAuthorString
= "";
414 authorString
= CdmUtils
.Nz(author
.getNomenclaturalTitle());
416 if (exAuthor
!= null){
417 exAuthorString
= CdmUtils
.Nz(exAuthor
.getNomenclaturalTitle());
419 if (exAuthorString
.length() > 0 ){
420 exAuthorString
= exAuthorString
+ ExAuthorSeperator
;
422 result
= exAuthorString
+ authorString
;
429 * @see eu.etaxonomy.cdm.strategy.INameCacheStrategy#getTaggedName(eu.etaxonomy.cdm.model.common.CdmBase)
432 public List
<Object
> getTaggedName(T nonViralName
) {
433 List
<Object
> tags
= new ArrayList
<Object
>();
435 if (nonViralName
.isProtectedNameCache() ||
436 nonViralName
.isProtectedAuthorshipCache() ||
437 nonViralName
.isProtectedFullTitleCache() ||
438 nonViralName
.isProtectedTitleCache()){
439 tags
.add(nonViralName
.getTitleCache());
443 // Why does it make sense to add the nameCache in case of non existing genusOrUninomial?
444 // if (nonViralName.getGenusOrUninomial() == null){
445 // tags.add(nonViralName.getNameCache());
448 if (nonViralName
.getGenusOrUninomial() != null) {
449 tags
.add(nonViralName
.getGenusOrUninomial());
451 if (nonViralName
.isSpecies() || nonViralName
.isInfraSpecific()){
452 tags
.add(nonViralName
.getSpecificEpithet());
456 if (nonViralName
.isInfraSpecific() && ! nonViralName
.getSpecificEpithet().equals(nonViralName
.getInfraSpecificEpithet())){
457 tags
.add(nonViralName
.getRank());
458 tags
.add(nonViralName
.getInfraSpecificEpithet());
461 if (nonViralName
.isInfraGeneric()){
462 //TODO choose right strategy or generic approach?
463 // --- strategy 1 ---
465 if (nonViralName
.getRank().isSpeciesAggregate()){
466 tags
.add(nonViralName
.getSpecificEpithet());
467 tags
.add(getSpeciesAggregateEpithet(nonViralName
));
469 tags
.add(nonViralName
.getRank());
470 tags
.add(nonViralName
.getInfraGenericEpithet());
472 // --- strategy 2 ---
473 // tags.add('('+nvn.getInfraGenericEpithet()+')');
475 Team authorTeam
= Team
.NewInstance();
476 authorTeam
.setProtectedTitleCache(true);
477 authorTeam
.setTitleCache(nonViralName
.getAuthorshipCache(), true);
478 tags
.add(authorTeam
);
480 // Name is an autonym. Rank and infraspecific epitheton follow the author
481 if (nonViralName
.isInfraSpecific() && nonViralName
.getSpecificEpithet().equals(nonViralName
.getInfraSpecificEpithet())){
482 tags
.add(nonViralName
.getRank());
483 tags
.add(nonViralName
.getInfraSpecificEpithet());
486 if(! "".equals(nonViralName
.getAppendedPhrase())&& (nonViralName
.getAppendedPhrase() != null)){
487 tags
.add(nonViralName
.getAppendedPhrase());
494 //***************************** PRIVATES ***************************************/
496 protected String
getRanklessNameCache(NonViralName nonViralName
){
498 result
= (result
+ (CdmUtils
.Nz(nonViralName
.getGenusOrUninomial()))).trim().replace("null", "");
499 result
+= " " + (CdmUtils
.Nz(nonViralName
.getSpecificEpithet())).trim();
500 result
+= " " + (CdmUtils
.Nz(nonViralName
.getInfraSpecificEpithet())).trim();
501 result
= result
.trim().replace("null", "");
502 //result += " (rankless)";
503 result
= addAppendedPhrase(result
, nonViralName
);
508 protected String
getGenusOrUninomialNameCache(NonViralName nonViralName
){
510 result
= getUninomialPart(nonViralName
);
511 result
= addAppendedPhrase(result
, nonViralName
).trim();
516 private String
getUninomialPart(NonViralName nonViralName
) {
518 result
= CdmUtils
.Nz(nonViralName
.getGenusOrUninomial()).trim();
519 if (nonViralName
.isMonomHybrid()){
520 result
= NonViralNameParserImplRegExBase
.hybridSign
+ result
;
525 protected String
getInfraGenusNameCache(NonViralName nonViralName
){
527 Rank rank
= nonViralName
.getRank();
528 if (rank
.isSpeciesAggregate()){
529 return getSpeciesAggregateCache(nonViralName
);
531 String infraGenericMarker
= "'unhandled infrageneric rank'";
534 infraGenericMarker
= rank
.getInfraGenericMarker();
535 } catch (UnknownCdmTypeException e
) {
536 infraGenericMarker
= "'unhandled infrageneric rank'";
539 result
= getUninomialPart(nonViralName
);
540 result
+= " " + infraGenericMarker
+ " " + (CdmUtils
.Nz(nonViralName
.getInfraGenericEpithet())).trim().replace("null", "");
541 result
= addAppendedPhrase(result
, nonViralName
).trim();
546 protected String
getSpeciesAggregateCache(NonViralName nonViralName
){
547 String result
= getGenusAndSpeciesPart(nonViralName
);
549 result
+= " " + getSpeciesAggregateEpithet(nonViralName
);
550 result
= addAppendedPhrase(result
, nonViralName
).trim();
554 private String
getSpeciesAggregateEpithet(NonViralName nonViralName
) {
557 marker
= nonViralName
.getRank().getInfraGenericMarker();
558 } catch (UnknownCdmTypeException e
) {
559 marker
= "'unknown aggregat type'";
564 protected String
getSpeciesNameCache(NonViralName nonViralName
){
565 String result
= getGenusAndSpeciesPart(nonViralName
);
566 result
= addAppendedPhrase(result
, nonViralName
).trim();
567 result
= result
.replace("\\s\\", " ");
572 protected String
getInfraSpeciesNameCache(NonViralName nonViralName
){
573 return getInfraSpeciesNameCache(nonViralName
, true);
576 protected String
getInfraSpeciesNameCache(NonViralName nonViralName
, boolean includeMarker
){
577 String result
= getGenusAndSpeciesPart(nonViralName
);
579 result
+= " " + (nonViralName
.getRank().getAbbreviation()).trim().replace("null", "");
581 String infrSpecEpi
= CdmUtils
.Nz(nonViralName
.getInfraSpecificEpithet());
582 if (nonViralName
.isTrinomHybrid()){
583 infrSpecEpi
= NonViralNameParserImplRegExBase
.hybridSign
+ infrSpecEpi
;
585 result
+= " " + (infrSpecEpi
).trim().replace("null", "");
586 result
= addAppendedPhrase(result
, nonViralName
).trim();
591 private String
getGenusAndSpeciesPart(NonViralName nonViralName
) {
594 result
= getUninomialPart(nonViralName
);
597 boolean hasInfraGenericEpi
= StringUtils
.isNotBlank(nonViralName
.getInfraGenericEpithet());
598 if (hasInfraGenericEpi
){
599 String infrGenEpi
= nonViralName
.getInfraGenericEpithet().trim();
600 if (nonViralName
.isBinomHybrid()){
601 infrGenEpi
= NonViralNameParserImplRegExBase
.hybridSign
+ infrGenEpi
;
603 result
+= " (" + infrGenEpi
+ ")";
606 String specEpi
= CdmUtils
.Nz(nonViralName
.getSpecificEpithet()).trim();
607 if (! hasInfraGenericEpi
&& nonViralName
.isBinomHybrid() ||
608 hasInfraGenericEpi
&& nonViralName
.isTrinomHybrid()){
609 specEpi
= NonViralNameParserImplRegExBase
.hybridSign
+ specEpi
;
611 result
+= " " + (specEpi
).replace("null", "");
616 protected String
addAppendedPhrase(String resultString
, NonViralName nonViralName
){
617 String appendedPhrase
= nonViralName
==null ?
null : nonViralName
.getAppendedPhrase();
618 if (resultString
== null){
619 return appendedPhrase
;
620 }else if(appendedPhrase
== null || "".equals(appendedPhrase
.trim())) {
622 }else if ("".equals(resultString
)){
623 return resultString
+ appendedPhrase
;
625 return resultString
+ " " + appendedPhrase
;
630 public String
getLastEpithet(T taxonNameBase
) {
631 Rank rank
= taxonNameBase
.getRank();
632 if(rank
.isGenus() || rank
.isSupraGeneric()) {
633 return taxonNameBase
.getGenusOrUninomial();
634 } else if(rank
.isInfraGeneric()) {
635 return taxonNameBase
.getInfraGenericEpithet();
636 } else if(rank
.isSpecies()) {
637 return taxonNameBase
.getSpecificEpithet();
639 return taxonNameBase
.getInfraSpecificEpithet();