Project

General

Profile

« Previous | Next » 

Revision ffe5e099

Added by Andreas Müller about 5 years ago

ref #6794 add termType to FeatureTree and FeatureNode

View differences:

cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/common/IHasTermType.java
1
/**
2
* Copyright (C) 2019 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.common;
10

  
11
/**
12
 * @author a.mueller
13
 * @since 22.01.2019
14
 *
15
 */
16
public interface IHasTermType {
17

  
18
    public TermType getTermType();
19

  
20
    public static void checkTermTypeNull(IHasTermType term) {
21
        if (term.getTermType()== null){
22
            throw new IllegalArgumentException("Term types must not be null");
23
        }
24
    }
25
    public static void checkTermTypes(IHasTermType term, IHasTermType term2) {
26
        if (term != null && term2 != null){
27
            checkTermTypeNull(term);
28
            checkTermTypeNull(term2);
29
            if (term.getTermType()!= term.getTermType()){
30
                throw new IllegalArgumentException("Term types must match");
31
            }
32
        }
33
    }
34
}
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/common/TermBase.java
54 54
})
55 55
@MappedSuperclass
56 56
@Audited
57
public abstract class TermBase extends IdentifiableEntity<IIdentifiableEntityCacheStrategy<TermBase> >{
57
public abstract class TermBase
58
            extends IdentifiableEntity<IIdentifiableEntityCacheStrategy<TermBase>>
59
            implements IHasTermType {
60

  
58 61
    private static final long serialVersionUID = 1471561531632115822L;
59 62
    @SuppressWarnings("unused")
60 63
    private static final Logger logger = Logger.getLogger(TermBase.class);
......
111 114

  
112 115
//******************** GETTER /SETTER ********************************/
113 116

  
114
	public TermType getTermType() {
117
	@Override
118
    public TermType getTermType() {
115 119
		return termType;
116 120
	}
121
	@Deprecated //the term type should never be changed, might be removed in future
117 122
	public void setTermType(TermType termType) {
118 123
		this.termType = termType;
119 124
	}
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/description/FeatureNode.java
27 27
import javax.persistence.OrderColumn;
28 28
import javax.persistence.Table;
29 29
import javax.persistence.Transient;
30
import javax.validation.constraints.NotNull;
30 31
import javax.xml.bind.annotation.XmlAccessType;
31 32
import javax.xml.bind.annotation.XmlAccessorType;
33
import javax.xml.bind.annotation.XmlAttribute;
32 34
import javax.xml.bind.annotation.XmlElement;
33 35
import javax.xml.bind.annotation.XmlElementWrapper;
34 36
import javax.xml.bind.annotation.XmlIDREF;
......
39 41
import org.apache.log4j.Logger;
40 42
import org.hibernate.annotations.Cascade;
41 43
import org.hibernate.annotations.CascadeType;
44
import org.hibernate.annotations.Type;
42 45
import org.hibernate.envers.Audited;
43 46

  
44 47
import eu.etaxonomy.cdm.hibernate.HHH_9751_Util;
48
import eu.etaxonomy.cdm.model.common.CdmBase;
49
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
50
import eu.etaxonomy.cdm.model.common.IHasTermType;
45 51
import eu.etaxonomy.cdm.model.common.ITreeNode;
52
import eu.etaxonomy.cdm.model.common.TermType;
46 53
import eu.etaxonomy.cdm.model.common.VersionableEntity;
47 54

  
48 55
/**
......
61 68
@XmlAccessorType(XmlAccessType.FIELD)
62 69
@XmlType(name = "FeatureNode", propOrder = {
63 70
		"featureTree",
71
		"termType",
64 72
		"feature",
65 73
		"parent",
66 74
		"treeIndex",
......
74 82
@Audited
75 83
@Table(name="FeatureNode", indexes = { @Index(name = "featureNodeTreeIndex", columnList = "treeIndex") })
76 84
public class FeatureNode extends VersionableEntity
77
            implements ITreeNode<FeatureNode>, Cloneable {
85
            implements ITreeNode<FeatureNode>, IHasTermType, Cloneable {
78 86
	private static final Logger logger = Logger.getLogger(FeatureNode.class);
79 87

  
80 88
    //This is the main key a node belongs to. Although other keys may also reference
......
88 96
//    @NotNull
89 97
	private FeatureTree featureTree;
90 98

  
91
	@XmlElement(name = "Feature")
99
    /**
100
     * The {@link TermType type} of this term node.
101
     * Must be the same type as for the {@link FeatureTree term collection}
102
     * this node belongs to and as the term type of the term this node links to.
103
     */
104
    @XmlAttribute(name ="TermType")
105
    @Column(name="termType")
106
    @NotNull
107
    @Type(type = "eu.etaxonomy.cdm.hibernate.EnumUserType",
108
        parameters = {@org.hibernate.annotations.Parameter(name  = "enumClass", value = "eu.etaxonomy.cdm.model.common.TermType")}
109
    )
110
    @Audited
111
    private TermType termType;
112

  
113
    @XmlElement(name = "Feature")
92 114
    @XmlIDREF
93 115
    @XmlSchemaType(name = "IDREF")
94 116
    @ManyToOne(fetch = FetchType.LAZY)
95
	private Feature feature;
117
	private DefinedTermBase feature;
96 118

  
97 119
    @XmlElement(name = "Parent")
98 120
    @XmlIDREF
......
140 162
// ***************************** FACTORY *********************************/
141 163

  
142 164
	/**
165
     * Creates a new empty term node instance.
166
     *
167
     * @see #NewInstance(Feature)
168
     */
169
    public static FeatureNode NewInstance(TermType termType){
170
        return new FeatureNode(termType);
171
    }
172

  
173
	/**
143 174
	 * Creates a new empty feature node instance.
144 175
	 *
145 176
	 * @see #NewInstance(Feature)
146 177
	 */
147 178
	public static FeatureNode NewInstance(){
148
		return new FeatureNode();
179
		return new FeatureNode(TermType.Feature);
149 180
	}
150 181

  
151 182
	/**
......
156 187
	 * @see 			#NewInstance()
157 188
	 */
158 189
	public static FeatureNode NewInstance(Feature feature){
159
		FeatureNode result = new FeatureNode();
160
		result.setFeature(feature);
190
		FeatureNode result = new FeatureNode(TermType.Feature);
191
		result.setTerm(feature);
161 192
		return result;
162 193
	}
163 194

  
164 195
// ******************** CONSTRUCTOR ***************************************/
165 196

  
197
	//TODO needed?
198
    @Deprecated
199
    protected FeatureNode(){}
166 200

  
167 201
	/**
168 202
	 * Class constructor: creates a new empty feature node instance.
169 203
	 */
170
	protected FeatureNode() {
171
		super();
204
	protected FeatureNode(TermType termType) {
205
	    this.termType = termType;
206
	    IHasTermType.checkTermTypeNull(this);
172 207
	}
173 208

  
209
    @Override
210
    public TermType getTermType() {
211
        return termType;
212
    }
174 213

  
175 214
//*************************** TREE ************************************/
176 215

  
......
179 218
	}
180 219

  
181 220
	protected void setFeatureTree(FeatureTree featureTree) {
182
		this.featureTree = featureTree;
221
		checkTermType(featureTree);
222
	    this.featureTree = featureTree;
183 223
	}
184 224

  
185 225
//** ********************** FEATURE ******************************/
......
187 227
	/**
188 228
	 * Returns the {@link Feature feature} <i>this</i> feature node is based on.
189 229
	 */
230
	@Deprecated
190 231
	public Feature getFeature() {
191
		return feature;
232
		return CdmBase.deproxy(feature, Feature.class);
192 233
	}
193 234
	/**
194 235
	 * @see	#getFeature()
195 236
	 */
237
	@Deprecated
196 238
	public void setFeature(Feature feature) {
239
	    checkTermType(feature);
197 240
		this.feature = feature;
198 241
	}
199 242

  
243
	   /**
244
     * Returns the {@link Feature feature} <i>this</i> feature node is based on.
245
     */
246
    public DefinedTermBase getTerm() {
247
        return feature;
248
    }
249
    /**
250
     * @see #getFeature()
251
     */
252
    public void setTerm(DefinedTermBase term) {
253
        checkTermType(term);
254
        this.feature = term;
255
    }
256

  
200 257
//** ********************** PARENT ******************************/
201 258

  
202 259
	/**
......
217 274
	 * @see				#getParent()
218 275
	 */
219 276
	protected void setParent(FeatureNode parent) {
220
		this.parent = parent;
277
		checkTermType(parent);
278
	    this.parent = parent;
221 279
	}
222 280

  
223 281
//** ********************** CHILDREN ******************************/
......
273 331
	 * @see				#removeChild(int)
274 332
	 */
275 333
	public void addChild(FeatureNode child, int index){
334
	    checkTermType(child);
276 335
	    List<FeatureNode> children = this.getChildNodes();
277 336
		if (index < 0 || index > children.size() + 1){
278 337
			throw new IndexOutOfBoundsException("Wrong index: " + index);
......
521 580
//	}
522 581

  
523 582
	/**
583
     * Throws {@link IllegalArgumentException} if the given
584
     * term has not the same term type as this term or if term type is null.
585
     * @param term
586
     */
587
    private void checkTermType(IHasTermType term) {
588
        IHasTermType.checkTermTypes(term, this);
589
    }
590

  
591
	/**
524 592
	 * Returns all features that are contained in this node or a child node
525 593
	 *
526 594
	 * @param featureNode
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/description/FeatureTree.java
15 15
import java.util.Set;
16 16
import java.util.UUID;
17 17

  
18
import javax.persistence.Column;
18 19
import javax.persistence.Entity;
19 20
import javax.persistence.FetchType;
20 21
import javax.persistence.OneToMany;
21 22
import javax.persistence.OneToOne;
22 23
import javax.persistence.Transient;
24
import javax.validation.constraints.NotNull;
23 25
import javax.xml.bind.annotation.XmlAccessType;
24 26
import javax.xml.bind.annotation.XmlAccessorType;
27
import javax.xml.bind.annotation.XmlAttribute;
25 28
import javax.xml.bind.annotation.XmlElement;
26 29
import javax.xml.bind.annotation.XmlElementWrapper;
27 30
import javax.xml.bind.annotation.XmlRootElement;
......
30 33
import org.apache.log4j.Logger;
31 34
import org.hibernate.annotations.Cascade;
32 35
import org.hibernate.annotations.CascadeType;
36
import org.hibernate.annotations.Type;
33 37
import org.hibernate.envers.Audited;
34 38

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

  
39 45
/**
......
59 65
@XmlAccessorType(XmlAccessType.FIELD)
60 66
@XmlType(name = "FeatureTree", propOrder = {
61 67
    "root",
62
    "representations",
63
    "allowDuplicates"
68
    "termType",
69
    "allowDuplicates",
70
    "representations"
71

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

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

  
......
76 87
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
77 88
	private FeatureNode root;
78 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;
79 101

  
80 102
    // TODO needed? FeatureTree was a TermBase until v3.3 but was removed from
81 103
	//it as TermBase got the termType which does not apply to FeatureTree.
......
98 120

  
99 121
//******************** FACTORY METHODS ******************************************/
100 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
    }
101 131

  
102 132
    /**
103 133
	 * Creates a new feature tree instance with an empty {@link #getRoot() root node}.
......
106 136
	 * @see #NewInstance(List)
107 137
	 */
108 138
	public static FeatureTree NewInstance(){
109
		return new FeatureTree();
139
		return new FeatureTree(TermType.Feature);
110 140
	}
111 141

  
112 142
	/**
......
119 149
	 * @see 			#NewInstance(List)
120 150
	 */
121 151
	public static FeatureTree NewInstance(UUID uuid){
122
		FeatureTree result =  new FeatureTree();
152
		FeatureTree result =  new FeatureTree(TermType.Feature);
123 153
		result.setUuid(uuid);
124 154
		return result;
125 155
	}
......
136 166
	 * @see 				#NewInstance(UUID)
137 167
	 */
138 168
	public static FeatureTree NewInstance(List<Feature> featureList){
139
		FeatureTree result =  new FeatureTree();
169
		FeatureTree result =  new FeatureTree(TermType.Feature);
140 170
		FeatureNode root = result.getRoot();
141 171

  
142 172
		for (Feature feature : featureList){
......
150 180

  
151 181
// ******************** CONSTRUCTOR *************************************/
152 182

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

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

  
163 198
// ****************** GETTER / SETTER **********************************/
164 199

  
165
	/**
200
	@Override
201
    public TermType getTermType() {
202
        return termType;
203
    }
204
    /**
166 205
	 * Returns the topmost {@link FeatureNode feature node} (root node) of <i>this</i>
167 206
	 * feature tree. The root node does not have any parent. Since feature nodes
168 207
	 * recursively point to their child nodes the complete feature tree is
......
199 238
        this.allowDuplicates = allowDuplicates;
200 239
    }
201 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

  
202 250
//******************** METHODS ***********************************************/
203 251

  
204 252
	/**
......
243 291

  
244 292
	}
245 293

  
294

  
246 295
}
cdmlib-model/src/test/java/eu/etaxonomy/cdm/model/description/FeatureTreeTest.java
59 59
	@Test
60 60
	public void testAddChild(){
61 61
		FeatureNode node21 = FeatureNode.NewInstance();
62
		node21.setFeature(Feature.ANATOMY());
62
		node21.setTerm(Feature.ANATOMY());
63 63
		node1.addChild(node21, 1);
64 64

  
65 65
		assertEquals(node1.getChildNodes().size(), 2);
......
73 73
	@Test
74 74
	public void testClone(){
75 75
		FeatureNode node21 = FeatureNode.NewInstance();
76
		node21.setFeature(Feature.ADDITIONAL_PUBLICATION());
76
		node21.setTerm(Feature.ADDITIONAL_PUBLICATION());
77 77
		node1.addChild(node21, 1);
78 78
		FeatureTree clone = (FeatureTree) testTree.clone();
79
		assertEquals (clone.getRoot().getFeature(), testTree.getRoot().getFeature());
79
		assertEquals (clone.getRoot().getTerm(), testTree.getRoot().getTerm());
80 80
		assertNotSame(clone.getRoot(), testTree.getRoot());
81 81
		List<FeatureNode> children = clone.getRootChildren();
82 82

  
......
87 87

  
88 88
		assertEquals(children.get(0).getTerm(), node2.getTerm());
89 89
		assertNotSame(children.get(0), node2);
90
		assertEquals(children.get(1).getFeature(), node21.getFeature());
90
		assertEquals(children.get(1).getTerm(), node21.getTerm());
91 91
		assertNotSame(children.get(1), node21);
92
		assertEquals(children.get(0).getChildAt(0).getFeature(), node3.getFeature());
92
		assertEquals(children.get(0).getChildAt(0).getTerm(), node3.getTerm());
93 93
		assertNotSame(children.get(0).getChildAt(0), node3);
94 94
	}
95 95

  
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/update/ColumnAdder.java
62 62
	public static final ColumnAdder NewStringInstance(String stepName, String tableName, String newColumnName, int length, boolean includeAudTable){
63 63
		return new ColumnAdder(stepName, tableName, newColumnName, "nvarchar("+length+")", includeAudTable, null, false, null);
64 64
	}
65
    public static final ColumnAdder NewStringInstance(String stepName, String tableName, String newColumnName, int length, String defaultValue, boolean includeAudTable){
66
        return new ColumnAdder(stepName, tableName, newColumnName, "nvarchar("+length+")", includeAudTable, defaultValue, false, null);
67
    }
65 68

  
66 69
	public static final ColumnAdder NewClobInstance(String stepName, String tableName, String newColumnName, boolean includeAudTable){
67 70
		return new ColumnAdder(stepName, tableName, newColumnName, "clob", includeAudTable, null, false, null);
......
103 106
				defaultValueQuery = defaultValueQuery.replace("@tableName", tableName);
104 107
				defaultValueQuery = defaultValueQuery.replace("@columnName", newColumnName);
105 108
				datasource.executeUpdate(defaultValueQuery);
109
            }else if (defaultValue instanceof String){
110
                String defaultValueQuery = "UPDATE @tableName SET @columnName = " + (defaultValue == null ? "NULL" : "'" + defaultValue + "'");
111
                defaultValueQuery = defaultValueQuery.replace("@tableName", tableName);
112
                defaultValueQuery = defaultValueQuery.replace("@columnName", newColumnName);
113
                datasource.executeUpdate(defaultValueQuery);
106 114
			}else if (defaultValue != null){
107 115
				logger.warn("Default Value not implemented for type " + defaultValue.getClass().getName());
108 116
			}
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/update/v50_51/SchemaUpdater_50_55.java
24 24
import eu.etaxonomy.cdm.database.update.SimpleSchemaUpdaterStep;
25 25
import eu.etaxonomy.cdm.database.update.TermRepresentationUpdater;
26 26
import eu.etaxonomy.cdm.database.update.v47_50.SchemaUpdater_47_50;
27
import eu.etaxonomy.cdm.model.common.TermType;
27 28

  
28 29
/**
29 30
/**
......
127 128
        step = ColumnAdder.NewBooleanInstance(stepName, tableName, newColumnName, INCLUDE_AUDIT, false);
128 129
        stepList.add(step);
129 130

  
131
        //#6794 add term type to feature tree
132
        stepName = "Add termType to feature tree";
133
        tableName = "FeatureTree";
134
        newColumnName = "termType";
135
        step = ColumnAdder.NewStringInstance(stepName, tableName, newColumnName, 255, TermType.Feature.getKey(), INCLUDE_AUDIT)
136
                .setNotNull(NOT_NULL);
137
        stepList.add(step);
138

  
139
        //#6794 add term type to feature node
140
        stepName = "Add termType to feature node";
141
        tableName = "FeatureNode";
142
        newColumnName = "termType";
143
        step = ColumnAdder.NewStringInstance(stepName, tableName, newColumnName, 255, TermType.Feature.getKey(), INCLUDE_AUDIT)
144
                .setNotNull(NOT_NULL);
145
        stepList.add(step);
146

  
147

  
130 148
        return stepList;
131 149

  
132 150
	}
cdmlib-services/src/test/java/eu/etaxonomy/cdm/test/function/Datasource.java
39 39
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
40 40
import eu.etaxonomy.cdm.model.common.init.TermNotFoundException;
41 41
import eu.etaxonomy.cdm.model.description.Distribution;
42
import eu.etaxonomy.cdm.model.description.Feature;
42 43
import eu.etaxonomy.cdm.model.description.FeatureNode;
43 44
import eu.etaxonomy.cdm.model.description.FeatureTree;
44 45
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
......
236 237
		appCtr.getClassificationService().saveOrUpdate(cl);
237 238

  
238 239
		FeatureTree ft1 = FeatureTree.NewInstance();
239
		FeatureNode fn1 = FeatureNode.NewInstance(null);
240
		FeatureNode fn1 = FeatureNode.NewInstance((Feature)null);
240 241
		ft1.getRoot().addChild(fn1);
241 242
		appCtr.getFeatureNodeService().save(fn1);
242 243

  
243
		FeatureNode fn2 = FeatureNode.NewInstance(null);
244
		FeatureNode fn2 = FeatureNode.NewInstance((Feature)null);
244 245
		fn1.addChild(fn2);
245 246

  
246
		FeatureNode fn3 = FeatureNode.NewInstance(null);
247
		FeatureNode fn3 = FeatureNode.NewInstance((Feature)null);
247 248
		fn1.addChild(fn2, 0);
248 249

  
249 250
		appCtr.getFeatureNodeService().saveOrUpdate(fn1);
cdmlib-services/src/test/resources/eu/etaxonomy/cdm/api/service/FeatureNodeServiceImplTest-indexing.xml
1 1
<?xml version='1.0' encoding='UTF-8'?>
2 2
<dataset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../service/dataset.xsd">
3
    <FEATURETREE ID="1" UUID="6c2bc8d9-ee62-4222-be89-4a8e31770878"  PROTECTEDTITLECACHE="true" ROOT_ID="1" ALLOWDUPLICATES="false" />
4
    <FEATURETREE ID="2" UUID="43d67247-936f-42a3-a739-bbcde372e334"  PROTECTEDTITLECACHE="true" ROOT_ID="7" ALLOWDUPLICATES="false" />
3
    <FEATURETREE TERMTYPE="FE" ID="1" UUID="6c2bc8d9-ee62-4222-be89-4a8e31770878"  PROTECTEDTITLECACHE="true" ROOT_ID="1" ALLOWDUPLICATES="false" />
4
    <FEATURETREE TERMTYPE="FE" ID="2" UUID="43d67247-936f-42a3-a739-bbcde372e334"  PROTECTEDTITLECACHE="true" ROOT_ID="7" ALLOWDUPLICATES="false" />
5 5

  
6
    <FEATURENODE ID="1" FEATURE_ID="[null]" PARENT_ID="[null]" TREEINDEX="#t1#1#" SORTINDEX="[null]" FEATURETREE_ID="1" UUID="324a1a77-689c-44be-8e65-347d835f4111" />
7
    <FEATURENODE ID="2" FEATURE_ID="912" PARENT_ID="1" TREEINDEX="#t1#1#2#" SORTINDEX="0" FEATURETREE_ID="1" UUID="484a1a77-689c-44be-8e65-347d835f47e8" />
8
    <FEATURENODE ID="3" FEATURE_ID="913" PARENT_ID="1" TREEINDEX="#t1#1#3#" SORTINDEX="1" FEATURETREE_ID="1" UUID="2d41f0c2-b785-4f73-a436-cc2d5e93cc5b" />
9
    <FEATURENODE ID="4" FEATURE_ID="913" PARENT_ID="2" TREEINDEX="#t1#1#2#4#" SORTINDEX="0" FEATURETREE_ID="1" UUID="fdaec4bd-c78e-44df-ae87-28f18110968c" />
10
    <FEATURENODE ID="5" FEATURE_ID="913" PARENT_ID="2" TREEINDEX="#t1#1#2#5#" SORTINDEX="1" FEATURETREE_ID="1" UUID="c4d5170a-7967-4dac-ab76-ae2019eefde5" />
11
    <FEATURENODE ID="6" FEATURE_ID="913" PARENT_ID="4" TREEINDEX="#t1#1#2#4#6#" SORTINDEX="0" FEATURETREE_ID="1" UUID="b419ba5e-9c8b-449c-ad86-7abfca9a7340" />
12
    <FEATURENODE ID="7" FEATURE_ID="913" PARENT_ID="[null]" TREEINDEX="#t2#7#" SORTINDEX="0" FEATURETREE_ID="2" UUID="bb2c2d69-2b36-4f21-9374-b375ada8448c" />
6
    <FEATURENODE TERMTYPE="FE" ID="1" FEATURE_ID="[null]" PARENT_ID="[null]" TREEINDEX="#t1#1#" SORTINDEX="[null]" FEATURETREE_ID="1" UUID="324a1a77-689c-44be-8e65-347d835f4111" />
7
    <FEATURENODE TERMTYPE="FE" ID="2" FEATURE_ID="912" PARENT_ID="1" TREEINDEX="#t1#1#2#" SORTINDEX="0" FEATURETREE_ID="1" UUID="484a1a77-689c-44be-8e65-347d835f47e8" />
8
    <FEATURENODE TERMTYPE="FE" ID="3" FEATURE_ID="913" PARENT_ID="1" TREEINDEX="#t1#1#3#" SORTINDEX="1" FEATURETREE_ID="1" UUID="2d41f0c2-b785-4f73-a436-cc2d5e93cc5b" />
9
    <FEATURENODE TERMTYPE="FE" ID="4" FEATURE_ID="913" PARENT_ID="2" TREEINDEX="#t1#1#2#4#" SORTINDEX="0" FEATURETREE_ID="1" UUID="fdaec4bd-c78e-44df-ae87-28f18110968c" />
10
    <FEATURENODE TERMTYPE="FE" ID="5" FEATURE_ID="913" PARENT_ID="2" TREEINDEX="#t1#1#2#5#" SORTINDEX="1" FEATURETREE_ID="1" UUID="c4d5170a-7967-4dac-ab76-ae2019eefde5" />
11
    <FEATURENODE TERMTYPE="FE" ID="6" FEATURE_ID="913" PARENT_ID="4" TREEINDEX="#t1#1#2#4#6#" SORTINDEX="0" FEATURETREE_ID="1" UUID="b419ba5e-9c8b-449c-ad86-7abfca9a7340" />
12
    <FEATURENODE TERMTYPE="FE" ID="7" FEATURE_ID="913" PARENT_ID="[null]" TREEINDEX="#t2#7#" SORTINDEX="0" FEATURETREE_ID="2" UUID="bb2c2d69-2b36-4f21-9374-b375ada8448c" />
13 13

  
14 14
</dataset>
cdmlib-test/src/main/resources/dbscripts/001-cdm.h2.sql
1997 1997
    ID INTEGER NOT NULL,
1998 1998
    CREATED TIMESTAMP,
1999 1999
    UUID VARCHAR(36),
2000
    TERMTYPE VARCHAR(4),
2000 2001
    UPDATED TIMESTAMP,
2001 2002
    SORTINDEX INTEGER,
2002 2003
    TREEINDEX VARCHAR(255),
......
2013 2014
    REVTYPE TINYINT,
2014 2015
    CREATED TIMESTAMP,
2015 2016
    UUID VARCHAR(36),
2017
    TERMTYPE VARCHAR(4),
2016 2018
    UPDATED TIMESTAMP,
2017 2019
    SORTINDEX INTEGER,
2018 2020
    TREEINDEX VARCHAR(255),
......
2051 2053
    ID INTEGER NOT NULL,
2052 2054
    CREATED TIMESTAMP,
2053 2055
    UUID VARCHAR(36),
2056
    TERMTYPE VARCHAR(4),
2054 2057
    UPDATED TIMESTAMP,
2055 2058
    LSID_AUTHORITY VARCHAR(255),
2056 2059
    LSID_LSID VARCHAR(255),
......
2071 2074
    REVTYPE TINYINT,
2072 2075
    CREATED TIMESTAMP,
2073 2076
    UUID VARCHAR(36),
2077
    TERMTYPE VARCHAR(4),
2074 2078
    UPDATED TIMESTAMP,
2075 2079
    LSID_AUTHORITY VARCHAR(255),
2076 2080
    LSID_LSID VARCHAR(255),

Also available in: Unified diff