Project

General

Profile

Download (9.94 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
package eu.etaxonomy.cdm.model.term;
10

    
11
import java.util.ArrayList;
12
import java.util.HashSet;
13
import java.util.List;
14
import java.util.Set;
15
import java.util.UUID;
16

    
17
import javax.persistence.Entity;
18
import javax.persistence.FetchType;
19
import javax.persistence.OneToOne;
20
import javax.persistence.Transient;
21
import javax.validation.constraints.NotNull;
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.logging.log4j.LogManager;
29
import org.apache.logging.log4j.Logger;
30
import org.hibernate.annotations.Cascade;
31
import org.hibernate.annotations.CascadeType;
32
import org.hibernate.envers.Audited;
33

    
34
import eu.etaxonomy.cdm.common.SetMap;
35
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
36
import eu.etaxonomy.cdm.model.description.Feature;
37

    
38
/**
39
 * The class to arrange {@link DefinedTermBase terms} in a tree structure.
40
 * A term tree is build on {@link TermNode term nodes}.
41
 *
42
 * Special term trees:
43
 *
44
 * <B>Feature</B> trees are essential as interactive multiple-access keys for
45
 * determination process and for systematic output arrangement of
46
 * {@link DescriptionElementBase description elements} according to different goals
47
 * but may also be used to define flat feature subsets for filtering purposes.<BR>
48
 * <P>
49
 * If used as feature tree this class corresponds partially to ConceptTreeDefType
50
 * according to the SDD schema.
51
 * <P>
52
 * Note: The tree structure of terms used for purposes described above has
53
 * nothing in common with the possible hierarchical structure of terms
54
 * depending on their grade of precision.
55
 *
56
 * @author  m.doering
57
 * @since 08-Nov-2007 13:06:16
58
 */
59
@XmlAccessorType(XmlAccessType.FIELD)
60
@XmlType(name = "TermTree", propOrder = {
61
    "root",
62
})
63
@XmlRootElement(name = "TermTree")
64
@Entity
65
//@Indexed disabled to reduce clutter in indexes, since this type is not used by any search
66
//@Indexed(index = "eu.etaxonomy.cdm.model.term.TermTree")
67
@Audited
68
public class TermTree <T extends DefinedTermBase>
69
            extends TermGraphBase<T, TermNode>
70
            implements ITermTree<T, TermNode> {
71

    
72
	private static final long serialVersionUID = -6713834139003172735L;
73
	private static final Logger logger = LogManager.getLogger();
74

    
75
    // TODO representations needed? TermTree was a TermBase until v3.3 but was removed from
76
    //it as TermBase got the termType which does not apply to TermTree.
77
    //We need to check how far representations and uri is still required
78
    //or can be deleted. Current implementations seem all to use the title cache
79
    //instead of representation. This may not be correct.
80
	// Note: since model 5.8 representations are back as FeatureTree became TermTree and
81
	//inherits from TermBase. Need to check if they are correctly handled. Anyway,
82
	//translations should be synchronized all over the system (there is a ticket for this)
83

    
84
	@XmlElement(name = "Root")
85
	@OneToOne(fetch = FetchType.LAZY, targetEntity=TermNode.class)
86
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
87
	private TermNode<T> root;
88

    
89
//******************** FACTORY METHODS ******************************************/
90

    
91
    /**
92
     * Creates a new term collection instance for the given term type
93
     * with an empty {@link #getRoot() root node}.
94
     * @param termType the {@link TermType term type}, must not be null
95
     */
96
    public static <T extends DefinedTermBase<T>> TermTree<T> NewInstance(@NotNull TermType termType){
97
        return new TermTree<>(termType);
98
    }
99

    
100
    /**
101
     * Creates a new term collection instance for the given term type
102
     * with an empty {@link #getRoot() root node}.
103
     * @param termType the {@link TermType term type}, must not be null
104
     */
105
    public static <T extends DefinedTermBase> TermTree<T> NewInstance(@NotNull TermType termType, @SuppressWarnings("unused") Class<T> clazz){
106
        return new TermTree<>(termType);
107
    }
108

    
109
    public static TermTree<Feature> NewFeatureInstance(){
110
        return new TermTree<>(TermType.Feature);
111
    }
112

    
113
	/**
114
     * Creates a new feature tree instance with an empty {@link #getRoot() root node}
115
     * and assigns to the new feature tree the given
116
     * UUID (universally unique identifier).
117
     *
118
     * @param   uuid    the universally unique identifier
119
     * @see             #NewInstance()
120
     * @see             #NewInstance(List)
121
     */
122
    public static <T extends DefinedTermBase<T>> TermTree<T> NewFeatureInstance(UUID uuid){
123
        TermTree<T> result =  new TermTree<>(TermType.Feature);
124
        result.setUuid(uuid);
125
        return result;
126
    }
127

    
128
	/**
129
	 * Creates a new feature tree instance with a {@link #getRoot() root node}
130
	 * the children of which are the feature nodes build on the base of the
131
	 * given list of {@link Feature features}. This corresponds to a flat feature tree.
132
	 * For each feature within the list a new {@link TermNode feature node} without
133
	 * children nodes will be created.
134
	 *
135
	 * @param	featureList	the feature list
136
	 * @see 				#NewInstance()
137
	 * @see 				#NewInstance(UUID)
138
	 */
139
	public static TermTree<Feature> NewFeatureInstance(List<Feature> featureList){
140
		TermTree<Feature> result =  new TermTree<>(TermType.Feature);
141
		TermNode<Feature> root = result.getRoot();
142

    
143
		for (Feature feature : featureList){
144
			root.addChild(feature);
145
		}
146

    
147
		return result;
148
	}
149

    
150
// ******************** CONSTRUCTOR *************************************/
151

    
152
	//for hibernate (+JAXB?) use only, *packet* private required by bytebuddy
153
    @Deprecated
154
    TermTree(){}
155

    
156
	/**
157
	 * Class constructor: creates a new feature tree instance with an empty
158
	 * {@link #getRoot() root node}.
159
	 */
160
	protected TermTree(TermType termType) {
161
        super(termType);
162
		root = new TermNode<>(termType);
163
		root.setGraph(this);
164
	}
165

    
166
// ****************** GETTER / SETTER **********************************/
167

    
168
    /**
169
	 * Returns the topmost {@link TermNode feature node} (root node) of <i>this</i>
170
	 * feature tree. The root node does not have any parent. Since feature nodes
171
	 * recursively point to their child nodes the complete feature tree is
172
	 * defined by its root node.
173
	 */
174
	public TermNode<T> getRoot() {
175
		return root;
176
	}
177

    
178
    /**
179
     * @deprecated this method is only for internal use when deleting a {@link TermTree}
180
     * from a database. It should never be called for other reasons.
181
     */
182
    @Deprecated
183
    public void removeRootNode() {
184
        this.root = null;
185
    }
186

    
187
	/**
188
	 * Returns the (ordered) list of {@link TermNode feature nodes} which are immediate
189
	 * children of the root node of <i>this</i> feature tree.
190
	 */
191
	@Override
192
	@Transient
193
	public List<TermNode<T>> getRootChildren(){
194
		List<TermNode<T>> result = new ArrayList<>();
195
		result.addAll(root.getChildNodes());
196
		return result;
197
	}
198

    
199
//******************** METHODS ***********************************************/
200

    
201
	/**
202
	 * Computes a set of distinct terms that are present in this term tree
203
	 */
204
    @Override
205
    @Transient
206
	public Set<T> getDistinctTerms(){
207
	    Set<T> terms = new HashSet<>();
208
	    return root.getDistinctTermsRecursive(terms);
209
	}
210

    
211
    @Override
212
    public List<T> asTermList() {
213
        List<T> result = new ArrayList<>();
214
        for (TermNode<T> node : getRootChildren()){
215
            result.add(node.getTerm());
216
            for (TermNode<T> child : node.getChildNodes()){
217
                result.addAll(child.asTermListRecursive());
218
            }
219
        }
220
        return result;
221
    }
222

    
223
    public Set<T> independentTerms() {
224
        Set<T> terms = root.getIndependentTermsRecursive();
225
        return terms;
226
    }
227

    
228
    /**
229
     * Returns the first node having <code>term</code>
230
     * as term. Using depth search.
231
     */
232
    @Transient
233
    public TermNode<T> getNodeForTerm(T term){
234
        return getRoot().getNodeForTerm(term);
235
    }
236

    
237
    /**
238
     * Returns all nodes having <code>term</code>
239
     * as term. Using depth search.
240
     */
241
    @Transient
242
    public Set<TermNode<T>> getNodesForTerm(T term){
243
        return getRoot().getNodesForTerm(term);
244
    }
245

    
246
    /**
247
     * Returns the parent term for the given
248
     * as defined by this tree. If more than 1 node use the
249
     * given term an arbitrary first node is used.
250
     * If the node has only the invisible root node as parent
251
     * <code>null</code> is returned.
252
     */
253
    @Transient
254
    public T getParentTerm(T term){
255
        TermNode<T> node = getNodeForTerm(term);
256
        return node == null? null : node.getParentTerm();
257
    }
258

    
259
    /**
260
     * Returns a map for an area and its parents.
261
     */
262
    @Transient
263
    public SetMap<T, T> getParentMap() {
264
        SetMap<T, T> result = new SetMap<>();
265
        getRoot().fillParentMap(result);
266
        return result;
267
    }
268

    
269
    @Transient
270
    public SetMap<T, TermNode<T>> getTermNodesMap() {
271
        SetMap<T, TermNode<T>> result = new SetMap<>();
272
        getRoot().fillTermNodeMap(result);
273
        return result;
274
    }
275

    
276
//*********************** CLONE ********************************************************/
277

    
278
	/**
279
	 * Clones <i>this</i> {@link TermTree}. This is a shortcut that enables to create
280
	 * a new instance that differs only slightly from <i>this</i> tree by
281
	 * modifying only some of the attributes.
282
	 * {@link TermNode tree nodes} always belong only to one tree, so all
283
	 * {@link TermNode tree nodes} are cloned to build
284
	 * the new {@link TermTree}
285
	 *
286
	 * @see eu.etaxonomy.cdm.model.term.TermBase#clone()
287
	 * @see java.lang.Object#clone()
288
	 */
289
    @Override
290
	public TermTree<T> clone() {
291
		try {
292
		    TermTree<T> result = (TermTree<T>)super.clone();
293
		    result.root = this.getRoot().cloneDescendants();
294
	        return result;
295
		}catch (CloneNotSupportedException e) {
296
		    String message = "Clone not possible. Object does not implement cloneable";
297
			logger.warn(message);
298
			throw new RuntimeException(message);
299
		}
300
	}
301
}
(28-28/32)