Project

General

Profile

Download (10.2 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.rmi.UnexpectedException;
13
import java.util.ArrayList;
14
import java.util.HashSet;
15
import java.util.List;
16
import java.util.Set;
17
import java.util.UUID;
18

    
19
import javax.persistence.Column;
20
import javax.persistence.Entity;
21
import javax.persistence.FetchType;
22
import javax.persistence.OneToMany;
23
import javax.persistence.OneToOne;
24
import javax.persistence.Transient;
25
import javax.validation.constraints.NotNull;
26
import javax.xml.bind.annotation.XmlAccessType;
27
import javax.xml.bind.annotation.XmlAccessorType;
28
import javax.xml.bind.annotation.XmlAttribute;
29
import javax.xml.bind.annotation.XmlElement;
30
import javax.xml.bind.annotation.XmlElementWrapper;
31
import javax.xml.bind.annotation.XmlRootElement;
32
import javax.xml.bind.annotation.XmlType;
33

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

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

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

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

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

    
87
	@XmlElement(name = "Root")
88
	@OneToOne(fetch = FetchType.LAZY, targetEntity=FeatureNode.class)
89
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
90
	private FeatureNode<T> root;
91

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

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

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

    
123
//******************** FACTORY METHODS ******************************************/
124

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

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

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

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

    
174
		for (Feature feature : featureList){
175
			FeatureNode<Feature> child = FeatureNode.NewInstance(feature);
176
			root.addChild(child);
177
		}
178

    
179
		return result;
180
	}
181

    
182

    
183
// ******************** CONSTRUCTOR *************************************/
184

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

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

    
200
// ****************** GETTER / SETTER **********************************/
201

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

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

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

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

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

    
252
//******************** METHODS ***********************************************/
253

    
254
	/**
255
	 * Computes a set of distinct terms that are present in this feature tree
256
	 *
257
	 * @return
258
	 */
259
	@Transient
260
	public Set<T> getDistinctFeatures(){
261
	    if(termType.equals(TermType.Feature) || termType.isKindOf(TermType.Feature)){
262
	        Set<T> features = new HashSet<>();
263
	        return root.getDistinctFeaturesRecursive(features);
264
	    }
265
	    String message = "FeatureTree is not of type FEATURE.";
266
	    logger.warn(message, new UnexpectedException(message));
267
	    return new HashSet<>();
268
	}
269

    
270
//*********************** CLONE ********************************************************/
271

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

    
296
		return result;
297

    
298
	}
299

    
300

    
301
}
(12-12/37)