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
.annotations
.Target
;
43 import org
.hibernate
.envers
.Audited
;
44 import org
.hibernate
.search
.annotations
.Analyze
;
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
.validator
.constraints
.NotEmpty
;
51 import org
.springframework
.beans
.factory
.annotation
.Configurable
;
53 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
54 import eu
.etaxonomy
.cdm
.model
.agent
.INomenclaturalAuthor
;
55 import eu
.etaxonomy
.cdm
.model
.agent
.TeamOrPersonBase
;
56 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
57 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
58 import eu
.etaxonomy
.cdm
.model
.reference
.INomenclaturalReference
;
59 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
60 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.CacheUpdate
;
61 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.INonViralNameCacheStrategy
;
62 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.NonViralNameDefaultCacheStrategy
;
63 import eu
.etaxonomy
.cdm
.strategy
.match
.Match
;
64 import eu
.etaxonomy
.cdm
.strategy
.match
.Match
.ReplaceMode
;
65 import eu
.etaxonomy
.cdm
.strategy
.match
.MatchMode
;
66 import eu
.etaxonomy
.cdm
.strategy
.merge
.Merge
;
67 import eu
.etaxonomy
.cdm
.strategy
.merge
.MergeMode
;
68 import eu
.etaxonomy
.cdm
.validation
.Level2
;
69 import eu
.etaxonomy
.cdm
.validation
.Level3
;
70 import eu
.etaxonomy
.cdm
.validation
.annotation
.CorrectEpithetsForRank
;
71 import eu
.etaxonomy
.cdm
.validation
.annotation
.MustHaveAuthority
;
72 import eu
.etaxonomy
.cdm
.validation
.annotation
.NoDuplicateNames
;
73 import eu
.etaxonomy
.cdm
.validation
.annotation
.NullOrNotEmpty
;
76 * The taxon name class for all non viral taxa. Parenthetical authorship is derived
77 * from basionym relationship. The scientific name including author strings and
78 * maybe year can be stored as a string in the inherited {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache} attribute.
79 * The year itself is an information obtained from the {@link eu.etaxonomy.cdm.model.reference.Reference#getYear() nomenclatural reference}.
80 * The scientific name string without author strings and year can be stored in the {@link #getNameCache() nameCache} attribute.
82 * This class corresponds partially to: <ul>
83 * <li> TaxonName according to the TDWG ontology
84 * <li> ScientificName and CanonicalName according to the TCS
85 * <li> ScientificName according to the ABCD schema
90 * @created 08-Nov-2007 13:06:39
92 @XmlAccessorType(XmlAccessType
.FIELD
)
93 @XmlType(name
= "NonViralName", propOrder
= {
96 "infraGenericEpithet",
98 "infraSpecificEpithet",
99 "combinationAuthorTeam",
100 "exCombinationAuthorTeam",
101 "basionymAuthorTeam",
102 "exBasionymAuthorTeam",
104 "protectedAuthorshipCache",
105 "protectedNameCache",
106 "hybridParentRelations",
107 "hybridChildRelations",
113 @XmlRootElement(name
= "NonViralName")
115 @Indexed(index
= "eu.etaxonomy.cdm.model.name.TaxonNameBase")
118 @CorrectEpithetsForRank(groups
= Level2
.class)
119 @MustHaveAuthority(groups
= Level2
.class)
120 @NoDuplicateNames(groups
= Level3
.class)
121 public class NonViralName
<T
extends NonViralName
> extends TaxonNameBase
<T
, INonViralNameCacheStrategy
> implements Cloneable
{
122 private static final long serialVersionUID
= 4441110073881088033L;
123 private static final Logger logger
= Logger
.getLogger(NonViralName
.class);
125 @XmlElement(name
= "NameCache")
126 @Fields({@Field(name
= "nameCache_tokenized",index
= org
.hibernate
.search
.annotations
.Index
.YES
), //TODO H42
127 @Field(index
= Index
.YES
, analyze
= Analyze
.NO
) //TODO H42 was UN_TOKENIZED
129 @Match(value
=MatchMode
.CACHE
, cacheReplaceMode
=ReplaceMode
.DEFINED
,
130 cacheReplacedProperties
={"genusOrUninomial", "infraGenericEpithet", "specificEpithet", "infraSpecificEpithet"} )
131 @NotEmpty(groups
= Level2
.class) // implictly NotNull
133 private String nameCache
;
135 @XmlElement(name
= "ProtectedNameCache")
136 @CacheUpdate(value
="nameCache")
137 protected boolean protectedNameCache
;
139 @XmlElement(name
= "GenusOrUninomial")
140 @Field(index
=Index
.YES
) //TODO H42
141 @Match(MatchMode
.EQUAL_REQUIRED
)
142 @CacheUpdate("nameCache")
145 @Pattern(regexp
= "[A-Z][a-z\\u00E4\\u00EB\\u00EF\\u00F6\\u00FC\\-]+", groups
=Level2
.class, message
="{eu.etaxonomy.cdm.model.name.NonViralName.allowedCharactersForUninomial.message}")
146 @NotEmpty(groups
= Level3
.class)
147 private String genusOrUninomial
;
149 @XmlElement(name
= "InfraGenericEpithet")
150 @Field(index
=Index
.YES
) //TODO H42
151 @CacheUpdate("nameCache")
154 @Pattern(regexp
= "[a-z\\u00E4\\u00EB\\u00EF\\u00F6\\u00FC\\-]+", groups
=Level2
.class,message
="{eu.etaxonomy.cdm.model.name.NonViralName.allowedCharactersForEpithet.message}")
155 private String infraGenericEpithet
;
157 @XmlElement(name
= "SpecificEpithet")
158 @Field(index
=Index
.YES
) //TODO H42
159 @CacheUpdate("nameCache")
162 @Pattern(regexp
= "[a-z\\u00E4\\u00EB\\u00EF\\u00F6\\u00FC\\-]+", groups
=Level2
.class, message
= "{eu.etaxonomy.cdm.model.name.NonViralName.allowedCharactersForEpithet.message}")
163 private String specificEpithet
;
165 @XmlElement(name
= "InfraSpecificEpithet")
166 @Field(index
=Index
.YES
) //TODO H42
167 @CacheUpdate("nameCache")
170 @Pattern(regexp
= "[a-z\\u00E4\\u00EB\\u00EF\\u00F6\\u00FC\\-]+", groups
=Level2
.class, message
= "{eu.etaxonomy.cdm.model.name.NonViralName.allowedCharactersForEpithet.message}")
171 private String infraSpecificEpithet
;
173 @XmlElement(name
= "CombinationAuthorTeam", type
= TeamOrPersonBase
.class)
175 @XmlSchemaType(name
= "IDREF")
176 @ManyToOne(fetch
= FetchType
.LAZY
)
177 @Target(TeamOrPersonBase
.class)
178 @Cascade(CascadeType
.SAVE_UPDATE
)
179 @CacheUpdate("authorshipCache")
181 private INomenclaturalAuthor combinationAuthorTeam
;
183 @XmlElement(name
= "ExCombinationAuthorTeam", type
= TeamOrPersonBase
.class)
185 @XmlSchemaType(name
= "IDREF")
186 @ManyToOne(fetch
= FetchType
.LAZY
)
187 @Target(TeamOrPersonBase
.class)
188 @Cascade(CascadeType
.SAVE_UPDATE
)
189 @CacheUpdate("authorshipCache")
191 private INomenclaturalAuthor exCombinationAuthorTeam
;
193 @XmlElement(name
= "BasionymAuthorTeam", type
= TeamOrPersonBase
.class)
195 @XmlSchemaType(name
= "IDREF")
196 @ManyToOne(fetch
= FetchType
.LAZY
)
197 @Target(TeamOrPersonBase
.class)
198 @Cascade(CascadeType
.SAVE_UPDATE
)
199 @CacheUpdate("authorshipCache")
201 private INomenclaturalAuthor basionymAuthorTeam
;
203 @XmlElement(name
= "ExBasionymAuthorTeam", type
= TeamOrPersonBase
.class)
205 @XmlSchemaType(name
= "IDREF")
206 @ManyToOne(fetch
= FetchType
.LAZY
)
207 @Target(TeamOrPersonBase
.class)
208 @Cascade(CascadeType
.SAVE_UPDATE
)
209 @CacheUpdate("authorshipCache")
211 private INomenclaturalAuthor exBasionymAuthorTeam
;
213 @XmlElement(name
= "AuthorshipCache")
214 @Fields({@Field(name
= "authorshipCache_tokenized",index
= org
.hibernate
.search
.annotations
.Index
.YES
), //TODO H42
215 @Field(index
= Index
.YES
, analyze
= Analyze
.NO
) //TODO H42 was UN_TOKENIZED
217 @Match(value
=MatchMode
.CACHE
, cacheReplaceMode
=ReplaceMode
.DEFINED
,
218 cacheReplacedProperties
={"combinationAuthorTeam", "basionymAuthorTeam", "exCombinationAuthorTeam", "exBasionymAuthorTeam"} )
221 @Pattern(regexp
= "[A-Za-z0-9 \\u00E4\\u00EB\\u00EF\\u00F6\\u00FC\\-\\&\\,\\(\\)\\.]+", groups
=Level2
.class, message
= "{eu.etaxonomy.cdm.model.name.NonViralName.allowedCharactersForAuthority.message}")
222 private String authorshipCache
;
224 @XmlElement(name
= "ProtectedAuthorshipCache")
225 @CacheUpdate("authorshipCache")
226 protected boolean protectedAuthorshipCache
;
228 @XmlElementWrapper(name
= "HybridRelationsFromThisName")
229 @XmlElement(name
= "HybridRelationsFromThisName")
230 @OneToMany(mappedBy
="relatedFrom", fetch
= FetchType
.LAZY
)
231 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
, CascadeType
.DELETE_ORPHAN
})
232 @Merge(MergeMode
.RELATION
)
234 private Set
<HybridRelationship
> hybridParentRelations
= new HashSet
<HybridRelationship
>();
236 @XmlElementWrapper(name
= "HybridRelationsToThisName")
237 @XmlElement(name
= "HybridRelationsToThisName")
238 @OneToMany(mappedBy
="relatedTo", fetch
= FetchType
.LAZY
)
239 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
, CascadeType
.DELETE
, CascadeType
.DELETE_ORPHAN
}) //a hybrid relation can be deleted automatically if the child is deleted.
240 @Merge(MergeMode
.RELATION
)
242 private Set
<HybridRelationship
> hybridChildRelations
= new HashSet
<HybridRelationship
>();
244 //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
245 //hybrid name may not have either an authorteam nor other name components.
246 @XmlElement(name
="IsHybridFormula")
247 @CacheUpdate("nameCache")
248 private boolean hybridFormula
= false;
250 @XmlElement(name
="IsMonomHybrid")
251 @CacheUpdate("nameCache")
252 private boolean monomHybrid
= false;
254 @XmlElement(name
="IsBinomHybrid")
255 @CacheUpdate("nameCache")
256 private boolean binomHybrid
= false;
258 @XmlElement(name
="IsTrinomHybrid")
259 @CacheUpdate("nameCache")
260 private boolean trinomHybrid
= false;
263 * Creates a new non viral taxon name instance
264 * only containing its {@link common.Rank rank} and
265 * the {@link eu.etaxonomy.cdm.strategy.cache.name.NonViralNameDefaultCacheStrategy default cache strategy}.
267 * @param rank the rank to be assigned to <i>this</i> non viral taxon name
268 * @see #NewInstance(Rank, HomotypicalGroup)
269 * @see #NonViralName(Rank, HomotypicalGroup)
270 * @see #NonViralName()
271 * @see #NonViralName(Rank, String, String, String, String, TeamOrPersonBase, Reference, String, HomotypicalGroup)
272 * @see eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy
273 * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy
274 * @see eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy
276 public static NonViralName
NewInstance(Rank rank
){
277 return new NonViralName(rank
, null);
281 * Creates a new non viral taxon name instance
282 * only containing its {@link common.Rank rank},
283 * its {@link HomotypicalGroup homotypical group} and
284 * the {@link eu.etaxonomy.cdm.strategy.cache.name.NonViralNameDefaultCacheStrategy default cache strategy}.
285 * The new non viral taxon name instance will be also added to the set of
286 * non viral taxon names belonging to this homotypical group.
288 * @param rank the rank to be assigned to <i>this</i> non viral taxon name
289 * @param homotypicalGroup the homotypical group to which <i>this</i> non viral taxon name belongs
290 * @see #NewInstance(Rank)
291 * @see #NonViralName(Rank, HomotypicalGroup)
292 * @see #NonViralName()
293 * @see #NonViralName(Rank, String, String, String, String, TeamOrPersonBase, Reference, String, HomotypicalGroup)
294 * @see eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy
295 * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy
296 * @see eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy
298 public static NonViralName
NewInstance(Rank rank
, HomotypicalGroup homotypicalGroup
){
299 return new NonViralName(rank
, homotypicalGroup
);
302 // ************************** CONSTRUCTORS *************/
304 //needed by hibernate
306 * Class constructor: creates a new non viral taxon name instance
307 * only containing the {@link eu.etaxonomy.cdm.strategy.cache.name.NonViralNameDefaultCacheStrategy default cache strategy}.
309 * @see #NonViralName(Rank, HomotypicalGroup)
310 * @see #NonViralName(Rank, String, String, String, String, TeamOrPersonBase, Reference, String, HomotypicalGroup)
311 * @see eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy
312 * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy
313 * @see eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy
315 protected NonViralName(){
317 setNameCacheStrategy();
321 * Class constructor: creates a new non viral taxon name instance
322 * only containing its {@link Rank rank},
323 * its {@link HomotypicalGroup homotypical group} and
324 * the {@link eu.etaxonomy.cdm.strategy.cache.name.NonViralNameDefaultCacheStrategy default cache strategy}.
325 * The new non viral taxon name instance will be also added to the set of
326 * non viral taxon names belonging to this homotypical group.
328 * @param rank the rank to be assigned to <i>this</i> non viral taxon name
329 * @param homotypicalGroup the homotypical group to which <i>this</i> non viral taxon name belongs
330 * @see #NonViralName()
331 * @see #NonViralName(Rank, String, String, String, String, TeamOrPersonBase, Reference, String, HomotypicalGroup)
332 * @see #NewInstance(Rank, HomotypicalGroup)
333 * @see eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy
334 * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy
335 * @see eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy
337 protected NonViralName(Rank rank
, HomotypicalGroup homotypicalGroup
) {
338 super(rank
, homotypicalGroup
);
339 setNameCacheStrategy();
342 * Class constructor: creates a new non viral taxon name instance
343 * containing its {@link Rank rank},
344 * its {@link HomotypicalGroup homotypical group},
345 * its scientific name components, its {@link eu.etaxonomy.cdm.model.agent.TeamOrPersonBase author(team)},
346 * its {@link eu.etaxonomy.cdm.model.reference.Reference nomenclatural reference} and
347 * the {@link eu.etaxonomy.cdm.strategy.cache.name.NonViralNameDefaultCacheStrategy default cache strategy}.
348 * The new non viral taxon name instance will be also added to the set of
349 * non viral taxon names belonging to this homotypical group.
351 * @param rank the rank to be assigned to <i>this</i> non viral taxon name
352 * @param genusOrUninomial the string for <i>this</i> non viral taxon name
353 * if its rank is genus or higher or for the genus part
354 * if its rank is lower than genus
355 * @param infraGenericEpithet the string for the first epithet of
356 * <i>this</i> non viral taxon name if its rank is lower than genus
357 * and higher than species aggregate
358 * @param specificEpithet the string for the first epithet of
359 * <i>this</i> non viral taxon name if its rank is species aggregate or lower
360 * @param infraSpecificEpithet the string for the second epithet of
361 * <i>this</i> non viral taxon name if its rank is lower than species
362 * @param combinationAuthorTeam the author or the team who published <i>this</i> non viral taxon name
363 * @param nomenclaturalReference the nomenclatural reference where <i>this</i> non viral taxon name was published
364 * @param nomenclMicroRef the string with the details for precise location within the nomenclatural reference
365 * @param homotypicalGroup the homotypical group to which <i>this</i> non viral taxon name belongs
366 * @see #NonViralName()
367 * @see #NonViralName(Rank, HomotypicalGroup)
368 * @see #NewInstance(Rank, HomotypicalGroup)
369 * @see eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy
370 * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy
371 * @see eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy
373 protected NonViralName(Rank rank
, String genusOrUninomial
, String infraGenericEpithet
, String specificEpithet
, String infraSpecificEpithet
, TeamOrPersonBase combinationAuthorTeam
, INomenclaturalReference nomenclaturalReference
, String nomenclMicroRef
, HomotypicalGroup homotypicalGroup
) {
374 super(rank
, homotypicalGroup
);
375 setNameCacheStrategy();
376 setGenusOrUninomial(genusOrUninomial
);
377 setInfraGenericEpithet (infraGenericEpithet
);
378 setSpecificEpithet(specificEpithet
);
379 setInfraSpecificEpithet(infraSpecificEpithet
);
380 setCombinationAuthorTeam(combinationAuthorTeam
);
381 setNomenclaturalReference((Reference
)nomenclaturalReference
);
382 this.setNomenclaturalMicroReference(nomenclMicroRef
);
387 //**************************** METHODS **************************************/
390 private void setNameCacheStrategy(){
391 if (getClass() == NonViralName
.class){
392 this.cacheStrategy
= NonViralNameDefaultCacheStrategy
.NewInstance();
396 protected void initListener(){
397 PropertyChangeListener listener
= new PropertyChangeListener() {
398 public void propertyChange(PropertyChangeEvent e
) {
399 boolean protectedByLowerCache
= false;
401 if (fieldHasCacheUpdateProperty(e
.getPropertyName(), "authorshipCache")){
402 if (protectedAuthorshipCache
){
403 protectedByLowerCache
= true;
405 authorshipCache
= null;
410 if (fieldHasCacheUpdateProperty(e
.getPropertyName(), "nameCache")){
411 if (protectedNameCache
){
412 protectedByLowerCache
= true;
418 if (! fieldHasNoUpdateProperty(e
.getPropertyName(), "titleCache")){
419 if (isProtectedTitleCache()|| protectedByLowerCache
== true ){
420 protectedByLowerCache
= true;
426 if (! fieldHasNoUpdateProperty(e
.getPropertyName(), "fullTitleCache")){
427 if (isProtectedFullTitleCache()|| protectedByLowerCache
== true ){
428 protectedByLowerCache
= true;
430 fullTitleCache
= null;
435 addPropertyChangeListener(listener
); //didn't use this.addXXX to make lsid.AssemblerTest run in cdmlib-remote
438 private static Map
<String
, java
.lang
.reflect
.Field
> allFields
= null;
440 protected Map
<String
, java
.lang
.reflect
.Field
> getAllFields(){
441 if (allFields
== null){
442 allFields
= CdmUtils
.getAllFields(this.getClass(), CdmBase
.class, false, false, false, true);
448 * @param propertyName
452 private boolean fieldHasCacheUpdateProperty(String propertyName
, String cacheName
) {
453 java
.lang
.reflect
.Field field
;
455 field
= getAllFields().get(propertyName
);
457 CacheUpdate updateAnnotation
= field
.getAnnotation(CacheUpdate
.class);
458 if (updateAnnotation
!= null){
459 for (String value
: updateAnnotation
.value()){
460 if (cacheName
.equals(value
)){
467 } catch (SecurityException e1
) {
472 private boolean fieldHasNoUpdateProperty(String propertyName
, String cacheName
) {
473 java
.lang
.reflect
.Field field
;
474 //do not update fields with the same name
475 if (cacheName
.equals(propertyName
)){
478 //evaluate annotation
480 field
= getAllFields().get(propertyName
);
482 CacheUpdate updateAnnotation
= field
.getAnnotation(CacheUpdate
.class);
483 if (updateAnnotation
!= null){
484 for (String value
: updateAnnotation
.noUpdate()){
485 if (cacheName
.equals(value
)){
492 } catch (SecurityException e1
) {
499 * Returns the {@link eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor author (team)} that published <i>this</i> non viral
502 * @return the nomenclatural author (team) of <i>this</i> non viral taxon name
503 * @see eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor
504 * @see eu.etaxonomy.cdm.model.agent.TeamOrPersonBase#getNomenclaturalTitle()
506 public INomenclaturalAuthor
getCombinationAuthorTeam(){
507 return this.combinationAuthorTeam
;
511 * @see #getCombinationAuthorTeam()
513 public void setCombinationAuthorTeam(INomenclaturalAuthor combinationAuthorTeam
){
514 this.combinationAuthorTeam
= combinationAuthorTeam
;
518 * Returns the {@link eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor author (team)} that contributed to
519 * the publication of <i>this</i> non viral taxon name as generally stated by
520 * the {@link #getCombinationAuthorTeam() combination author (team)} itself.<BR>
521 * An ex-author(-team) is an author(-team) to whom a taxon name was ascribed
522 * although it is not the author(-team) of a valid publication (for instance
523 * without the validating description or diagnosis in case of a name for a
524 * new taxon). The name of this ascribed authorship, followed by "ex", may
525 * be inserted before the name(s) of the publishing author(s) of the validly
526 * published name:<BR>
527 * <i>Lilium tianschanicum</i> was described by Grubov (1977) as a new species and
528 * its name was ascribed to Ivanova; since there is no indication that
529 * Ivanova provided the validating description, the name may be cited as
530 * <i>Lilium tianschanicum</i> N. A. Ivanova ex Grubov or <i>Lilium tianschanicum</i> Grubov.
532 * The presence of an author (team) of <i>this</i> non viral taxon name is a
533 * condition for the existence of an ex author (team) for <i>this</i> same name.
535 * @return the nomenclatural ex author (team) of <i>this</i> non viral taxon name
536 * @see #getCombinationAuthorTeam()
537 * @see eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor
538 * @see eu.etaxonomy.cdm.model.agent.TeamOrPersonBase#getNomenclaturalTitle()
540 public INomenclaturalAuthor
getExCombinationAuthorTeam(){
541 return this.exCombinationAuthorTeam
;
545 * @see #getExCombinationAuthorTeam()
547 public void setExCombinationAuthorTeam(INomenclaturalAuthor exCombinationAuthorTeam
){
548 this.exCombinationAuthorTeam
= exCombinationAuthorTeam
;
552 * Returns the {@link eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor author (team)} that published the original combination
553 * on which <i>this</i> non viral taxon name is nomenclaturally based. Such an
554 * author (team) can only exist if <i>this</i> non viral taxon name is a new
555 * combination due to a taxonomical revision.
557 * @return the nomenclatural basionym author (team) of <i>this</i> non viral taxon name
558 * @see #getCombinationAuthorTeam()
559 * @see eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor
560 * @see eu.etaxonomy.cdm.model.agent.TeamOrPersonBase#getNomenclaturalTitle()
562 public INomenclaturalAuthor
getBasionymAuthorTeam(){
563 return basionymAuthorTeam
;
567 * @see #getBasionymAuthorTeam()
569 public void setBasionymAuthorTeam(INomenclaturalAuthor basionymAuthorTeam
) {
570 this.basionymAuthorTeam
= basionymAuthorTeam
;
574 * Returns the {@link eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor author (team)} that contributed to
575 * the publication of the original combination <i>this</i> non viral taxon name is
576 * based on. This should have been generally stated by
577 * the {@link #getBasionymAuthorTeam() basionym author (team)} itself.
578 * The presence of a basionym author (team) of <i>this</i> non viral taxon name is a
579 * condition for the existence of an ex basionym author (team)
580 * for <i>this</i> same name.
582 * @return the nomenclatural ex basionym author (team) of <i>this</i> non viral taxon name
583 * @see #getBasionymAuthorTeam()
584 * @see #getExCombinationAuthorTeam()
585 * @see #getCombinationAuthorTeam()
586 * @see eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor
587 * @see eu.etaxonomy.cdm.model.agent.TeamOrPersonBase#getNomenclaturalTitle()
589 public INomenclaturalAuthor
getExBasionymAuthorTeam(){
590 return exBasionymAuthorTeam
;
594 * @see #getExBasionymAuthorTeam()
596 public void setExBasionymAuthorTeam(INomenclaturalAuthor exBasionymAuthorTeam
) {
597 this.exBasionymAuthorTeam
= exBasionymAuthorTeam
;
600 * Returns either the scientific name string (without authorship) for <i>this</i>
601 * non viral taxon name if its rank is genus or higher (monomial) or the string for
602 * the genus part of it if its {@link Rank rank} is lower than genus (bi- or trinomial).
603 * Genus or uninomial strings begin with an upper case letter.
605 * @return the string containing the suprageneric name, the genus name or the genus part of <i>this</i> non viral taxon name
606 * @see #getNameCache()
608 public String
getGenusOrUninomial() {
609 return genusOrUninomial
;
613 * @see #getGenusOrUninomial()
615 public void setGenusOrUninomial(String genusOrUninomial
) {
616 this.genusOrUninomial
= genusOrUninomial
;
620 * Returns the genus subdivision epithet string (infrageneric part) for
621 * <i>this</i> non viral taxon name if its {@link Rank rank} is infrageneric (lower than genus and
622 * higher than species aggregate: binomial). Genus subdivision epithet
623 * strings begin with an upper case letter.
625 * @return the string containing the infrageneric part of <i>this</i> non viral taxon name
626 * @see #getNameCache()
628 public String
getInfraGenericEpithet(){
629 return this.infraGenericEpithet
;
633 * @see #getInfraGenericEpithet()
635 public void setInfraGenericEpithet(String infraGenericEpithet
){
636 this.infraGenericEpithet
= infraGenericEpithet
;
640 * Returns the species epithet string for <i>this</i> non viral taxon name if its {@link Rank rank} is
641 * species aggregate or lower (bi- or trinomial). Species epithet strings
642 * begin with a lower case letter.
644 * @return the string containing the species epithet of <i>this</i> non viral taxon name
645 * @see #getNameCache()
647 public String
getSpecificEpithet(){
648 return this.specificEpithet
;
652 * @see #getSpecificEpithet()
654 public void setSpecificEpithet(String specificEpithet
){
655 this.specificEpithet
= specificEpithet
;
659 * Returns the species subdivision epithet string (infraspecific part) for
660 * <i>this</i> non viral taxon name if its {@link Rank rank} is infraspecific
661 * (lower than species: trinomial). Species subdivision epithet strings
662 * begin with a lower case letter.
664 * @return the string containing the infraspecific part of <i>this</i> non viral taxon name
665 * @see #getNameCache()
667 public String
getInfraSpecificEpithet(){
668 return this.infraSpecificEpithet
;
672 * @see #getInfraSpecificEpithet()
674 public void setInfraSpecificEpithet(String infraSpecificEpithet
){
675 this.infraSpecificEpithet
= infraSpecificEpithet
;
679 * Generates and returns the string with the scientific name of <i>this</i>
680 * non viral taxon name including author strings and maybe year according to
681 * the strategy defined in
682 * {@link eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy INonViralNameCacheStrategy}.
683 * This string may be stored in the inherited
684 * {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache} attribute.
685 * This method overrides the generic and inherited
686 * TaxonNameBase#generateTitle() method.
688 * @return the string with the composed name of <i>this</i> non viral taxon name with authorship (and maybe year)
689 * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle()
690 * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache()
691 * @see TaxonNameBase#generateTitle()
694 // public String generateTitle(){
695 // if (cacheStrategy == null){
696 // logger.warn("No CacheStrategy defined for nonViralName: " + this.getUuid());
699 // return cacheStrategy.getTitleCache(this);
704 public String
generateFullTitle(){
705 if (cacheStrategy
== null){
706 logger
.warn("No CacheStrategy defined for nonViralName: " + this.getUuid());
709 return cacheStrategy
.getFullTitleCache(this);
714 * Generates the composed name string of <i>this</i> non viral taxon name without author
715 * strings or year according to the strategy defined in
716 * {@link eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy INonViralNameCacheStrategy}.
717 * The result might be stored in {@link #getNameCache() nameCache} if the
718 * flag {@link #isProtectedNameCache() protectedNameCache} is not set.
720 * @return the string with the composed name of <i>this</i> non viral taxon name without authors or year
721 * @see #getNameCache()
723 protected String
generateNameCache(){
724 if (cacheStrategy
== null){
725 logger
.warn("No CacheStrategy defined for taxonName: " + this.toString());
728 return cacheStrategy
.getNameCache(this);
733 * Returns or generates the nameCache (scientific name
734 * without author strings and year) string for <i>this</i> non viral taxon name. If the
735 * {@link #isProtectedNameCache() protectedNameCache} flag is not set (False)
736 * the string will be generated according to a defined strategy,
737 * otherwise the value of the actual nameCache string will be returned.
739 * @return the string which identifies <i>this</i> non viral taxon name (without authors or year)
740 * @see #generateNameCache()
743 public String
getNameCache() {
744 if (protectedNameCache
){
745 return this.nameCache
;
747 // is title dirty, i.e. equal NULL?
748 if (nameCache
== null){
749 this.nameCache
= generateNameCache();
755 * Assigns a nameCache string to <i>this</i> non viral taxon name and protects it from being overwritten.
756 * Sets the protectedNameCache flag to <code>true</code>.
758 * @param nameCache the string which identifies <i>this</i> non viral taxon name (without authors or year)
759 * @see #getNameCache()
761 public void setNameCache(String nameCache
){
762 setNameCache(nameCache
, true);
766 * Assigns a nameCache string to <i>this</i> non viral taxon name and protects it from being overwritten.
767 * Sets the protectedNameCache flag to <code>true</code>.
769 * @param nameCache the string which identifies <i>this</i> non viral taxon name (without authors or year)
770 * @param protectedNameCache if true teh protectedNameCache is set to <code>true</code> or otherwise set to
772 * @see #getNameCache()
774 public void setNameCache(String nameCache
, boolean protectedNameCache
){
775 this.nameCache
= nameCache
;
776 this.setProtectedNameCache(protectedNameCache
);
780 * Returns the boolean value of the flag intended to protect (true)
781 * or not (false) the {@link #getNameCache() nameCache} (scientific name without author strings and year)
782 * string of <i>this</i> non viral taxon name.
784 * @return the boolean value of the protectedNameCache flag
785 * @see #getNameCache()
787 public boolean isProtectedNameCache() {
788 return protectedNameCache
;
792 * @see #isProtectedNameCache()
794 public void setProtectedNameCache(boolean protectedNameCache
) {
795 this.protectedNameCache
= protectedNameCache
;
800 * Generates and returns a concatenated and formated authorteams string
801 * including basionym and combination authors of <i>this</i> non viral taxon name
802 * according to the strategy defined in
803 * {@link eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy#getAuthorshipCache(NonViralName) INonViralNameCacheStrategy}.
805 * @return the string with the concatenated and formated authorteams for <i>this</i> non viral taxon name
806 * @see eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy#getAuthorshipCache(NonViralName)
808 public String
generateAuthorship(){
809 if (cacheStrategy
== null){
810 logger
.warn("No CacheStrategy defined for nonViralName: " + this.getUuid());
813 return ((INonViralNameCacheStrategy
<T
>)cacheStrategy
).getAuthorshipCache((T
)this);
818 * Returns the concatenated and formated authorteams string including
819 * basionym and combination authors of <i>this</i> non viral taxon name.
820 * If the protectedAuthorshipCache flag is set this method returns the
821 * string stored in the the authorshipCache attribute, otherwise it
822 * generates the complete authorship string, returns it and stores it in
823 * the authorshipCache attribute.
825 * @return the string with the concatenated and formated authorteams for <i>this</i> non viral taxon name
826 * @see #generateAuthorship()
829 public String
getAuthorshipCache() {
830 if (protectedAuthorshipCache
){
831 return this.authorshipCache
;
833 if (this.authorshipCache
== null ){
834 this.authorshipCache
= generateAuthorship();
836 //TODO get is Dirty of authors, make better if possible
837 this.setAuthorshipCache(generateAuthorship(), protectedAuthorshipCache
); //throw change event to inform higher caches
840 return authorshipCache
;
845 * Updates the authorship cache if any changes appeared in the authors nomenclatural caches.
846 * Deletes the titleCache and the fullTitleCache if not protected and if any change has happened
849 private void updateAuthorshipCache() {
850 //updates the authorship cache if necessary and via the listener updates all higher caches
851 if (protectedAuthorshipCache
== false){
852 String oldCache
= this.authorshipCache
;
853 String newCache
= this.getAuthorshipCache();
854 if ( (oldCache
== null && newCache
!= null) || CdmUtils
.nullSafeEqual(oldCache
,newCache
)){
855 this.setAuthorshipCache(this.getAuthorshipCache(), false);
861 * Assigns an authorshipCache string to <i>this</i> non viral taxon name. Sets the isProtectedAuthorshipCache
862 * flag to <code>true</code>.
864 * @param authorshipCache the string which identifies the complete authorship of <i>this</i> non viral taxon name
865 * @see #getAuthorshipCache()
867 public void setAuthorshipCache(String authorshipCache
) {
868 setAuthorshipCache(authorshipCache
, true);
872 public String
getFullTitleCache(){
873 updateAuthorshipCache();
874 return super.getFullTitleCache();
877 public String
getTitleCache(){
878 if(!protectedTitleCache
) {
879 updateAuthorshipCache();
882 return super.getTitleCache();
887 * Assigns an authorshipCache string to <i>this</i> non viral taxon name.
889 * @param authorshipCache the string which identifies the complete authorship of <i>this</i> non viral taxon name
890 * @param protectedAuthorshipCache if true the isProtectedAuthorshipCache flag is set to <code>true</code>, otherwise
891 * the flag is set to <code>false</code>.
892 * @see #getAuthorshipCache()
894 public void setAuthorshipCache(String authorshipCache
, boolean protectedAuthorshipCache
) {
895 this.authorshipCache
= authorshipCache
;
896 this.setProtectedAuthorshipCache(protectedAuthorshipCache
);
899 public void setTitleCache(String titleCache
, boolean protectCache
){
900 super.setTitleCache(titleCache
, protectCache
);
904 * Returns the boolean value "false" since the components of <i>this</i> taxon name
905 * cannot follow the rules of a corresponding {@link NomenclaturalCode nomenclatural code}
906 * which is not defined for this class. The nomenclature code depends on
907 * the concrete name subclass ({@link BacterialName BacterialName},
908 * {@link BotanicalName BotanicalName}, {@link CultivarPlantName CultivarPlantName} or
909 * {@link ZoologicalName ZoologicalName} to which <i>this</i> non viral taxon name belongs.
910 * This method overrides the isCodeCompliant method from the abstract
911 * {@link TaxonNameBase#isCodeCompliant() TaxonNameBase} class.
914 * @see TaxonNameBase#isCodeCompliant()
918 public boolean isCodeCompliant() {
920 logger
.warn("is CodeCompliant not yet implemented");
925 * @see eu.etaxonomy.cdm.model.name.TaxonNameBase#getNomeclaturalCode()
928 * Returns null as {@link NomenclaturalCode nomenclatural code} that governs
929 * the construction of <i>this</i> non viral taxon name since there is no specific
930 * nomenclatural code defined. The real implementention takes place in the
931 * subclasses {@link BacterialName BacterialName},
932 * {@link BotanicalName BotanicalName}, {@link CultivarPlantName CultivarPlantName} and
933 * {@link ZoologicalName ZoologicalName}.
934 * This method overrides the getNomeclaturalCode method from {@link TaxonNameBase TaxonNameBase}.
937 * @see #isCodeCompliant()
938 * @see TaxonNameBase#getHasProblem()
942 public NomenclaturalCode
getNomenclaturalCode() {
943 logger
.warn("Non Viral Name has no specific Code defined. Use subclasses");
948 * Returns the boolean value of the flag intended to protect (true)
949 * or not (false) the {@link #getAuthorshipCache() authorshipCache} (complete authorship string)
950 * of <i>this</i> non viral taxon name.
952 * @return the boolean value of the protectedAuthorshipCache flag
953 * @see #getAuthorshipCache()
955 public boolean isProtectedAuthorshipCache() {
956 return protectedAuthorshipCache
;
960 * @see #isProtectedAuthorshipCache()
961 * @see #getAuthorshipCache()
963 public void setProtectedAuthorshipCache(boolean protectedAuthorshipCache
) {
964 this.protectedAuthorshipCache
= protectedAuthorshipCache
;
969 * Returns the boolean value of the flag indicating whether the name of <i>this</i>
970 * botanical taxon name is a hybrid formula (true) or not (false). A hybrid
971 * named by a hybrid formula (composed with its parent names by placing the
972 * multiplication sign between them) does not have an own published name
973 * and therefore has neither an {@link NonViralName#getAuthorshipCache() autorship}
974 * nor other name components. If this flag is set no other hybrid flags may
977 * @return the boolean value of the isHybridFormula flag
978 * @see #isMonomHybrid()
979 * @see #isBinomHybrid()
980 * @see #isTrinomHybrid()
982 public boolean isHybridFormula(){
983 return this.hybridFormula
;
987 * @see #isHybridFormula()
989 public void setHybridFormula(boolean hybridFormula
){
990 this.hybridFormula
= hybridFormula
;
994 * Returns the boolean value of the flag indicating whether <i>this</i> botanical
995 * taxon name is the name of an intergeneric hybrid (true) or not (false).
996 * In this case the multiplication sign is placed before the scientific
997 * name. If this flag is set no other hybrid flags may be set.
999 * @return the boolean value of the isMonomHybrid flag
1000 * @see #isHybridFormula()
1001 * @see #isBinomHybrid()
1002 * @see #isTrinomHybrid()
1004 public boolean isMonomHybrid(){
1005 return this.monomHybrid
;
1009 * @see #isMonomHybrid()
1010 * @see #isBinomHybrid()
1011 * @see #isTrinomHybrid()
1013 public void setMonomHybrid(boolean monomHybrid
){
1014 this.monomHybrid
= monomHybrid
;
1018 * Returns the boolean value of the flag indicating whether <i>this</i> botanical
1019 * taxon name is the name of an interspecific hybrid (true) or not (false).
1020 * In this case the multiplication sign is placed before the species
1021 * epithet. If this flag is set no other hybrid flags may be set.
1023 * @return the boolean value of the isBinomHybrid flag
1024 * @see #isHybridFormula()
1025 * @see #isMonomHybrid()
1026 * @see #isTrinomHybrid()
1028 public boolean isBinomHybrid(){
1029 return this.binomHybrid
;
1033 * @see #isBinomHybrid()
1034 * @see #isMonomHybrid()
1035 * @see #isTrinomHybrid()
1037 public void setBinomHybrid(boolean binomHybrid
){
1038 this.binomHybrid
= binomHybrid
;
1042 * Returns the boolean value of the flag indicating whether <i>this</i> botanical
1043 * taxon name is the name of an infraspecific hybrid (true) or not (false).
1044 * In this case the term "notho-" (optionally abbreviated "n-") is used as
1045 * a prefix to the term denoting the infraspecific rank of <i>this</i> botanical
1046 * taxon name. If this flag is set no other hybrid flags may be set.
1048 * @return the boolean value of the isTrinomHybrid flag
1049 * @see #isHybridFormula()
1050 * @see #isMonomHybrid()
1051 * @see #isBinomHybrid()
1053 public boolean isTrinomHybrid(){
1054 return this.trinomHybrid
;
1058 * @see #isTrinomHybrid()
1059 * @see #isBinomHybrid()
1060 * @see #isMonomHybrid()
1062 public void setTrinomHybrid(boolean trinomHybrid
){
1063 this.trinomHybrid
= trinomHybrid
;
1068 * Returns the set of all {@link HybridRelationship hybrid relationships}
1069 * in which <i>this</i> taxon name is involved as a {@link common.RelationshipBase#getRelatedFrom() parent}.
1071 * @see #getHybridRelationships()
1072 * @see #getChildRelationships()
1073 * @see HybridRelationshipType
1075 public Set
<HybridRelationship
> getHybridParentRelations() {
1076 if(hybridParentRelations
== null) {
1077 this.hybridParentRelations
= new HashSet
<HybridRelationship
>();
1079 return hybridParentRelations
;
1082 private void setHybridParentRelations(Set
<HybridRelationship
> hybridParentRelations
) {
1083 this.hybridParentRelations
= hybridParentRelations
;
1088 * Returns the set of all {@link HybridRelationship hybrid relationships}
1089 * in which <i>this</i> taxon name is involved as a {@link common.RelationshipBase#getRelatedTo() child}.
1091 * @see #getHybridRelationships()
1092 * @see #getParentRelationships()
1093 * @see HybridRelationshipType
1095 public Set
<HybridRelationship
> getHybridChildRelations() {
1096 if(hybridChildRelations
== null) {
1097 this.hybridChildRelations
= new HashSet
<HybridRelationship
>();
1099 return hybridChildRelations
;
1102 private void setHybridChildRelations(Set
<HybridRelationship
> hybridChildRelations
) {
1103 this.hybridChildRelations
= hybridChildRelations
;
1107 * Returns the set of all {@link HybridRelationship hybrid relationships}
1108 * in which <i>this</i> taxon name is involved as a {@link common.RelationshipBase#getRelatedFrom() parent}.
1109 * @see #getHybridParentRelations()
1110 * @see #getHybridRelationships()
1111 * @see #getChildRelationships()
1112 * @see HybridRelationshipType
1113 * @deprecated use {@link #getHybridParentRelations()} instead. Will be removed in higher versions.
1116 public Set
<HybridRelationship
> getParentRelationships() {
1117 return getHybridParentRelations();
1121 * Returns the hybrid child relationships ordered by relationship type, or if equal
1122 * by title cache of the related names.
1123 * @see #getHybridParentRelations()
1126 public List
<HybridRelationship
> getOrderedChildRelationships(){
1127 List
<HybridRelationship
> result
= new ArrayList
<HybridRelationship
>();
1128 result
.addAll(this.hybridChildRelations
);
1129 Collections
.sort(result
);
1130 Collections
.reverse(result
);
1137 * @see #getHybridChildRelations()
1138 * @deprecated use {@link #getHybridChildRelations()} instead. Will be removed in higher versions.
1142 public Set
<HybridRelationship
> getChildRelationships() {
1143 return this.getHybridChildRelations();
1147 * Adds the given {@link HybridRelationship hybrid relationship} to the set
1148 * of {@link #getHybridRelationships() hybrid relationships} of both non-viral names
1149 * involved in this hybrid relationship. One of both non-viral names
1150 * must be <i>this</i> non-viral name otherwise no addition will be carried
1151 * out. The {@link eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedTo() child
1152 * non viral taxon name} must be a hybrid, which means that one of its four hybrid flags must be set.
1154 * @param relationship the hybrid relationship to be added
1155 * @see #isHybridFormula()
1156 * @see #isMonomHybrid()
1157 * @see #isBinomHybrid()
1158 * @see #isTrinomHybrid()
1159 * @see #getHybridRelationships()
1160 * @see #getParentRelationships()
1161 * @see #getChildRelationships()
1162 * @see #addRelationship(RelationshipBase)
1163 * @throws IllegalArgumentException
1165 protected void addHybridRelationship(HybridRelationship rel
) {
1166 if (rel
!=null && rel
.getHybridName().equals(this)){
1167 this.hybridChildRelations
.add(rel
);
1168 }else if(rel
!=null && rel
.getParentName().equals(this)){
1169 this.hybridParentRelations
.add(rel
);
1171 throw new IllegalArgumentException("Hybrid relationship is either null or the relationship does not reference this name");
1178 * Does the same as the addHybridRelationship method if the given
1179 * {@link common.RelationshipBase relation} is also a {@link HybridRelationship hybrid relationship}.
1180 * Otherwise this method does the same as the overwritten {@link TaxonNameBase#addRelationship(RelationshipBase) addRelationship}
1181 * method from TaxonNameBase.
1183 * @param relation the relationship to be added to some of <i>this</i> taxon name's relationships sets
1184 * @see #addHybridRelationship(HybridRelationship)
1185 * @see TaxonNameBase#addRelationship(RelationshipBase)
1186 * @see TaxonNameBase#addNameRelationship(NameRelationship)
1187 * @deprecated to be used by RelationshipBase only
1190 @Deprecated //to be used by RelationshipBase only
1191 public void addRelationship(RelationshipBase relation
) {
1192 if (relation
instanceof HybridRelationship
){
1193 addHybridRelationship((HybridRelationship
)relation
);
1195 super.addRelationship(relation
);
1200 * Creates a new {@link HybridRelationship#HybridRelationship(BotanicalName, BotanicalName, HybridRelationshipType, String) hybrid relationship}
1201 * to <i>this</i> botanical name. A HybridRelationship may be of type
1202 * "is first/second parent" or "is male/female parent". By invoking this
1203 * method <i>this</i> botanical name becomes a hybrid child of the parent
1206 * @param parentName the botanical name of the parent for this new hybrid name relationship
1207 * @param type the type of this new name relationship
1208 * @param ruleConsidered the string which specifies the rule on which this name relationship is based
1210 * @see #addHybridChild(BotanicalName, HybridRelationshipType,String )
1211 * @see #getRelationsToThisName()
1212 * @see #getNameRelations()
1213 * @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
1214 * @see #addNameRelationship(NameRelationship)
1216 public HybridRelationship
addHybridParent(NonViralName parentName
, HybridRelationshipType type
, String ruleConsidered
){
1217 return new HybridRelationship(this, parentName
, type
, ruleConsidered
);
1221 * Creates a new {@link HybridRelationship#HybridRelationship(BotanicalName, BotanicalName, HybridRelationshipType, String) hybrid relationship}
1222 * to <i>this</i> botanical name. A HybridRelationship may be of type
1223 * "is first/second parent" or "is male/female parent". By invoking this
1224 * method <i>this</i> botanical name becomes a parent of the hybrid child
1227 * @param childName the botanical name of the child for this new hybrid name relationship
1228 * @param type the type of this new name relationship
1229 * @param ruleConsidered the string which specifies the rule on which this name relationship is based
1231 * @see #addHybridParent(BotanicalName, HybridRelationshipType,String )
1232 * @see #getRelationsToThisName()
1233 * @see #getNameRelations()
1234 * @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
1235 * @see #addNameRelationship(NameRelationship)
1237 public HybridRelationship
addHybridChild(NonViralName childName
, HybridRelationshipType type
, String ruleConsidered
){
1238 return new HybridRelationship(childName
, this, type
, ruleConsidered
);
1243 * Removes one {@link HybridRelationship hybrid relationship} from the set of
1244 * {@link #getHybridRelationships() hybrid relationships} in which <i>this</i> botanical taxon name
1245 * is involved. The hybrid relationship will also be removed from the set
1246 * belonging to the second botanical taxon name involved.
1248 * @param relationship the hybrid relationship which should be deleted from the corresponding sets
1249 * @see #getHybridRelationships()
1251 public void removeHybridRelationship(HybridRelationship hybridRelation
) {
1252 if (hybridRelation
== null) {
1256 NonViralName parent
= hybridRelation
.getParentName();
1257 NonViralName child
= hybridRelation
.getHybridName();
1259 hybridRelation
.setHybridName(null);
1260 hybridRelation
.setParentName(null);
1262 if (parent
!= null) {
1263 parent
.removeHybridRelationship(hybridRelation
);
1266 if (child
!= null) {
1267 child
.removeHybridRelationship(hybridRelation
);
1270 this.hybridChildRelations
.remove(hybridRelation
);
1271 this.hybridParentRelations
.remove(hybridRelation
);
1275 public void removeHybridChild(NonViralName child
) {
1276 Set
<HybridRelationship
> hybridRelationships
= new HashSet
<HybridRelationship
>();
1277 hybridRelationships
.addAll(this.getChildRelationships());
1278 hybridRelationships
.addAll(this.getParentRelationships());
1279 for(HybridRelationship hybridRelationship
: hybridRelationships
) {
1280 // remove name relationship from this side
1281 if (hybridRelationship
.getParentName().equals(this) && hybridRelationship
.getHybridName().equals(child
)) {
1282 this.removeHybridRelationship(hybridRelationship
);
1287 public void removeHybridParent(NonViralName parent
) {
1288 Set
<HybridRelationship
> hybridRelationships
= new HashSet
<HybridRelationship
>();
1289 hybridRelationships
.addAll(this.getChildRelationships());
1290 hybridRelationships
.addAll(this.getParentRelationships());
1291 for(HybridRelationship hybridRelationship
: hybridRelationships
) {
1292 // remove name relationship from this side
1293 if (hybridRelationship
.getParentName().equals(parent
) && hybridRelationship
.getHybridName().equals(this)) {
1294 this.removeHybridRelationship(hybridRelationship
);
1300 * Needs to be implemented by those classes that handle autonyms (e.g. botanical names).
1303 public boolean isAutonym(){
1309 // * Returns the boolean value indicating whether <i>this</i> names rank is Rank "unranked"
1310 // * (uuid = 'a965befb-70a9-4747-a18f-624456c65223') but most likely it is an infrageneric rank
1311 // * due to existing atomized data for the genus epithet and the infrageneric epithet but missing
1312 // * specific epithet.
1313 // * Returns false if <i>this</i> names rank is null.
1315 // * @see #isSupraGeneric()
1316 // * @see #isGenus()
1317 // * @see #isSpeciesAggregate()
1318 // * @see #isSpecies()
1319 // * @see #isInfraSpecific()
1322 // public boolean isInfragenericUnranked() {
1323 // Rank rank = this.getRank();
1324 // if (rank == null || ! rank.equals(Rank.UNRANKED())){
1327 // if (StringUtils.isBlank(this.getSpecificEpithet()) && StringUtils.isBlank(this.getInfraSpecificEpithet()) ){
1336 * Tests if the given name has any authors.
1337 * @return false if no author ((ex)combination or (ex)basionym) exists, true otherwise
1339 public boolean hasAuthors() {
1340 return (this.getCombinationAuthorTeam() != null ||
1341 this.getExCombinationAuthorTeam() != null ||
1342 this.getBasionymAuthorTeam() != null ||
1343 this.getExBasionymAuthorTeam() != null);
1347 * Shortcut. Returns the combination authors title cache. Returns null if no combination author exists.
1350 public String
computeCombinationAuthorNomenclaturalTitle() {
1351 return computeNomenclaturalTitle(this.getCombinationAuthorTeam());
1355 * Shortcut. Returns the basionym authors title cache. Returns null if no basionym author exists.
1358 public String
computeBasionymAuthorNomenclaturalTitle() {
1359 return computeNomenclaturalTitle(this.getBasionymAuthorTeam());
1364 * Shortcut. Returns the ex-combination authors title cache. Returns null if no ex-combination author exists.
1367 public String
computeExCombinationAuthorNomenclaturalTitle() {
1368 return computeNomenclaturalTitle(this.getExCombinationAuthorTeam());
1372 * Shortcut. Returns the ex-basionym authors title cache. Returns null if no exbasionym author exists.
1375 public String
computeExBasionymAuthorNomenclaturalTitle() {
1376 return computeNomenclaturalTitle(this.getExBasionymAuthorTeam());
1379 private String
computeNomenclaturalTitle(INomenclaturalAuthor author
){
1380 if (author
== null){
1383 return author
.getNomenclaturalTitle();
1387 //*********************** CLONE ********************************************************/
1390 * Clones <i>this</i> non-viral name. This is a shortcut that enables to create
1391 * a new instance that differs only slightly from <i>this</i> non-viral name by
1392 * modifying only some of the attributes.
1394 * @see eu.etaxonomy.cdm.model.name.TaxonNameBase#clone()
1395 * @see java.lang.Object#clone()
1398 public Object
clone() {
1399 NonViralName result
= (NonViralName
)super.clone();
1401 //HybridChildRelations
1402 result
.hybridChildRelations
= new HashSet
<HybridRelationship
>();
1403 for (HybridRelationship hybridRelationship
: getHybridChildRelations()){
1404 HybridRelationship newChildRelationship
= (HybridRelationship
)hybridRelationship
.clone();
1405 newChildRelationship
.setRelatedTo(result
);
1406 result
.hybridChildRelations
.add(newChildRelationship
);
1409 //HybridParentRelations
1410 result
.hybridParentRelations
= new HashSet
<HybridRelationship
>();
1411 for (HybridRelationship hybridRelationship
: getHybridParentRelations()){
1412 HybridRelationship newParentRelationship
= (HybridRelationship
)hybridRelationship
.clone();
1413 newParentRelationship
.setRelatedFrom(result
);
1414 result
.hybridParentRelations
.add(newParentRelationship
);
1418 if (! protectedNameCache
){
1419 result
.nameCache
= null;
1423 if (! protectedAuthorshipCache
){
1424 result
.authorshipCache
= null;
1427 //no changes to: basionamyAuthorTeam, combinationAuthorTeam, exBasionymAuthorTeam, exCombinationAuthorTeam
1428 //genusOrUninomial, infraGenericEpithet, specificEpithet, infraSpecificEpithet,
1429 //protectedAuthorshipCache, protectedNameCache
1430 //binomHybrid, monomHybrid, trinomHybrid, hybridFormula,