3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
11 package eu
.etaxonomy
.cdm
.model
.taxon
;
13 import java
.util
.ArrayList
;
14 import java
.util
.HashSet
;
15 import java
.util
.List
;
18 import javax
.persistence
.Entity
;
19 import javax
.persistence
.FetchType
;
20 import javax
.persistence
.ManyToOne
;
21 import javax
.persistence
.OneToMany
;
22 import javax
.persistence
.Transient
;
23 import javax
.xml
.bind
.annotation
.XmlAccessType
;
24 import javax
.xml
.bind
.annotation
.XmlAccessorType
;
25 import javax
.xml
.bind
.annotation
.XmlElement
;
26 import javax
.xml
.bind
.annotation
.XmlElementWrapper
;
27 import javax
.xml
.bind
.annotation
.XmlIDREF
;
28 import javax
.xml
.bind
.annotation
.XmlRootElement
;
29 import javax
.xml
.bind
.annotation
.XmlSchemaType
;
30 import javax
.xml
.bind
.annotation
.XmlType
;
32 import org
.apache
.log4j
.Logger
;
33 import org
.hibernate
.annotations
.Cascade
;
34 import org
.hibernate
.annotations
.CascadeType
;
35 import org
.hibernate
.envers
.Audited
;
37 import eu
.etaxonomy
.cdm
.model
.common
.AnnotatableEntity
;
38 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceBase
;
45 @XmlAccessorType(XmlAccessType
.FIELD
)
46 @XmlType(name
= "TaxonNode", propOrder
= {
51 "referenceForParentChildRelation",
52 "microReferenceForParentChildRelation",
56 @XmlRootElement(name
= "TaxonNode")
59 public class TaxonNode
extends AnnotatableEntity
{
60 private static final long serialVersionUID
= -4743289894926587693L;
61 @SuppressWarnings("unused")
62 private static final Logger logger
= Logger
.getLogger(TaxonNode
.class);
64 @XmlElement(name
= "taxon")
66 @XmlSchemaType(name
= "IDREF")
67 @ManyToOne(fetch
= FetchType
.LAZY
)
68 @Cascade({CascadeType
.SAVE_UPDATE
})
72 @XmlElement(name
= "parent")
74 @XmlSchemaType(name
= "IDREF")
75 @ManyToOne(fetch
= FetchType
.LAZY
)
76 @Cascade({CascadeType
.SAVE_UPDATE
})
77 private TaxonNode parent
;
80 @XmlElement(name
= "taxonomicTree")
82 @XmlSchemaType(name
= "IDREF")
83 @ManyToOne(fetch
= FetchType
.LAZY
)
84 @Cascade({CascadeType
.SAVE_UPDATE
})
85 private TaxonomicTree taxonomicTree
;
87 @XmlElementWrapper(name
= "childNodes")
88 @XmlElement(name
= "childNode")
90 @XmlSchemaType(name
= "IDREF")
91 @OneToMany(mappedBy
="parent", fetch
=FetchType
.LAZY
)
92 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
})
93 private Set
<TaxonNode
> childNodes
= new HashSet
<TaxonNode
>();
95 @XmlElement(name
= "reference")
97 @XmlSchemaType(name
= "IDREF")
98 @ManyToOne(fetch
= FetchType
.LAZY
)
99 @Cascade({CascadeType
.SAVE_UPDATE
})
100 private ReferenceBase referenceForParentChildRelation
;
102 @XmlElement(name
= "microReference")
103 private String microReferenceForParentChildRelation
;
105 @XmlElement(name
= "countChildren")
106 private int countChildren
;
108 // private Taxon originalConcept;
110 @XmlElement(name
= "synonymToBeUsed")
112 @XmlSchemaType(name
= "IDREF")
113 @ManyToOne(fetch
= FetchType
.LAZY
)
114 @Cascade({CascadeType
.SAVE_UPDATE
})
115 private Synonym synonymToBeUsed
;
118 protected TaxonNode(){
122 //to create nodes either use TaxonomicView.addRoot() or TaxonNode.addChild();
123 protected TaxonNode (Taxon taxon
, TaxonomicTree taxonomicTree
){
125 setTaxonomicView(taxonomicTree
);
130 //************************ METHODS **************************/
132 public TaxonNode
addChild(Taxon taxon
){
133 return addChild(taxon
, null, null, null);
136 public TaxonNode
addChild(Taxon taxon
, ReferenceBase ref
, String microReference
){
137 return addChild(taxon
, ref
, microReference
, null);
140 public TaxonNode
addChild(Taxon taxon
, ReferenceBase ref
, String microReference
, Synonym synonymUsed
){
141 if (this.getTaxonomicTree().isTaxonInTree(taxon
)){
142 throw new IllegalArgumentException("Taxon may not be twice in a taxonomic view");
144 TaxonNode childNode
= new TaxonNode(taxon
, this.getTaxonomicTree());
145 addChildNote(childNode
, ref
, microReference
, synonymUsed
);
149 protected void addChildNote(TaxonNode childNode
, ReferenceBase ref
, String microReference
, Synonym synonymUsed
){
150 if (! childNode
.getTaxonomicTree().equals(this.getTaxonomicTree())){
151 throw new IllegalArgumentException("addChildNote(): both nodes must be part of the same view");
153 childNode
.setParent(this);
154 childNodes
.add(childNode
);
155 this.countChildren
++;
156 childNode
.setReferenceForParentChildRelation(ref
);
157 childNode
.setMicroReferenceForParentChildRelation(microReference
);
158 childNode
.setSynonymToBeUsed(synonymUsed
);
162 * This removes recursively all child nodes from this node and from this taxonomic view.
163 * TODO remove orphan nodes completely
168 public boolean removeChild(TaxonNode node
){
169 boolean result
= false;
171 for (TaxonNode grandChildNode
: node
.getChildNodes()){
172 node
.removeChild(grandChildNode
);
174 result
= childNodes
.remove(node
);
175 this.countChildren
--;
176 if (this.countChildren
< 0){
177 throw new IllegalStateException("children count must not be negative ");
179 node
.getTaxon().removeTaxonNode(node
);
180 node
.setParent(null);
181 node
.setTaxonomicView(null);
188 * Remove this taxonNode From its taxonomic view.
190 * @return true on success
192 public boolean remove(){
194 return taxonomicTree
.removeRoot(this);
196 return getParent().removeChild(this);
200 //*********** GETTER / SETTER ***********************************/
202 public Taxon
getTaxon() {
205 protected void setTaxon(Taxon taxon
) {
208 taxon
.addTaxonNode(this);
211 public TaxonNode
getParent() {
214 protected void setParent(TaxonNode parent
) {
215 this.parent
= parent
;
217 public TaxonomicTree
getTaxonomicTree() {
218 return taxonomicTree
;
220 //invisible part of the bidirectional relationship, for public use TaxonomicView.addRoot() or TaxonNode.addChild()
221 protected void setTaxonomicView(TaxonomicTree taxonomicTree
) {
222 this.taxonomicTree
= taxonomicTree
;
224 public Set
<TaxonNode
> getChildNodes() {
229 * Returns a set containing this node and all nodes that are descendants of this node
233 protected Set
<TaxonNode
> getAllNodes(){
234 Set
<TaxonNode
> nodeSet
= new HashSet
<TaxonNode
>();
238 for(TaxonNode childNode
: getChildNodes()){
239 nodeSet
.addAll(childNode
.getAllNodes());
245 // protected void setChildNodes(List<TaxonNode> childNodes) {
246 // this.childNodes = childNodes;
248 public ReferenceBase
getReferenceForParentChildRelation() {
249 return referenceForParentChildRelation
;
251 public void setReferenceForParentChildRelation(
252 ReferenceBase referenceForParentChildRelation
) {
253 this.referenceForParentChildRelation
= referenceForParentChildRelation
;
255 public String
getMicroReferenceForParentChildRelation() {
256 return microReferenceForParentChildRelation
;
258 public void setMicroReferenceForParentChildRelation(
259 String microReferenceForParentChildRelation
) {
260 this.microReferenceForParentChildRelation
= microReferenceForParentChildRelation
;
262 public int getCountChildren() {
263 return countChildren
;
265 public void setCountChildren(int countChildren
) {
266 this.countChildren
= countChildren
;
268 // public Taxon getOriginalConcept() {
269 // return originalConcept;
271 // public void setOriginalConcept(Taxon originalConcept) {
272 // this.originalConcept = originalConcept;
274 public Synonym
getSynonymToBeUsed() {
275 return synonymToBeUsed
;
277 public void setSynonymToBeUsed(Synonym synonymToBeUsed
) {
278 this.synonymToBeUsed
= synonymToBeUsed
;
282 * Whether this TaxonNode is a root node
285 public boolean isRootNode(){
286 return parent
== null;
290 * Whether this TaxonNode is a descendant of the given TaxonNode
292 * @param possibleParent
293 * @return true if this is a descendant
296 public boolean isDescendant(TaxonNode possibleParent
){
297 return possibleParent
.getAllNodes().contains(this);