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.
10 package eu
.etaxonomy
.cdm
.model
.name
;
13 import java
.beans
.PropertyChangeEvent
;
14 import java
.beans
.PropertyChangeListener
;
15 import java
.util
.ArrayList
;
16 import java
.util
.Collections
;
17 import java
.util
.HashSet
;
18 import java
.util
.List
;
22 import javax
.persistence
.Entity
;
23 import javax
.persistence
.FetchType
;
24 import javax
.persistence
.ManyToOne
;
25 import javax
.persistence
.OneToMany
;
26 import javax
.persistence
.Transient
;
27 import javax
.validation
.constraints
.NotNull
;
28 import javax
.validation
.constraints
.Pattern
;
29 import javax
.validation
.constraints
.Size
;
30 import javax
.xml
.bind
.annotation
.XmlAccessType
;
31 import javax
.xml
.bind
.annotation
.XmlAccessorType
;
32 import javax
.xml
.bind
.annotation
.XmlElement
;
33 import javax
.xml
.bind
.annotation
.XmlElementWrapper
;
34 import javax
.xml
.bind
.annotation
.XmlIDREF
;
35 import javax
.xml
.bind
.annotation
.XmlRootElement
;
36 import javax
.xml
.bind
.annotation
.XmlSchemaType
;
37 import javax
.xml
.bind
.annotation
.XmlType
;
39 import org
.apache
.log4j
.Logger
;
40 import org
.hibernate
.annotations
.Cascade
;
41 import org
.hibernate
.annotations
.CascadeType
;
42 import org
.hibernate
.envers
.Audited
;
43 import org
.hibernate
.search
.annotations
.Analyze
;
44 import org
.hibernate
.search
.annotations
.Analyzer
;
45 import org
.hibernate
.search
.annotations
.Field
;
46 import org
.hibernate
.search
.annotations
.Fields
;
47 import org
.hibernate
.search
.annotations
.Index
;
48 import org
.hibernate
.search
.annotations
.Indexed
;
49 import org
.hibernate
.search
.annotations
.IndexedEmbedded
;
50 import org
.hibernate
.search
.annotations
.Store
;
51 import org
.hibernate
.validator
.constraints
.NotEmpty
;
52 import org
.springframework
.beans
.factory
.annotation
.Configurable
;
54 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
55 import eu
.etaxonomy
.cdm
.model
.agent
.INomenclaturalAuthor
;
56 import eu
.etaxonomy
.cdm
.model
.agent
.TeamOrPersonBase
;
57 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
58 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
59 import eu
.etaxonomy
.cdm
.model
.reference
.INomenclaturalReference
;
60 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
61 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.CacheUpdate
;
62 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.INonViralNameCacheStrategy
;
63 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.NonViralNameDefaultCacheStrategy
;
64 import eu
.etaxonomy
.cdm
.strategy
.match
.Match
;
65 import eu
.etaxonomy
.cdm
.strategy
.match
.Match
.ReplaceMode
;
66 import eu
.etaxonomy
.cdm
.strategy
.match
.MatchMode
;
67 import eu
.etaxonomy
.cdm
.strategy
.merge
.Merge
;
68 import eu
.etaxonomy
.cdm
.strategy
.merge
.MergeMode
;
69 import eu
.etaxonomy
.cdm
.validation
.Level2
;
70 import eu
.etaxonomy
.cdm
.validation
.Level3
;
71 import eu
.etaxonomy
.cdm
.validation
.annotation
.CorrectEpithetsForRank
;
72 import eu
.etaxonomy
.cdm
.validation
.annotation
.MustHaveAuthority
;
73 import eu
.etaxonomy
.cdm
.validation
.annotation
.NoDuplicateNames
;
74 import eu
.etaxonomy
.cdm
.validation
.annotation
.NullOrNotEmpty
;
77 * The taxon name class for all non viral taxa. Parenthetical authorship is derived
78 * from basionym relationship. The scientific name including author strings and
79 * maybe year can be stored as a string in the inherited {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache} attribute.
80 * The year itself is an information obtained from the {@link eu.etaxonomy.cdm.model.reference.Reference#getYear() nomenclatural reference}.
81 * The scientific name string without author strings and year can be stored in the {@link #getNameCache() nameCache} attribute.
83 * This class corresponds partially to: <ul>
84 * <li> TaxonName according to the TDWG ontology
85 * <li> ScientificName and CanonicalName according to the TCS
86 * <li> ScientificName according to the ABCD schema
91 * @created 08-Nov-2007 13:06:39
93 @XmlAccessorType(XmlAccessType
.FIELD
)
94 @XmlType(name
= "NonViralName", propOrder
= {
97 "infraGenericEpithet",
99 "infraSpecificEpithet",
100 "combinationAuthorTeam",
101 "exCombinationAuthorTeam",
102 "basionymAuthorTeam",
103 "exBasionymAuthorTeam",
105 "protectedAuthorshipCache",
106 "protectedNameCache",
107 "hybridParentRelations",
108 "hybridChildRelations",
114 @XmlRootElement(name
= "NonViralName")
116 @Indexed(index
= "eu.etaxonomy.cdm.model.name.TaxonNameBase")
119 @CorrectEpithetsForRank(groups
= Level2
.class)
120 @MustHaveAuthority(groups
= Level2
.class)
121 @NoDuplicateNames(groups
= Level3
.class)
122 public class NonViralName
<T
extends NonViralName
> extends TaxonNameBase
<T
, INonViralNameCacheStrategy
> implements Cloneable
{
123 private static final long serialVersionUID
= 4441110073881088033L;
124 private static final Logger logger
= Logger
.getLogger(NonViralName
.class);
126 @XmlElement(name
= "NameCache")
128 @Field(name
= "nameCache_tokenized"),
129 @Field(store
= Store
.YES
, index
= Index
.YES
, analyze
= Analyze
.YES
)
131 @Analyzer (impl
= org
.apache
.lucene
.analysis
.KeywordAnalyzer
.class)
132 @Match(value
=MatchMode
.CACHE
, cacheReplaceMode
=ReplaceMode
.DEFINED
,
133 cacheReplacedProperties
={"genusOrUninomial", "infraGenericEpithet", "specificEpithet", "infraSpecificEpithet"} )
134 @NotEmpty(groups
= Level2
.class) // implicitly NotNull
136 private String nameCache
;
138 @XmlElement(name
= "ProtectedNameCache")
139 @CacheUpdate(value
="nameCache")
140 protected boolean protectedNameCache
;
142 @XmlElement(name
= "GenusOrUninomial")
143 @Field(analyze
= Analyze
.YES
,indexNullAs
=Field
.DEFAULT_NULL_TOKEN
)
144 @Match(MatchMode
.EQUAL_REQUIRED
)
145 @CacheUpdate("nameCache")
147 @Pattern(regexp
= "[A-Z][a-z\\u00E4\\u00EB\\u00EF\\u00F6\\u00FC\\-]+", groups
=Level2
.class, message
="{eu.etaxonomy.cdm.model.name.NonViralName.allowedCharactersForUninomial.message}")
149 @NotEmpty(groups
= Level3
.class) //TODO shouldn't this be only @NotNull as @NullOrNotEmpty already checks for not being empty.
150 private String genusOrUninomial
;
152 @XmlElement(name
= "InfraGenericEpithet")
153 @Field(analyze
= Analyze
.YES
,indexNullAs
=Field
.DEFAULT_NULL_TOKEN
)
154 @CacheUpdate("nameCache")
158 @Pattern(regexp
= "[a-z\\u00E4\\u00EB\\u00EF\\u00F6\\u00FC\\-]+", groups
=Level2
.class,message
="{eu.etaxonomy.cdm.model.name.NonViralName.allowedCharactersForEpithet.message}")
159 private String infraGenericEpithet
;
161 @XmlElement(name
= "SpecificEpithet")
162 @Field(analyze
= Analyze
.YES
,indexNullAs
=Field
.DEFAULT_NULL_TOKEN
)
163 @CacheUpdate("nameCache")
167 @Pattern(regexp
= "[a-z\\u00E4\\u00EB\\u00EF\\u00F6\\u00FC\\-]+", groups
=Level2
.class, message
= "{eu.etaxonomy.cdm.model.name.NonViralName.allowedCharactersForEpithet.message}")
168 private String specificEpithet
;
170 @XmlElement(name
= "InfraSpecificEpithet")
171 @Field(analyze
= Analyze
.YES
,indexNullAs
=Field
.DEFAULT_NULL_TOKEN
)
172 @CacheUpdate("nameCache")
176 @Pattern(regexp
= "[a-z\\u00E4\\u00EB\\u00EF\\u00F6\\u00FC\\-]+", groups
=Level2
.class, message
= "{eu.etaxonomy.cdm.model.name.NonViralName.allowedCharactersForEpithet.message}")
177 private String infraSpecificEpithet
;
179 @XmlElement(name
= "CombinationAuthorTeam", type
= TeamOrPersonBase
.class)
181 @XmlSchemaType(name
= "IDREF")
182 @ManyToOne(fetch
= FetchType
.LAZY
)
183 // @Target(TeamOrPersonBase.class)
184 @Cascade(CascadeType
.SAVE_UPDATE
)
185 @CacheUpdate("authorshipCache")
187 private TeamOrPersonBase
<?
> combinationAuthorTeam
;
189 @XmlElement(name
= "ExCombinationAuthorTeam", type
= TeamOrPersonBase
.class)
191 @XmlSchemaType(name
= "IDREF")
192 @ManyToOne(fetch
= FetchType
.LAZY
)
193 // @Target(TeamOrPersonBase.class)
194 @Cascade(CascadeType
.SAVE_UPDATE
)
195 @CacheUpdate("authorshipCache")
197 private TeamOrPersonBase
<?
> exCombinationAuthorTeam
;
199 @XmlElement(name
= "BasionymAuthorTeam", type
= TeamOrPersonBase
.class)
201 @XmlSchemaType(name
= "IDREF")
202 @ManyToOne(fetch
= FetchType
.LAZY
)
203 // @Target(TeamOrPersonBase.class)
204 @Cascade(CascadeType
.SAVE_UPDATE
)
205 @CacheUpdate("authorshipCache")
207 private TeamOrPersonBase
<?
> basionymAuthorTeam
;
209 @XmlElement(name
= "ExBasionymAuthorTeam", type
= TeamOrPersonBase
.class)
211 @XmlSchemaType(name
= "IDREF")
212 @ManyToOne(fetch
= FetchType
.LAZY
)
213 // @Target(TeamOrPersonBase.class)
214 @Cascade(CascadeType
.SAVE_UPDATE
)
215 @CacheUpdate("authorshipCache")
217 private TeamOrPersonBase
<?
> exBasionymAuthorTeam
;
219 @XmlElement(name
= "AuthorshipCache")
221 @Field(name
= "authorshipCache_tokenized"),
222 @Field(analyze
= Analyze
.NO
)
224 @Match(value
=MatchMode
.CACHE
, cacheReplaceMode
=ReplaceMode
.DEFINED
,
225 cacheReplacedProperties
={"combinationAuthorTeam", "basionymAuthorTeam", "exCombinationAuthorTeam", "exBasionymAuthorTeam"} )
229 @Pattern(regexp
= "[A-Za-z0-9 \\u00E4\\u00EB\\u00EF\\u00F6\\u00FC\\-\\&\\,\\(\\)\\.]+", groups
=Level2
.class, message
= "{eu.etaxonomy.cdm.model.name.NonViralName.allowedCharactersForAuthority.message}")
230 private String authorshipCache
;
232 @XmlElement(name
= "ProtectedAuthorshipCache")
233 @CacheUpdate("authorshipCache")
234 protected boolean protectedAuthorshipCache
;
236 @XmlElementWrapper(name
= "HybridRelationsFromThisName")
237 @XmlElement(name
= "HybridRelationsFromThisName")
238 @OneToMany(mappedBy
="relatedFrom", fetch
= FetchType
.LAZY
, orphanRemoval
=true)
239 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
})
240 @Merge(MergeMode
.RELATION
)
242 private Set
<HybridRelationship
> hybridParentRelations
= new HashSet
<HybridRelationship
>();
244 @XmlElementWrapper(name
= "HybridRelationsToThisName")
245 @XmlElement(name
= "HybridRelationsToThisName")
246 @OneToMany(mappedBy
="relatedTo", fetch
= FetchType
.LAZY
, orphanRemoval
=true) //a hybrid relation can be deleted automatically if the child is deleted.
247 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
, CascadeType
.DELETE
})
248 @Merge(MergeMode
.RELATION
)
250 private Set
<HybridRelationship
> hybridChildRelations
= new HashSet
<HybridRelationship
>();
252 //if set: this name is a hybrid formula (a hybrid that does not have an own name) and no other hybrid flags may be set. A
253 //hybrid name may not have either an authorteam nor other name components.
254 @XmlElement(name
="IsHybridFormula")
255 @CacheUpdate("nameCache")
256 private boolean hybridFormula
= false;
258 @XmlElement(name
="IsMonomHybrid")
259 @CacheUpdate("nameCache")
260 private boolean monomHybrid
= false;
262 @XmlElement(name
="IsBinomHybrid")
263 @CacheUpdate("nameCache")
264 private boolean binomHybrid
= false;
266 @XmlElement(name
="IsTrinomHybrid")
267 @CacheUpdate("nameCache")
268 private boolean trinomHybrid
= false;
271 * Creates a new non viral taxon name instance
272 * only containing its {@link common.Rank rank} and
273 * the {@link eu.etaxonomy.cdm.strategy.cache.name.NonViralNameDefaultCacheStrategy default cache strategy}.
275 * @param rank the rank to be assigned to <i>this</i> non viral taxon name
276 * @see #NewInstance(Rank, HomotypicalGroup)
277 * @see #NonViralName(Rank, HomotypicalGroup)
278 * @see #NonViralName()
279 * @see #NonViralName(Rank, String, String, String, String, TeamOrPersonBase, Reference, String, HomotypicalGroup)
280 * @see eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy
281 * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy
282 * @see eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy
284 public static NonViralName
NewInstance(Rank rank
){
285 return new NonViralName(rank
, null);
289 * Creates a new non viral taxon name instance
290 * only containing its {@link common.Rank rank},
291 * its {@link HomotypicalGroup homotypical group} and
292 * the {@link eu.etaxonomy.cdm.strategy.cache.name.NonViralNameDefaultCacheStrategy default cache strategy}.
293 * The new non viral taxon name instance will be also added to the set of
294 * non viral taxon names belonging to this homotypical group.
296 * @param rank the rank to be assigned to <i>this</i> non viral taxon name
297 * @param homotypicalGroup the homotypical group to which <i>this</i> non viral taxon name belongs
298 * @see #NewInstance(Rank)
299 * @see #NonViralName(Rank, HomotypicalGroup)
300 * @see #NonViralName()
301 * @see #NonViralName(Rank, String, String, String, String, TeamOrPersonBase, Reference, String, HomotypicalGroup)
302 * @see eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy
303 * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy
304 * @see eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy
306 public static NonViralName
NewInstance(Rank rank
, HomotypicalGroup homotypicalGroup
){
307 return new NonViralName(rank
, homotypicalGroup
);
310 // ************************** CONSTRUCTORS *************/
312 //needed by hibernate
314 * Class constructor: creates a new non viral taxon name instance
315 * only containing the {@link eu.etaxonomy.cdm.strategy.cache.name.NonViralNameDefaultCacheStrategy default cache strategy}.
317 * @see #NonViralName(Rank, HomotypicalGroup)
318 * @see #NonViralName(Rank, String, String, String, String, TeamOrPersonBase, Reference, String, HomotypicalGroup)
319 * @see eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy
320 * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy
321 * @see eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy
323 protected NonViralName(){
325 setNameCacheStrategy();
329 * Class constructor: creates a new non viral taxon name instance
330 * only containing its {@link Rank rank},
331 * its {@link HomotypicalGroup homotypical group} and
332 * the {@link eu.etaxonomy.cdm.strategy.cache.name.NonViralNameDefaultCacheStrategy default cache strategy}.
333 * The new non viral taxon name instance will be also added to the set of
334 * non viral taxon names belonging to this homotypical group.
336 * @param rank the rank to be assigned to <i>this</i> non viral taxon name
337 * @param homotypicalGroup the homotypical group to which <i>this</i> non viral taxon name belongs
338 * @see #NonViralName()
339 * @see #NonViralName(Rank, String, String, String, String, TeamOrPersonBase, Reference, String, HomotypicalGroup)
340 * @see #NewInstance(Rank, HomotypicalGroup)
341 * @see eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy
342 * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy
343 * @see eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy
345 protected NonViralName(Rank rank
, HomotypicalGroup homotypicalGroup
) {
346 super(rank
, homotypicalGroup
);
347 setNameCacheStrategy();
350 * Class constructor: creates a new non viral taxon name instance
351 * containing its {@link Rank rank},
352 * its {@link HomotypicalGroup homotypical group},
353 * its scientific name components, its {@link eu.etaxonomy.cdm.model.agent.TeamOrPersonBase author(team)},
354 * its {@link eu.etaxonomy.cdm.model.reference.Reference nomenclatural reference} and
355 * the {@link eu.etaxonomy.cdm.strategy.cache.name.NonViralNameDefaultCacheStrategy default cache strategy}.
356 * The new non viral taxon name instance will be also added to the set of
357 * non viral taxon names belonging to this homotypical group.
359 * @param rank the rank to be assigned to <i>this</i> non viral taxon name
360 * @param genusOrUninomial the string for <i>this</i> non viral taxon name
361 * if its rank is genus or higher or for the genus part
362 * if its rank is lower than genus
363 * @param infraGenericEpithet the string for the first epithet of
364 * <i>this</i> non viral taxon name if its rank is lower than genus
365 * and higher than species aggregate
366 * @param specificEpithet the string for the first epithet of
367 * <i>this</i> non viral taxon name if its rank is species aggregate or lower
368 * @param infraSpecificEpithet the string for the second epithet of
369 * <i>this</i> non viral taxon name if its rank is lower than species
370 * @param combinationAuthorTeam the author or the team who published <i>this</i> non viral taxon name
371 * @param nomenclaturalReference the nomenclatural reference where <i>this</i> non viral taxon name was published
372 * @param nomenclMicroRef the string with the details for precise location within the nomenclatural reference
373 * @param homotypicalGroup the homotypical group to which <i>this</i> non viral taxon name belongs
374 * @see #NonViralName()
375 * @see #NonViralName(Rank, HomotypicalGroup)
376 * @see #NewInstance(Rank, HomotypicalGroup)
377 * @see eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy
378 * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy
379 * @see eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy
381 protected NonViralName(Rank rank
, String genusOrUninomial
, String infraGenericEpithet
, String specificEpithet
, String infraSpecificEpithet
, TeamOrPersonBase combinationAuthorTeam
, INomenclaturalReference nomenclaturalReference
, String nomenclMicroRef
, HomotypicalGroup homotypicalGroup
) {
382 super(rank
, homotypicalGroup
);
383 setNameCacheStrategy();
384 setGenusOrUninomial(genusOrUninomial
);
385 setInfraGenericEpithet (infraGenericEpithet
);
386 setSpecificEpithet(specificEpithet
);
387 setInfraSpecificEpithet(infraSpecificEpithet
);
388 setCombinationAuthorTeam(combinationAuthorTeam
);
389 setNomenclaturalReference(nomenclaturalReference
);
390 this.setNomenclaturalMicroReference(nomenclMicroRef
);
395 //**************************** METHODS **************************************/
398 private void setNameCacheStrategy(){
399 if (getClass() == NonViralName
.class){
400 this.cacheStrategy
= NonViralNameDefaultCacheStrategy
.NewInstance();
405 protected void initListener(){
406 PropertyChangeListener listener
= new PropertyChangeListener() {
408 public void propertyChange(PropertyChangeEvent e
) {
409 boolean protectedByLowerCache
= false;
411 if (fieldHasCacheUpdateProperty(e
.getPropertyName(), "authorshipCache")){
412 if (protectedAuthorshipCache
){
413 protectedByLowerCache
= true;
415 authorshipCache
= null;
420 if (fieldHasCacheUpdateProperty(e
.getPropertyName(), "nameCache")){
421 if (protectedNameCache
){
422 protectedByLowerCache
= true;
428 if (! fieldHasNoUpdateProperty(e
.getPropertyName(), "titleCache")){
429 if (isProtectedTitleCache()|| protectedByLowerCache
== true ){
430 protectedByLowerCache
= true;
436 if (! fieldHasNoUpdateProperty(e
.getPropertyName(), "fullTitleCache")){
437 if (isProtectedFullTitleCache()|| protectedByLowerCache
== true ){
438 protectedByLowerCache
= true;
440 fullTitleCache
= null;
445 addPropertyChangeListener(listener
); //didn't use this.addXXX to make lsid.AssemblerTest run in cdmlib-remote
448 private static Map
<String
, java
.lang
.reflect
.Field
> allFields
= null;
450 protected Map
<String
, java
.lang
.reflect
.Field
> getAllFields(){
451 if (allFields
== null){
452 allFields
= CdmUtils
.getAllFields(this.getClass(), CdmBase
.class, false, false, false, true);
458 * @param propertyName
462 private boolean fieldHasCacheUpdateProperty(String propertyName
, String cacheName
) {
463 java
.lang
.reflect
.Field field
;
465 field
= getAllFields().get(propertyName
);
467 CacheUpdate updateAnnotation
= field
.getAnnotation(CacheUpdate
.class);
468 if (updateAnnotation
!= null){
469 for (String value
: updateAnnotation
.value()){
470 if (cacheName
.equals(value
)){
477 } catch (SecurityException e1
) {
482 private boolean fieldHasNoUpdateProperty(String propertyName
, String cacheName
) {
483 java
.lang
.reflect
.Field field
;
484 //do not update fields with the same name
485 if (cacheName
.equals(propertyName
)){
488 //evaluate annotation
490 field
= getAllFields().get(propertyName
);
492 CacheUpdate updateAnnotation
= field
.getAnnotation(CacheUpdate
.class);
493 if (updateAnnotation
!= null){
494 for (String value
: updateAnnotation
.noUpdate()){
495 if (cacheName
.equals(value
)){
502 } catch (SecurityException e1
) {
509 * Returns the {@link eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor author (team)} that published <i>this</i> non viral
512 * @return the nomenclatural author (team) of <i>this</i> non viral taxon name
513 * @see eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor
514 * @see eu.etaxonomy.cdm.model.agent.TeamOrPersonBase#getNomenclaturalTitle()
516 public TeamOrPersonBase
<?
> getCombinationAuthorTeam(){
517 return this.combinationAuthorTeam
;
521 * @see #getCombinationAuthorTeam()
523 public void setCombinationAuthorTeam(TeamOrPersonBase
<?
> combinationAuthorTeam
){
524 this.combinationAuthorTeam
= combinationAuthorTeam
;
528 * Returns the {@link eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor author (team)} that contributed to
529 * the publication of <i>this</i> non viral taxon name as generally stated by
530 * the {@link #getCombinationAuthorTeam() combination author (team)} itself.<BR>
531 * An ex-author(-team) is an author(-team) to whom a taxon name was ascribed
532 * although it is not the author(-team) of a valid publication (for instance
533 * without the validating description or diagnosis in case of a name for a
534 * new taxon). The name of this ascribed authorship, followed by "ex", may
535 * be inserted before the name(s) of the publishing author(s) of the validly
536 * published name:<BR>
537 * <i>Lilium tianschanicum</i> was described by Grubov (1977) as a new species and
538 * its name was ascribed to Ivanova; since there is no indication that
539 * Ivanova provided the validating description, the name may be cited as
540 * <i>Lilium tianschanicum</i> N. A. Ivanova ex Grubov or <i>Lilium tianschanicum</i> Grubov.
542 * The presence of an author (team) of <i>this</i> non viral taxon name is a
543 * condition for the existence of an ex author (team) for <i>this</i> same name.
545 * @return the nomenclatural ex author (team) of <i>this</i> non viral taxon name
546 * @see #getCombinationAuthorTeam()
547 * @see eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor
548 * @see eu.etaxonomy.cdm.model.agent.TeamOrPersonBase#getNomenclaturalTitle()
550 public TeamOrPersonBase
<?
> getExCombinationAuthorTeam(){
551 return this.exCombinationAuthorTeam
;
555 * @see #getExCombinationAuthorTeam()
557 public void setExCombinationAuthorTeam(TeamOrPersonBase
<?
> exCombinationAuthorTeam
){
558 this.exCombinationAuthorTeam
= exCombinationAuthorTeam
;
562 * Returns the {@link eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor author (team)} that published the original combination
563 * on which <i>this</i> non viral taxon name is nomenclaturally based. Such an
564 * author (team) can only exist if <i>this</i> non viral taxon name is a new
565 * combination due to a taxonomical revision.
567 * @return the nomenclatural basionym author (team) of <i>this</i> non viral taxon name
568 * @see #getCombinationAuthorTeam()
569 * @see eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor
570 * @see eu.etaxonomy.cdm.model.agent.TeamOrPersonBase#getNomenclaturalTitle()
572 public TeamOrPersonBase
<?
> getBasionymAuthorTeam(){
573 return basionymAuthorTeam
;
577 * @see #getBasionymAuthorTeam()
579 public void setBasionymAuthorTeam(TeamOrPersonBase
<?
> basionymAuthorTeam
) {
580 this.basionymAuthorTeam
= basionymAuthorTeam
;
584 * Returns the {@link eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor author (team)} that contributed to
585 * the publication of the original combination <i>this</i> non viral taxon name is
586 * based on. This should have been generally stated by
587 * the {@link #getBasionymAuthorTeam() basionym author (team)} itself.
588 * The presence of a basionym author (team) of <i>this</i> non viral taxon name is a
589 * condition for the existence of an ex basionym author (team)
590 * for <i>this</i> same name.
592 * @return the nomenclatural ex basionym author (team) of <i>this</i> non viral taxon name
593 * @see #getBasionymAuthorTeam()
594 * @see #getExCombinationAuthorTeam()
595 * @see #getCombinationAuthorTeam()
596 * @see eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor
597 * @see eu.etaxonomy.cdm.model.agent.TeamOrPersonBase#getNomenclaturalTitle()
599 public TeamOrPersonBase
<?
> getExBasionymAuthorTeam(){
600 return exBasionymAuthorTeam
;
604 * @see #getExBasionymAuthorTeam()
606 public void setExBasionymAuthorTeam(TeamOrPersonBase
<?
> exBasionymAuthorTeam
) {
607 this.exBasionymAuthorTeam
= exBasionymAuthorTeam
;
610 * Returns either the scientific name string (without authorship) for <i>this</i>
611 * non viral taxon name if its rank is genus or higher (monomial) or the string for
612 * the genus part of it if its {@link Rank rank} is lower than genus (bi- or trinomial).
613 * Genus or uninomial strings begin with an upper case letter.
615 * @return the string containing the suprageneric name, the genus name or the genus part of <i>this</i> non viral taxon name
616 * @see #getNameCache()
618 public String
getGenusOrUninomial() {
619 return genusOrUninomial
;
623 * @see #getGenusOrUninomial()
625 public void setGenusOrUninomial(String genusOrUninomial
) {
626 this.genusOrUninomial
= genusOrUninomial
;
630 * Returns the genus subdivision epithet string (infrageneric part) for
631 * <i>this</i> non viral taxon name if its {@link Rank rank} is infrageneric (lower than genus and
632 * higher than species aggregate: binomial). Genus subdivision epithet
633 * strings begin with an upper case letter.
635 * @return the string containing the infrageneric part of <i>this</i> non viral taxon name
636 * @see #getNameCache()
638 public String
getInfraGenericEpithet(){
639 return this.infraGenericEpithet
;
643 * @see #getInfraGenericEpithet()
645 public void setInfraGenericEpithet(String infraGenericEpithet
){
646 this.infraGenericEpithet
= infraGenericEpithet
;
650 * Returns the species epithet string for <i>this</i> non viral taxon name if its {@link Rank rank} is
651 * species aggregate or lower (bi- or trinomial). Species epithet strings
652 * begin with a lower case letter.
654 * @return the string containing the species epithet of <i>this</i> non viral taxon name
655 * @see #getNameCache()
657 public String
getSpecificEpithet(){
658 return this.specificEpithet
;
662 * @see #getSpecificEpithet()
664 public void setSpecificEpithet(String specificEpithet
){
665 this.specificEpithet
= specificEpithet
;
669 * Returns the species subdivision epithet string (infraspecific part) for
670 * <i>this</i> non viral taxon name if its {@link Rank rank} is infraspecific
671 * (lower than species: trinomial). Species subdivision epithet strings
672 * begin with a lower case letter.
674 * @return the string containing the infraspecific part of <i>this</i> non viral taxon name
675 * @see #getNameCache()
677 public String
getInfraSpecificEpithet(){
678 return this.infraSpecificEpithet
;
682 * @see #getInfraSpecificEpithet()
684 public void setInfraSpecificEpithet(String infraSpecificEpithet
){
685 this.infraSpecificEpithet
= infraSpecificEpithet
;
689 * Generates and returns the string with the scientific name of <i>this</i>
690 * non viral taxon name including author strings and maybe year according to
691 * the strategy defined in
692 * {@link eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy INonViralNameCacheStrategy}.
693 * This string may be stored in the inherited
694 * {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache} attribute.
695 * This method overrides the generic and inherited
696 * TaxonNameBase#generateTitle() method.
698 * @return the string with the composed name of <i>this</i> non viral taxon name with authorship (and maybe year)
699 * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle()
700 * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache()
701 * @see TaxonNameBase#generateTitle()
704 // public String generateTitle(){
705 // if (cacheStrategy == null){
706 // logger.warn("No CacheStrategy defined for nonViralName: " + this.getUuid());
709 // return cacheStrategy.getTitleCache(this);
714 public String
generateFullTitle(){
715 if (cacheStrategy
== null){
716 logger
.warn("No CacheStrategy defined for nonViralName: " + this.getUuid());
719 return cacheStrategy
.getFullTitleCache(this);
724 * Generates the composed name string of <i>this</i> non viral taxon name without author
725 * strings or year according to the strategy defined in
726 * {@link eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy INonViralNameCacheStrategy}.
727 * The result might be stored in {@link #getNameCache() nameCache} if the
728 * flag {@link #isProtectedNameCache() protectedNameCache} is not set.
730 * @return the string with the composed name of <i>this</i> non viral taxon name without authors or year
731 * @see #getNameCache()
733 protected String
generateNameCache(){
734 if (cacheStrategy
== null){
735 logger
.warn("No CacheStrategy defined for taxonName: " + this.toString());
738 return cacheStrategy
.getNameCache(this);
743 * Returns or generates the nameCache (scientific name
744 * without author strings and year) string for <i>this</i> non viral taxon name. If the
745 * {@link #isProtectedNameCache() protectedNameCache} flag is not set (False)
746 * the string will be generated according to a defined strategy,
747 * otherwise the value of the actual nameCache string will be returned.
749 * @return the string which identifies <i>this</i> non viral taxon name (without authors or year)
750 * @see #generateNameCache()
753 public String
getNameCache() {
754 if (protectedNameCache
){
755 return this.nameCache
;
757 // is title dirty, i.e. equal NULL?
758 if (nameCache
== null){
759 this.nameCache
= generateNameCache();
765 * Assigns a nameCache string to <i>this</i> non viral taxon name and protects it from being overwritten.
766 * Sets the protectedNameCache flag to <code>true</code>.
768 * @param nameCache the string which identifies <i>this</i> non viral taxon name (without authors or year)
769 * @see #getNameCache()
771 public void setNameCache(String nameCache
){
772 setNameCache(nameCache
, true);
776 * Assigns a nameCache string to <i>this</i> non viral taxon name and protects it from being overwritten.
777 * Sets the protectedNameCache flag to <code>true</code>.
779 * @param nameCache the string which identifies <i>this</i> non viral taxon name (without authors or year)
780 * @param protectedNameCache if true teh protectedNameCache is set to <code>true</code> or otherwise set to
782 * @see #getNameCache()
784 public void setNameCache(String nameCache
, boolean protectedNameCache
){
785 this.nameCache
= nameCache
;
786 this.setProtectedNameCache(protectedNameCache
);
790 * Returns the boolean value of the flag intended to protect (true)
791 * or not (false) the {@link #getNameCache() nameCache} (scientific name without author strings and year)
792 * string of <i>this</i> non viral taxon name.
794 * @return the boolean value of the protectedNameCache flag
795 * @see #getNameCache()
797 public boolean isProtectedNameCache() {
798 return protectedNameCache
;
802 * @see #isProtectedNameCache()
804 public void setProtectedNameCache(boolean protectedNameCache
) {
805 this.protectedNameCache
= protectedNameCache
;
810 * Generates and returns a concatenated and formated authorteams string
811 * including basionym and combination authors of <i>this</i> non viral taxon name
812 * according to the strategy defined in
813 * {@link eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy#getAuthorshipCache(NonViralName) INonViralNameCacheStrategy}.
815 * @return the string with the concatenated and formated authorteams for <i>this</i> non viral taxon name
816 * @see eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy#getAuthorshipCache(NonViralName)
818 public String
generateAuthorship(){
819 if (cacheStrategy
== null){
820 logger
.warn("No CacheStrategy defined for nonViralName: " + this.getUuid());
823 return ((INonViralNameCacheStrategy
<T
>)cacheStrategy
).getAuthorshipCache((T
)this);
828 * Returns the concatenated and formated authorteams string including
829 * basionym and combination authors of <i>this</i> non viral taxon name.
830 * If the protectedAuthorshipCache flag is set this method returns the
831 * string stored in the the authorshipCache attribute, otherwise it
832 * generates the complete authorship string, returns it and stores it in
833 * the authorshipCache attribute.
835 * @return the string with the concatenated and formated authorteams for <i>this</i> non viral taxon name
836 * @see #generateAuthorship()
839 public String
getAuthorshipCache() {
840 if (protectedAuthorshipCache
){
841 return this.authorshipCache
;
843 if (this.authorshipCache
== null ){
844 this.authorshipCache
= generateAuthorship();
846 //TODO get is Dirty of authors, make better if possible
847 this.setAuthorshipCache(generateAuthorship(), protectedAuthorshipCache
); //throw change event to inform higher caches
850 return authorshipCache
;
855 * Updates the authorship cache if any changes appeared in the authors nomenclatural caches.
856 * Deletes the titleCache and the fullTitleCache if not protected and if any change has happened
859 private void updateAuthorshipCache() {
860 //updates the authorship cache if necessary and via the listener updates all higher caches
861 if (protectedAuthorshipCache
== false){
862 String oldCache
= this.authorshipCache
;
863 String newCache
= this.getAuthorshipCache();
864 if ( (oldCache
== null && newCache
!= null) || CdmUtils
.nullSafeEqual(oldCache
,newCache
)){
865 this.setAuthorshipCache(this.getAuthorshipCache(), false);
871 * Assigns an authorshipCache string to <i>this</i> non viral taxon name. Sets the isProtectedAuthorshipCache
872 * flag to <code>true</code>.
874 * @param authorshipCache the string which identifies the complete authorship of <i>this</i> non viral taxon name
875 * @see #getAuthorshipCache()
877 public void setAuthorshipCache(String authorshipCache
) {
878 setAuthorshipCache(authorshipCache
, true);
883 public String
getFullTitleCache(){
884 updateAuthorshipCache();
885 return super.getFullTitleCache();
889 public String
getTitleCache(){
890 if(!protectedTitleCache
) {
891 updateAuthorshipCache();
894 return super.getTitleCache();
899 * Assigns an authorshipCache string to <i>this</i> non viral taxon name.
901 * @param authorshipCache the string which identifies the complete authorship of <i>this</i> non viral taxon name
902 * @param protectedAuthorshipCache if true the isProtectedAuthorshipCache flag is set to <code>true</code>, otherwise
903 * the flag is set to <code>false</code>.
904 * @see #getAuthorshipCache()
906 public void setAuthorshipCache(String authorshipCache
, boolean protectedAuthorshipCache
) {
907 this.authorshipCache
= authorshipCache
;
908 this.setProtectedAuthorshipCache(protectedAuthorshipCache
);
912 public void setTitleCache(String titleCache
, boolean protectCache
){
913 super.setTitleCache(titleCache
, protectCache
);
917 * Returns the boolean value "false" since the components of <i>this</i> taxon name
918 * cannot follow the rules of a corresponding {@link NomenclaturalCode nomenclatural code}
919 * which is not defined for this class. The nomenclature code depends on
920 * the concrete name subclass ({@link BacterialName BacterialName},
921 * {@link BotanicalName BotanicalName}, {@link CultivarPlantName CultivarPlantName} or
922 * {@link ZoologicalName ZoologicalName} to which <i>this</i> non viral taxon name belongs.
923 * This method overrides the isCodeCompliant method from the abstract
924 * {@link TaxonNameBase#isCodeCompliant() TaxonNameBase} class.
927 * @see TaxonNameBase#isCodeCompliant()
931 public boolean isCodeCompliant() {
933 logger
.warn("is CodeCompliant not yet implemented");
938 * @see eu.etaxonomy.cdm.model.name.TaxonNameBase#getNomeclaturalCode()
941 * Returns null as {@link NomenclaturalCode nomenclatural code} that governs
942 * the construction of <i>this</i> non viral taxon name since there is no specific
943 * nomenclatural code defined. The real implementention takes place in the
944 * subclasses {@link BacterialName BacterialName},
945 * {@link BotanicalName BotanicalName}, {@link CultivarPlantName CultivarPlantName} and
946 * {@link ZoologicalName ZoologicalName}.
947 * This method overrides the getNomeclaturalCode method from {@link TaxonNameBase TaxonNameBase}.
950 * @see #isCodeCompliant()
951 * @see TaxonNameBase#getHasProblem()
955 public NomenclaturalCode
getNomenclaturalCode() {
956 logger
.warn("Non Viral Name has no specific Code defined. Use subclasses");
961 * Returns the boolean value of the flag intended to protect (true)
962 * or not (false) the {@link #getAuthorshipCache() authorshipCache} (complete authorship string)
963 * of <i>this</i> non viral taxon name.
965 * @return the boolean value of the protectedAuthorshipCache flag
966 * @see #getAuthorshipCache()
968 public boolean isProtectedAuthorshipCache() {
969 return protectedAuthorshipCache
;
973 * @see #isProtectedAuthorshipCache()
974 * @see #getAuthorshipCache()
976 public void setProtectedAuthorshipCache(boolean protectedAuthorshipCache
) {
977 this.protectedAuthorshipCache
= protectedAuthorshipCache
;
982 * Returns the boolean value of the flag indicating whether the name of <i>this</i>
983 * botanical taxon name is a hybrid formula (true) or not (false). A hybrid
984 * named by a hybrid formula (composed with its parent names by placing the
985 * multiplication sign between them) does not have an own published name
986 * and therefore has neither an {@link NonViralName#getAuthorshipCache() autorship}
987 * nor other name components. If this flag is set no other hybrid flags may
990 * @return the boolean value of the isHybridFormula flag
991 * @see #isMonomHybrid()
992 * @see #isBinomHybrid()
993 * @see #isTrinomHybrid()
995 public boolean isHybridFormula(){
996 return this.hybridFormula
;
1000 * @see #isHybridFormula()
1002 public void setHybridFormula(boolean hybridFormula
){
1003 this.hybridFormula
= hybridFormula
;
1007 * Returns the boolean value of the flag indicating whether <i>this</i> botanical
1008 * taxon name is the name of an intergeneric hybrid (true) or not (false).
1009 * In this case the multiplication sign is placed before the scientific
1010 * name. If this flag is set no other hybrid flags may be set.
1012 * @return the boolean value of the isMonomHybrid flag
1013 * @see #isHybridFormula()
1014 * @see #isBinomHybrid()
1015 * @see #isTrinomHybrid()
1017 public boolean isMonomHybrid(){
1018 return this.monomHybrid
;
1022 * @see #isMonomHybrid()
1023 * @see #isBinomHybrid()
1024 * @see #isTrinomHybrid()
1026 public void setMonomHybrid(boolean monomHybrid
){
1027 this.monomHybrid
= monomHybrid
;
1031 * Returns the boolean value of the flag indicating whether <i>this</i> botanical
1032 * taxon name is the name of an interspecific hybrid (true) or not (false).
1033 * In this case the multiplication sign is placed before the species
1034 * epithet. If this flag is set no other hybrid flags may be set.
1036 * @return the boolean value of the isBinomHybrid flag
1037 * @see #isHybridFormula()
1038 * @see #isMonomHybrid()
1039 * @see #isTrinomHybrid()
1041 public boolean isBinomHybrid(){
1042 return this.binomHybrid
;
1046 * @see #isBinomHybrid()
1047 * @see #isMonomHybrid()
1048 * @see #isTrinomHybrid()
1050 public void setBinomHybrid(boolean binomHybrid
){
1051 this.binomHybrid
= binomHybrid
;
1055 * Returns the boolean value of the flag indicating whether <i>this</i> botanical
1056 * taxon name is the name of an infraspecific hybrid (true) or not (false).
1057 * In this case the term "notho-" (optionally abbreviated "n-") is used as
1058 * a prefix to the term denoting the infraspecific rank of <i>this</i> botanical
1059 * taxon name. If this flag is set no other hybrid flags may be set.
1061 * @return the boolean value of the isTrinomHybrid flag
1062 * @see #isHybridFormula()
1063 * @see #isMonomHybrid()
1064 * @see #isBinomHybrid()
1066 public boolean isTrinomHybrid(){
1067 return this.trinomHybrid
;
1071 * @see #isTrinomHybrid()
1072 * @see #isBinomHybrid()
1073 * @see #isMonomHybrid()
1075 public void setTrinomHybrid(boolean trinomHybrid
){
1076 this.trinomHybrid
= trinomHybrid
;
1081 * Returns the set of all {@link HybridRelationship hybrid relationships}
1082 * in which <i>this</i> taxon name is involved as a {@link common.RelationshipBase#getRelatedFrom() parent}.
1084 * @see #getHybridRelationships()
1085 * @see #getChildRelationships()
1086 * @see HybridRelationshipType
1088 public Set
<HybridRelationship
> getHybridParentRelations() {
1089 if(hybridParentRelations
== null) {
1090 this.hybridParentRelations
= new HashSet
<HybridRelationship
>();
1092 return hybridParentRelations
;
1095 private void setHybridParentRelations(Set
<HybridRelationship
> hybridParentRelations
) {
1096 this.hybridParentRelations
= hybridParentRelations
;
1101 * Returns the set of all {@link HybridRelationship hybrid relationships}
1102 * in which <i>this</i> taxon name is involved as a {@link common.RelationshipBase#getRelatedTo() child}.
1104 * @see #getHybridRelationships()
1105 * @see #getParentRelationships()
1106 * @see HybridRelationshipType
1108 public Set
<HybridRelationship
> getHybridChildRelations() {
1109 if(hybridChildRelations
== null) {
1110 this.hybridChildRelations
= new HashSet
<HybridRelationship
>();
1112 return hybridChildRelations
;
1115 private void setHybridChildRelations(Set
<HybridRelationship
> hybridChildRelations
) {
1116 this.hybridChildRelations
= hybridChildRelations
;
1120 * Returns the set of all {@link HybridRelationship hybrid relationships}
1121 * in which <i>this</i> taxon name is involved as a {@link common.RelationshipBase#getRelatedFrom() parent}.
1122 * @see #getHybridParentRelations()
1123 * @see #getHybridRelationships()
1124 * @see #getChildRelationships()
1125 * @see HybridRelationshipType
1126 * @deprecated use {@link #getHybridParentRelations()} instead. Will be removed in higher versions.
1130 public Set
<HybridRelationship
> getParentRelationships() {
1131 return getHybridParentRelations();
1135 * Returns the hybrid child relationships ordered by relationship type, or if equal
1136 * by title cache of the related names.
1137 * @see #getHybridParentRelations()
1140 public List
<HybridRelationship
> getOrderedChildRelationships(){
1141 List
<HybridRelationship
> result
= new ArrayList
<HybridRelationship
>();
1142 result
.addAll(this.hybridChildRelations
);
1143 Collections
.sort(result
);
1144 Collections
.reverse(result
);
1151 * @see #getHybridChildRelations()
1152 * @deprecated use {@link #getHybridChildRelations()} instead. Will be removed in higher versions.
1156 public Set
<HybridRelationship
> getChildRelationships() {
1157 return this.getHybridChildRelations();
1161 * Adds the given {@link HybridRelationship hybrid relationship} to the set
1162 * of {@link #getHybridRelationships() hybrid relationships} of both non-viral names
1163 * involved in this hybrid relationship. One of both non-viral names
1164 * must be <i>this</i> non-viral name otherwise no addition will be carried
1165 * out. The {@link eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedTo() child
1166 * non viral taxon name} must be a hybrid, which means that one of its four hybrid flags must be set.
1168 * @param relationship the hybrid relationship to be added
1169 * @see #isHybridFormula()
1170 * @see #isMonomHybrid()
1171 * @see #isBinomHybrid()
1172 * @see #isTrinomHybrid()
1173 * @see #getHybridRelationships()
1174 * @see #getParentRelationships()
1175 * @see #getChildRelationships()
1176 * @see #addRelationship(RelationshipBase)
1177 * @throws IllegalArgumentException
1179 protected void addHybridRelationship(HybridRelationship rel
) {
1180 if (rel
!=null && rel
.getHybridName().equals(this)){
1181 this.hybridChildRelations
.add(rel
);
1182 }else if(rel
!=null && rel
.getParentName().equals(this)){
1183 this.hybridParentRelations
.add(rel
);
1185 throw new IllegalArgumentException("Hybrid relationship is either null or the relationship does not reference this name");
1192 * Does the same as the addHybridRelationship method if the given
1193 * {@link common.RelationshipBase relation} is also a {@link HybridRelationship hybrid relationship}.
1194 * Otherwise this method does the same as the overwritten {@link TaxonNameBase#addRelationship(RelationshipBase) addRelationship}
1195 * method from TaxonNameBase.
1197 * @param relation the relationship to be added to some of <i>this</i> taxon name's relationships sets
1198 * @see #addHybridRelationship(HybridRelationship)
1199 * @see TaxonNameBase#addRelationship(RelationshipBase)
1200 * @see TaxonNameBase#addNameRelationship(NameRelationship)
1201 * @deprecated to be used by RelationshipBase only
1204 @Deprecated //to be used by RelationshipBase only
1205 public void addRelationship(RelationshipBase relation
) {
1206 if (relation
instanceof HybridRelationship
){
1207 addHybridRelationship((HybridRelationship
)relation
);
1209 super.addRelationship(relation
);
1214 * Creates a new {@link HybridRelationship#HybridRelationship(BotanicalName, BotanicalName, HybridRelationshipType, String) hybrid relationship}
1215 * to <i>this</i> botanical name. A HybridRelationship may be of type
1216 * "is first/second parent" or "is male/female parent". By invoking this
1217 * method <i>this</i> botanical name becomes a hybrid child of the parent
1220 * @param parentName the botanical name of the parent for this new hybrid name relationship
1221 * @param type the type of this new name relationship
1222 * @param ruleConsidered the string which specifies the rule on which this name relationship is based
1224 * @see #addHybridChild(BotanicalName, HybridRelationshipType,String )
1225 * @see #getRelationsToThisName()
1226 * @see #getNameRelations()
1227 * @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
1228 * @see #addNameRelationship(NameRelationship)
1230 public HybridRelationship
addHybridParent(NonViralName parentName
, HybridRelationshipType type
, String ruleConsidered
){
1231 return new HybridRelationship(this, parentName
, type
, ruleConsidered
);
1235 * Creates a new {@link HybridRelationship#HybridRelationship(BotanicalName, BotanicalName, HybridRelationshipType, String) hybrid relationship}
1236 * to <i>this</i> botanical name. A HybridRelationship may be of type
1237 * "is first/second parent" or "is male/female parent". By invoking this
1238 * method <i>this</i> botanical name becomes a parent of the hybrid child
1241 * @param childName the botanical name of the child for this new hybrid name relationship
1242 * @param type the type of this new name relationship
1243 * @param ruleConsidered the string which specifies the rule on which this name relationship is based
1245 * @see #addHybridParent(BotanicalName, HybridRelationshipType,String )
1246 * @see #getRelationsToThisName()
1247 * @see #getNameRelations()
1248 * @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
1249 * @see #addNameRelationship(NameRelationship)
1251 public HybridRelationship
addHybridChild(NonViralName childName
, HybridRelationshipType type
, String ruleConsidered
){
1252 return new HybridRelationship(childName
, this, type
, ruleConsidered
);
1257 * Removes one {@link HybridRelationship hybrid relationship} from the set of
1258 * {@link #getHybridRelationships() hybrid relationships} in which <i>this</i> botanical taxon name
1259 * is involved. The hybrid relationship will also be removed from the set
1260 * belonging to the second botanical taxon name involved.
1262 * @param relationship the hybrid relationship which should be deleted from the corresponding sets
1263 * @see #getHybridRelationships()
1265 public void removeHybridRelationship(HybridRelationship hybridRelation
) {
1266 if (hybridRelation
== null) {
1270 NonViralName
<?
> parent
= hybridRelation
.getParentName();
1271 NonViralName
<?
> child
= hybridRelation
.getHybridName();
1273 hybridRelation
.setHybridName(null);
1274 hybridRelation
.setParentName(null);
1276 if (parent
!= null) {
1277 parent
.removeHybridRelationship(hybridRelation
);
1280 if (child
!= null) {
1281 child
.removeHybridRelationship(hybridRelation
);
1284 this.hybridChildRelations
.remove(hybridRelation
);
1285 this.hybridParentRelations
.remove(hybridRelation
);
1289 public void removeHybridChild(NonViralName child
) {
1290 Set
<HybridRelationship
> hybridRelationships
= new HashSet
<HybridRelationship
>();
1291 hybridRelationships
.addAll(this.getChildRelationships());
1292 hybridRelationships
.addAll(this.getParentRelationships());
1293 for(HybridRelationship hybridRelationship
: hybridRelationships
) {
1294 // remove name relationship from this side
1295 if (hybridRelationship
.getParentName().equals(this) && hybridRelationship
.getHybridName().equals(child
)) {
1296 this.removeHybridRelationship(hybridRelationship
);
1301 public void removeHybridParent(NonViralName parent
) {
1302 Set
<HybridRelationship
> hybridRelationships
= new HashSet
<HybridRelationship
>();
1303 hybridRelationships
.addAll(this.getChildRelationships());
1304 hybridRelationships
.addAll(this.getParentRelationships());
1305 for(HybridRelationship hybridRelationship
: hybridRelationships
) {
1306 // remove name relationship from this side
1307 if (hybridRelationship
.getParentName().equals(parent
) && hybridRelationship
.getHybridName().equals(this)) {
1308 this.removeHybridRelationship(hybridRelationship
);
1314 * Needs to be implemented by those classes that handle autonyms (e.g. botanical names).
1317 public boolean isAutonym(){
1323 // * Returns the boolean value indicating whether <i>this</i> names rank is Rank "unranked"
1324 // * (uuid = 'a965befb-70a9-4747-a18f-624456c65223') but most likely it is an infrageneric rank
1325 // * due to existing atomized data for the genus epithet and the infrageneric epithet but missing
1326 // * specific epithet.
1327 // * Returns false if <i>this</i> names rank is null.
1329 // * @see #isSupraGeneric()
1330 // * @see #isGenus()
1331 // * @see #isSpeciesAggregate()
1332 // * @see #isSpecies()
1333 // * @see #isInfraSpecific()
1336 // public boolean isInfragenericUnranked() {
1337 // Rank rank = this.getRank();
1338 // if (rank == null || ! rank.equals(Rank.UNRANKED())){
1341 // if (StringUtils.isBlank(this.getSpecificEpithet()) && StringUtils.isBlank(this.getInfraSpecificEpithet()) ){
1350 * Tests if the given name has any authors.
1351 * @return false if no author ((ex)combination or (ex)basionym) exists, true otherwise
1353 public boolean hasAuthors() {
1354 return (this.getCombinationAuthorTeam() != null ||
1355 this.getExCombinationAuthorTeam() != null ||
1356 this.getBasionymAuthorTeam() != null ||
1357 this.getExBasionymAuthorTeam() != null);
1361 * Shortcut. Returns the combination authors title cache. Returns null if no combination author exists.
1364 public String
computeCombinationAuthorNomenclaturalTitle() {
1365 return computeNomenclaturalTitle(this.getCombinationAuthorTeam());
1369 * Shortcut. Returns the basionym authors title cache. Returns null if no basionym author exists.
1372 public String
computeBasionymAuthorNomenclaturalTitle() {
1373 return computeNomenclaturalTitle(this.getBasionymAuthorTeam());
1378 * Shortcut. Returns the ex-combination authors title cache. Returns null if no ex-combination author exists.
1381 public String
computeExCombinationAuthorNomenclaturalTitle() {
1382 return computeNomenclaturalTitle(this.getExCombinationAuthorTeam());
1386 * Shortcut. Returns the ex-basionym authors title cache. Returns null if no exbasionym author exists.
1389 public String
computeExBasionymAuthorNomenclaturalTitle() {
1390 return computeNomenclaturalTitle(this.getExBasionymAuthorTeam());
1393 private String
computeNomenclaturalTitle(INomenclaturalAuthor author
){
1394 if (author
== null){
1397 return author
.getNomenclaturalTitle();
1401 //*********************** CLONE ********************************************************/
1404 * Clones <i>this</i> non-viral name. This is a shortcut that enables to create
1405 * a new instance that differs only slightly from <i>this</i> non-viral name by
1406 * modifying only some of the attributes.
1408 * @see eu.etaxonomy.cdm.model.name.TaxonNameBase#clone()
1409 * @see java.lang.Object#clone()
1412 public Object
clone() {
1413 NonViralName
<?
> result
= (NonViralName
<?
>)super.clone();
1415 //HybridChildRelations
1416 result
.hybridChildRelations
= new HashSet
<HybridRelationship
>();
1417 for (HybridRelationship hybridRelationship
: getHybridChildRelations()){
1418 HybridRelationship newChildRelationship
= (HybridRelationship
)hybridRelationship
.clone();
1419 newChildRelationship
.setRelatedTo(result
);
1420 result
.hybridChildRelations
.add(newChildRelationship
);
1423 //HybridParentRelations
1424 result
.hybridParentRelations
= new HashSet
<HybridRelationship
>();
1425 for (HybridRelationship hybridRelationship
: getHybridParentRelations()){
1426 HybridRelationship newParentRelationship
= (HybridRelationship
)hybridRelationship
.clone();
1427 newParentRelationship
.setRelatedFrom(result
);
1428 result
.hybridParentRelations
.add(newParentRelationship
);
1432 if (! protectedNameCache
){
1433 result
.nameCache
= null;
1437 if (! protectedAuthorshipCache
){
1438 result
.authorshipCache
= null;
1441 //no changes to: basionamyAuthorTeam, combinationAuthorTeam, exBasionymAuthorTeam, exCombinationAuthorTeam
1442 //genusOrUninomial, infraGenericEpithet, specificEpithet, infraSpecificEpithet,
1443 //protectedAuthorshipCache, protectedNameCache
1444 //binomHybrid, monomHybrid, trinomHybrid, hybridFormula,