merge 3.0.2 to trunk
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / taxon / Taxon.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.taxon;
11
12
13 import java.lang.reflect.Field;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.Iterator;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22
23 import javax.persistence.Entity;
24 import javax.persistence.FetchType;
25 import javax.persistence.ManyToOne;
26 import javax.persistence.OneToMany;
27 import javax.persistence.Transient;
28 import javax.validation.Valid;
29 import javax.validation.constraints.NotNull;
30 import javax.xml.bind.annotation.XmlAccessType;
31 import javax.xml.bind.annotation.XmlAccessorType;
32 import javax.xml.bind.annotation.XmlAttribute;
33 import javax.xml.bind.annotation.XmlElement;
34 import javax.xml.bind.annotation.XmlElementWrapper;
35 import javax.xml.bind.annotation.XmlIDREF;
36 import javax.xml.bind.annotation.XmlRootElement;
37 import javax.xml.bind.annotation.XmlSchemaType;
38 import javax.xml.bind.annotation.XmlType;
39
40 import org.apache.log4j.Logger;
41 import org.hibernate.annotations.Cascade;
42 import org.hibernate.annotations.CascadeType;
43 import org.hibernate.envers.Audited;
44 import org.hibernate.search.annotations.Indexed;
45 import org.springframework.beans.factory.annotation.Configurable;
46 import org.springframework.util.ReflectionUtils;
47
48 import eu.etaxonomy.cdm.model.common.IRelated;
49 import eu.etaxonomy.cdm.model.common.RelationshipBase;
50 import eu.etaxonomy.cdm.model.description.TaxonDescription;
51 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
52 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
53 import eu.etaxonomy.cdm.model.reference.Reference;
54 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
55 import eu.etaxonomy.cdm.strategy.cache.taxon.TaxonBaseDefaultCacheStrategy;
56
57 /**
58 * The class for "accepted/correct" {@link TaxonBase taxa} (only these taxa according to
59 * the opinion of the {@link eu.etaxonomy.cdm.model.reference.Reference reference} can build a classification).
60 * An {@link java.lang.Iterable interface} is supported to iterate through taxonomic children.<BR>
61 * Splitting taxa in "accepted/correct" and {@link Synonym "synonyms"} makes it easier to handle
62 * particular relationships between ("accepted/correct") taxa on the one hand
63 * and between ("synonym") taxa and ("accepted/correct") taxa on the other.
64 *
65 * @author m.doering
66 * @version 1.0
67 * @created 08-Nov-2007 13:06:56
68 */
69 @XmlAccessorType(XmlAccessType.FIELD)
70 @XmlType(name = "Taxon", propOrder = {
71 "taxonomicParentCache",
72 "taxonNodes",
73 "taxonomicChildrenCount",
74 "synonymRelations",
75 "relationsFromThisTaxon",
76 "relationsToThisTaxon",
77 "descriptions"
78 })
79 @XmlRootElement(name = "Taxon")
80 @Entity
81 @Indexed(index = "eu.etaxonomy.cdm.model.taxon.TaxonBase")
82 @Audited
83 @Configurable
84 public class Taxon extends TaxonBase<IIdentifiableEntityCacheStrategy<Taxon>> implements IRelated<RelationshipBase>{
85 private static final long serialVersionUID = -584946869762749006L;
86 private static final Logger logger = Logger.getLogger(Taxon.class);
87
88 @XmlElementWrapper(name = "Descriptions")
89 @XmlElement(name = "Description")
90 @OneToMany(mappedBy="taxon", fetch= FetchType.LAZY)
91 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
92 @NotNull
93 private Set<TaxonDescription> descriptions = new HashSet<TaxonDescription>();
94
95 // all related synonyms
96 @XmlElementWrapper(name = "SynonymRelations")
97 @XmlElement(name = "SynonymRelationship")
98 @OneToMany(mappedBy="relatedTo", fetch=FetchType.LAZY)
99 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
100 @NotNull
101 @Valid
102 private Set<SynonymRelationship> synonymRelations = new HashSet<SynonymRelationship>();
103
104 // all taxa relations with rel.fromTaxon==this
105 @XmlElementWrapper(name = "RelationsFromThisTaxon")
106 @XmlElement(name = "FromThisTaxonRelationship")
107 @OneToMany(mappedBy="relatedFrom", fetch=FetchType.LAZY)
108 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
109 @NotNull
110 @Valid
111 private Set<TaxonRelationship> relationsFromThisTaxon = new HashSet<TaxonRelationship>();
112
113 // all taxa relations with rel.toTaxon==this
114 @XmlElementWrapper(name = "RelationsToThisTaxon")
115 @XmlElement(name = "ToThisTaxonRelationship")
116 @XmlIDREF
117 @XmlSchemaType(name = "IDREF")
118 @OneToMany(mappedBy="relatedTo", fetch=FetchType.LAZY)
119 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
120 @NotNull
121 @Valid
122 private Set<TaxonRelationship> relationsToThisTaxon = new HashSet<TaxonRelationship>();
123
124 @XmlAttribute(name= "taxonStatusUnknown")
125 private boolean taxonStatusUnknown = false;
126
127 @XmlAttribute(name= "unplaced")
128 private boolean unplaced = false;
129
130 @XmlAttribute(name= "excluded")
131 private boolean excluded = false;
132
133 // shortcut to the taxonomicIncluded (parent) taxon. Managed by the taxonRelations setter
134 @XmlElement(name = "TaxonomicParentCache")
135 @XmlIDREF
136 @XmlSchemaType(name = "IDREF")
137 @ManyToOne(fetch = FetchType.LAZY)
138 @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
139 private Taxon taxonomicParentCache;
140
141
142
143 @XmlElementWrapper(name = "taxonNodes")
144 @XmlElement(name = "taxonNode")
145 @XmlIDREF
146 @XmlSchemaType(name = "IDREF")
147 @OneToMany(mappedBy="taxon", fetch=FetchType.LAZY)
148 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
149 private Set<TaxonNode> taxonNodes = new HashSet<TaxonNode>();
150
151 //cached number of taxonomic children
152 @XmlElement(name = "TaxonomicChildrenCount")
153 @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
154 private int taxonomicChildrenCount;
155
156 // ************* CONSTRUCTORS *************/
157
158 //TODO should be private, but still produces Spring init errors
159 @Deprecated
160 public Taxon(){
161 this.cacheStrategy = new TaxonBaseDefaultCacheStrategy<Taxon>();
162 }
163
164 /**
165 * Class constructor: creates a new (accepted/correct) taxon instance with
166 * the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.Reference reference}
167 * using it.
168 *
169 * @param taxonNameBase the taxon name used
170 * @param sec the reference using the taxon name
171 * @see TaxonBase#TaxonBase(TaxonNameBase, Reference)
172 */
173 public Taxon(TaxonNameBase taxonNameBase, Reference sec){
174 super(taxonNameBase, sec);
175 this.cacheStrategy = new TaxonBaseDefaultCacheStrategy<Taxon>();
176 }
177
178 //********* METHODS **************************************/
179
180 /**
181 * Creates a new (accepted/correct) taxon instance with
182 * the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.Reference reference}
183 * using it.
184 *
185 * @param taxonNameBase the taxon name used
186 * @param sec the reference using the taxon name
187 * @see #Taxon(TaxonNameBase, Reference)
188 */
189 public static Taxon NewInstance(TaxonNameBase taxonNameBase, Reference sec){
190 Taxon result = new Taxon(taxonNameBase, sec);
191 return result;
192 }
193
194 /**
195 * Creates a new taxon instance with an unknown status (accepted/synonym) and with
196 * the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.Reference reference}
197 * using it.
198 *
199 * @param taxonNameBase the taxon name used
200 * @param sec the reference using the taxon name
201 * @see #Taxon(TaxonNameBase, Reference)
202 */
203 public static Taxon NewUnknownStatusInstance(TaxonNameBase taxonNameBase, Reference sec){
204 Taxon result = new Taxon(taxonNameBase, sec);
205 result.setTaxonStatusUnknown(true);
206 return result;
207 }
208
209 /**
210 * Returns the set of {@link eu.etaxonomy.cdm.model.description.TaxonDescription taxon descriptions}
211 * concerning <i>this</i> taxon.
212 *
213 * @see #removeDescription(TaxonDescription)
214 * @see #addDescription(TaxonDescription)
215 * @see eu.etaxonomy.cdm.model.description.TaxonDescription#getTaxon()
216 */
217 public Set<TaxonDescription> getDescriptions() {
218 if(descriptions == null) {
219 descriptions = new HashSet<TaxonDescription>();
220 }
221 return descriptions;
222 }
223
224 /**
225 * Adds a new {@link eu.etaxonomy.cdm.model.description.TaxonDescription taxon description} to the set
226 * of taxon descriptions assigned to <i>this</i> (accepted/correct) taxon.
227 * Due to bidirectionality the content of the {@link eu.etaxonomy.cdm.model.description.TaxonDescription#getTaxon() taxon attribute} of the
228 * taxon description itself will be replaced with <i>this</i> taxon. The taxon
229 * description will also be removed from the set of taxon descriptions
230 * assigned to its previous taxon.
231 *
232 * @param description the taxon description to be added for <i>this</i> taxon
233 * @see #getDescriptions()
234 * @see #removeDescription(TaxonDescription)
235 * @see eu.etaxonomy.cdm.model.description.TaxonDescription#getTaxon()
236 */
237 public void addDescription(TaxonDescription description) {
238 if (description.getTaxon() != null){
239 description.getTaxon().removeDescription(description);
240 }
241 Field field = ReflectionUtils.findField(TaxonDescription.class, "taxon", Taxon.class);
242 ReflectionUtils.makeAccessible(field);
243 ReflectionUtils.setField(field, description, this);
244 descriptions.add(description);
245
246 }
247 /**
248 * Removes one element from the set of {@link eu.etaxonomy.cdm.model.description.TaxonDescription taxon descriptions} assigned
249 * to <i>this</i> (accepted/correct) taxon. Due to bidirectionality the content of
250 * the {@link eu.etaxonomy.cdm.model.description.TaxonDescription#getTaxon() taxon attribute} of the taxon description
251 * itself will be set to "null".
252 *
253 * @param description the taxon description which should be removed
254 * @see #getDescriptions()
255 * @see #addDescription(TaxonDescription)
256 * @see eu.etaxonomy.cdm.model.description.TaxonDescription#getTaxon()
257 */
258 public void removeDescription(TaxonDescription description) {
259 //description.setTaxon(null) for not visible method
260 Field field = ReflectionUtils.findField(TaxonDescription.class, "taxon", Taxon.class);
261 ReflectionUtils.makeAccessible(field);
262 ReflectionUtils.setField(field, description, null);
263 descriptions.remove(description);
264 }
265
266 /**
267 * Returns the image gallery for a taxon. If there are multiple taxon descriptions
268 * marked as image galleries an arbitrary one is chosen.
269 * If no image gallery exists, a new one is created if <code>createNewIfNotExists</code>
270 * is <code>true</code>.
271 * @param createNewIfNotExists
272 * @return
273 */
274 public TaxonDescription getImageGallery(boolean createNewIfNotExists) {
275 TaxonDescription result = null;
276 Set<TaxonDescription> descriptions= getDescriptions();
277 for (TaxonDescription description : descriptions){
278 if (description.isImageGallery()){
279 result = description;
280 break;
281 }
282 }
283 if (result == null && createNewIfNotExists){
284 result = TaxonDescription.NewInstance(this);
285 result.setImageGallery(true);
286 }
287 return result;
288 }
289
290
291
292 public Set<TaxonNode> getTaxonNodes() {
293 return taxonNodes;
294 }
295 // protected void setTaxonNodes(Set<TaxonNode> taxonNodes) {
296 // this.taxonNodes = taxonNodes;
297 // }
298 protected void addTaxonNode(TaxonNode taxonNode){
299 taxonNodes.add(taxonNode);
300 }
301 protected void removeTaxonNode(TaxonNode taxonNode){
302 taxonNodes.remove(taxonNode);
303 }
304
305
306
307
308 /**
309 * Returns the set of all {@link SynonymRelationship synonym relationships}
310 * in which <i>this</i> ("accepted/correct") taxon is involved. <i>This</i> taxon can only
311 * be the target of these synonym relationships.
312 *
313 * @see #addSynonymRelation(SynonymRelationship)
314 * @see #removeSynonymRelation(SynonymRelationship)
315 * @see #getSynonyms()
316 */
317 public Set<SynonymRelationship> getSynonymRelations() {
318 if(synonymRelations == null) {
319 this.synonymRelations = new HashSet<SynonymRelationship>();
320 }
321 return synonymRelations;
322 }
323
324 /**
325 * Adds an existing {@link SynonymRelationship synonym relationship} to the set of
326 * {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon. If
327 * the target of the synonym relationship does not match with <i>this</i> taxon
328 * no addition will be carried out.
329 *
330 * @param synonymRelation the synonym relationship to be added to <i>this</i> taxon's
331 * synonym relationships set
332 * @see #getSynonymRelations()
333 * @see #addSynonym(Synonym, SynonymRelationshipType)
334 * @see #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
335 * @see #addSynonymName(TaxonNameBase, SynonymRelationshipType)
336 * @see #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
337 */
338 protected void addSynonymRelation(SynonymRelationship synonymRelation) {
339 this.synonymRelations.add(synonymRelation);
340 }
341 /**
342 * Removes one element from the set of {@link SynonymRelationship synonym relationships} assigned
343 * to <i>this</i> (accepted/correct) taxon. Due to bidirectionality the given
344 * synonym relationship will also be removed from the set of synonym
345 * relationships assigned to the {@link Synonym#getSynonymRelations() synonym} involved in the
346 * relationship. Furthermore the content of
347 * the {@link SynonymRelationship#getAcceptedTaxon() accepted taxon} attribute and of the
348 * {@link SynonymRelationship#getSynonym() synonym} attribute within the synonym relationship
349 * itself will be set to "null".
350 *
351 * @param synonymRelation the synonym relationship which should be deleted
352 * @param removeSynonymNameFromHomotypicalGroup
353 * if set to true the synonym name will also be deleted from its homotypical group
354 * @see #getSynonymRelations()
355 * @see #addSynonymRelation(SynonymRelationship)
356 * @see #removeSynonym(Synonym)
357 */
358 public void removeSynonymRelation(SynonymRelationship synonymRelation, boolean removeSynonymNameFromHomotypicalGroup) {
359 synonymRelation.setAcceptedTaxon(null);
360 Synonym synonym = synonymRelation.getSynonym();
361 if (synonym != null){
362 synonymRelation.setSynonym(null);
363 synonym.removeSynonymRelation(synonymRelation);
364 if(removeSynonymNameFromHomotypicalGroup){
365 synonym.getName().getHomotypicalGroup().removeTypifiedName(synonym.getName());
366 }
367 }
368 this.synonymRelations.remove(synonymRelation);
369 }
370
371 /**
372 * Like {@link Taxon#removeSynonymRelation(SynonymRelationship, boolean)} but synonym name will be deleted from homotypical group
373 * by default
374 *
375 * @param synonymRelation the synonym relationship which should be deleted
376 *
377 * @see #removeSynonymRelation(SynonymRelationship, boolean)
378 */
379 public void removeSynonymRelation(SynonymRelationship synonymRelation){
380 removeSynonymRelation(synonymRelation, true);
381 }
382
383
384 /**
385 * Returns the set of all {@link TaxonRelationship taxon relationships}
386 * between two taxa in which <i>this</i> taxon is involved as a source.
387 *
388 * @see #getRelationsToThisTaxon()
389 * @see #getTaxonRelations()
390 */
391 public Set<TaxonRelationship> getRelationsFromThisTaxon() {
392 if(relationsFromThisTaxon == null) {
393 this.relationsFromThisTaxon = new HashSet<TaxonRelationship>();
394 }
395 return relationsFromThisTaxon;
396 }
397
398
399 /**
400 * Returns the set of all {@link TaxonRelationship taxon relationships}
401 * between two taxa in which <i>this</i> taxon is involved as a target.
402 *
403 * @see #getRelationsFromThisTaxon()
404 * @see #getTaxonRelations()
405 */
406 public Set<TaxonRelationship> getRelationsToThisTaxon() {
407 if(relationsToThisTaxon == null) {
408 this.relationsToThisTaxon = new HashSet<TaxonRelationship>();
409 }
410 return relationsToThisTaxon;
411 }
412 /**
413 * @see #getRelationsToThisTaxon()
414 */
415 protected void setRelationsToThisTaxon(Set<TaxonRelationship> relationsToThisTaxon) {
416 this.relationsToThisTaxon = relationsToThisTaxon;
417 }
418
419 /**
420 * @see #getRelationsFromThisTaxon()
421 */
422 protected void setRelationsFromThisTaxon(Set<TaxonRelationship> relationsFromThisTaxon) {
423 this.relationsFromThisTaxon = relationsFromThisTaxon;
424 }
425
426 /**
427 * Returns the set of all {@link TaxonRelationship taxon relationships}
428 * between two taxa in which <i>this</i> taxon is involved either as a source or
429 * as a target.
430 *
431 * @see #getRelationsFromThisTaxon()
432 * @see #getRelationsToThisTaxon()
433 */
434 @Transient
435 public Set<TaxonRelationship> getTaxonRelations() {
436 Set<TaxonRelationship> rels = new HashSet<TaxonRelationship>();
437 rels.addAll(getRelationsToThisTaxon());
438 rels.addAll(getRelationsFromThisTaxon());
439 return rels;
440 }
441
442 /**
443 * If a relationships between <i>this</i> and the given taxon exists they will be returned.
444 * <i>This</i> taxon is involved either as a source or as a target in the relationships.
445 * The method will return <code>null</code> if no relations exist between the two taxa.
446 *
447 * @param possiblyRelatedTaxon
448 * a taxon to check for a relationship
449 * @return
450 * a set of <code>TaxonRelationship</code>s or <code>null</null> if none exists.
451 */
452 public Set<TaxonRelationship> getTaxonRelations(Taxon possiblyRelatedTaxon){
453 Set<TaxonRelationship> relations = new HashSet<TaxonRelationship>();
454
455 for(TaxonRelationship relationship : getTaxonRelations()){
456 if(relationship.getFromTaxon().equals(possiblyRelatedTaxon))
457 relations.add(relationship);
458 if(relationship.getToTaxon().equals(possiblyRelatedTaxon))
459 relations.add(relationship);
460 }
461
462 return relations.size() > 0 ? relations : null;
463 }
464
465 /**
466 * Removes one {@link TaxonRelationship taxon relationship} from one of both sets of
467 * {@link #getTaxonRelations() taxon relationships} in which <i>this</i> taxon is involved
468 * either as a {@link #getRelationsFromThisTaxon() source} or as a {@link #getRelationsToThisTaxon() target}.
469 * The taxon relationship will also be removed from one of both sets
470 * belonging to the second taxon involved. Furthermore the inherited RelatedFrom and
471 * RelatedTo attributes of the given taxon relationship will be nullified.<P>
472 * If the taxon relationship concerns the classification possible
473 * modifications of the {@link #getTaxonomicParent() parent taxon} or of the number of
474 * {@link #getTaxonomicChildrenCount() childrens} will be stored.
475 *
476 * @param rel the taxon relationship which should be removed from one
477 * of both sets
478 * @see #getTaxonRelations()
479 * @see #getTaxonomicParent()
480 * @see #getTaxonomicChildrenCount()
481 * @see eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom()
482 * @see eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedTo()
483 *
484 */
485 public void removeTaxonRelation(TaxonRelationship rel) {
486 this.relationsToThisTaxon.remove(rel);
487 this.relationsFromThisTaxon.remove(rel);
488 Taxon fromTaxon = rel.getFromTaxon();
489 Taxon toTaxon = rel.getToTaxon();
490 // check if this removes the taxonomical parent. If so, also remove shortcut to the higher taxon
491 if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) ){
492 if (fromTaxon != null && fromTaxon.equals(this)){
493 this.taxonomicParentCache = null;
494 }else if (toTaxon != null && toTaxon.equals(this)){
495 this.setTaxonomicChildrenCount(computeTaxonomicChildrenCount());
496 }
497 }
498 //delete Relationship from other related Taxon
499 if (fromTaxon != null && fromTaxon != this){
500 rel.setToTaxon(null); //remove this Taxon from relationship
501 fromTaxon.removeTaxonRelation(rel);
502 }
503 if (toTaxon != null && toTaxon != this){
504 rel.setFromTaxon(null); //remove this Taxon from relationship
505 toTaxon.removeTaxonRelation(rel);
506 }
507 }
508
509 /**
510 * Adds an existing {@link TaxonRelationship taxon relationship} either to the set of
511 * {@link #getRelationsToThisTaxon() taxon relationships to <i>this</i> taxon} or to the set of
512 * {@link #getRelationsFromThisTaxon() taxon relationships from <i>this</i> taxon}. If neither the
513 * source nor the target of the taxon relationship match with <i>this</i> taxon
514 * no addition will be carried out. The taxon relationship will also be
515 * added to the second taxon involved in the given relationship.<P>
516 * If the taxon relationship concerns the classification possible
517 * modifications of the {@link #getTaxonomicParent() parent taxon} or of the number of
518 * {@link #getTaxonomicChildrenCount() childrens} will be stored.
519 *
520 * @param rel the taxon relationship to be added to one of <i>this</i> taxon's taxon relationships sets
521 * @see #addTaxonRelation(Taxon, TaxonRelationshipType, Reference, String)
522 * @see #getTaxonRelations()
523 * @see #getRelationsFromThisTaxon()
524 * @see #getRelationsToThisTaxon()
525 * @see #getTaxonomicParent()
526 * @see #getTaxonomicChildrenCount()
527 */
528 public void addTaxonRelation(TaxonRelationship rel) {
529 if (rel!=null && rel.getType()!=null && !getTaxonRelations().contains(rel) ){
530 Taxon toTaxon=rel.getToTaxon();
531 Taxon fromTaxon=rel.getFromTaxon();
532 if ( this.equals(toTaxon) || this.equals(fromTaxon) ){
533 if (this.equals(fromTaxon)){
534 relationsFromThisTaxon.add(rel);
535 // also add relation to other taxon object
536 if (toTaxon!=null){
537 toTaxon.addTaxonRelation(rel);
538 }
539 // check if this sets the taxonomical parent. If so, remember a shortcut to this taxon
540 if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) && toTaxon!=null ){
541 this.taxonomicParentCache = toTaxon;
542 }
543 }else if (this.equals(toTaxon)){
544 relationsToThisTaxon.add(rel);
545 // also add relation to other taxon object
546 if (fromTaxon!=null){
547 fromTaxon.addTaxonRelation(rel);
548 }
549 if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) && fromTaxon!=null ){
550 this.taxonomicChildrenCount++;
551 }
552
553 }
554 }else if (toTaxon == null || fromTaxon == null){
555 if (toTaxon == null){
556 toTaxon = this;
557 relationsToThisTaxon.add(rel);
558 if (fromTaxon!= null){
559 fromTaxon.addTaxonRelation(rel);
560 }
561 if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) && fromTaxon!=null ){
562 this.taxonomicChildrenCount++;
563 }
564 }else if (fromTaxon == null && toTaxon != null){
565 fromTaxon = this;
566 relationsFromThisTaxon.add(rel);
567 if (toTaxon!=null){
568 toTaxon.addTaxonRelation(rel);
569 }
570 if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) && toTaxon!=null ){
571 this.taxonomicParentCache = toTaxon;
572 }
573 }
574 }
575 }
576 }
577
578 /* (non-Javadoc)
579 * @see eu.etaxonomy.cdm.model.common.IRelated#addRelationship(eu.etaxonomy.cdm.model.common.RelationshipBase)
580 */
581 @Deprecated //for inner use by RelationshipBase only
582 public void addRelationship(RelationshipBase rel){
583 if (rel instanceof TaxonRelationship){
584 addTaxonRelation((TaxonRelationship)rel);
585 }else if (rel instanceof SynonymRelationship){
586 addSynonymRelation((SynonymRelationship)rel);
587 }else{
588 throw new ClassCastException("Wrong Relationsship type for Taxon.addRelationship");
589 }
590 }
591
592 /**
593 * Creates a new {@link TaxonRelationship taxon relationship} instance where <i>this</i> taxon
594 * plays the source role and adds it to the set of
595 * {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to <i>this</i> taxon.
596 * The taxon relationship will also be added to the set of taxon
597 * relationships to the second taxon involved in the created relationship.<P>
598 * If the taxon relationship concerns the classification possible
599 * modifications of the {@link #getTaxonomicParent() parent taxon} or of the number of
600 * {@link #getTaxonomicChildrenCount() childrens} will be stored.
601 *
602 * @param toTaxon the taxon which plays the target role in the new taxon relationship
603 * @param type the taxon relationship type for the new taxon relationship
604 * @param citation the reference source for the new taxon relationship
605 * @param microcitation the string with the details describing the exact localisation within the reference
606 * @return
607 * @see #addTaxonRelation(TaxonRelationship)
608 * @see #getTaxonRelations()
609 * @see #getRelationsFromThisTaxon()
610 * @see #getRelationsToThisTaxon()
611 * @see #getTaxonomicParent()
612 * @see #getTaxonomicChildrenCount()
613 */
614 public TaxonRelationship addTaxonRelation(Taxon toTaxon, TaxonRelationshipType type, Reference citation, String microcitation) {
615 return new TaxonRelationship(this, toTaxon, type, citation, microcitation);
616 }
617 /**
618 * Creates a new {@link TaxonRelationship taxon relationship} (with {@link TaxonRelationshipType taxon relationship type}
619 * "misapplied name for") instance where <i>this</i> taxon plays the target role
620 * and adds it to the set of {@link #getRelationsToThisTaxon() taxon relationships to <i>this</i> taxon}.
621 * The taxon relationship will also be added to the set of taxon
622 * relationships to the other (misapplied name) taxon involved in the created relationship.
623 *
624 * @param misappliedNameTaxon the taxon which plays the target role in the new taxon relationship
625 * @param citation the reference source for the new taxon relationship
626 * @param microcitation the string with the details describing the exact localisation within the reference
627 * @return
628 * @see #getMisappliedNames()
629 * @see #addTaxonRelation(Taxon, TaxonRelationshipType, Reference, String)
630 * @see #addTaxonRelation(TaxonRelationship)
631 * @see #getTaxonRelations()
632 * @see #getRelationsFromThisTaxon()
633 * @see #getRelationsToThisTaxon()
634 */
635 public TaxonRelationship addMisappliedName(Taxon misappliedNameTaxon, Reference citation, String microcitation) {
636 return misappliedNameTaxon.addTaxonRelation(this, TaxonRelationshipType.MISAPPLIED_NAME_FOR(), citation, microcitation);
637 }
638
639 // public void removeMisappliedName(Taxon misappliedNameTaxon){
640 // Set<TaxonRelationship> taxRels = this.getTaxonRelations();
641 // for (TaxonRelationship taxRel : taxRels ){
642 // if (taxRel.getType().equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())
643 // && taxRel.getFromTaxon().equals(misappliedNameTaxon)){
644 // this.removeTaxonRelation(taxRel);
645 // }
646 // }
647 // }
648
649 /**
650 * TODO update documentation
651 * Removes one {@link TaxonRelationship taxon relationship} with {@link TaxonRelationshipType taxon relationship type}
652 * taxonRelType and with the given child taxon playing the
653 * source role from the set of {@link #getRelationsToThisTaxon() "taxon relationships to"} belonging
654 * to <i>this</i> taxon. The taxon relationship will also be removed from the set
655 * of {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to the other side taxon.
656 * Furthermore, the inherited RelatedFrom and RelatedTo attributes of the
657 * taxon relationship will be nullified.<P>
658 *
659 * @param taxon the taxon which plays the source role in the taxon relationship
660 * @param taxonRelType the taxon relationship type
661 */
662 public void removeTaxon(Taxon taxon, TaxonRelationshipType taxonRelType){
663 Set<TaxonRelationship> taxRels = this.getTaxonRelations();
664 for (TaxonRelationship taxRel : taxRels ){
665 if (taxRel.getType().equals(taxonRelType)
666 && taxRel.getFromTaxon().equals(taxon)){
667 this.removeTaxonRelation(taxRel);
668 }
669 }
670 }
671
672 /**
673 * Creates a new {@link TaxonRelationship taxon relationship} (with {@link TaxonRelationshipType taxon relationship type}
674 * "taxonomically included in") instance where <i>this</i> taxon plays the target
675 * role (parent) and adds it to the set of
676 * {@link #getRelationsToThisTaxon() "taxon relationships to"} belonging to <i>this</i> taxon.
677 * The taxon relationship will also be added to the set of
678 * {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to the second taxon
679 * (child) involved in the created relationship.<P>
680 * Since the taxon relationship concerns the modifications
681 * of the number of {@link #getTaxonomicChildrenCount() childrens} for <i>this</i> taxon and
682 * of the {@link #getTaxonomicParent() parent taxon} for the child taxon will be stored.
683 * The {@link name.Rank rank} of the taxon name used as a parent taxon must be higher
684 * than the rank of the taxon name used as a child taxon.
685 *
686 * @param child the taxon which plays the source role (child) in the new taxon relationship
687 * @param citation the reference source for the new taxon relationship
688 * @param microcitation the string with the details describing the exact localisation within the reference
689 * @see #setTaxonomicParent(Taxon, Reference, String)
690 * @see #addTaxonRelation(Taxon, TaxonRelationshipType, Reference, String)
691 * @see #addTaxonRelation(TaxonRelationship)
692 * @see #getTaxonRelations()
693 * @see #getRelationsFromThisTaxon()
694 * @see #getRelationsToThisTaxon()
695 * @see #getTaxonomicParent()
696 * @see #getTaxonomicChildrenCount()
697 */
698 @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
699 public void addTaxonomicChild(Taxon child, Reference citation, String microcitation){
700 if (child == null){
701 throw new NullPointerException("Child Taxon is 'null'");
702 }else{
703 child.setTaxonomicParent(this, citation, microcitation);
704 }
705 }
706
707 /**
708 * Removes one {@link TaxonRelationship taxon relationship} with {@link TaxonRelationshipType taxon relationship type}
709 * "taxonomically included in" and with the given child taxon playing the
710 * source role from the set of {@link #getRelationsToThisTaxon() "taxon relationships to"} belonging
711 * to <i>this</i> taxon. The taxon relationship will also be removed from the set
712 * of {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to the child taxon.
713 * Furthermore the inherited RelatedFrom and RelatedTo attributes of the
714 * taxon relationship will be nullified.<P>
715 * Since the taxon relationship concerns the classification modifications
716 * of the number of {@link #getTaxonomicChildrenCount() childrens} for <i>this</i> taxon and
717 * of the {@link #getTaxonomicParent() parent taxon} for the child taxon will be stored.
718 *
719 * @param child the taxon playing the source role in the relationship to be removed
720 * @see #removeTaxonRelation(TaxonRelationship)
721 * @see #getRelationsToThisTaxon()
722 * @see #getRelationsFromThisTaxon()
723 * @see #getTaxonomicParent()
724 * @see #getTaxonomicChildrenCount()
725 * @see eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom()
726 * @see eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedTo()
727 *
728 */
729 @Deprecated //will be removed in future versions. Use classification/TaxonNode instead
730 public void removeTaxonomicChild(Taxon child){
731 Set<TaxonRelationship> taxRels = this.getTaxonRelations();
732 for (TaxonRelationship taxRel : taxRels ){
733 if (taxRel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN())
734 && taxRel.getFromTaxon().equals(child)){
735 this.removeTaxonRelation(taxRel);
736 }
737 }
738 }
739
740 /**
741 * Returns the taxon which is the next higher taxon (parent) of <i>this</i> taxon
742 * within the classification and which is stored in the
743 * TaxonomicParentCache attribute. Each taxon can have only one parent taxon.
744 * The child taxon and the parent taxon play the source respectively the
745 * target role in one {@link TaxonRelationship taxon relationship} with
746 * {@link TaxonRelationshipType taxon relationship type} "taxonomically included in".
747 * The {@link name.Rank rank} of the taxon name used as a parent taxon must be higher
748 * than the rank of the taxon name used as a child taxon.
749 *
750 * @see #setTaxonomicParent(Taxon, Reference, String)
751 * @see #getTaxonomicChildren()
752 * @see #getTaxonomicChildrenCount()
753 * @see #getRelationsFromThisTaxon()
754 */
755 @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
756 public Taxon getTaxonomicParent() {
757 return this.taxonomicParentCache;
758 }
759
760 /**
761 * Sets the taxononomic parent of <i>this</i> taxon to null.
762 * Note that this method does not handle taxonomic relationships.
763 */
764 @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
765 public void nullifyTaxonomicParent() {
766 this.taxonomicParentCache = null;
767 }
768
769 /**
770 * Replaces both the taxonomic parent cache with the given new parent taxon
771 * and the corresponding taxon relationship with a new {@link TaxonRelationship taxon relationship}
772 * (with {@link TaxonRelationshipType taxon relationship type} "taxonomically included in") instance.
773 * In the new taxon relationship <i>this</i> taxon plays the source role (child).
774 * This method creates and adds the new taxon relationship to the set of
775 * {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to <i>this</i> taxon.
776 * The taxon relationship will also be added to the set of
777 * {@link #getRelationsToThisTaxon() "taxon relationships to"} belonging to the second taxon
778 * (parent) involved in the new relationship.<P>
779 * Since the taxon relationship concerns the classification modifications
780 * of the {@link #getTaxonomicParent() parent taxon} for <i>this</i> taxon and of the number of
781 * {@link #getTaxonomicChildrenCount() childrens} for the child taxon will be stored.
782 *
783 * @param newParent the taxon which plays the target role (parent) in the new taxon relationship
784 * @param citation the reference source for the new taxon relationship
785 * @param microcitation the string with the details describing the exact localisation within the reference
786 * @see #removeTaxonRelation(TaxonRelationship)
787 * @see #getTaxonomicParent()
788 * @see #addTaxonRelation(Taxon, TaxonRelationshipType, Reference, String)
789 * @see #addTaxonRelation(TaxonRelationship)
790 * @see #getTaxonRelations()
791 * @see #getRelationsFromThisTaxon()
792 * @see #getRelationsToThisTaxon()
793 * @see #getTaxonomicChildrenCount()
794 */
795 @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
796 public void setTaxonomicParent(Taxon newParent, Reference citation, String microcitation){
797 //remove previously existing parent relationship!!!
798 Taxon oldParent = this.getTaxonomicParent();
799 Set<TaxonRelationship> taxRels = this.getTaxonRelations();
800 for (TaxonRelationship taxRel : taxRels ){
801 if (taxRel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) && taxRel.getToTaxon().equals(oldParent)){
802 this.removeTaxonRelation(taxRel);
803 }
804 }
805 //add new parent
806 if (newParent != null){
807 addTaxonRelation(newParent, TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN(),citation,microcitation);
808 }
809 }
810
811 /**
812 * Returns the set of taxa which have <i>this</i> taxon as next higher taxon
813 * (parent) within the classification. Each taxon can have several child
814 * taxa. The child taxon and the parent taxon play the source respectively
815 * the target role in one {@link TaxonRelationship taxon relationship} with
816 * {@link TaxonRelationshipType taxon relationship type} "taxonomically included in".
817 * The {@link name.Rank rank} of the taxon name used as a parent taxon must be higher
818 * than the rank of the taxon name used as a child taxon.
819 *
820 * @see #getTaxonomicParent()
821 * @see #addTaxonomicChild(Taxon, Reference, String)
822 * @see #getTaxonomicChildrenCount()
823 * @see #getRelationsToThisTaxon()
824 */
825 @Transient
826 @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
827 public Set<Taxon> getTaxonomicChildren() {
828 Set<Taxon> taxa = new HashSet<Taxon>();
829 Set<TaxonRelationship> rels = this.getRelationsToThisTaxon();
830 for (TaxonRelationship rel: rels){
831 TaxonRelationshipType tt = rel.getType();
832 TaxonRelationshipType incl = TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN();
833 if (tt.equals(incl)){
834 taxa.add(rel.getFromTaxon());
835 }
836 }
837 return taxa;
838 }
839
840 /**
841 * Returns the number of taxa which have <i>this</i> taxon as next higher taxon
842 * (parent) within the classification and the number of which is stored in
843 * the TaxonomicChildrenCount attribute. Each taxon can have several child
844 * taxa. The child taxon and the parent taxon play the source respectively
845 * the target role in one {@link TaxonRelationship taxon relationship} with
846 * {@link TaxonRelationshipType taxon relationship type} "taxonomically included in".
847 * The {@link name.Rank rank} of the taxon name used as a parent taxon must be higher
848 * than the rank of the taxon name used as a child taxon.
849 *
850 * @see #getTaxonomicChildren()
851 * @see #getRelationsToThisTaxon()
852 */
853 @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
854 public int getTaxonomicChildrenCount(){
855 return taxonomicChildrenCount;
856 }
857
858 /**
859 * @see #getTaxonomicChildrenCount()
860 */
861 @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
862 public void setTaxonomicChildrenCount(int taxonomicChildrenCount) {
863 this.taxonomicChildrenCount = taxonomicChildrenCount;
864 }
865
866 /**
867 * Returns the boolean value indicating whether <i>this</i> taxon has at least one
868 * taxonomic child taxon within the classification (true) or not (false).
869 *
870 * @see #getTaxonomicChildrenCount()
871 * @see #getTaxonomicChildren()
872 */
873 @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
874 public boolean hasTaxonomicChildren(){
875 return this.taxonomicChildrenCount > 0;
876 }
877
878 @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
879 private int computeTaxonomicChildrenCount(){
880 int count = 0;
881 for (TaxonRelationship rel: this.getRelationsToThisTaxon()){
882 if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN())){
883 count++;
884 }
885 }
886 return count;
887 }
888
889
890 /**
891 * Returns the boolean value indicating whether <i>this</i> taxon is a misaplication
892 * (misapplied name) for at least one other taxon.
893 */
894 // TODO cache as for #hasTaxonomicChildren
895 @Transient
896 public boolean isMisapplication(){
897 return computeMisapliedNameRelations() > 0;
898 }
899
900 /**
901 * Counts the number of misaplied names relationships where this taxon represents the
902 * misaplied name for another taxon.
903 * @return
904 */
905 private int computeMisapliedNameRelations(){
906 int count = 0;
907 for (TaxonRelationship rel: this.getRelationsFromThisTaxon()){
908 if (rel.getType().equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())){
909 count++;
910 }
911 }
912 return count;
913 }
914
915 /**
916 * Returns the boolean value indicating whether <i>this</i> taxon is a related
917 * concept for at least one other taxon.
918 */
919 @Transient
920 public boolean isRelatedConcept(){
921 return computeConceptRelations() > 0;
922 }
923
924 /**
925 * Counts the number of concept relationships where this taxon represents the
926 * related concept for another taxon.
927 * @return
928 */
929 private int computeConceptRelations(){
930 int count = 0;
931 for (TaxonRelationship rel: this.getRelationsFromThisTaxon()){
932 TaxonRelationshipType type = rel.getType();
933 if (type.isConceptRelationship()){
934 count++;
935 }
936 }
937 return count;
938 }
939
940 /**
941 * Returns the boolean value indicating whether <i>this</i> taxon has at least one
942 * {@link Synonym synonym} (true) or not (false). If true the {@link #getSynonymRelations() set of synonym relationships}
943 * belonging to <i>this</i> ("accepted/correct") taxon is not empty .
944 *
945 * @see #getSynonymRelations()
946 * @see #getSynonyms()
947 * @see #getSynonymNames()
948 * @see #removeSynonym(Synonym)
949 * @see SynonymRelationship
950 */
951 public boolean hasSynonyms(){
952 return this.getSynonymRelations().size() > 0;
953 }
954
955
956 /**
957 * Returns the boolean value indicating whether <i>this</i> taxon is at least
958 * involved in one {@link #getTaxonRelations() taxon relationship} between
959 * two taxa (true), either as a source or as a target, or not (false).
960 *
961 * @see #getTaxonRelations()
962 * @see #getRelationsToThisTaxon()
963 * @see #getRelationsFromThisTaxon()
964 * @see #removeTaxonRelation(TaxonRelationship)
965 * @see TaxonRelationship
966 */
967 public boolean hasTaxonRelationships(){
968 return this.getTaxonRelations().size() > 0;
969 }
970
971 /*
972 * MISAPPLIED NAMES
973 */
974 /**
975 * Returns the set of taxa playing the source role in {@link TaxonRelationship taxon relationships}
976 * (with {@link TaxonRelationshipType taxon relationship type} "misapplied name for") where
977 * <i>this</i> taxon plays the target role. A misapplied name is a taxon the
978 * {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} of which has been erroneously used
979 * by its {@link TaxonBase#getSec() taxon reference} to denominate the same real taxon
980 * as the one meant by <i>this</i> ("accepted/correct") taxon.
981 *
982 * @see #getTaxonRelations()
983 * @see #getRelationsToThisTaxon()
984 * @see #addMisappliedName(Taxon, Reference, String)
985 */
986 @Transient
987 public Set<Taxon> getMisappliedNames(){
988 Set<Taxon> taxa = new HashSet<Taxon>();
989 Set<TaxonRelationship> rels = this.getRelationsToThisTaxon();
990 for (TaxonRelationship rel: rels){
991 TaxonRelationshipType tt = rel.getType();
992 TaxonRelationshipType incl = TaxonRelationshipType.MISAPPLIED_NAME_FOR();
993 if (tt.equals(incl)){
994 taxa.add(rel.getFromTaxon());
995 }
996 }
997 return taxa;
998 }
999
1000
1001 /*
1002 * DEALING WITH SYNONYMS
1003 */
1004 /**
1005 * Returns the set of all {@link Synonym synonyms} of <i>this</i> ("accepted/correct") taxon.
1006 * Each synonym is the source and <i>this</i> taxon is the target of a {@link SynonymRelationship synonym relationship}
1007 * belonging to the {@link #getSynonymRelations() set of synonym relationships} assigned to <i>this</i> taxon.
1008 * For a particular synonym and for a particular ("accepted/correct") taxon
1009 * there can be several synonym relationships (if two or more
1010 * {@link SynonymRelationshipType synonym relationship types} - for instance
1011 * "pro parte synonym of" and "is homotypic synonym of" - must be combined).
1012 *
1013 * @see #getSynonymsSortedByType()
1014 * @see #getSynonymNames()
1015 * @see #getSynonymRelations()
1016 * @see #addSynonym(Synonym, SynonymRelationshipType)
1017 * @see #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1018 * @see #removeSynonymRelation(SynonymRelationship)
1019 * @see #removeSynonym(Synonym)
1020 */
1021 @Transient
1022 public Set<Synonym> getSynonyms(){
1023 Set<Synonym> syns = new HashSet<Synonym>();
1024 for (SynonymRelationship rel: this.getSynonymRelations()){
1025 syns.add(rel.getSynonym());
1026 }
1027 return syns;
1028 }
1029 /**
1030 * Returns the set of all {@link Synonym synonyms} of <i>this</i> ("accepted/correct") taxon
1031 * sorted by the different {@link SynonymRelationshipType categories of synonym relationships}.
1032 * Each synonym is the source and <i>this</i> taxon is the target of a {@link SynonymRelationship synonym relationship}
1033 * belonging to the {@link #getSynonymRelations() set of synonym relationships} assigned to <i>this</i> taxon.
1034 *
1035 * @see #getSynonyms()
1036 * @see #getSynonymNames()
1037 * @see #getSynonymRelations()
1038 * @see #addSynonym(Synonym, SynonymRelationshipType)
1039 * @see #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1040 * @see #removeSynonymRelation(SynonymRelationship)
1041 * @see #removeSynonym(Synonym)
1042 */
1043 @Transient
1044 public Set<Synonym> getSynonymsSortedByType(){
1045 // FIXME: need to sort synonyms according to type!!!
1046 logger.warn("getSynonymsSortedByType() not yet implemented");
1047 return getSynonyms();
1048 }
1049 /**
1050 * Returns the set of all {@link name.TaxonNameBase taxon names} used as {@link Synonym synonyms}
1051 * of <i>this</i> ("accepted/correct") taxon. Each synonym is the source and
1052 * <i>this</i> taxon is the target of a {@link SynonymRelationship synonym relationship} belonging
1053 * to the {@link #getSynonymRelations() set of synonym relationships} assigned to <i>this</i> taxon.
1054 *
1055 * @see #getSynonyms()
1056 * @see #getSynonymsSortedByType()
1057 * @see #getSynonymRelations()
1058 * @see #addSynonymName(TaxonNameBase, SynonymRelationshipType)
1059 * @see #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1060 * @see #removeSynonymRelation(SynonymRelationship)
1061 * @see #removeSynonym(Synonym)
1062 */
1063 @Transient
1064 public Set<TaxonNameBase> getSynonymNames(){
1065 Set<TaxonNameBase> names = new HashSet<TaxonNameBase>();
1066 for (SynonymRelationship rel: this.getSynonymRelations()){
1067 names.add(rel.getSynonym().getName());
1068 }
1069 return names;
1070 }
1071 /**
1072 * Creates a new {@link SynonymRelationship synonym relationship} (with the given {@link Synonym synonym}
1073 * and with the given {@link SynonymRelationshipType synonym relationship type}), returns it and adds it
1074 * to the set of {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon.
1075 * The new synonym relationship will also be added to the set of
1076 * {@link Synonym#getSynonymRelations() synonym relationships} belonging to the synonym
1077 * involved in this synonym relationship.<BR>
1078 * The returned synonym relationship allows to add further information to it.
1079 *
1080 * @param synonym the synonym involved in the relationship to be created
1081 * and added to <i>this</i> taxon's synonym relationships set
1082 * @param synonymType the synonym relationship category of the synonym
1083 * relationship to be added
1084 * @return the created synonym relationship
1085 * @see #addSynonymRelation(SynonymRelationship)
1086 * @see #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1087 * @see #addSynonymName(TaxonNameBase, SynonymRelationshipType)
1088 * @see #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
1089 * @see #addHomotypicSynonym(Synonym, Reference, String)
1090 * @see #addHomotypicSynonymName(TaxonNameBase, Reference, String)
1091 * @see #addHeterotypicSynonymName(TaxonNameBase)
1092 * @see #addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, Reference, String)
1093 * @see #getSynonymRelations()
1094 * @see #removeSynonym(Synonym)
1095 * @see Synonym#getSynonymRelations()
1096 */
1097 public SynonymRelationship addSynonym(Synonym synonym, SynonymRelationshipType synonymType){
1098 return addSynonym(synonym, synonymType, null, null);
1099 }
1100 /**
1101 * Creates a new {@link SynonymRelationship synonym relationship} (with the given {@link Synonym synonym},
1102 * with the given {@link SynonymRelationshipType synonym relationship type} and with the
1103 * {@link eu.etaxonomy.cdm.model.reference.Reference reference source} on which the relationship assertion is based),
1104 * returns it and adds it to the set of {@link #getSynonymRelations() synonym relationships}
1105 * assigned to <i>this</i> taxon. The new synonym relationship will also be
1106 * added to the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging to the synonym
1107 * involved in this synonym relationship.<BR>
1108 * The returned synonym relationship allows to add further information to it.
1109 *
1110 * @param synonym the synonym involved in the relationship to be created
1111 * and added to <i>this</i> taxon's synonym relationships set
1112 * @param synonymType the synonym relationship category of the synonym
1113 * relationship to be added
1114 * @param citation the reference source for the new synonym relationship
1115 * @param microcitation the string with the details describing the exact localisation within the reference
1116 * @return the created synonym relationship
1117 * @see #addSynonymRelation(SynonymRelationship)
1118 * @see #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1119 * @see #addSynonymName(TaxonNameBase, SynonymRelationshipType)
1120 * @see #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
1121 * @see #addHomotypicSynonym(Synonym, Reference, String)
1122 * @see #addHomotypicSynonymName(TaxonNameBase, Reference, String)
1123 * @see #addHeterotypicSynonymName(TaxonNameBase)
1124 * @see #addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, Reference, String)
1125 * @see #getSynonymRelations()
1126 * @see #removeSynonym(Synonym)
1127 * @see Synonym#getSynonymRelations()
1128 */
1129 public SynonymRelationship addSynonym(Synonym synonym, SynonymRelationshipType synonymType, Reference citation, String citationMicroReference){
1130 SynonymRelationship synonymRelationship = new SynonymRelationship(synonym, this, synonymType, citation, citationMicroReference);
1131 return synonymRelationship;
1132 }
1133
1134 /**
1135 * Creates a new {@link Synonym synonym} (with the given {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}),
1136 * a new {@link SynonymRelationship synonym relationship} (with the new synonym and with the given
1137 * {@link SynonymRelationshipType synonym relationship type}), returns the relationship and adds it
1138 * to the set of {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon.
1139 * The new synonym will have the same {@link TaxonBase#getSec() concept reference}
1140 * as <i>this</i> taxon. The new synonym relationship will also be added to
1141 * the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
1142 * to the created synonym.<BR>
1143 * The returned synonym relationship allows to add further information to it.
1144 *
1145 * @param synonymName the taxon name to be used as a synonym to be added
1146 * to <i>this</i> taxon's set of synonyms
1147 * @param synonymType the synonym relationship category of the synonym
1148 * relationship to be added
1149 * @return the created synonym relationship
1150 * @see #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
1151 * @see #addSynonym(Synonym, SynonymRelationshipType)
1152 * @see #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1153 * @see #addSynonymRelation(SynonymRelationship)
1154 * @see #addHomotypicSynonym(Synonym, Reference, String)
1155 * @see #addHomotypicSynonymName(TaxonNameBase, Reference, String)
1156 * @see #addHeterotypicSynonymName(TaxonNameBase)
1157 * @see #addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, Reference, String)
1158 * @see #getSynonymRelations()
1159 * @see #removeSynonym(Synonym)
1160 * @see Synonym#getSynonymRelations()
1161 */
1162 public SynonymRelationship addSynonymName(TaxonNameBase synonymName, SynonymRelationshipType synonymType){
1163 return addSynonymName(synonymName, synonymType, null, null);
1164 }
1165 /**
1166 * Creates a new {@link Synonym synonym} (with the given {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}),
1167 * a new {@link SynonymRelationship synonym relationship} (with the new synonym, with the given
1168 * {@link SynonymRelationshipType synonym relationship type} and with the {@link eu.etaxonomy.cdm.model.reference.Reference reference source}
1169 * on which the relationship assertion is based), returns the relationship
1170 * and adds it to the set of {@link #getSynonymRelations() synonym relationships} assigned
1171 * to <i>this</i> taxon. The new synonym will have the same {@link TaxonBase#getSec() concept reference}
1172 * as <i>this</i> taxon. The new synonym relationship will also be added to
1173 * the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
1174 * to the created synonym.<BR>
1175 * The returned synonym relationship allows to add further information to it.
1176 *
1177 * @param synonymName the taxon name to be used as a synonym to be added
1178 * to <i>this</i> taxon's set of synonyms
1179 * @param synonymType the synonym relationship category of the synonym
1180 * relationship to be added
1181 * @param citation the reference source for the new synonym relationship
1182 * @param microcitation the string with the details describing the exact localisation within the reference
1183 * @return the created synonym relationship
1184 * @see #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
1185 * @see #addSynonym(Synonym, SynonymRelationshipType)
1186 * @see #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1187 * @see #addSynonymRelation(SynonymRelationship)
1188 * @see #addHomotypicSynonym(Synonym, Reference, String)
1189 * @see #addHomotypicSynonymName(TaxonNameBase, Reference, String)
1190 * @see #addHeterotypicSynonymName(TaxonNameBase)
1191 * @see #addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, Reference, String)
1192 * @see #getSynonymRelations()
1193 * @see #removeSynonym(Synonym)
1194 * @see Synonym#getSynonymRelations()
1195 */
1196 public SynonymRelationship addSynonymName(TaxonNameBase synonymName, SynonymRelationshipType synonymType, Reference citation, String citationMicroReference){
1197 Synonym synonym = Synonym.NewInstance(synonymName, this.getSec());
1198 return addSynonym(synonym, synonymType, citation, citationMicroReference);
1199 }
1200
1201 /**
1202 * Creates a new {@link Synonym synonym} (with the given {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}),
1203 * a new {@link SynonymRelationship synonym relationship} (with the new synonym and with the
1204 * {@link SynonymRelationshipType#HETEROTYPIC_SYNONYM_OF() "is heterotypic synonym of" relationship type}),
1205 * returns the relationship and adds it to the set of
1206 * {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon.
1207 * The new synonym will have the same {@link TaxonBase#getSec() concept reference}
1208 * as <i>this</i> taxon. The new synonym relationship will also be added to
1209 * the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
1210 * to the created synonym.<BR>
1211 * The returned synonym relationship allows to add further information to it.
1212 *
1213 * @param synonymName the taxon name to be used as an heterotypic synonym
1214 * to be added to <i>this</i> taxon's set of synonyms
1215 * @return the created synonym relationship
1216 * @see #addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, Reference, String)
1217 * @see #addSynonymName(TaxonNameBase, SynonymRelationshipType)
1218 * @see #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
1219 * @see #addSynonym(Synonym, SynonymRelationshipType)
1220 * @see #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1221 * @see #addSynonymRelation(SynonymRelationship)
1222 * @see #addHomotypicSynonym(Synonym, Reference, String)
1223 * @see #addHomotypicSynonymName(TaxonNameBase, Reference, String)
1224 * @see #getSynonymRelations()
1225 * @see #removeSynonym(Synonym)
1226 * @see Synonym#getSynonymRelations()
1227 */
1228 public SynonymRelationship addHeterotypicSynonymName(TaxonNameBase synonymName){
1229 return addHeterotypicSynonymName(synonymName, null, null, null);
1230 }
1231
1232 /**
1233 * Creates a new {@link Synonym synonym} (with the given {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}),
1234 * a new {@link SynonymRelationship synonym relationship} (with the new synonym, with the
1235 * {@link SynonymRelationshipType#HETEROTYPIC_SYNONYM_OF() "is heterotypic synonym of" relationship type}
1236 * and with the {@link eu.etaxonomy.cdm.model.reference.Reference reference source}
1237 * on which the relationship assertion is based), returns the relationship
1238 * and adds it to the set of {@link #getSynonymRelations() synonym relationships} assigned
1239 * to <i>this</i> taxon. The new synonym will have the same {@link TaxonBase#getSec() concept reference}
1240 * as <i>this</i> taxon. Furthermore the new synonym relationship will be
1241 * added to the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
1242 * to the created synonym and the taxon name used as synonym will be added
1243 * to the given {@link name.HomotypicalGroup homotypical group}.<BR>
1244 * The returned synonym relationship allows to add further information to it.
1245 *
1246 * @param synonymName the taxon name to be used as an heterotypic synonym
1247 * to be added to <i>this</i> taxon's set of synonyms
1248 * @param homotypicalGroup the homotypical group to which the taxon name
1249 * of the synonym will be added
1250 * @param citation the reference source for the new synonym relationship
1251 * @param microcitation the string with the details describing the exact localisation
1252 * within the reference
1253 * @return the created synonym relationship
1254 * @see #addHeterotypicSynonymName(TaxonNameBase)
1255 * @see #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
1256 * @see #addSynonymName(TaxonNameBase, SynonymRelationshipType)
1257 * @see #addSynonym(Synonym, SynonymRelationshipType)
1258 * @see #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1259 * @see #addSynonymRelation(SynonymRelationship)
1260 * @see #addHomotypicSynonym(Synonym, Reference, String)
1261 * @see #addHomotypicSynonymName(TaxonNameBase, Reference, String)
1262 * @see #getSynonymRelations()
1263 * @see #removeSynonym(Synonym)
1264 * @see Synonym#getSynonymRelations()
1265 */
1266 public SynonymRelationship addHeterotypicSynonymName(TaxonNameBase synonymName, HomotypicalGroup homotypicalGroup, Reference citation, String microCitation){
1267 Synonym synonym = Synonym.NewInstance(synonymName, this.getSec());
1268 if (homotypicalGroup != null){
1269 homotypicalGroup.addTypifiedName(synonymName);
1270 }
1271 return addSynonym(synonym, SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), citation, microCitation);
1272 }
1273
1274 /**
1275 * Creates a new {@link Synonym synonym} (with the given {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}),
1276 * a new {@link SynonymRelationship synonym relationship} (with the new synonym, with the
1277 * {@link SynonymRelationshipType#HOMOTYPIC_SYNONYM_OF() "is homotypic synonym of" relationship type})
1278 * and with the {@link eu.etaxonomy.cdm.model.reference.Reference reference source}
1279 * on which the relationship assertion is based), returns the relationship
1280 * and adds it to the set of {@link #getSynonymRelations() synonym relationships} assigned
1281 * to <i>this</i> taxon. The new synonym will have the same {@link TaxonBase#getSec() concept reference}
1282 * as <i>this</i> taxon. Furthermore the new synonym relationship will be
1283 * added to the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
1284 * to the created synonym and the taxon name used as synonym will be added
1285 * to the same {@link eu.etaxonomy.cdm.model.name.HomotypicalGroup homotypical group} to which the taxon name
1286 * of <i>this</i> taxon belongs.<BR>
1287 * The returned synonym relationship allows to add further information to it.
1288 *
1289 * @param synonymName the taxon name to be used as an homotypic synonym
1290 * to be added to <i>this</i> taxon's set of synonyms
1291 * @param citation the reference source for the new synonym relationship
1292 * @param microcitation the string with the details describing the exact localisation
1293 * within the reference
1294 * @return the created synonym relationship
1295 * @see #addHomotypicSynonym(Synonym, Reference, String)
1296 * @see #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
1297 * @see #addSynonymName(TaxonNameBase, SynonymRelationshipType)
1298 * @see #addSynonym(Synonym, SynonymRelationshipType)
1299 * @see #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1300 * @see #addSynonymRelation(SynonymRelationship)
1301 * @see #addHeterotypicSynonymName(TaxonNameBase)
1302 * @see #addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, Reference, String)
1303 * @see #getSynonymRelations()
1304 * @see #removeSynonym(Synonym)
1305 * @see Synonym#getSynonymRelations()
1306 */
1307 public SynonymRelationship addHomotypicSynonymName(TaxonNameBase synonymName, Reference citation, String microCitation){
1308 Synonym synonym = Synonym.NewInstance(synonymName, this.getSec());
1309 return addHomotypicSynonym(synonym, citation, microCitation);
1310 }
1311
1312 /**
1313 * Creates a new {@link SynonymRelationship synonym relationship} (with the given {@link Synonym synonym},
1314 * with the {@link SynonymRelationshipType#HOMOTYPIC_SYNONYM_OF() "is homotypic synonym of" relationship type}
1315 * and with the {@link eu.etaxonomy.cdm.model.reference.Reference reference source} on which the relationship
1316 * assertion is based), returns it and adds it to the set of
1317 * {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon.
1318 * Furthermore the new synonym relationship will be added to the set of
1319 * {@link Synonym#getSynonymRelations() synonym relationships} belonging to the synonym
1320 * involved in this synonym relationship and the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}
1321 * used as synonym will be added to the same {@link eu.etaxonomy.cdm.model.name.HomotypicalGroup homotypical group}
1322 * to which the taxon name of <i>this</i> taxon belongs.<BR>
1323 * The returned synonym relationship allows to add further information to it.
1324 *
1325 * @param synonym the synonym involved in the "is homotypic synonym of" relationship to be created
1326 * and added to <i>this</i> taxon's synonym relationships set
1327 * @param citation the reference source for the new synonym relationship
1328 * @param microcitation the string with the details describing the exact localisation within the reference
1329 * @return the created synonym relationship
1330 * @see #addHomotypicSynonymName(TaxonNameBase, Reference, String)
1331 * @see #addSynonym(Synonym, SynonymRelationshipType)
1332 * @see #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1333 * @see #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
1334 * @see #addSynonymName(TaxonNameBase, SynonymRelationshipType)
1335 * @see #addSynonymRelation(SynonymRelationship)
1336 * @see #addHeterotypicSynonymName(TaxonNameBase)
1337 * @see #addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, Reference, String)
1338 * @see #getSynonymRelations()
1339 * @see #removeSynonym(Synonym)
1340 * @see Synonym#getSynonymRelations()
1341 */
1342 public SynonymRelationship addHomotypicSynonym(Synonym synonym, Reference citation, String microCitation){
1343 if (this.getName() != null){
1344 if (this.getName().getHomotypicalGroup().getTypifiedNames().isEmpty()){
1345 this.getName().getHomotypicalGroup().getTypifiedNames().add(this.getName());
1346
1347 }
1348 this.getName().getHomotypicalGroup().addTypifiedName(synonym.getName());
1349
1350 }
1351 SynonymRelationship synRel = addSynonym(synonym, SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF(), citation, microCitation);
1352 return synRel;
1353 }
1354
1355 /**
1356 * Removes the element(s) from the set of {@link SynonymRelationship synonym relationships}
1357 * assigned to <i>this</i> ("accepted/correct") taxon in which the given synonym is involved.
1358 * Due to bidirectionality the same synonym relationships will also be
1359 * removed from the set of synonym relationships assigned to the
1360 * {@link Synonym#getSynonymRelations() synonym} involved in the relationship. Furthermore the content of
1361 * the {@link SynonymRelationship#getAcceptedTaxon() accepted taxon} attribute and of the
1362 * {@link SynonymRelationship#getSynonym() synonym} attribute within the synonym relationships
1363 * themselves will be set to "null".
1364 *
1365 * @param synonym the synonym involved in the synonym relationship which should be deleted
1366 * @see #getSynonymRelations()
1367 * @see #addSynonym(Synonym, SynonymRelationshipType)
1368 * @see #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1369 * @see #removeSynonymRelation(SynonymRelationship)
1370 */
1371 public void removeSynonym(Synonym synonym){
1372 Set<SynonymRelationship> synonymRelationships = new HashSet<SynonymRelationship>();
1373 synonymRelationships.addAll(this.getSynonymRelations());
1374 for(SynonymRelationship synonymRelationship : synonymRelationships){
1375 if (synonymRelationship.getAcceptedTaxon().equals(this) && synonymRelationship.getSynonym().equals(synonym)){
1376 this.removeSynonymRelation(synonymRelationship);
1377 }
1378 }
1379 }
1380
1381
1382 /**
1383 * Retrieves the ordered list (depending on the date of publication) of
1384 * homotypic {@link Synonym synonyms} (according to the same {@link eu.etaxonomy.cdm.model.reference.Reference reference}
1385 * as for <i>this</i> taxon) under the condition that the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon names}
1386 * of these synonyms and the taxon name of <i>this</i> taxon belong to the
1387 * same {@link eu.etaxonomy.cdm.model.name.HomotypicalGroup homotypical group}.
1388 *
1389 * @return the ordered list of homotypic synonyms
1390 * @see #getHomotypicSynonymsByHomotypicRelationship()
1391 * @see #getSynonyms()
1392 * @see #getHomotypicSynonymyGroups()
1393 * @see eu.etaxonomy.cdm.model.name.HomotypicalGroup
1394 * @see eu.etaxonomy.cdm.model.name.HomotypicalGroup#getSynonymsInGroup(Reference)
1395 */
1396 @Transient
1397 public List<Synonym> getHomotypicSynonymsByHomotypicGroup(){
1398 if (this.getHomotypicGroup() == null){
1399 return null;
1400 }else{
1401 return this.getHomotypicGroup().getSynonymsInGroup(this.getSec());
1402 }
1403 }
1404
1405 /**
1406 * Retrieves the ordered list (depending on the date of publication) of
1407 * homotypic {@link Synonym synonyms} (according to the same {@link eu.etaxonomy.cdm.model.reference.Reference reference}
1408 * as for <i>this</i> taxon) under the condition that these synonyms and
1409 * <i>this</i> taxon are involved in {@link SynonymRelationship synonym relationships} with an
1410 * "is homotypic synonym of" {@link SynonymRelationshipType#HOMOTYPIC_SYNONYM_OF() synonym relationship type}.
1411 *
1412 * @return the ordered list of homotypic synonyms
1413 * @see #getHomotypicSynonymsByHomotypicGroup()
1414 * @see #getSynonyms()
1415 * @see #getHomotypicSynonymyGroups()
1416 * @see SynonymRelationshipType
1417 */
1418 @Transient
1419 public List<Synonym> getHomotypicSynonymsByHomotypicRelationship(){
1420 Set<SynonymRelationship> synonymRelations = this.getSynonymRelations();
1421 List<Synonym> result = new ArrayList<Synonym>();
1422 for(SynonymRelationship synonymRelation : synonymRelations) {
1423 if(synonymRelation.getType().equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())){
1424 result.add(synonymRelation.getSynonym());
1425 }
1426 }
1427 return result;
1428 }
1429
1430 /**
1431 * Returns the ordered list of all {@link eu.etaxonomy.cdm.model.name.HomotypicalGroup homotypical groups} {@link Synonym synonyms} of
1432 * <i>this</i> taxon belongs to. {@link eu.etaxonomy.cdm.model.name.TaxonNameBase Taxon names} of homotypic synonyms
1433 * belong to the same homotypical group as the taxon name of <i>this</i>
1434 * taxon. Taxon names of heterotypic synonyms belong to at least one other
1435 * homotypical group. <BR>
1436 * The list returned is ordered according to the date of publication of the
1437 * first published name within each homotypical group.
1438 *
1439 * @see #getHeterotypicSynonymyGroups()
1440 * @see #getSynonyms()
1441 * @see eu.etaxonomy.cdm.model.name.HomotypicalGroup
1442 */
1443 @Transient
1444 public List<HomotypicalGroup> getHomotypicSynonymyGroups(){
1445 List<HomotypicalGroup> result = new ArrayList<HomotypicalGroup>();
1446 result.add(this.getHomotypicGroup());
1447 for (TaxonNameBase taxonNameBase :this.getSynonymNames()){
1448 if (taxonNameBase != null) {
1449 if (!result.contains(taxonNameBase.getHomotypicalGroup())){
1450 result.add(taxonNameBase.getHomotypicalGroup());
1451 }
1452 } // TODO: give error message to user
1453 }
1454 // TODO: sort list according to date of first published name within each group
1455 return result;
1456 }
1457
1458
1459
1460 /**
1461 * @return the taxonStatusUnknown
1462 */
1463 public boolean isTaxonStatusUnknown() {
1464 return taxonStatusUnknown;
1465 }
1466
1467 /**
1468 * @param taxonStatusUnknown the taxonStatusUnknown to set
1469 */
1470 public void setTaxonStatusUnknown(boolean taxonStatusUnknown) {
1471 this.taxonStatusUnknown = taxonStatusUnknown;
1472 }
1473
1474
1475
1476
1477 public boolean isUnplaced() {
1478 return unplaced;
1479 }
1480
1481 public void setUnplaced(boolean unplaced) {
1482 this.unplaced = unplaced;
1483 }
1484
1485 public boolean isExcluded() {
1486 return excluded;
1487 }
1488
1489 public void setExcluded(boolean excluded) {
1490 this.excluded = excluded;
1491 }
1492
1493 /**
1494 * Returns the ordered list of all {@link eu.etaxonomy.cdm.model.name.HomotypicalGroup homotypical groups} heterotypic
1495 * {@link Synonym synonyms} of <i>this</i> taxon belongs to.
1496 * {@link eu.etaxonomy.cdm.model.name.TaxonNameBase Taxon names} of heterotypic synonyms belong to at least
1497 * one homotypical group which cannot be the homotypical group to which the
1498 * taxon name of <i>this</i> taxon belongs. This method returns the same
1499 * list as the {@link #getHomotypicSynonymyGroups() getHomotypicSynonymyGroups} method
1500 * but the homotypical group to which the taxon name of <i>this</i> taxon
1501 * belongs.<BR>
1502 * The list returned is ordered according to the date of publication of the
1503 * first published name within each homotypical group.
1504 *
1505 * @see #getHeterotypicSynonymyGroups()
1506 * @see #getSynonyms()
1507 * @see SynonymRelationshipType#HETEROTYPIC_SYNONYM_OF()
1508 * @see eu.etaxonomy.cdm.model.name.HomotypicalGroup
1509 */
1510 @Transient
1511 public List<HomotypicalGroup> getHeterotypicSynonymyGroups(){
1512 List<HomotypicalGroup> list = getHomotypicSynonymyGroups();
1513 list.remove(this.getHomotypicGroup());
1514 //sort
1515 Map<Synonym, HomotypicalGroup> map = new HashMap<Synonym, HomotypicalGroup>();
1516 for (HomotypicalGroup homotypicalGroup: list){
1517 List<Synonym> synonymList = homotypicalGroup.getSynonymsInGroup(getSec());
1518 if (synonymList.size() > 0){
1519 map.put(synonymList.get(0), homotypicalGroup);
1520 }
1521 }
1522 List<Synonym> keyList = new ArrayList<Synonym>();
1523 keyList.addAll(map.keySet());
1524 Collections.sort(keyList, new TaxonComparator());
1525
1526 List<HomotypicalGroup> result = new ArrayList<HomotypicalGroup>();
1527 for(Synonym synonym: keyList){
1528 result.add(map.get(synonym));
1529 }
1530 //sort end
1531 return result;
1532 }
1533
1534 /**
1535 * Returns the image gallery description. If no image gallery exists, a new one is created using the
1536 * defined title and adds the string "-Image Gallery" to the title.</BR>
1537 * If multiple image galleries exist an arbitrary one is choosen.
1538 * @param title
1539 * @return
1540 */
1541 @Transient
1542 public TaxonDescription getOrCreateImageGallery(String title){
1543 return getOrCreateImageGallery(title, true, false);
1544 }
1545
1546 /**
1547 * Returns the image gallery description. If no image gallery exists, a new one is created using the
1548 * defined title.</BR>
1549 * If onlyTitle == true we look only for an image gallery with this title, create a new one otherwise.
1550 * If multiple image galleries exist that match the conditions an arbitrary one is choosen.
1551 * @param title
1552 * @param onlyTitle
1553 * @param if true, the String "Image Gallery
1554 * @return
1555 */
1556 @Transient
1557 public TaxonDescription getOrCreateImageGallery(String title, boolean addImageGalleryToTitle, boolean onlyTitle){
1558 TaxonDescription result = null;
1559 String titleCache = (title == null) ? "Image Gallery" : title;
1560 if (title != null && addImageGalleryToTitle){
1561 titleCache = titleCache+ "-Image Gallery";
1562 }
1563 Set<TaxonDescription> descriptionSet = this.getDescriptions();
1564 for (TaxonDescription desc: descriptionSet){
1565 if (desc.isImageGallery()){
1566 if (onlyTitle && ! titleCache.equals(desc.getTitleCache())){
1567 continue;
1568 }
1569 result = desc;
1570 if (onlyTitle && titleCache.equals(desc.getTitleCache())){
1571 break;
1572 }
1573 }
1574 }
1575 if (result == null){
1576 result = TaxonDescription.NewInstance();
1577 result.setTitleCache(titleCache, true);
1578 this.addDescription(result);
1579 result.setImageGallery(true);
1580 }
1581 return result;
1582 }
1583 }