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
.SortedSet
;
16 import java
.util
.UUID
;
18 import org
.apache
.commons
.lang
.StringUtils
;
19 import org
.apache
.log4j
.Logger
;
21 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
22 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
23 import eu
.etaxonomy
.cdm
.model
.agent
.INomenclaturalAuthor
;
24 import eu
.etaxonomy
.cdm
.model
.agent
.Team
;
25 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
26 import eu
.etaxonomy
.cdm
.model
.common
.Representation
;
27 import eu
.etaxonomy
.cdm
.model
.name
.HybridRelationship
;
28 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatus
;
29 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatusType
;
30 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
31 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
32 import eu
.etaxonomy
.cdm
.model
.reference
.INomenclaturalReference
;
33 import eu
.etaxonomy
.cdm
.strategy
.exceptions
.UnknownCdmTypeException
;
34 import eu
.etaxonomy
.cdm
.strategy
.parser
.NonViralNameParserImplRegExBase
;
38 * This class is a default implementation for the INonViralNameCacheStrategy<T extends NonViralName> interface.
39 * The method actually implements a cache strategy for botanical names so no method has to be overwritten by
40 * a subclass for botanic names.
41 * Where differing from this Default BotanicNameCacheStrategy other subclasses should overwrite the existing methods
42 * e.g. a CacheStrategy for zoological names should overwrite getAuthorAndExAuthor
50 public class NonViralNameDefaultCacheStrategy
<T
extends NonViralName
> extends NameCacheStrategyBase
<T
> implements INonViralNameCacheStrategy
<T
> {
51 private static final Logger logger
= Logger
.getLogger(NonViralNameDefaultCacheStrategy
.class);
53 final static UUID uuid
= UUID
.fromString("1cdda0d1-d5bc-480f-bf08-40a510a2f223");
55 protected String NameAuthorSeperator
= " ";
56 protected String BasionymStart
= "(";
57 protected String BasionymEnd
= ")";
58 protected String ExAuthorSeperator
= " ex ";
59 protected CharSequence BasionymAuthorCombinationAuthorSeperator
= " ";
62 public UUID
getUuid(){
69 * @return NonViralNameDefaultCacheStrategy A new instance of NonViralNameDefaultCacheStrategy
71 public static NonViralNameDefaultCacheStrategy
NewInstance(){
72 return new NonViralNameDefaultCacheStrategy();
78 protected NonViralNameDefaultCacheStrategy(){
82 /* **************** GETTER / SETTER **************************************/
85 * String that separates the NameCache part from the AuthorCache part
88 public String
getNameAuthorSeperator() {
89 return NameAuthorSeperator
;
93 public void setNameAuthorSeperator(String nameAuthorSeperator
) {
94 NameAuthorSeperator
= nameAuthorSeperator
;
99 * String the basionym author part starts with e.g. '('.
100 * This should correspond with the {@link NonViralNameDefaultCacheStrategy#getBasionymEnd() basionymEnd} attribute
103 public String
getBasionymStart() {
104 return BasionymStart
;
108 public void setBasionymStart(String basionymStart
) {
109 BasionymStart
= basionymStart
;
114 * String the basionym author part ends with e.g. ')'.
115 * This should correspond with the {@link NonViralNameDefaultCacheStrategy#getBasionymStart() basionymStart} attribute
118 public String
getBasionymEnd() {
123 public void setBasionymEnd(String basionymEnd
) {
124 BasionymEnd
= basionymEnd
;
129 * String to seperate ex author from author.
132 public String
getExAuthorSeperator() {
133 return ExAuthorSeperator
;
137 public void setExAuthorSeperator(String exAuthorSeperator
) {
138 ExAuthorSeperator
= exAuthorSeperator
;
143 * String that seperates the basionym/original_combination author part from the combination author part
146 public CharSequence
getBasionymAuthorCombinationAuthorSeperator() {
147 return BasionymAuthorCombinationAuthorSeperator
;
151 public void setBasionymAuthorCombinationAuthorSeperator(
152 CharSequence basionymAuthorCombinationAuthorSeperator
) {
153 BasionymAuthorCombinationAuthorSeperator
= basionymAuthorCombinationAuthorSeperator
;
157 //** *****************************************************************************************/
161 * @see eu.etaxonomy.cdm.strategy.INameCacheStrategy#getNameCache()
164 public String
getTitleCache(T nonViralName
) {
165 if (nonViralName
== null){
169 if (nonViralName
.isProtectedTitleCache()){
170 return nonViralName
.getTitleCache();
173 if (nonViralName
.isHybridFormula()){
176 String hybridSeparator
= " " + NonViralNameParserImplRegExBase
.hybridSign
+ " ";
177 List
<HybridRelationship
> rels
= nonViralName
.getOrderedChildRelationships();
178 for (HybridRelationship rel
: rels
){
179 result
= CdmUtils
.concat(hybridSeparator
, result
, rel
.getParentName().getTitleCache()).trim();
182 }else if (nonViralName
.isAutonym()){
184 result
= handleAutonym(nonViralName
);
186 String nameCache
= nonViralName
.getNameCache(); //OLD: CdmUtils.Nz(getNameCache(nonViralName));
187 if (nameIncludesAuthorship(nonViralName
)){
188 String authorCache
= CdmUtils
.Nz(getAuthorshipCache(nonViralName
));
189 result
= CdmUtils
.concat(NameAuthorSeperator
, nameCache
, authorCache
);
199 * @param nonViralName
203 private String
handleAutonym(T nonViralName
) {
205 String speciesPart
= getSpeciesNameCache(nonViralName
);
206 //TODO should this include basionym authors and ex authors
207 INomenclaturalAuthor author
= nonViralName
.getCombinationAuthorTeam();
208 String authorPart
= "";
210 authorPart
= CdmUtils
.Nz(author
.getNomenclaturalTitle());
212 INomenclaturalAuthor basAuthor
= nonViralName
.getBasionymAuthorTeam();
213 String basAuthorPart
= "";
214 if (basAuthor
!= null){
215 basAuthorPart
= CdmUtils
.Nz(basAuthor
.getNomenclaturalTitle());
217 if (! "".equals(basAuthorPart
)){
218 authorPart
= "("+ basAuthorPart
+")" + authorPart
;
220 String infraSpeciesPart
= (CdmUtils
.Nz(nonViralName
.getInfraSpecificEpithet()));
222 String infraSpeciesSeparator
= "";
223 if (nonViralName
.getRank() == null || !nonViralName
.getRank().isInfraSpecific()){
224 //TODO handle exception
225 logger
.warn("Rank for autonym does not exist or is not lower than species !!");
227 infraSpeciesSeparator
= nonViralName
.getRank().getAbbreviation();
230 result
= CdmUtils
.concat(" ", new String
[]{speciesPart
, authorPart
, infraSpeciesSeparator
, infraSpeciesPart
});
231 result
= result
.trim().replace("null", "");
235 protected boolean nameIncludesAuthorship(NonViralName nonViralName
){
236 Rank rank
= nonViralName
.getRank();
237 if (rank
!= null && rank
.isSpeciesAggregate()){
249 public String
getFullTitleCache(T nonViralName
) {
251 if (nonViralName
== null){
255 if (nonViralName
.isProtectedFullTitleCache() == true) {
256 return nonViralName
.getFullTitleCache();
261 String titleCache
= nonViralName
.getTitleCache(); // OLD: getTitleCache(nonViralName);
263 String microReference
= nonViralName
.getNomenclaturalMicroReference();
264 INomenclaturalReference ref
= nonViralName
.getNomenclaturalReference();
265 String referenceBaseCache
= null;
267 INomenclaturalReference nomenclaturalReference
= HibernateProxyHelper
.deproxy(ref
, INomenclaturalReference
.class);
268 nomenclaturalReference
.setCacheStrategy(nomenclaturalReference
.getType().getCacheStrategy());
269 referenceBaseCache
= nomenclaturalReference
.getNomenclaturalCitation(microReference
);
272 //make nomenclatural status
273 String ncStatusCache
= "";
274 Set
<NomenclaturalStatus
> ncStati
= nonViralName
.getStatus();
275 Iterator
<NomenclaturalStatus
> iterator
= ncStati
.iterator();
276 while (iterator
.hasNext()) {
277 NomenclaturalStatus ncStatus
= (NomenclaturalStatus
)iterator
.next();
278 // since the NewInstance method of nomencatural status allows null as parameter
279 // we have to check for null values here
280 String suffix
= "not defined";
281 if(ncStatus
.getType() != null){
282 NomenclaturalStatusType statusType
= ncStatus
.getType();
283 Language lang
= Language
.LATIN();
284 Representation repr
= statusType
.getRepresentation(lang
);
286 suffix
= repr
.getAbbreviatedLabel();
288 String message
= "No latin representation available for nom. status. " + statusType
.getTitleCache();
289 logger
.warn(message
);
290 throw new IllegalStateException(message
);
292 }else if(ncStatus
.getRuleConsidered() != null && ! ncStatus
.getRuleConsidered().equals("")){
293 suffix
= ncStatus
.getRuleConsidered();
295 ncStatusCache
= ", " + suffix
;
297 String refConcat
= " ";
298 if (referenceBaseCache
!= null && ! referenceBaseCache
.trim().startsWith("in ")){
301 result
= CdmUtils
.concat(refConcat
, titleCache
, referenceBaseCache
);
302 result
= CdmUtils
.concat("", result
, ncStatusCache
);
308 * Generates and returns the "name cache" (only scientific name without author teams and year).
309 * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy#getNameCache(eu.etaxonomy.cdm.model.name.TaxonNameBase)
311 public String
getNameCache(T nonViralName
) {
312 if (nonViralName
== null){
316 Rank rank
= nonViralName
.getRank();
318 if (nonViralName
.isProtectedNameCache()){
319 result
= nonViralName
.getNameCache();
320 }else if (rank
== null){
321 result
= getRanklessNameCache(nonViralName
);
322 }else if (nonViralName
.isInfragenericUnranked()){
323 result
= getUnrankedInfragenericNameCache(nonViralName
);
324 }else if (rank
.isInfraSpecific()){
325 result
= getInfraSpeciesNameCache(nonViralName
);
326 }else if (rank
.isSpecies()){
327 result
= getSpeciesNameCache(nonViralName
);
328 }else if (rank
.isInfraGeneric()){
329 result
= getInfraGenusNameCache(nonViralName
);
330 }else if (rank
.isGenus()){
331 result
= getGenusOrUninomialNameCache(nonViralName
);
332 }else if (rank
.isSupraGeneric()){
333 result
= getGenusOrUninomialNameCache(nonViralName
);
335 logger
.warn("Name Strategy for Name (UUID: " + nonViralName
.getUuid() + ") not yet implemented");
343 // * @param nonViralName
346 // private boolean isInfragenericUnranked(T nonViralName) {
347 // Rank rank = nonViralName.getRank();
348 // if (rank == null || ! rank.equals(Rank.UNRANKED())){
351 // if (StringUtils.isBlank(nonViralName.getSpecificEpithet()) && StringUtils.isBlank(nonViralName.getInfraSpecificEpithet()) ){
359 private String
getUnrankedInfragenericNameCache(T nonViralName
) {
361 Rank rank
= nonViralName
.getRank();
362 if (rank
.isSpeciesAggregate()){
363 return getSpeciesAggregateCache(nonViralName
);
365 String infraGenericMarker
= rank
.getAbbreviation();
366 result
= CdmUtils
.Nz(nonViralName
.getGenusOrUninomial()).trim();
367 result
+= " " + infraGenericMarker
+ " " + (CdmUtils
.Nz(nonViralName
.getInfraGenericEpithet())).trim().replace("null", "");
368 result
= addAppendedPhrase(result
, nonViralName
).trim();
374 * @see eu.etaxonomy.cdm.strategy.cache.INonViralNameCacheStrategy#getAuthorCache(eu.etaxonomy.cdm.model.name.NonViralName)
376 public String
getAuthorshipCache(T nonViralName
) {
377 if (nonViralName
== null){
381 if (nonViralName
.isProtectedAuthorshipCache() == true) {
382 return nonViralName
.getAuthorshipCache();
384 return getNonCacheAuthorshipCache(nonViralName
);
389 * Returns the authorshipcache string for the atomized authorship fields. Does not use the authorshipfield.
390 * @throws NullPointerException if nonViralName is null.
391 * @param nonViralName
394 protected String
getNonCacheAuthorshipCache(T nonViralName
){
396 INomenclaturalAuthor combinationAuthor
= nonViralName
.getCombinationAuthorTeam();
397 INomenclaturalAuthor exCombinationAuthor
= nonViralName
.getExCombinationAuthorTeam();
398 INomenclaturalAuthor basionymAuthor
= nonViralName
.getBasionymAuthorTeam();
399 INomenclaturalAuthor exBasionymAuthor
= nonViralName
.getExBasionymAuthorTeam();
400 String basionymPart
= "";
401 String authorPart
= "";
403 if (basionymAuthor
!= null || exBasionymAuthor
!= null){
404 basionymPart
= BasionymStart
+ getAuthorAndExAuthor(basionymAuthor
, exBasionymAuthor
) + BasionymEnd
;
406 if (combinationAuthor
!= null || exCombinationAuthor
!= null){
407 authorPart
= getAuthorAndExAuthor(combinationAuthor
, exCombinationAuthor
);
409 result
= CdmUtils
.concat(BasionymAuthorCombinationAuthorSeperator
, basionymPart
, authorPart
);
414 * Returns the AuthorCache part for a combination of an author and an ex author. This applies on combination authors
415 * as well as on basionym/orginal combination authors.
416 * @param author the author
417 * @param exAuthor the ex-author
420 protected String
getAuthorAndExAuthor(INomenclaturalAuthor author
, INomenclaturalAuthor exAuthor
){
422 String authorString
= "";
423 String exAuthorString
= "";
425 authorString
= CdmUtils
.Nz(author
.getNomenclaturalTitle());
427 if (exAuthor
!= null){
428 exAuthorString
= CdmUtils
.Nz(exAuthor
.getNomenclaturalTitle());
430 if (exAuthorString
.length() > 0 ){
431 exAuthorString
= exAuthorString
+ ExAuthorSeperator
;
433 result
= exAuthorString
+ authorString
;
440 * @see eu.etaxonomy.cdm.strategy.INameCacheStrategy#getTaggedName(eu.etaxonomy.cdm.model.common.CdmBase)
443 public List
<Object
> getTaggedName(T nonViralName
) {
444 List
<Object
> tags
= new ArrayList
<Object
>();
446 if (nonViralName
.isProtectedNameCache() ||
447 nonViralName
.isProtectedAuthorshipCache() ||
448 nonViralName
.isProtectedFullTitleCache() ||
449 nonViralName
.isProtectedTitleCache()){
450 tags
.add(nonViralName
.getTitleCache());
454 // Why does it make sense to add the nameCache in case of non existing genusOrUninomial?
455 // if (nonViralName.getGenusOrUninomial() == null){
456 // tags.add(nonViralName.getNameCache());
459 if (nonViralName
.getGenusOrUninomial() != null) {
460 tags
.add(nonViralName
.getGenusOrUninomial());
462 if (nonViralName
.isSpecies() || nonViralName
.isInfraSpecific()){
463 tags
.add(nonViralName
.getSpecificEpithet());
467 if (nonViralName
.isInfraSpecific() && ! nonViralName
.getSpecificEpithet().equals(nonViralName
.getInfraSpecificEpithet())){
468 tags
.add(nonViralName
.getRank());
469 tags
.add(nonViralName
.getInfraSpecificEpithet());
472 if (nonViralName
.isInfraGeneric()){
473 //TODO choose right strategy or generic approach?
474 // --- strategy 1 ---
476 if (nonViralName
.getRank().isSpeciesAggregate()){
477 tags
.add(nonViralName
.getSpecificEpithet());
478 tags
.add(getSpeciesAggregateEpithet(nonViralName
));
480 tags
.add(nonViralName
.getRank());
481 tags
.add(nonViralName
.getInfraGenericEpithet());
483 // --- strategy 2 ---
484 // tags.add('('+nvn.getInfraGenericEpithet()+')');
486 Team authorTeam
= Team
.NewInstance();
487 authorTeam
.setProtectedTitleCache(true);
488 authorTeam
.setTitleCache(nonViralName
.getAuthorshipCache(), true);
489 tags
.add(authorTeam
);
491 // Name is an autonym. Rank and infraspecific epitheton follow the author
492 if (nonViralName
.isInfraSpecific() && nonViralName
.getSpecificEpithet().equals(nonViralName
.getInfraSpecificEpithet())){
493 tags
.add(nonViralName
.getRank());
494 tags
.add(nonViralName
.getInfraSpecificEpithet());
497 if(! "".equals(nonViralName
.getAppendedPhrase())&& (nonViralName
.getAppendedPhrase() != null)){
498 tags
.add(nonViralName
.getAppendedPhrase());
505 //***************************** PRIVATES ***************************************/
507 protected String
getRanklessNameCache(NonViralName nonViralName
){
509 result
= (result
+ (CdmUtils
.Nz(nonViralName
.getGenusOrUninomial()))).trim().replace("null", "");
510 result
+= " " + (CdmUtils
.Nz(nonViralName
.getSpecificEpithet())).trim();
511 result
+= " " + (CdmUtils
.Nz(nonViralName
.getInfraSpecificEpithet())).trim();
512 result
= result
.trim().replace("null", "");
513 //result += " (rankless)";
514 result
= addAppendedPhrase(result
, nonViralName
);
519 protected String
getGenusOrUninomialNameCache(NonViralName nonViralName
){
521 result
= getUninomialPart(nonViralName
);
522 result
= addAppendedPhrase(result
, nonViralName
).trim();
527 private String
getUninomialPart(NonViralName nonViralName
) {
529 result
= CdmUtils
.Nz(nonViralName
.getGenusOrUninomial()).trim();
530 if (nonViralName
.isMonomHybrid()){
531 result
= NonViralNameParserImplRegExBase
.hybridSign
+ result
;
536 protected String
getInfraGenusNameCache(NonViralName nonViralName
){
538 Rank rank
= nonViralName
.getRank();
539 if (rank
.isSpeciesAggregate()){
540 return getSpeciesAggregateCache(nonViralName
);
542 String infraGenericMarker
= "'unhandled infrageneric rank'";
545 infraGenericMarker
= rank
.getInfraGenericMarker();
546 } catch (UnknownCdmTypeException e
) {
547 infraGenericMarker
= "'unhandled infrageneric rank'";
550 result
= getUninomialPart(nonViralName
);
551 result
+= " " + infraGenericMarker
+ " " + (CdmUtils
.Nz(nonViralName
.getInfraGenericEpithet())).trim().replace("null", "");
552 result
= addAppendedPhrase(result
, nonViralName
).trim();
557 protected String
getSpeciesAggregateCache(NonViralName nonViralName
){
558 String result
= getGenusAndSpeciesPart(nonViralName
);
560 result
+= " " + getSpeciesAggregateEpithet(nonViralName
);
561 result
= addAppendedPhrase(result
, nonViralName
).trim();
565 private String
getSpeciesAggregateEpithet(NonViralName nonViralName
) {
568 marker
= nonViralName
.getRank().getInfraGenericMarker();
569 } catch (UnknownCdmTypeException e
) {
570 marker
= "'unknown aggregat type'";
575 protected String
getSpeciesNameCache(NonViralName nonViralName
){
576 String result
= getGenusAndSpeciesPart(nonViralName
);
577 result
= addAppendedPhrase(result
, nonViralName
).trim();
578 result
= result
.replace("\\s\\", " ");
583 protected String
getInfraSpeciesNameCache(NonViralName nonViralName
){
584 return getInfraSpeciesNameCache(nonViralName
, true);
587 protected String
getInfraSpeciesNameCache(NonViralName nonViralName
, boolean includeMarker
){
588 String result
= getGenusAndSpeciesPart(nonViralName
);
590 result
+= " " + (nonViralName
.getRank().getAbbreviation()).trim().replace("null", "");
592 String infrSpecEpi
= CdmUtils
.Nz(nonViralName
.getInfraSpecificEpithet());
593 if (nonViralName
.isTrinomHybrid()){
594 infrSpecEpi
= NonViralNameParserImplRegExBase
.hybridSign
+ infrSpecEpi
;
596 result
+= " " + (infrSpecEpi
).trim().replace("null", "");
597 result
= addAppendedPhrase(result
, nonViralName
).trim();
602 private String
getGenusAndSpeciesPart(NonViralName nonViralName
) {
605 result
= getUninomialPart(nonViralName
);
608 boolean hasInfraGenericEpi
= StringUtils
.isNotBlank(nonViralName
.getInfraGenericEpithet());
609 if (hasInfraGenericEpi
){
610 String infrGenEpi
= nonViralName
.getInfraGenericEpithet().trim();
611 if (nonViralName
.isBinomHybrid()){
612 infrGenEpi
= NonViralNameParserImplRegExBase
.hybridSign
+ infrGenEpi
;
614 result
+= " (" + infrGenEpi
+ ")";
617 String specEpi
= CdmUtils
.Nz(nonViralName
.getSpecificEpithet()).trim();
618 if (! hasInfraGenericEpi
&& nonViralName
.isBinomHybrid() ||
619 hasInfraGenericEpi
&& nonViralName
.isTrinomHybrid()){
620 specEpi
= NonViralNameParserImplRegExBase
.hybridSign
+ specEpi
;
622 result
+= " " + (specEpi
).replace("null", "");
627 protected String
addAppendedPhrase(String resultString
, NonViralName nonViralName
){
628 String appendedPhrase
= nonViralName
==null ?
null : nonViralName
.getAppendedPhrase();
629 if (resultString
== null){
630 return appendedPhrase
;
631 }else if(appendedPhrase
== null || "".equals(appendedPhrase
.trim())) {
633 }else if ("".equals(resultString
)){
634 return resultString
+ appendedPhrase
;
636 return resultString
+ " " + appendedPhrase
;
641 public String
getLastEpithet(T taxonNameBase
) {
642 Rank rank
= taxonNameBase
.getRank();
643 if(rank
.isGenus() || rank
.isSupraGeneric()) {
644 return taxonNameBase
.getGenusOrUninomial();
645 } else if(rank
.isInfraGeneric()) {
646 return taxonNameBase
.getInfraGenericEpithet();
647 } else if(rank
.isSpecies()) {
648 return taxonNameBase
.getSpecificEpithet();
650 return taxonNameBase
.getInfraSpecificEpithet();