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
.common
.UTF8
;
22 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
23 import eu
.etaxonomy
.cdm
.model
.agent
.INomenclaturalAuthor
;
24 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
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
.INonViralName
;
29 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationship
;
30 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationshipType
;
31 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatus
;
32 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatusType
;
33 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
34 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
35 import eu
.etaxonomy
.cdm
.model
.reference
.INomenclaturalReference
;
36 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
37 import eu
.etaxonomy
.cdm
.strategy
.cache
.HTMLTagRules
;
38 import eu
.etaxonomy
.cdm
.strategy
.cache
.TagEnum
;
39 import eu
.etaxonomy
.cdm
.strategy
.cache
.TaggedCacheHelper
;
40 import eu
.etaxonomy
.cdm
.strategy
.cache
.TaggedText
;
41 import eu
.etaxonomy
.cdm
.strategy
.exceptions
.UnknownCdmTypeException
;
42 import eu
.etaxonomy
.cdm
.strategy
.parser
.NonViralNameParserImplRegExBase
;
46 * This class is a default implementation for the INonViralNameCacheStrategy<T extends NonViralName>
48 * The method implements a cache strategy for botanical names so no method has to be overwritten by
49 * a subclass for botanic names.
50 * Where differing from this default botanic name strategy other subclasses should overwrite the
51 * existing methods, e.g. a CacheStrategy for zoological names should overwrite getAuthorAndExAuthor
54 public class NonViralNameDefaultCacheStrategy
<T
extends INonViralName
>
55 extends NameCacheStrategyBase
<T
>
56 implements INonViralNameCacheStrategy
<T
> {
57 private static final Logger logger
= Logger
.getLogger(NonViralNameDefaultCacheStrategy
.class);
58 private static final long serialVersionUID
= -6577757501563212669L;
60 final static UUID uuid
= UUID
.fromString("1cdda0d1-d5bc-480f-bf08-40a510a2f223");
62 protected String NameAuthorSeperator
= " ";
63 protected String BasionymStart
= "(";
64 protected String BasionymEnd
= ")";
65 protected String ExAuthorSeperator
= " ex ";
66 private static String NOTHO
= "notho";
67 protected CharSequence BasionymAuthorCombinationAuthorSeperator
= " ";
70 public UUID
getUuid(){
77 * @return NonViralNameDefaultCacheStrategy A new instance of NonViralNameDefaultCacheStrategy
79 public static NonViralNameDefaultCacheStrategy
NewInstance(){
80 return new NonViralNameDefaultCacheStrategy();
85 * @return NonViralNameDefaultCacheStrategy A new instance of NonViralNameDefaultCacheStrategy
87 public static <T
extends INonViralName
> NonViralNameDefaultCacheStrategy
<T
> NewInstance(Class
<T
> clazz
){
88 return new NonViralNameDefaultCacheStrategy
<T
>();
94 protected NonViralNameDefaultCacheStrategy(){
98 /* **************** GETTER / SETTER **************************************/
101 * String that separates the NameCache part from the AuthorCache part
104 public String
getNameAuthorSeperator() {
105 return NameAuthorSeperator
;
109 public void setNameAuthorSeperator(String nameAuthorSeperator
) {
110 NameAuthorSeperator
= nameAuthorSeperator
;
115 * String the basionym author part starts with e.g. '('.
116 * This should correspond with the {@link NonViralNameDefaultCacheStrategy#getBasionymEnd() basionymEnd} attribute
119 public String
getBasionymStart() {
120 return BasionymStart
;
124 public void setBasionymStart(String basionymStart
) {
125 BasionymStart
= basionymStart
;
130 * String the basionym author part ends with e.g. ')'.
131 * This should correspond with the {@link NonViralNameDefaultCacheStrategy#getBasionymStart() basionymStart} attribute
134 public String
getBasionymEnd() {
139 public void setBasionymEnd(String basionymEnd
) {
140 BasionymEnd
= basionymEnd
;
145 * String to separate ex author from author.
148 public String
getExAuthorSeperator() {
149 return ExAuthorSeperator
;
153 public void setExAuthorSeperator(String exAuthorSeperator
) {
154 ExAuthorSeperator
= exAuthorSeperator
;
159 * String that separates the basionym/original_combination author part from the combination author part
162 public CharSequence
getBasionymAuthorCombinationAuthorSeperator() {
163 return BasionymAuthorCombinationAuthorSeperator
;
167 public void setBasionymAuthorCombinationAuthorSeperator( CharSequence basionymAuthorCombinationAuthorSeperator
) {
168 BasionymAuthorCombinationAuthorSeperator
= basionymAuthorCombinationAuthorSeperator
;
172 //** *****************************************************************************************/
175 public String
getTitleCache(T nonViralName
) {
176 return getTitleCache(nonViralName
, null);
180 public String
getTitleCache(T nonViralName
, HTMLTagRules htmlTagRules
) {
181 List
<TaggedText
> tags
= getTaggedTitle(nonViralName
);
185 String result
= createString(tags
, htmlTagRules
);
191 public String
getFullTitleCache(T nonViralName
, HTMLTagRules htmlTagRules
) {
192 List
<TaggedText
> tags
= getTaggedFullTitle(nonViralName
);
196 String result
= createString(tags
, htmlTagRules
);
202 public String
getFullTitleCache(T nonViralName
) {
203 return getFullTitleCache(nonViralName
, null);
208 * Generates and returns the "name cache" (only scientific name without author teams and year).
209 * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy#getNameCache(eu.etaxonomy.cdm.model.name.TaxonNameBase)
212 public String
getNameCache(T nonViralName
) {
213 List
<TaggedText
> tags
= getTaggedName(nonViralName
);
217 String result
= createString(tags
);
223 // ******************* Authorship ******************************/
226 public String
getAuthorshipCache(T nonViralName
) {
227 if (nonViralName
== null){
231 if (nonViralName
.isProtectedAuthorshipCache() == true) {
232 return nonViralName
.getAuthorshipCache();
234 return getNonCacheAuthorshipCache(nonViralName
);
238 * Returns the authorshipcache string for the atomized authorship fields. Does not use the authorship field.
239 * @throws NullPointerException if nonViralName is null.
240 * @param nonViralName
243 protected String
getNonCacheAuthorshipCache(T nonViralName
){
245 INomenclaturalAuthor combinationAuthor
= nonViralName
.getCombinationAuthorship();
246 INomenclaturalAuthor exCombinationAuthor
= nonViralName
.getExCombinationAuthorship();
247 INomenclaturalAuthor basionymAuthor
= nonViralName
.getBasionymAuthorship();
248 INomenclaturalAuthor exBasionymAuthor
= nonViralName
.getExBasionymAuthorship();
249 String basionymPart
= "";
250 String authorPart
= "";
252 if (basionymAuthor
!= null || exBasionymAuthor
!= null){
253 basionymPart
= BasionymStart
+ getAuthorAndExAuthor(basionymAuthor
, exBasionymAuthor
) + BasionymEnd
;
255 if (combinationAuthor
!= null || exCombinationAuthor
!= null){
256 authorPart
= getAuthorAndExAuthor(combinationAuthor
, exCombinationAuthor
);
258 result
= CdmUtils
.concat(BasionymAuthorCombinationAuthorSeperator
, basionymPart
, authorPart
);
259 // if ("".equals(result)){
266 * Returns the AuthorCache part for a combination of an author and an ex author. This applies on combination authors
267 * as well as on basionym/orginal combination authors.
268 * @param author the author
269 * @param exAuthor the ex-author
272 protected String
getAuthorAndExAuthor(INomenclaturalAuthor author
, INomenclaturalAuthor exAuthor
){
274 String authorString
= "";
275 String exAuthorString
= "";
277 authorString
= CdmUtils
.Nz(author
.getNomenclaturalTitle());
279 if (exAuthor
!= null){
280 exAuthorString
= CdmUtils
.Nz(exAuthor
.getNomenclaturalTitle());
282 if (exAuthorString
.length() > 0 ){
283 exAuthorString
= exAuthorString
+ ExAuthorSeperator
;
285 result
= exAuthorString
+ authorString
;
291 * Checks if the given name should include the author in it's cached version.<BR>
292 * This is usually the case but not for <i>species aggregates</i>.
293 * @param nonViralName
296 protected boolean nameIncludesAuthorship(INonViralName nonViralName
){
297 Rank rank
= nonViralName
.getRank();
298 if (rank
!= null && rank
.isSpeciesAggregate()){
305 // ************* TAGGED NAME ***************************************/
308 public List
<TaggedText
> getTaggedFullTitle(T nonViralName
) {
309 List
<TaggedText
> tags
= new ArrayList
<>();
312 if (nonViralName
== null){
316 //protected full title cache
317 if (nonViralName
.isProtectedFullTitleCache()){
318 tags
.add(new TaggedText(TagEnum
.fullName
, nonViralName
.getFullTitleCache()));
323 // String titleCache = nonViralName.getTitleCache();
324 List
<TaggedText
> titleTags
= getTaggedTitle(nonViralName
);
325 tags
.addAll(titleTags
);
328 String microReference
= nonViralName
.getNomenclaturalMicroReference();
329 INomenclaturalReference ref
= nonViralName
.getNomenclaturalReference();
330 String referenceCache
= null;
332 Reference reference
= HibernateProxyHelper
.deproxy(ref
, Reference
.class);
333 referenceCache
= reference
.getNomenclaturalCitation(microReference
);
336 if (StringUtils
.isNotBlank(referenceCache
)){
337 if (! referenceCache
.trim().startsWith("in ")){
338 String refConcat
= ", ";
339 tags
.add(new TaggedText(TagEnum
.separator
, refConcat
));
341 tags
.add(new TaggedText(TagEnum
.reference
, referenceCache
));
344 addOriginalSpelling(tags
, nonViralName
);
346 //nomenclatural status
347 tags
.addAll(getNomStatusTags(nonViralName
, true, false));
354 * @param nonViralName
359 public List
<TaggedText
> getNomStatusTags(T nonViralName
, boolean includeSeparatorBefore
,
360 boolean includeSeparatorAfter
) {
361 Set
<NomenclaturalStatus
> ncStati
= nonViralName
.getStatus();
362 Iterator
<NomenclaturalStatus
> iterator
= ncStati
.iterator();
363 List
<TaggedText
> nomStatusTags
= new ArrayList
<TaggedText
>();
364 while (iterator
.hasNext()) {
365 NomenclaturalStatus ncStatus
= iterator
.next();
366 // since the NewInstance method of nomencatural status allows null as parameter
367 // we have to check for null values here
368 String nomStatusStr
= "not defined";
369 if(ncStatus
.getType() != null){
370 NomenclaturalStatusType statusType
= ncStatus
.getType();
371 Language lang
= Language
.LATIN();
372 Representation repr
= statusType
.getRepresentation(lang
);
374 nomStatusStr
= repr
.getAbbreviatedLabel();
376 String message
= "No latin representation available for nom. status. " + statusType
.getTitleCache();
377 logger
.warn(message
);
378 throw new IllegalStateException(message
);
380 }else if(StringUtils
.isNotBlank(ncStatus
.getRuleConsidered())){
381 nomStatusStr
= ncStatus
.getRuleConsidered();
383 String statusSeparator
= ", ";
384 if (includeSeparatorBefore
){
385 nomStatusTags
.add(new TaggedText(TagEnum
.separator
, statusSeparator
));
387 nomStatusTags
.add(new TaggedText(TagEnum
.nomStatus
, nomStatusStr
));
388 if (includeSeparatorAfter
){
389 nomStatusTags
.add(new TaggedText(TagEnum
.postSeparator
, ","));
392 return nomStatusTags
;
396 public List
<TaggedText
> getTaggedTitle(T nonViralName
) {
397 if (nonViralName
== null){
401 List
<TaggedText
> tags
= new ArrayList
<>();
403 //TODO how to handle protected fullTitleCache here?
405 if (nonViralName
.isProtectedTitleCache()){
406 //protected title cache
407 tags
.add(new TaggedText(TagEnum
.name
, nonViralName
.getTitleCache()));
409 }else if (nonViralName
.isHybridFormula()){
411 String hybridSeparator
= NonViralNameParserImplRegExBase
.hybridSign
;
412 boolean isFirst
= true;
413 List
<HybridRelationship
> rels
= nonViralName
.getOrderedChildRelationships();
414 for (HybridRelationship rel
: rels
){
416 tags
.add(new TaggedText(TagEnum
.hybridSign
, hybridSeparator
));
419 tags
.addAll(getTaggedTitle((T
)rel
.getParentName()));
422 }else if (nonViralName
.isAutonym()){
424 tags
.addAll(handleTaggedAutonym(nonViralName
));
426 // String nameCache = nonViralName.getNameCache(); //OLD: CdmUtils.Nz(getNameCache(nonViralName));
428 List
<TaggedText
> nameTags
= getTaggedName(nonViralName
);
429 tags
.addAll(nameTags
);
430 String authorCache
= getAuthorshipCache(nonViralName
);
431 if (StringUtils
.isNotBlank(authorCache
)){
432 tags
.add(new TaggedText(TagEnum
.authors
, authorCache
));
440 * Returns the tag list of the name part (without author and reference).
441 * @param nonViralName
445 public List
<TaggedText
> getTaggedName(T nonViralName
) {
446 if (nonViralName
== null){
449 List
<TaggedText
> tags
= new ArrayList
<>();
450 Rank rank
= nonViralName
.getRank();
452 if (nonViralName
.isProtectedNameCache()){
453 tags
.add(new TaggedText(TagEnum
.name
, nonViralName
.getNameCache()));
454 }else if (nonViralName
.isHybridFormula()){
456 String hybridSeparator
= NonViralNameParserImplRegExBase
.hybridSign
;
457 boolean isFirst
= true;
458 List
<HybridRelationship
> rels
= nonViralName
.getOrderedChildRelationships();
459 for (HybridRelationship rel
: rels
){
461 tags
.add(new TaggedText(TagEnum
.hybridSign
, hybridSeparator
));
464 tags
.addAll(getTaggedName((T
)rel
.getParentName()));
468 }else if (rank
== null){
469 tags
= getRanklessTaggedNameCache(nonViralName
);
470 // }else if (nonViralName.isInfragenericUnranked()){
471 // result = getUnrankedInfragenericNameCache(nonViralName);
472 }else if (rank
.isInfraSpecific()){
473 tags
= getInfraSpeciesTaggedNameCache(nonViralName
);
474 }else if (rank
.isSpecies() || isAggregateWithAuthorship(nonViralName
, rank
) ){ //exception see #4288
475 tags
= getSpeciesTaggedNameCache(nonViralName
);
476 }else if (rank
.isInfraGeneric()){
477 tags
= getInfraGenusTaggedNameCache(nonViralName
);
478 }else if (rank
.isGenus()){
479 tags
= getGenusOrUninomialTaggedNameCache(nonViralName
);
480 }else if (rank
.isSupraGeneric()){
481 tags
= getGenusOrUninomialTaggedNameCache(nonViralName
);
483 logger
.warn("Name Strategy for Name (UUID: " + nonViralName
.getUuid() + ") not yet implemented");
485 //TODO handle appended phrase here instead of different places, check first if this is true for all
495 //***************************** PRIVATES ***************************************/
498 private boolean isAggregateWithAuthorship(T nonViralName
, Rank rank
) {
502 return rank
.isSpeciesAggregate() && ( isNotBlank(nonViralName
.getAuthorshipCache()) || nonViralName
.getNomenclaturalReference() != null );
508 * Returns the tag list for an autonym taxon.
510 * @see NonViralName#isAutonym()
511 * @see BotanicalName#isAutonym()
512 * @param nonViralName
515 private List
<TaggedText
> handleTaggedAutonym(T nonViralName
) {
516 List
<TaggedText
> tags
= null;
517 if (nonViralName
.isInfraSpecific()){
519 tags
= getSpeciesTaggedNameCache(nonViralName
);
522 String authorCache
= getAuthorshipCache(nonViralName
);
523 if (StringUtils
.isNotBlank(authorCache
)){
524 tags
.add(new TaggedText(TagEnum
.authors
, authorCache
));
528 //infra species marker
529 if (nonViralName
.getRank() == null || !nonViralName
.getRank().isInfraSpecific()){
530 //TODO handle exception
531 logger
.warn("Rank for autonym does not exist or is not lower than species !!");
533 String infraSpeciesMarker
= nonViralName
.getRank().getAbbreviation();
534 if (nonViralName
.isTrinomHybrid()){
535 infraSpeciesMarker
= CdmUtils
.concat("", NOTHO
, infraSpeciesMarker
);
537 if (StringUtils
.isNotBlank(infraSpeciesMarker
)){
538 tags
.add(new TaggedText(TagEnum
.rank
, infraSpeciesMarker
));
543 String infraSpeciesPart
= CdmUtils
.Nz(nonViralName
.getInfraSpecificEpithet()).trim();
544 if (StringUtils
.isNotBlank(infraSpeciesPart
)){
545 tags
.add(new TaggedText(TagEnum
.name
, infraSpeciesPart
));
548 } else if (nonViralName
.isInfraGeneric()){
550 tags
=getGenusOrUninomialTaggedNameCache(nonViralName
);
553 //infra species marker
554 if (nonViralName
.getRank() == null || !nonViralName
.getRank().isInfraGeneric()){
555 //TODO handle exception
556 logger
.warn("Rank for autonym does not exist or is not lower than species !!");
558 Rank rank
= nonViralName
.getRank();
559 String infraGenericMarker
= rank
.getAbbreviation();
560 if (rank
.equals(Rank
.SECTION_BOTANY()) || rank
.equals(Rank
.SUBSECTION_BOTANY())){
561 infraGenericMarker
= infraGenericMarker
.replace("(bot.)", "");
563 if (StringUtils
.isNotBlank(infraGenericMarker
)){
564 tags
.add(new TaggedText(TagEnum
.rank
, infraGenericMarker
));
569 String infraGenericPart
= CdmUtils
.Nz(nonViralName
.getInfraGenericEpithet()).trim();
570 if (StringUtils
.isNotBlank(infraGenericPart
)){
571 tags
.add(new TaggedText(TagEnum
.name
, infraGenericPart
));
582 * Returns the tag list for rankless taxa.
583 * @param nonViralName
586 protected List
<TaggedText
> getRanklessTaggedNameCache(INonViralName nonViralName
){
587 List
<TaggedText
> tags
= getUninomialTaggedPart(nonViralName
);
588 String speciesEpi
= CdmUtils
.Nz(nonViralName
.getSpecificEpithet()).trim();
589 if (StringUtils
.isNotBlank(speciesEpi
)){
590 tags
.add(new TaggedText(TagEnum
.name
, speciesEpi
));
593 String infraSpeciesEpi
= CdmUtils
.Nz(nonViralName
.getInfraSpecificEpithet());
594 if (StringUtils
.isNotBlank(infraSpeciesEpi
)){
595 tags
.add(new TaggedText(TagEnum
.name
, infraSpeciesEpi
));
598 //result += " (rankless)";
599 addAppendedTaggedPhrase(tags
, nonViralName
);
604 * Returns the tag list for the first epithet (including a hybrid sign if required).
605 * @param nonViralName
608 private List
<TaggedText
> getUninomialTaggedPart(INonViralName nonViralName
) {
609 List
<TaggedText
> tags
= new ArrayList
<>();
611 if (nonViralName
.isMonomHybrid()){
612 addHybridPrefix(tags
);
615 String uninomial
= CdmUtils
.Nz(nonViralName
.getGenusOrUninomial()).trim();
616 if (StringUtils
.isNotBlank(uninomial
)){
617 tags
.add(new TaggedText(TagEnum
.name
, uninomial
));
624 * Returns the tag list for an genus or higher taxon.
626 * @param nonViralName
629 protected List
<TaggedText
> getGenusOrUninomialTaggedNameCache(INonViralName nonViralName
){
630 List
<TaggedText
> tags
= getUninomialTaggedPart(nonViralName
);
631 addAppendedTaggedPhrase(tags
, nonViralName
);
636 * Returns the tag list for an infrageneric taxon (including species aggregates).
638 * @see #getSpeciesAggregateTaggedCache(NonViralName)
639 * @param nonViralName
642 protected List
<TaggedText
> getInfraGenusTaggedNameCache(INonViralName nonViralName
){
643 Rank rank
= nonViralName
.getRank();
644 if (rank
!= null && rank
.isSpeciesAggregate() && isBlank(nonViralName
.getAuthorshipCache())){
645 return getSpeciesAggregateTaggedCache(nonViralName
);
649 List
<TaggedText
> tags
= getUninomialTaggedPart(nonViralName
);
652 String infraGenericMarker
;
655 infraGenericMarker
= rank
.getInfraGenericMarker();
656 if (rank
.equals(Rank
.SECTION_BOTANY()) || rank
.equals(Rank
.SUBSECTION_BOTANY())){
657 infraGenericMarker
= infraGenericMarker
.replace("(bot.)", "");
659 } catch (UnknownCdmTypeException e
) {
660 infraGenericMarker
= "'unhandled infrageneric rank'";
663 infraGenericMarker
= "'undefined infrageneric rank'";
665 String infraGenEpi
= CdmUtils
.Nz(nonViralName
.getInfraGenericEpithet()).trim();
666 if (nonViralName
.isBinomHybrid()){
667 infraGenericMarker
= CdmUtils
.concat("", NOTHO
, infraGenericMarker
);
670 addInfraGenericPart(nonViralName
, tags
, infraGenericMarker
, infraGenEpi
);
672 addAppendedTaggedPhrase(tags
, nonViralName
);
678 * Default implementation for the infrageneric part of a name.
679 * This is usually the infrageneric marker and the infrageneric epitheton. But may be
680 * implemented differently e.g. for zoological names the infrageneric epitheton
681 * may be surrounded by brackets and the marker left out.
682 * @param nonViralName
684 * @param infraGenericMarker
686 protected void addInfraGenericPart(
687 @SuppressWarnings("unused") INonViralName name
,
688 List
<TaggedText
> tags
,
689 String infraGenericMarker
,
690 String infraGenEpi
) {
692 tags
.add(new TaggedText(TagEnum
.rank
, infraGenericMarker
));
695 if (StringUtils
.isNotBlank(infraGenEpi
)){
696 tags
.add(new TaggedText(TagEnum
.name
, infraGenEpi
));
701 * Returns the tag list for a species aggregate (or similar) taxon.<BR>
702 * Possible ranks for a <i>species aggregate</i> are "aggr.", "species group", ...
703 * @param nonViralName
706 protected List
<TaggedText
> getSpeciesAggregateTaggedCache(INonViralName nonViralName
){
707 if (! isBlank(nonViralName
.getAuthorshipCache())){
708 List
<TaggedText
> result
= getSpeciesTaggedNameCache(nonViralName
);
713 List
<TaggedText
> tags
= getGenusAndSpeciesTaggedPart(nonViralName
);
715 addSpeciesAggregateTaggedEpithet(tags
, nonViralName
);
716 addAppendedTaggedPhrase(tags
, nonViralName
);
721 * Adds the aggregate tag to the tag list.
723 * @param nonViralName
725 private void addSpeciesAggregateTaggedEpithet(List
<TaggedText
> tags
, INonViralName nonViralName
) {
728 marker
= nonViralName
.getRank().getInfraGenericMarker();
729 } catch (UnknownCdmTypeException e
) {
730 marker
= "'unknown aggregat type'";
732 if (StringUtils
.isNotBlank(marker
)){
733 tags
.add(new TaggedText(TagEnum
.rank
, marker
));
739 * Returns the tag list for a species taxon.
740 * @param nonViralName
743 protected List
<TaggedText
> getSpeciesTaggedNameCache(INonViralName nonViralName
){
744 List
<TaggedText
> tags
= getGenusAndSpeciesTaggedPart(nonViralName
);
745 addAppendedTaggedPhrase(tags
, nonViralName
);
750 * Creates the tag list for an infraspecific taxon. In include is true the result will contain
751 * @param nonViralName
754 protected List
<TaggedText
> getInfraSpeciesTaggedNameCache(T nonViralName
){
755 return getInfraSpeciesTaggedNameCache(nonViralName
, true);
759 * Creates the tag list for an infraspecific taxon. If include is true the result will contain
760 * the infraspecific marker (e.g. "var.")
761 * @param nonViralName
762 * @param includeMarker
765 protected List
<TaggedText
> getInfraSpeciesTaggedNameCache(INonViralName nonViralName
, boolean includeMarker
){
766 List
<TaggedText
> tags
= getGenusAndSpeciesTaggedPart(nonViralName
);
767 if (includeMarker
|| nonViralName
.isTrinomHybrid()){
768 String marker
= (nonViralName
.getRank().getAbbreviation()).trim().replace("null", "");
769 if (nonViralName
.isTrinomHybrid()){
770 marker
= CdmUtils
.concat("", NOTHO
, marker
);
772 if (StringUtils
.isNotBlank(marker
)){
773 tags
.add(new TaggedText(TagEnum
.rank
, marker
));
777 String infrSpecEpi
= CdmUtils
.Nz(nonViralName
.getInfraSpecificEpithet());
779 infrSpecEpi
= infrSpecEpi
.trim().replace("null", "");
781 if (StringUtils
.isNotBlank(infrSpecEpi
)){
782 tags
.add(new TaggedText(TagEnum
.name
, infrSpecEpi
));
785 addAppendedTaggedPhrase(tags
, nonViralName
);
791 * Adds a tag for the hybrid sign and an empty separator to avoid trailing whitespaces.
794 private void addHybridPrefix(List
<TaggedText
> tags
) {
795 tags
.add(new TaggedText(TagEnum
.hybridSign
, NonViralNameParserImplRegExBase
.hybridSign
));
796 tags
.add(new TaggedText(TagEnum
.separator
, "")); //no whitespace separator
800 * Creates the tag list for the genus and species part.
801 * @param nonViralName
804 private List
<TaggedText
> getGenusAndSpeciesTaggedPart(INonViralName nonViralName
) {
806 List
<TaggedText
> tags
= getUninomialTaggedPart(nonViralName
);
809 boolean hasInfraGenericEpi
= StringUtils
.isNotBlank(nonViralName
.getInfraGenericEpithet());
810 if (hasInfraGenericEpi
){
811 String infrGenEpi
= nonViralName
.getInfraGenericEpithet().trim();
812 if (nonViralName
.isBinomHybrid()){
813 //maybe not correct but not really expected to happen
814 infrGenEpi
= UTF8
.HYBRID
+ infrGenEpi
;
816 infrGenEpi
= "(" + infrGenEpi
+ ")";
817 tags
.add(new TaggedText(TagEnum
.name
, infrGenEpi
));
821 String specEpi
= CdmUtils
.Nz(nonViralName
.getSpecificEpithet()).trim();
822 if (! hasInfraGenericEpi
&& nonViralName
.isBinomHybrid() ||
823 hasInfraGenericEpi
&& nonViralName
.isTrinomHybrid()){
824 addHybridPrefix(tags
);
826 if (StringUtils
.isNotBlank(specEpi
)){
827 tags
.add(new TaggedText(TagEnum
.name
, specEpi
));
832 protected void addOriginalSpelling(List
<TaggedText
> tags
, INonViralName nonViralName
){
833 String originalName
= getOriginalNameString(nonViralName
, tags
);
834 if (StringUtils
.isNotBlank(originalName
)){
835 tags
.add(new TaggedText(TagEnum
.name
, originalName
));
840 * Adds the tag for the appended phrase if an appended phrase exists
842 * @param nonViralName
844 protected void addAppendedTaggedPhrase(List
<TaggedText
> tags
, INonViralName nonViralName
){
845 String appendedPhrase
= nonViralName
==null ?
null : nonViralName
.getAppendedPhrase();
846 if (StringUtils
.isNotEmpty(appendedPhrase
)){
847 tags
.add(new TaggedText(TagEnum
.name
, appendedPhrase
));
851 private String
getOriginalNameString(INonViralName currentName
, List
<TaggedText
> originalNameTaggs
) {
852 List
<String
> originalNameStrings
= new ArrayList
<>(1);
853 currentName
= CdmBase
.deproxy(currentName
);
854 //Hibernate.initialize(currentName.getRelationsToThisName());
855 for (NameRelationship nameRel
: currentName
.getRelationsToThisName()){ //handle list, just in case we have strange data; this may result in strange looking results
856 NameRelationshipType type
= nameRel
.getType();
857 if(type
!= null && type
.equals(NameRelationshipType
.ORIGINAL_SPELLING())){
858 String originalNameString
;
859 TaxonNameBase
<?
,?
> originalName
= nameRel
.getFromName();
860 if (!originalName
.isNonViral()){
861 originalNameString
= originalName
.getTitleCache();
863 INonViralName originalNvName
= CdmBase
.deproxy(originalName
);
864 originalNameString
= makeOriginalNameString(currentName
, originalNvName
, originalNameTaggs
);
866 originalNameStrings
.add("(as " + UTF8
.QUOT_DBL_LEFT
+ originalNameString
+ UTF8
.QUOT_DBL_RIGHT
+ ")");
869 if (originalNameStrings
.size() > 0){
870 String result
= CdmUtils
.concat("", originalNameStrings
.toArray(new String
[originalNameStrings
.size()])) ;
878 private String
makeOriginalNameString(INonViralName currentName
, INonViralName originalName
,
879 List
<TaggedText
> currentNameTags
) {
880 //use cache if necessary
881 String cacheToUse
= null;
882 if (originalName
.isProtectedNameCache() && StringUtils
.isNotBlank(originalName
.getNameCache())){
883 cacheToUse
= originalName
.getNameCache();
884 }else if (originalName
.isProtectedTitleCache() && StringUtils
.isNotBlank(originalName
.getTitleCache())){
885 cacheToUse
= originalName
.getTitleCache();
886 }else if (originalName
.isProtectedFullTitleCache() && StringUtils
.isNotBlank(originalName
.getFullTitleCache())){
887 cacheToUse
= originalName
.getFullTitleCache();
889 if (cacheToUse
!= null){
893 //get originalNameParts array
894 String originalNameString
= originalName
.getNameCache();
895 if (originalNameString
== null){
896 originalNameString
= originalName
.getTitleCache();
898 if (originalNameString
== null){ //should not happen
899 originalNameString
= originalName
.getFullTitleCache();
901 String
[] originalNameSplit
= originalNameString
.split("\\s+");
903 //get current name parts
904 String currentNameString
= createString(currentNameTags
);
905 String
[] currentNameSplit
= currentNameString
.split("\\s+");
908 String result
= originalNameString
;
909 for (int i
= 0; i
< Math
.min(originalNameSplit
.length
, currentNameSplit
.length
); i
++){
910 if (originalNameSplit
[i
].equals(currentNameSplit
[i
])){
911 result
= result
.replaceFirst(originalNameSplit
[i
], "").trim();
915 // if (originalName.getGenusOrUninomial() != null && originalName.getGenusOrUninomial().equals(currentName.getGenusOrUninomial())){
923 public String
getLastEpithet(T taxonNameBase
) {
924 Rank rank
= taxonNameBase
.getRank();
925 if(rank
.isGenus() || rank
.isSupraGeneric()) {
926 return taxonNameBase
.getGenusOrUninomial();
927 } else if(rank
.isInfraGeneric()) {
928 return taxonNameBase
.getInfraGenericEpithet();
929 } else if(rank
.isSpecies()) {
930 return taxonNameBase
.getSpecificEpithet();
932 return taxonNameBase
.getInfraSpecificEpithet();
941 private String
createString(List
<TaggedText
> tags
) {
942 return TaggedCacheHelper
.createString(tags
);
947 * @param htmlTagRules
950 private String
createString(List
<TaggedText
> tags
, HTMLTagRules htmlTagRules
) {
951 return TaggedCacheHelper
.createString(tags
, htmlTagRules
);