(no commit message)
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / name / BotanicalName.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
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.
8 */
9
10 package eu.etaxonomy.cdm.model.name;
11
12
13 import java.util.HashSet;
14 import java.util.Set;
15
16 import javax.persistence.Entity;
17 import javax.persistence.OneToMany;
18 import javax.persistence.Transient;
19 import javax.xml.bind.annotation.XmlAccessType;
20 import javax.xml.bind.annotation.XmlAccessorType;
21 import javax.xml.bind.annotation.XmlElement;
22 import javax.xml.bind.annotation.XmlElementWrapper;
23 import javax.xml.bind.annotation.XmlRootElement;
24 import javax.xml.bind.annotation.XmlType;
25
26 import org.apache.log4j.Logger;
27 import org.hibernate.annotations.Cascade;
28 import org.hibernate.annotations.CascadeType;
29
30 import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
31 import eu.etaxonomy.cdm.model.common.RelationshipBase;
32 import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
33 import eu.etaxonomy.cdm.strategy.cache.name.BotanicNameDefaultCacheStrategy;
34 import eu.etaxonomy.cdm.strategy.parser.INonViralNameParser;
35 import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
36
37 /**
38 * The taxon name class for plants and fungi.
39 *
40 * @author m.doering
41 * @version 1.0
42 * @created 08-Nov-2007 13:06:15
43 */
44 @XmlAccessorType(XmlAccessType.FIELD)
45 @XmlType(name = "", propOrder = {
46 "isHybridFormula",
47 "isMonomHybrid",
48 "isBinomHybrid",
49 "isTrinomHybrid",
50 "isAnamorphic",
51 "hybridRelationships"
52 })
53 @XmlRootElement(name = "BotanicalName")
54 @Entity
55 public class BotanicalName extends NonViralName {
56
57 private static final Logger logger = Logger.getLogger(BotanicalName.class);
58
59 //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
60 //hybrid name may not have either an authorteam nor other name components.
61 @XmlElement(name ="IsHybridFormula")
62 private boolean isHybridFormula = false;
63
64 @XmlElement(name ="IsMonomHybrid")
65 private boolean isMonomHybrid = false;
66
67 @XmlElement(name ="IsBinomHybrid")
68 private boolean isBinomHybrid = false;
69
70 @XmlElement(name ="IsTrinomHybrid")
71 private boolean isTrinomHybrid = false;
72
73 //Only for fungi: to indicate that the type of the name is asexual or not
74 @XmlElement(name ="IsAnamorphic")
75 private boolean isAnamorphic;
76
77 @XmlElementWrapper(name = "HybridRelationships")
78 @XmlElement(name = "HybridRelationship")
79 private Set<HybridRelationship> hybridRelationships = new HashSet();
80
81 static private INonViralNameParser nameParser = new NonViralNameParserImpl();
82
83 // ************* CONSTRUCTORS *************/
84 //needed by hibernate
85 /**
86 * Class constructor: creates a new botanical taxon name instance
87 * only containing the {@link eu.etaxonomy.cdm.strategy.cache.BotanicNameDefaultCacheStrategy default cache strategy}.
88 *
89 * @see #BotanicalName(Rank, HomotypicalGroup)
90 * @see #BotanicalName(Rank, String, String, String, String, TeamOrPersonBase, INomenclaturalReference, String, HomotypicalGroup)
91 * @see eu.etaxonomy.cdm.strategy.cache.BotanicNameDefaultCacheStrategy
92 */
93 protected BotanicalName(){
94 super();
95 this.cacheStrategy = BotanicNameDefaultCacheStrategy.NewInstance();
96 }
97 /**
98 * Class constructor: creates a new botanical taxon name instance
99 * only containing its {@link common.Rank rank},
100 * its {@link common.HomotypicalGroup homotypical group} and
101 * the {@link eu.etaxonomy.cdm.strategy.cache.BotanicNameDefaultCacheStrategy default cache strategy}.
102 * The new botanical taxon name instance will be also added to the set of
103 * botanical taxon names belonging to this homotypical group.
104 *
105 * @param rank the rank to be assigned to this botanical taxon name
106 * @param homotypicalGroup the homotypical group to which this botanical taxon name belongs
107 * @see #BotanicalName()
108 * @see #BotanicalName(Rank, String, String, String, TeamOrPersonBase, INomenclaturalReference, String, HomotypicalGroup)
109 * @see eu.etaxonomy.cdm.strategy.cache.BotanicNameDefaultCacheStrategy
110 */
111 protected BotanicalName(Rank rank, HomotypicalGroup homotypicalGroup) {
112 super(rank, homotypicalGroup);
113 this.cacheStrategy = BotanicNameDefaultCacheStrategy.NewInstance();
114 }
115 /**
116 * Class constructor: creates a new botanical taxon name instance
117 * containing its {@link common.Rank rank},
118 * its {@link common.HomotypicalGroup homotypical group},
119 * its scientific name components, its {@link agent.TeamOrPersonBase author(team)},
120 * its {@link reference.INomenclaturalReference nomenclatural reference} and
121 * the {@link eu.etaxonomy.cdm.strategy.cache.BotanicNameDefaultCacheStrategy default cache strategy}.
122 * The new botanical taxon name instance will be also added to the set of
123 * botanical taxon names belonging to this homotypical group.
124 *
125 * @param rank the rank to be assigned to this botanical taxon name
126 * @param genusOrUninomial the string for this botanical taxon name
127 * if its rank is genus or higher or for the genus part
128 * if its rank is lower than genus
129 * @param infraGenericEpithet the string for the first epithet of
130 * this botanical taxon name if its rank is lower than genus
131 * and higher than species aggregate
132 * @param specificEpithet the string for the first epithet of
133 * this botanical taxon name if its rank is species aggregate or lower
134 * @param infraSpecificEpithet the string for the second epithet of
135 * this botanical taxon name if its rank is lower than species
136 * @param combinationAuthorTeam the author or the team who published this botanical taxon name
137 * @param nomenclaturalReference the nomenclatural reference where this botanical taxon name was published
138 * @param nomenclMicroRef the string with the details for precise location within the nomenclatural reference
139 * @param homotypicalGroup the homotypical group to which this botanical taxon name belongs
140 * @see #BotanicalName()
141 * @see #BotanicalName(Rank, HomotypicalGroup)
142 * @see #NewInstance(Rank, String, String, String, String, TeamOrPersonBase, INomenclaturalReference, String, HomotypicalGroup)
143 * @see eu.etaxonomy.cdm.strategy.cache.BotanicNameDefaultCacheStrategy
144 * @see eu.etaxonomy.cdm.strategy.cache.INonViralNameCacheStrategy
145 * @see eu.etaxonomy.cdm.strategy.cache.IIdentifiableEntityCacheStrategy
146 */
147 protected BotanicalName(Rank rank, String genusOrUninomial, String infraGenericEpithet, String specificEpithet, String infraSpecificEpithet, TeamOrPersonBase combinationAuthorTeam, INomenclaturalReference nomenclaturalReference, String nomenclMicroRef, HomotypicalGroup homotypicalGroup) {
148 super(rank, genusOrUninomial, infraGenericEpithet, specificEpithet, infraSpecificEpithet, combinationAuthorTeam, nomenclaturalReference, nomenclMicroRef, homotypicalGroup);
149 this.cacheStrategy = BotanicNameDefaultCacheStrategy.NewInstance();
150 }
151
152
153 //********* METHODS **************************************/
154
155 /**
156 * Creates a new botanical taxon name instance
157 * only containing its {@link common.Rank rank} and
158 * the {@link eu.etaxonomy.cdm.strategy.cache.BotanicNameDefaultCacheStrategy default cache strategy}.
159 *
160 * @param rank the rank to be assigned to this botanical taxon name
161 * @see #BotanicalName(Rank, HomotypicalGroup)
162 * @see #NewInstance(Rank, HomotypicalGroup)
163 * @see #NewInstance(Rank, String, String, String, String, TeamOrPersonBase, INomenclaturalReference, String, HomotypicalGroup)
164 * @see eu.etaxonomy.cdm.strategy.cache.BotanicNameDefaultCacheStrategy
165 */
166 public static BotanicalName NewInstance(Rank rank){
167 return new BotanicalName(rank, null);
168 }
169 /**
170 * Creates a new botanical taxon name instance
171 * only containing its {@link common.Rank rank},
172 * its {@link common.HomotypicalGroup homotypical group} and
173 * the {@link eu.etaxonomy.cdm.strategy.cache.BotanicNameDefaultCacheStrategy default cache strategy}.
174 * The new botanical taxon name instance will be also added to the set of
175 * botanical taxon names belonging to this homotypical group.
176 *
177 * @param rank the rank to be assigned to this botanical taxon name
178 * @param homotypicalGroup the homotypical group to which this botanical taxon name belongs
179 * @see #NewInstance(Rank)
180 * @see #NewInstance(Rank, String, String, String, String, TeamOrPersonBase, INomenclaturalReference, String, HomotypicalGroup)
181 * @see #BotanicalName(Rank, HomotypicalGroup)
182 * @see eu.etaxonomy.cdm.strategy.cache.BotanicNameDefaultCacheStrategy
183 */
184 public static BotanicalName NewInstance(Rank rank, HomotypicalGroup homotypicalGroup){
185 return new BotanicalName(rank, homotypicalGroup);
186 }
187 /**
188 * Creates a new botanical taxon name instance
189 * containing its {@link common.Rank rank},
190 * its {@link common.HomotypicalGroup homotypical group},
191 * its scientific name components, its {@link agent.TeamOrPersonBase author(team)},
192 * its {@link reference.INomenclaturalReference nomenclatural reference} and
193 * the {@link eu.etaxonomy.cdm.strategy.cache.BotanicNameDefaultCacheStrategy default cache strategy}.
194 * The new botanical taxon name instance will be also added to the set of
195 * botanical taxon names belonging to this homotypical group.
196 *
197 * @param rank the rank to be assigned to this botanical taxon name
198 * @param genusOrUninomial the string for this botanical taxon name
199 * if its rank is genus or higher or for the genus part
200 * if its rank is lower than genus
201 * @param infraGenericEpithet the string for the first epithet of
202 * this botanical taxon name if its rank is lower than genus
203 * and higher than species aggregate
204 * @param specificEpithet the string for the first epithet of
205 * this botanical taxon name if its rank is species aggregate or lower
206 * @param infraSpecificEpithet the string for the second epithet of
207 * this botanical taxon name if its rank is lower than species
208 * @param combinationAuthorTeam the author or the team who published this botanical taxon name
209 * @param nomenclaturalReference the nomenclatural reference where this botanical taxon name was published
210 * @param nomenclMicroRef the string with the details for precise location within the nomenclatural reference
211 * @param homotypicalGroup the homotypical group to which this botanical taxon name belongs
212 * @see #NewInstance(Rank)
213 * @see #NewInstance(Rank, HomotypicalGroup)
214 * @see #ZoologicalName(Rank, String, String, String, String, TeamOrPersonBase, INomenclaturalReference, String, HomotypicalGroup)
215 * @see eu.etaxonomy.cdm.strategy.cache.BotanicNameDefaultCacheStrategy
216 */
217 public static BotanicalName NewInstance(Rank rank, String genusOrUninomial, String infraGenericEpithet, String specificEpithet, String infraSpecificEpithet, TeamOrPersonBase combinationAuthorTeam, INomenclaturalReference nomenclaturalReference, String nomenclMicroRef, HomotypicalGroup homotypicalGroup) {
218 return new BotanicalName(rank, genusOrUninomial, infraGenericEpithet, specificEpithet, infraSpecificEpithet, combinationAuthorTeam, nomenclaturalReference, nomenclMicroRef, homotypicalGroup);
219 }
220
221 /**
222 * Returns a botanical taxon name based on parsing a string representing
223 * all elements (according to the ICBN) of a botanical taxon name (where
224 * the scientific name is an uninomial) including authorship but without
225 * nomenclatural reference.
226 *
227 * @param fullNameString the string to be parsed
228 * @return the new botanical taxon name
229 */
230 public static BotanicalName PARSED_NAME(String fullNameString){
231 return PARSED_NAME(fullNameString, Rank.GENUS());
232 }
233
234 /**
235 * Returns a botanical taxon name based on parsing a string representing
236 * all elements (according to the ICBN) of a botanical taxon name including
237 * authorship but without nomenclatural reference. The parsing result
238 * depends on the given rank of the botanical taxon name to be created.
239 *
240 * @param fullNameString the string to be parsed
241 * @param rank the rank of the taxon name
242 * @return the new botanical taxon name
243 */
244 public static BotanicalName PARSED_NAME(String fullNameString, Rank rank){
245 if (nameParser == null){
246 nameParser = new NonViralNameParserImpl();
247 }
248 return (BotanicalName)nameParser.parseFullName(fullNameString, NomenclaturalCode.ICBN(), rank);
249 }
250
251 /**
252 * Returns a botanical taxon name based on parsing a string representing
253 * all elements (according to the ICBN) of a botanical taxon name (where
254 * the scientific name is an uninomial) including authorship and
255 * nomenclatural reference. Eventually a new {@link reference.INomenclaturalReference nomenclatural reference}
256 * instance will also be created.
257 *
258 * @param fullNameAndReferenceString the string to be parsed
259 * @return the new botanical taxon name
260 */
261 public static BotanicalName PARSED_REFERENCE(String fullNameAndReferenceString){
262 return PARSED_REFERENCE(fullNameAndReferenceString, Rank.GENUS());
263 }
264
265 /**
266 * Returns a botanical taxon name based on parsing a string representing
267 * all elements (according to the ICBN) of a botanical taxon name including
268 * authorship and nomenclatural reference. The parsing result depends on
269 * the given rank of the botanical taxon name to be created.
270 * Eventually a new {@link reference.INomenclaturalReference nomenclatural reference}
271 * instance will also be created.
272 *
273 * @param fullNameAndReferenceString the string to be parsed
274 * @return the new botanical taxon name
275 */
276 public static BotanicalName PARSED_REFERENCE(String fullNameAndReferenceString, Rank rank){
277 if (nameParser == null){
278 nameParser = new NonViralNameParserImpl();
279 }
280 return (BotanicalName)nameParser.parseFullReference(fullNameAndReferenceString, NomenclaturalCode.ICBN(), rank);
281 }
282
283
284 /**
285 * Returns the set of all {@link HybridRelationship hybrid relationships}
286 * in which this botanical taxon name is involved. Any botanical taxon name
287 * (even itself a hybrid taxon name) can be a parent of another hybrid
288 * taxon name.
289 *
290 * @see #getParentRelationships()
291 * @see #getChildRelationships()
292 * @see #addHybridRelationship(HybridRelationship)
293 * @see #addRelationship(RelationshipBase)
294 */
295 @OneToMany
296 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN})
297 public Set<HybridRelationship> getHybridRelationships() {
298 return hybridRelationships;
299 }
300 /**
301 * @see #getHybridRelationships()
302 */
303 protected void setHybridRelationships(Set<HybridRelationship> relationships) {
304 this.hybridRelationships = relationships;
305 }
306 /**
307 * Adds the given {@link HybridRelationship hybrid relationship} to the set
308 * of {@link #getHybridRelationships() hybrid relationships} of both botanical taxon names
309 * involved in this hybrid relationship. One of both botanical taxon names
310 * must be this botanical taxon name else no addition will be carried out.
311 * The {@link common.RelationshipBase#getRelatedTo() child botanical taxon name}
312 * must be a hybrid, which means that one of its four hybrid flags must be set.
313 *
314 * @param relationship the hybrid relationship to be added
315 * @see #isHybridFormula()
316 * @see #isMonomHybrid()
317 * @see #isBinomHybrid()
318 * @see #isTrinomHybrid()
319 * @see #getHybridRelationships()
320 * @see #getParentRelationships()
321 * @see #getChildRelationships()
322 * @see #addRelationship(RelationshipBase)
323 */
324 public void addHybridRelationship(HybridRelationship relationship) {
325 this.hybridRelationships.add(relationship);
326 }
327 /**
328 * Removes one {@link HybridRelationship hybrid relationship} from the set of
329 * {@link #getHybridRelationships() hybrid relationships} in which this botanical taxon name
330 * is involved. The hybrid relationship will also be removed from the set
331 * belonging to the second botanical taxon name involved.
332 *
333 * @param relationship the hybrid relationship which should be deleted from the corresponding sets
334 * @see #getHybridRelationships()
335 */
336 public void removeHybridRelationship(HybridRelationship relationship) {
337 this.hybridRelationships.remove(relationship);
338 }
339
340 /**
341 * Returns the set of all {@link HybridRelationship hybrid relationships}
342 * in which this botanical taxon name is involved as a {@link common.RelationshipBase#getRelatedFrom() parent}.
343 *
344 * @see #getHybridRelationships()
345 * @see #getChildRelationships()
346 * @see HybridRelationshipType
347 */
348 @Transient
349 public Set<HybridRelationship> getParentRelationships() {
350 // FIXME: filter relations
351 return hybridRelationships;
352 }
353 /**
354 * Returns the set of all {@link HybridRelationship hybrid relationships}
355 * in which this botanical taxon name is involved as a {@link common.RelationshipBase#getRelatedTo() child}.
356 *
357 * @see #getHybridRelationships()
358 * @see #getParentRelationships()
359 * @see HybridRelationshipType
360 */
361 @Transient
362 public Set<HybridRelationship> getChildRelationships() {
363 // FIXME: filter relations
364 return hybridRelationships;
365 }
366
367 /**
368 * Does the same as the addHybridRelationship method if the given
369 * {@link common.RelationshipBase relation} is also a {@link HybridRelationship hybrid relationship}.
370 * Otherwise this method does the same as the overwritten {@link TaxonNameBase#addRelationship(RelationshipBase) addRelationship}
371 * method from TaxonNameBase.
372 *
373 * @param relation the relationship to be added to some of this taxon name's relationships sets
374 * @see #addHybridRelationship(HybridRelationship)
375 * @see TaxonNameBase#addRelationship(RelationshipBase)
376 * @see TaxonNameBase#addNameRelationship(NameRelationship)
377 */
378 public void addRelationship(RelationshipBase relation) {
379 if (relation instanceof HybridRelationship){
380 addHybridRelationship((HybridRelationship)relation);
381 }else {
382 super.addRelationship(relation);
383 }
384 }
385
386 /**
387 * Returns the boolean value of the flag indicating whether the name of this
388 * botanical taxon name is a hybrid formula (true) or not (false). A hybrid
389 * named by a hybrid formula (composed with its parent names by placing the
390 * multiplication sign between them) does not have an own published name
391 * and therefore has neither an {@link NonViralName#getAuthorshipCache() autorship}
392 * nor other name components. If this flag is set no other hybrid flags may
393 * be set.
394 *
395 * @return the boolean value of the isHybridFormula flag
396 * @see #isMonomHybrid()
397 * @see #isBinomHybrid()
398 * @see #isTrinomHybrid()
399 */
400 public boolean isHybridFormula(){
401 return this.isHybridFormula;
402 }
403
404 /**
405 * @see #isHybridFormula()
406 */
407 public void setHybridFormula(boolean isHybridFormula){
408 this.isHybridFormula = isHybridFormula;
409 }
410
411 /**
412 * Returns the boolean value of the flag indicating whether this botanical
413 * taxon name is the name of an intergeneric hybrid (true) or not (false).
414 * In this case the multiplication sign is placed before the scientific
415 * name. If this flag is set no other hybrid flags may be set.
416 *
417 * @return the boolean value of the isMonomHybrid flag
418 * @see #isHybridFormula()
419 * @see #isBinomHybrid()
420 * @see #isTrinomHybrid()
421 */
422 public boolean isMonomHybrid(){
423 return this.isMonomHybrid;
424 }
425
426 /**
427 * @see #isMonomHybrid()
428 * @see #isBinomHybrid()
429 * @see #isTrinomHybrid()
430 */
431 public void setMonomHybrid(boolean isMonomHybrid){
432 this.isMonomHybrid = isMonomHybrid;
433 }
434
435 /**
436 * Returns the boolean value of the flag indicating whether this botanical
437 * taxon name is the name of an interspecific hybrid (true) or not (false).
438 * In this case the multiplication sign is placed before the species
439 * epithet. If this flag is set no other hybrid flags may be set.
440 *
441 * @return the boolean value of the isBinomHybrid flag
442 * @see #isHybridFormula()
443 * @see #isMonomHybrid()
444 * @see #isTrinomHybrid()
445 */
446 public boolean isBinomHybrid(){
447 return this.isBinomHybrid;
448 }
449
450 /**
451 * @see #isBinomHybrid()
452 * @see #isMonomHybrid()
453 * @see #isTrinomHybrid()
454 */
455 public void setBinomHybrid(boolean isBinomHybrid){
456 this.isBinomHybrid = isBinomHybrid;
457 }
458
459 /**
460 * Returns the boolean value of the flag indicating whether this botanical
461 * taxon name is the name of an infraspecific hybrid (true) or not (false).
462 * In this case the term "notho-" (optionally abbreviated "n-") is used as
463 * a prefix to the term denoting the infraspecific rank of this botanical
464 * taxon name. If this flag is set no other hybrid flags may be set.
465 *
466 * @return the boolean value of the isTrinomHybrid flag
467 * @see #isHybridFormula()
468 * @see #isMonomHybrid()
469 * @see #isBinomHybrid()
470 */
471 public boolean isTrinomHybrid(){
472 return this.isTrinomHybrid;
473 }
474
475 /**
476 * @see #isTrinomHybrid()
477 * @see #isBinomHybrid()
478 * @see #isMonomHybrid()
479 */
480 public void setTrinomHybrid(boolean isTrinomHybrid){
481 this.isTrinomHybrid = isTrinomHybrid;
482 }
483
484 /**
485 * Returns the boolean value of the flag indicating whether the specimen
486 * type of this botanical taxon name for a fungus is asexual (true) or not
487 * (false). This applies only in case of fungi. The Article 59 of the ICBN
488 * permits mycologists to give asexually reproducing fungi (anamorphs)
489 * separate names from their sexual states (teleomorphs).
490 *
491 * @return the boolean value of the isAnamorphic flag
492 */
493 public boolean isAnamorphic(){
494 return this.isAnamorphic;
495 }
496
497 /**
498 * @see #isAnamorphic()
499 */
500 public void setAnamorphic(boolean isAnamorphic){
501 this.isAnamorphic = isAnamorphic;
502 }
503
504
505 /**
506 * Returns the {@link NomenclaturalCode nomenclatural code} that governs
507 * the construction of this botanical taxon name, that is the
508 * International Code of Botanical Nomenclature. This method overrides
509 * the getNomeclaturalCode method from {@link TaxonNameBase#getNomeclaturalCode() TaxonNameBase}.
510 *
511 * @return the nomenclatural code for plants
512 * @see NonViralName#isCodeCompliant()
513 * @see TaxonNameBase#getHasProblem()
514 */
515 @Transient
516 @Override
517 public NomenclaturalCode getNomenclaturalCode(){
518 return NomenclaturalCode.ICBN();
519
520 }
521
522 }