#4716 reduicing clutter in the lucene index and solving performance problems which...
[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.OneToMany;
21 import javax.persistence.OneToOne;
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.XmlRootElement;
28 import javax.xml.bind.annotation.XmlType;
29
30 import org.apache.log4j.Logger;
31 import org.hibernate.annotations.Cascade;
32 import org.hibernate.annotations.CascadeType;
33 import org.hibernate.envers.Audited;
34
35 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
36 import eu.etaxonomy.cdm.model.common.Representation;
37 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
38
39 /**
40 * The class to arrange {@link Feature features} (characters) in a tree structure.
41 * Feature trees are essential as interactive multiple-access keys for
42 * determination process and for systematical output arrangement of
43 * {@link DescriptionElementBase description elements} according to different goals but may also be used
44 * to define flat feature subsets for filtering purposes.<BR>
45 * A feature tree is build on {@link FeatureNode feature nodes}.
46 * <P>
47 * This class corresponds partially to ConceptTreeDefType according to the SDD
48 * schema.
49 * <P>
50 * Note: The tree structure of features used for purposes described above has
51 * nothing in common with the possible hierarchical structure of features
52 * depending on their grade of precision.
53 *
54 * @see MediaKey
55 *
56 * @author m.doering
57 * @created 08-Nov-2007 13:06:16
58 */
59 @XmlAccessorType(XmlAccessType.FIELD)
60 @XmlType(name = "FeatureTree", propOrder = {
61 "root",
62 "representations"
63 })
64 @XmlRootElement(name = "FeatureTree")
65 @Entity
66 //@Indexed disabled to reduce clutter in indexes, since this type is not used by any search
67 //@Indexed(index = "eu.etaxonomy.cdm.model.description.FeatureTree")
68 @Audited
69 public class FeatureTree extends IdentifiableEntity<IIdentifiableEntityCacheStrategy> implements Cloneable{
70 private static final long serialVersionUID = -6713834139003172735L;
71 private static final Logger logger = Logger.getLogger(FeatureTree.class);
72
73 @XmlElement(name = "Root")
74 @OneToOne(fetch = FetchType.LAZY)
75 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
76 private FeatureNode root;
77
78
79 // TODO needed? FeatureTree was a TermBase until v3.3 but was removed from
80 //it as TermBase got the termType which does not apply to FeatureTree.
81 //We need to check how far representations and uri is still required
82 //or can be deleted. Current implementations seem all to use the title cache
83 //instead of representation. This may not be correct.
84 @XmlElementWrapper(name = "Representations")
85 @XmlElement(name = "Representation")
86 @OneToMany(fetch=FetchType.EAGER, orphanRemoval=true)
87 @Cascade( { CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
88 // @IndexedEmbedded no need for embedding since we are using the DefinedTermBaseClassBridge
89 private Set<Representation> representations = new HashSet<Representation>();
90 //make them private for now as we may delete representations in future
91 //otherwise if we decide to use representations we can make the getters public
92 private Set<Representation> getRepresentations() {return representations;}
93 private void setRepresentations(Set<Representation> representations) {this.representations = representations;}
94
95
96 //******************** FACTORY METHODS ******************************************/
97
98
99 /**
100 * Creates a new feature tree instance with an empty {@link #getRoot() root node}.
101 *
102 * @see #NewInstance(UUID)
103 * @see #NewInstance(List)
104 */
105 public static FeatureTree NewInstance(){
106 return new FeatureTree();
107 }
108
109 /**
110 * Creates a new feature tree instance with an empty {@link #getRoot() root node}
111 * and assigns to the new feature tree the given
112 * UUID (universally unique identifier).
113 *
114 * @param uuid the universally unique identifier
115 * @see #NewInstance()
116 * @see #NewInstance(List)
117 */
118 public static FeatureTree NewInstance(UUID uuid){
119 FeatureTree result = new FeatureTree();
120 result.setUuid(uuid);
121 return result;
122 }
123
124 /**
125 * Creates a new feature tree instance with a {@link #getRoot() root node}
126 * the children of which are the feature nodes build on the base of the
127 * given list of {@link Feature features}. This corresponds to a flat feature tree.
128 * For each feature within the list a new {@link FeatureNode feature node} without
129 * children nodes will be created.
130 *
131 * @param featureList the feature list
132 * @see #NewInstance()
133 * @see #NewInstance(UUID)
134 */
135 public static FeatureTree NewInstance(List<Feature> featureList){
136 FeatureTree result = new FeatureTree();
137 FeatureNode root = result.getRoot();
138
139 for (Feature feature : featureList){
140 FeatureNode child = FeatureNode.NewInstance(feature);
141 root.addChild(child);
142 }
143
144 return result;
145 }
146
147
148 // ******************** CONSTRUCTOR *************************************/
149
150 /**
151 * Class constructor: creates a new feature tree instance with an empty
152 * {@link #getRoot() root node}.
153 */
154 protected FeatureTree() {
155 super();
156 root = FeatureNode.NewInstance();
157 root.setFeatureTree(this);
158 }
159
160 // ****************** GETTER / SETTER **********************************/
161
162
163 // @OneToMany
164 // @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
165 // public Set<FeatureNode> getNodes() {
166 // return nodes;
167 // }
168 // public void setNodes(Set<FeatureNode> nodes) {
169 // this.nodes = nodes;
170 // }
171
172 /**
173 * Returns the topmost {@link FeatureNode feature node} (root node) of <i>this</i>
174 * feature tree. The root node does not have any parent. Since feature nodes
175 * recursively point to their child nodes the complete feature tree is
176 * defined by its root node.
177 */
178 public FeatureNode getRoot() {
179 return root;
180 }
181 /**
182 * @see #getRoot()
183 */
184 public void setRoot(FeatureNode root) {
185 this.root = root;
186 }
187
188 /**
189 * Returns the (ordered) list of {@link FeatureNode feature nodes} which are immediate
190 * children of the root node of <i>this</i> feature tree.
191 */
192 @Transient
193 public List<FeatureNode> getRootChildren(){
194 List<FeatureNode> result = new ArrayList<FeatureNode>();
195 result.addAll(root.getChildNodes());
196 return result;
197 }
198
199 /**
200 * Computes a set of distinct features that are present in this feature tree
201 *
202 * @return
203 */
204 @Transient
205 public Set<Feature> getDistinctFeatures(){
206 Set<Feature> features = new HashSet<Feature>();
207
208 return root.getDistinctFeaturesRecursive(features);
209 }
210
211 //*********************** CLONE ********************************************************/
212
213 /**
214 * Clones <i>this</i> FeatureTree. This is a shortcut that enables to create
215 * a new instance that differs only slightly from <i>this</i> FeatureTree by
216 * modifying only some of the attributes.
217 * FeatureNodes always belong only to one tree, so all FeatureNodes are cloned to build
218 * the new FeatureTree
219 *
220 *
221 * @see eu.etaxonomy.cdm.model.common.TermBase#clone()
222 * @see java.lang.Object#clone()
223 */
224 @Override
225
226 public Object clone() {
227 FeatureTree result;
228 try {
229 result = (FeatureTree)super.clone();
230 }catch (CloneNotSupportedException e) {
231 logger.warn("Object does not implement cloneable");
232 e.printStackTrace();
233 return null;
234 }
235 FeatureNode rootClone = this.getRoot().cloneDescendants();
236 result.root = rootClone;
237
238 return result;
239
240 }
241
242
243 }