more tests and features for #476: Implement free-text search methods for TaxonBase...
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / description / FeatureTree.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.description;
11
12 import java.util.ArrayList;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Set;
16 import java.util.UUID;
17
18 import javax.persistence.Entity;
19 import javax.persistence.FetchType;
20 import javax.persistence.OneToOne;
21 import javax.persistence.Transient;
22 import javax.xml.bind.annotation.XmlAccessType;
23 import javax.xml.bind.annotation.XmlAccessorType;
24 import javax.xml.bind.annotation.XmlElement;
25 import javax.xml.bind.annotation.XmlRootElement;
26 import javax.xml.bind.annotation.XmlType;
27
28 import org.apache.log4j.Logger;
29 import org.hibernate.annotations.Cascade;
30 import org.hibernate.annotations.CascadeType;
31 import org.hibernate.envers.Audited;
32 import org.hibernate.search.annotations.Indexed;
33
34 import eu.etaxonomy.cdm.model.common.TermBase;
35
36 /**
37 * The class to arrange {@link Feature features} (characters) in a tree structure.
38 * Feature trees are essential as interactive multiple-access keys for
39 * determination process and for systematical output arrangement of
40 * {@link DescriptionElementBase description elements} according to different goals but may also be used
41 * to define flat feature subsets for filtering purposes.<BR>
42 * A feature tree is build on {@link FeatureNode feature nodes}.
43 * <P>
44 * This class corresponds partially to ConceptTreeDefType according to the SDD
45 * schema.
46 * <P>
47 * Note: The tree structure of features used for purposes described above has
48 * nothing in common with the possible hierarchical structure of features
49 * depending on their grade of precision.
50 *
51 * @see MediaKey
52 * @author m.doering
53 * @version 1.0
54 * @created 08-Nov-2007 13:06:16
55 */
56 @XmlAccessorType(XmlAccessType.FIELD)
57 @XmlType(name = "FeatureTree", propOrder = {
58 "descriptionSeparated",
59 "root"
60 })
61 @XmlRootElement(name = "FeatureTree")
62 @Entity
63 @Indexed(index = "eu.etaxonomy.cdm.model.description.FeatureTree")
64 @Audited
65 public class FeatureTree extends TermBase implements Cloneable{
66 private static final long serialVersionUID = -6713834139003172735L;
67 @SuppressWarnings("unused")
68 private static final Logger logger = Logger.getLogger(FeatureTree.class);
69 //private Set<FeatureNode> nodes = new HashSet<FeatureNode>();
70
71 @XmlElement(name = "Root")
72 @OneToOne(fetch = FetchType.LAZY)
73 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
74 private FeatureNode root;
75
76 @XmlElement(name = "IsDescriptionSeparated")
77 private boolean descriptionSeparated = false;
78
79 /**
80 * Class constructor: creates a new feature tree instance with an empty
81 * {@link #getRoot() root node}.
82 */
83 protected FeatureTree() {
84 super();
85 root = FeatureNode.NewInstance();
86 root.setFeatureTree(this);
87 }
88
89 /**
90 * Creates a new feature tree instance with an empty {@link #getRoot() root node}.
91 *
92 * @see #NewInstance(UUID)
93 * @see #NewInstance(List)
94 */
95 public static FeatureTree NewInstance(){
96 return new FeatureTree();
97 }
98
99 /**
100 * Creates a new feature tree instance with an empty {@link #getRoot() root node}
101 * and assigns to the new feature tree the given
102 * UUID (universally unique identifier).
103 *
104 * @param uuid the universally unique identifier
105 * @see #NewInstance()
106 * @see #NewInstance(List)
107 */
108 public static FeatureTree NewInstance(UUID uuid){
109 FeatureTree result = new FeatureTree();
110 result.setUuid(uuid);
111 return result;
112 }
113
114 /**
115 * Creates a new feature tree instance with a {@link #getRoot() root node}
116 * the children of which are the feature nodes build on the base of the
117 * given list of {@link Feature features}. This corresponds to a flat feature tree.
118 * For each feature within the list a new {@link FeatureNode feature node} without
119 * children nodes will be created.
120 *
121 * @param featureList the feature list
122 * @see #NewInstance()
123 * @see #NewInstance(UUID)
124 */
125 public static FeatureTree NewInstance(List<Feature> featureList){
126 FeatureTree result = new FeatureTree();
127 FeatureNode root = result.getRoot();
128
129 for (Feature feature : featureList){
130 FeatureNode child = FeatureNode.NewInstance(feature);
131 root.addChild(child);
132 }
133
134 return result;
135 }
136
137 // Delete the isDescriptionSeparated flag ??
138 /**
139 * Returns the boolean value of the flag indicating whether the
140 * {@link DescriptionElementBase description elements} associated with the {@link Feature features}
141 * belonging to <i>this</i> feature tree should be treated separately (true)
142 * or not (false).
143 *
144 * @return the boolean value of the isDescriptionSeparated flag
145 */
146 public boolean isDescriptionSeparated() {
147 return descriptionSeparated;
148 }
149
150 /**
151 * @see #isDescriptionSeparated()
152 */
153 public void setDescriptionSeparated(boolean descriptionSeperated) {
154 this.descriptionSeparated = descriptionSeperated;
155 }
156
157 // @OneToMany
158 // @Cascade({CascadeType.SAVE_UPDATE})
159 // public Set<FeatureNode> getNodes() {
160 // return nodes;
161 // }
162 // public void setNodes(Set<FeatureNode> nodes) {
163 // this.nodes = nodes;
164 // }
165
166 /**
167 * Returns the topmost {@link FeatureNode feature node} (root node) of <i>this</i>
168 * feature tree. The root node does not have any parent. Since feature nodes
169 * recursively point to their child nodes the complete feature tree is
170 * defined by its root node.
171 */
172 public FeatureNode getRoot() {
173 return root;
174 }
175 /**
176 * @see #getRoot()
177 */
178 public void setRoot(FeatureNode root) {
179 this.root = root;
180 }
181
182 /**
183 * Returns the (ordered) list of {@link FeatureNode feature nodes} which are immediate
184 * children of the root node of <i>this</i> feature tree.
185 */
186 @Transient
187 public List<FeatureNode> getRootChildren(){
188 List<FeatureNode> result = new ArrayList<FeatureNode>();
189 result.addAll(root.getChildren());
190 return result;
191 }
192
193 /**
194 * Computes a set of distinct features that are present in this feature tree
195 *
196 * @return
197 */
198 @Transient
199 public Set<Feature> getDistinctFeatures(){
200 Set<Feature> features = new HashSet<Feature>();
201
202 return root.getDistinctFeaturesRecursive(features);
203 }
204
205 //*********************** CLONE ********************************************************/
206
207 /**
208 * Clones <i>this</i> FeatureTree. This is a shortcut that enables to create
209 * a new instance that differs only slightly from <i>this</i> FeatureTree by
210 * modifying only some of the attributes.
211 * FeatureNodes always belong only to one tree, so all FeatureNodes are cloned to build
212 * the new FeatureTree
213 *
214 *
215 * @see eu.etaxonomy.cdm.model.common.TermBase#clone()
216 * @see java.lang.Object#clone()
217 */
218 @Override
219
220 public Object clone() {
221 FeatureTree result;
222 try {
223 result = (FeatureTree)super.clone();
224 }catch (CloneNotSupportedException e) {
225 logger.warn("Object does not implement cloneable");
226 e.printStackTrace();
227 return null;
228 }
229 FeatureNode rootClone = (FeatureNode)this.getRoot().cloneDescendants();
230 result.root = rootClone;
231
232 return result;
233
234 }
235
236
237 }