Project

General

Profile

Download (9.7 KB) Statistics
| Branch: | Tag: | Revision:
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.Column;
19
import javax.persistence.Entity;
20
import javax.persistence.FetchType;
21
import javax.persistence.OneToMany;
22
import javax.persistence.OneToOne;
23
import javax.persistence.Transient;
24
import javax.validation.constraints.NotNull;
25
import javax.xml.bind.annotation.XmlAccessType;
26
import javax.xml.bind.annotation.XmlAccessorType;
27
import javax.xml.bind.annotation.XmlAttribute;
28
import javax.xml.bind.annotation.XmlElement;
29
import javax.xml.bind.annotation.XmlElementWrapper;
30
import javax.xml.bind.annotation.XmlRootElement;
31
import javax.xml.bind.annotation.XmlType;
32

    
33
import org.apache.log4j.Logger;
34
import org.hibernate.annotations.Cascade;
35
import org.hibernate.annotations.CascadeType;
36
import org.hibernate.annotations.Type;
37
import org.hibernate.envers.Audited;
38

    
39
import eu.etaxonomy.cdm.model.common.IHasTermType;
40
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
41
import eu.etaxonomy.cdm.model.common.Representation;
42
import eu.etaxonomy.cdm.model.common.TermType;
43
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
44

    
45
/**
46
 * The class to arrange {@link Feature features} (characters) in a tree structure.
47
 * Feature trees are essential as interactive multiple-access keys for
48
 * determination process and for systematical output arrangement of
49
 * {@link DescriptionElementBase description elements} according to different goals
50
 * but may also be used to define flat feature subsets for filtering purposes.<BR>
51
 * A feature tree is build on {@link FeatureNode feature nodes}.
52
 * <P>
53
 * This class corresponds partially to ConceptTreeDefType according to the SDD
54
 * schema.
55
 * <P>
56
 * Note: The tree structure of features used for purposes described above has
57
 * nothing in common with the possible hierarchical structure of features
58
 * depending on their grade of precision.
59
 *
60
 * @see		MediaKey
61
 *
62
 * @author  m.doering
63
 * @since 08-Nov-2007 13:06:16
64
 */
65
@XmlAccessorType(XmlAccessType.FIELD)
66
@XmlType(name = "FeatureTree", propOrder = {
67
    "root",
68
    "termType",
69
    "allowDuplicates",
70
    "representations"
71

    
72
})
73
@XmlRootElement(name = "FeatureTree")
74
@Entity
75
//@Indexed disabled to reduce clutter in indexes, since this type is not used by any search
76
//@Indexed(index = "eu.etaxonomy.cdm.model.description.FeatureTree")
77
@Audited
78
public class FeatureTree
79
            extends IdentifiableEntity<IIdentifiableEntityCacheStrategy>
80
            implements IHasTermType, Cloneable{
81

    
82
	private static final long serialVersionUID = -6713834139003172735L;
83
	private static final Logger logger = Logger.getLogger(FeatureTree.class);
84

    
85
	@XmlElement(name = "Root")
86
	@OneToOne(fetch = FetchType.LAZY)
87
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
88
	private FeatureNode root;
89

    
90
    /**
91
     * The {@link TermType type} of this term collection. All nodes in the graph must refer to a term of the same type.
92
     */
93
    @XmlAttribute(name ="TermType")
94
    @Column(name="termType")
95
    @NotNull
96
    @Type(type = "eu.etaxonomy.cdm.hibernate.EnumUserType",
97
        parameters = {@org.hibernate.annotations.Parameter(name  = "enumClass", value = "eu.etaxonomy.cdm.model.common.TermType")}
98
    )
99
    @Audited
100
    private TermType termType;
101

    
102
    // TODO needed? FeatureTree was a TermBase until v3.3 but was removed from
103
	//it as TermBase got the termType which does not apply to FeatureTree.
104
	//We need to check how far representations and uri is still required
105
	//or can be deleted. Current implementations seem all to use the title cache
106
	//instead of representation. This may not be correct.
107
	@XmlElementWrapper(name = "Representations")
108
    @XmlElement(name = "Representation")
109
    @OneToMany(fetch=FetchType.EAGER, orphanRemoval=true)
110
    @Cascade( { CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
111
    // @IndexedEmbedded no need for embedding since we are using the DefinedTermBaseClassBridge
112
    private Set<Representation> representations = new HashSet<>();
113
    //make them private for now as we may delete representations in future
114
	//otherwise if we decide to use representations we can make the getters public
115
	private Set<Representation> getRepresentations() {return representations;}
116
    private void setRepresentations(Set<Representation> representations) {this.representations = representations;}
117

    
118
    //#7372 indicates if this tree/graph allows duplicated terms/features
119
    private boolean allowDuplicates = false;
120

    
121
//******************** FACTORY METHODS ******************************************/
122

    
123
    /**
124
     * Creates a new term collection instance for the given term type
125
     * with an empty {@link #getRoot() root node}.
126
     * @param termType the {@link TermType term type}, must not be null
127
     */
128
    public static FeatureTree NewInstance(@NotNull TermType termType){
129
        return new FeatureTree(termType);
130
    }
131

    
132
    /**
133
	 * Creates a new feature tree instance with an empty {@link #getRoot() root node}.
134
	 *
135
	 * @see #NewInstance(UUID)
136
	 * @see #NewInstance(List)
137
	 */
138
	public static FeatureTree NewInstance(){
139
		return new FeatureTree(TermType.Feature);
140
	}
141

    
142
	/**
143
	 * Creates a new feature tree instance with an empty {@link #getRoot() root node}
144
	 * and assigns to the new feature tree the given
145
	 * UUID (universally unique identifier).
146
	 *
147
	 * @param	uuid	the universally unique identifier
148
	 * @see 			#NewInstance()
149
	 * @see 			#NewInstance(List)
150
	 */
151
	public static FeatureTree NewInstance(UUID uuid){
152
		FeatureTree result =  new FeatureTree(TermType.Feature);
153
		result.setUuid(uuid);
154
		return result;
155
	}
156

    
157
	/**
158
	 * Creates a new feature tree instance with a {@link #getRoot() root node}
159
	 * the children of which are the feature nodes build on the base of the
160
	 * given list of {@link Feature features}. This corresponds to a flat feature tree.
161
	 * For each feature within the list a new {@link FeatureNode feature node} without
162
	 * children nodes will be created.
163
	 *
164
	 * @param	featureList	the feature list
165
	 * @see 				#NewInstance()
166
	 * @see 				#NewInstance(UUID)
167
	 */
168
	public static FeatureTree NewInstance(List<Feature> featureList){
169
		FeatureTree result =  new FeatureTree(TermType.Feature);
170
		FeatureNode root = result.getRoot();
171

    
172
		for (Feature feature : featureList){
173
			FeatureNode child = FeatureNode.NewInstance(feature);
174
			root.addChild(child);
175
		}
176

    
177
		return result;
178
	}
179

    
180

    
181
// ******************** CONSTRUCTOR *************************************/
182

    
183
    //for JAXB only, TODO needed?
184
    @Deprecated
185
    protected FeatureTree(){}
186

    
187
	/**
188
	 * Class constructor: creates a new feature tree instance with an empty
189
	 * {@link #getRoot() root node}.
190
	 */
191
	protected FeatureTree(TermType termType) {
192
        this.termType = termType;
193
        checkTermType(this);
194
		root = FeatureNode.NewInstance(termType);
195
		root.setFeatureTree(this);
196
	}
197

    
198
// ****************** GETTER / SETTER **********************************/
199

    
200
	@Override
201
    public TermType getTermType() {
202
        return termType;
203
    }
204
    /**
205
	 * Returns the topmost {@link FeatureNode feature node} (root node) of <i>this</i>
206
	 * feature tree. The root node does not have any parent. Since feature nodes
207
	 * recursively point to their child nodes the complete feature tree is
208
	 * defined by its root node.
209
	 */
210
	public FeatureNode getRoot() {
211
		return root;
212
	}
213

    
214
    /**
215
     * @deprecated this method is only for internal use when deleting a {@link FeatureTree}
216
     * from a database. It should never be called for other reasons.
217
     */
218
    @Deprecated
219
    public void removeRootNode() {
220
        this.root = null;
221
    }
222

    
223
	/**
224
	 * Returns the (ordered) list of {@link FeatureNode feature nodes} which are immediate
225
	 * children of the root node of <i>this</i> feature tree.
226
	 */
227
	@Transient
228
	public List<FeatureNode> getRootChildren(){
229
		List<FeatureNode> result = new ArrayList<>();
230
		result.addAll(root.getChildNodes());
231
		return result;
232
	}
233

    
234
    public boolean isAllowDuplicates() {
235
        return allowDuplicates;
236
    }
237
    public void setAllowDuplicates(boolean allowDuplicates) {
238
        this.allowDuplicates = allowDuplicates;
239
    }
240

    
241
    /**
242
     * Throws {@link IllegalArgumentException} if the given
243
     * term has not the same term type as this term or if term type is null.
244
     * @param term
245
     */
246
    private void checkTermType(IHasTermType term) {
247
        IHasTermType.checkTermTypes(term, this);
248
    }
249

    
250
//******************** METHODS ***********************************************/
251

    
252
	/**
253
	 * Computes a set of distinct features that are present in this feature tree
254
	 *
255
	 * @return
256
	 */
257
	@Transient
258
	public Set<Feature> getDistinctFeatures(){
259
		Set<Feature> features = new HashSet<>();
260

    
261
		return root.getDistinctFeaturesRecursive(features);
262
	}
263

    
264
//*********************** CLONE ********************************************************/
265

    
266
	/**
267
	 * Clones <i>this</i> FeatureTree. This is a shortcut that enables to create
268
	 * a new instance that differs only slightly from <i>this</i> FeatureTree by
269
	 * modifying only some of the attributes.
270
	 * FeatureNodes always belong only to one tree, so all FeatureNodes are cloned to build
271
	 * the new FeatureTree
272
	 *
273
	 *
274
	 * @see eu.etaxonomy.cdm.model.common.TermBase#clone()
275
	 * @see java.lang.Object#clone()
276
	 */
277
	@Override
278
	public Object clone() {
279
		FeatureTree result;
280
		try {
281
			result = (FeatureTree)super.clone();
282
		}catch (CloneNotSupportedException e) {
283
			logger.warn("Object does not implement cloneable");
284
			e.printStackTrace();
285
			return null;
286
		}
287
		FeatureNode rootClone = this.getRoot().cloneDescendants();
288
		result.root = rootClone;
289

    
290
		return result;
291

    
292
	}
293

    
294

    
295
}
(12-12/37)