Project

General

Profile

« Previous | Next » 

Revision c693e3b1

Added by Patrick Plitzner about 5 years ago

ref #6794 Add generics to FeatureNode and FeatureTree

View differences:

cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/descriptive/word/out/WordExport.java
110 110
//        return new JAXBElement( new QName(Namespaces.NS_WORD12, "fldChar"), org.docx4j.wml.FldChar.class, fldchar);
111 111
//    }
112 112

  
113
    private void addChildNode(FeatureNode node, MainDocumentPart mainDocumentPart, int indent) throws Exception{
113
    private void addChildNode(FeatureNode<?> node, MainDocumentPart mainDocumentPart, int indent) throws Exception{
114 114
        String styleId = "Heading"+indent;
115 115

  
116 116
        for (FeatureNode childNode : node.getChildNodes()) {
cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/sdd/in/SDDImport.java
106 106
    private Map<String,String> citations = new HashMap<>();
107 107
    private Map<String,String> defaultUnitPrefixes = new HashMap<>();
108 108
    private Map<String,Person> editors = new HashMap<>();
109
    private Map<String,FeatureNode> featureNodes = new HashMap<>();
109
    private Map<String,FeatureNode<Feature>> featureNodes = new HashMap<>();
110 110
    private Map<String,Feature> features = new HashMap<>();
111 111
    private Map<String,String> locations = new HashMap<>();
112 112
    private Map<String,List<CdmBase>> mediaObject_ListCdmBase = new HashMap<>();
......
1753 1753

  
1754 1754
					FeatureTree featureTree =  FeatureTree.NewInstance();
1755 1755
					importRepresentation(elCharacterTree, sddNamespace, featureTree, "", cdmState);
1756
					FeatureNode root = featureTree.getRoot();
1756
					FeatureNode<Feature> root = featureTree.getRoot();
1757 1757
					List<Element> listeOfNodes = elCharacterTree.getChildren("Nodes", sddNamespace);
1758 1758

  
1759 1759
					//Nodes of CharacterTrees in SDD always refer to DescriptiveConcepts
......
1785 1785
	 * @param root
1786 1786
	 * @param elNodes
1787 1787
	 */
1788
	private void handleCharacterNodes(Namespace sddNamespace, FeatureNode root, Element elNodes) {
1788
	private void handleCharacterNodes(Namespace sddNamespace, FeatureNode<Feature> root, Element elNodes) {
1789 1789
		List<Element> listNodes = elNodes.getChildren("Node", sddNamespace);
1790 1790
		if (listNodes != null) {
1791 1791
			for (Element elNode : listNodes){
1792 1792
				String idN = elNode.getAttributeValue("id");
1793
				FeatureNode fn = null;
1793
				FeatureNode<Feature> fn = null;
1794 1794
				Feature dc = null;
1795 1795
				if (idN!=null) {
1796 1796
					// DescriptiveConcepts are used as nodes in CharacterTrees
......
1808 1808
					if (elParent!=null){
1809 1809
						String refP = elParent.getAttributeValue("ref");
1810 1810
						if (refP!=null) {
1811
							FeatureNode parent = featureNodes.get(refP);
1811
							FeatureNode<Feature> parent = featureNodes.get(refP);
1812 1812
							if (parent==null){
1813 1813
								root.addChild(fn); // if no parent found or the reference is broken, add the node to the root of the tree
1814 1814
							}
......
1832 1832
				Element elParent = elCharNode.getChild("Parent", sddNamespace);
1833 1833
				Element elCharacter = elCharNode.getChild("Character", sddNamespace);
1834 1834
				Element elDependencyRules = elCharNode.getChild("DependencyRules", sddNamespace);
1835
				FeatureNode fn = FeatureNode.NewInstance();
1835
				FeatureNode<Feature> fn = FeatureNode.NewInstance();
1836 1836

  
1837 1837
				if (elDependencyRules!=null){
1838 1838
					Element elInapplicableIf = elCharNode.getChild("InapplicableIf", sddNamespace);
......
1862 1862
				if (elParent!=null){
1863 1863
					String refP = elParent.getAttributeValue("ref");
1864 1864
					if ((refP!=null)&&(!refP.equals(""))) {
1865
					FeatureNode parent = featureNodes.get(refP);
1865
					FeatureNode<Feature> parent = featureNodes.get(refP);
1866 1866
						if (parent==null){
1867 1867
						parent = root; // if no parent found or the reference is broken, add the node to the root of the tree
1868 1868
						}
......
1872 1872
				String refC = elCharacter.getAttributeValue("ref");
1873 1873
				if ((refC!=null)&&(!refC.equals(""))){
1874 1874
					Feature character = features.get(refC);
1875
					fn.setFeature(character);
1875
					fn.setTerm(character);
1876 1876
					featureNodes.put(refC, fn);
1877 1877
				}
1878 1878
			}
cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/sdd/out/SDDDocumentBuilder.java
1272 1272
		}
1273 1273
	}
1274 1274

  
1275
	public void buildBranches(FeatureNode parent, ElementImpl element,
1275
	public void buildBranches(FeatureNode<Feature> parent, ElementImpl element,
1276 1276
			boolean isRoot) {
1277
		List<FeatureNode> children = parent.getChildNodes();
1277
		List<FeatureNode<Feature>> children = parent.getChildNodes();
1278 1278
		if (!parent.isLeaf()) {
1279 1279
			ElementImpl elCharNode = new ElementImpl(document, NODE);
1280 1280
			charnodeCount = buildReference(parent, featuretrees, ID,
......
1288 1288
			}
1289 1289
			ElementImpl elDescriptiveConcept = new ElementImpl(document,
1290 1290
					DESCRIPTIVE_CONCEPT);
1291
			Feature fref = parent.getFeature();
1291
			Feature fref = parent.getTerm();
1292 1292
			descriptiveConceptCount = buildReference(fref, descriptiveConcepts,
1293 1293
					REF, elDescriptiveConcept, "dc", descriptiveConceptCount);
1294 1294
			elCharNode.appendChild(elDescriptiveConcept);
1295 1295
			element.appendChild(elCharNode);
1296
			for (Iterator<FeatureNode> ifn = children.iterator(); ifn.hasNext();) {
1296
			for (Iterator<FeatureNode<Feature>> ifn = children.iterator(); ifn.hasNext();) {
1297 1297
				FeatureNode fn = ifn.next();
1298 1298
				buildBranches(fn, element, false);
1299 1299
			}
......
1306 1306
			charnodeCount = buildReference(parent, featuretrees, ID,
1307 1307
					elCharNode, "cn", charnodeCount);
1308 1308
			ElementImpl elCharacter = new ElementImpl(document, CHARACTER);
1309
			Feature fref = parent.getFeature();
1309
			Feature fref = parent.getTerm();
1310 1310
			boolean dependencies = false;
1311 1311
			ElementImpl elDependecyRules = new ElementImpl(document,
1312 1312
					"DependecyRules");
cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/taxonx2013/TaxonXTreatmentExtractor.java
308 308
        if (proibiospheretree == null){
309 309
            List<FeatureTree> trees = importer.getFeatureTreeService().list(FeatureTree.class, null, null, null, null);
310 310
            if (trees.size()==1) {
311
                FeatureTree ft = trees.get(0);
311
                FeatureTree<Feature> ft = trees.get(0);
312 312
                if (featuresMap==null) {
313 313
                    featuresMap=new HashMap<String, Feature>();
314 314
                }
......
2145 2145
                                    //System.out.println("NEW ACCEPTED HERE "+nameToBeFilled);
2146 2146
                                }
2147 2147
                                else {
2148
                                    acceptedTaxon= Taxon.NewInstance(nameToBeFilled,(Reference) nameToBeFilled.getNomenclaturalReference() );//TODO TOFIX reference
2148
                                    acceptedTaxon= Taxon.NewInstance(nameToBeFilled,nameToBeFilled.getNomenclaturalReference() );//TODO TOFIX reference
2149 2149
                                    //System.out.println("NEW ACCEPTED HERE2 "+nameToBeFilled);
2150 2150
                                }
2151 2151

  
cdmlib-io/src/test/java/eu/etaxonomy/cdm/io/jaxb/FeatureTest.java
1 1
/**
2 2
* Copyright (C) 2009 EDIT
3
* European Distributed Institute of Taxonomy 
3
* European Distributed Institute of Taxonomy
4 4
* http://www.e-taxonomy.eu
5
* 
5
*
6 6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7 7
* See LICENSE.TXT at the top of this package for the full license terms.
8 8
*/
......
22 22
import eu.etaxonomy.cdm.model.description.FeatureTree;
23 23

  
24 24
public class FeatureTest {
25
		
25

  
26 26
	    private String resource = "/eu/etaxonomy/cdm/io/jaxb/FeatureTest.xml";
27
	    
27

  
28 28
	    @Test
29 29
	    public void testUnmarshalFeatureTree() throws Exception {
30 30
	        CdmDocumentBuilder cdmDocumentBuilder = new CdmDocumentBuilder();
31 31
	        URI uri = new URI(URIEncoder.encode(this.getClass().getResource(resource).toString()));
32 32
	        DataSet dataSet = cdmDocumentBuilder.unmarshal(DataSet.class, new InputStreamReader(this.getClass().getResourceAsStream(resource)),uri.toString());
33
			
34
			FeatureTree featureTree = (FeatureTree)dataSet.getFeatureTrees().get(0);
33

  
34
			FeatureTree featureTree = dataSet.getFeatureTrees().get(0);
35 35
			Feature feature = (Feature)dataSet.getTerms().get(1);
36
			
36

  
37 37
			assertNotNull("FeatureTree must not be null",featureTree);
38 38
			assertNotNull("Feature must not be null",feature);
39
			
39

  
40 40
			assertNotNull("FeatureTree.root must not be null",featureTree.getRoot());
41 41
			FeatureNode featureNode = featureTree.getRoot();
42
			assertNotNull("FeatureNode.feature must not be null",featureNode.getFeature());
43
			assertEquals("FeatureNode.feature must equal Feature",feature,featureNode.getFeature());
44
			
42
			assertNotNull("FeatureNode.feature must not be null",featureNode.getTerm());
43
			assertEquals("FeatureNode.feature must equal Feature",feature,featureNode.getTerm());
44

  
45 45
			assertNotNull("FeatureNode.children must not be null",featureNode.getChildNodes());
46 46
			assertFalse("FeatureNode.children must not be empty",featureNode.getChildNodes().isEmpty());
47 47
			assertEquals("FeatureNode.children must have 4 child nodes",4,featureNode.getChildNodes().size());
48
			
48

  
49 49
	    }
50 50
}
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/description/DescriptiveDataSet.java
82 82
	@XmlSchemaType(name = "IDREF")
83 83
	@ManyToOne(fetch = FetchType.LAZY)
84 84
	@Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
85
	private FeatureTree descriptiveSystem;
85
	private FeatureTree<Character> descriptiveSystem;
86 86

  
87 87
	@XmlElementWrapper(name = "Descriptions")
88 88
	@XmlElement(name = "Description")
......
306 306
		}
307 307
	}
308 308

  
309
	public FeatureTree getDescriptiveSystem() {
309
	public FeatureTree<Character> getDescriptiveSystem() {
310 310
		return descriptiveSystem;
311 311
	}
312
	public void setDescriptiveSystem(FeatureTree descriptiveSystem) {
312
	public void setDescriptiveSystem(FeatureTree<Character> descriptiveSystem) {
313 313
		this.descriptiveSystem = descriptiveSystem;
314 314
	}
315 315

  
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/description/FeatureNode.java
45 45
import org.hibernate.envers.Audited;
46 46

  
47 47
import eu.etaxonomy.cdm.hibernate.HHH_9751_Util;
48
import eu.etaxonomy.cdm.model.common.CdmBase;
49 48
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
50 49
import eu.etaxonomy.cdm.model.common.IHasTermType;
51 50
import eu.etaxonomy.cdm.model.common.ITreeNode;
......
81 80
@Entity
82 81
@Audited
83 82
@Table(name="FeatureNode", indexes = { @Index(name = "featureNodeTreeIndex", columnList = "treeIndex") })
84
public class FeatureNode extends VersionableEntity
85
            implements ITreeNode<FeatureNode>, IHasTermType, Cloneable {
83
public class FeatureNode <T extends DefinedTermBase> extends VersionableEntity
84
            implements ITreeNode<FeatureNode<T>>, IHasTermType, Cloneable {
86 85
	private static final Logger logger = Logger.getLogger(FeatureNode.class);
87 86

  
88 87
    //This is the main key a node belongs to. Although other keys may also reference
......
90 89
	@XmlElement(name = "FeatureTree")
91 90
    @XmlIDREF
92 91
    @XmlSchemaType(name = "IDREF")
93
    @ManyToOne(fetch = FetchType.LAZY)
92
    @ManyToOne(fetch = FetchType.LAZY, targetEntity=FeatureTree.class)
94 93
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE}) //TODO this usage is incorrect, needed only for OneToMany, check why it is here, can it be removed??
95 94
	 //TODO Val #3379
96 95
//    @NotNull
97
	private FeatureTree featureTree;
96
	private FeatureTree<T> featureTree;
98 97

  
99 98
    /**
100 99
     * The {@link TermType type} of this term node.
......
113 112
    @XmlElement(name = "Feature")
114 113
    @XmlIDREF
115 114
    @XmlSchemaType(name = "IDREF")
116
    @ManyToOne(fetch = FetchType.LAZY)
117
	private DefinedTermBase feature;
115
    @ManyToOne(fetch = FetchType.LAZY, targetEntity=DefinedTermBase.class)
116
	private T feature;
118 117

  
119 118
    @XmlElement(name = "Parent")
120 119
    @XmlIDREF
......
122 121
    @ManyToOne(fetch = FetchType.LAZY, targetEntity=FeatureNode.class)
123 122
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
124 123
	@JoinColumn(name="parent_id")
125
	private FeatureNode parent;
124
	private FeatureNode<T> parent;
126 125

  
127 126

  
128 127
    @XmlElement(name = "treeIndex")
......
134 133
    //see https://dev.e-taxonomy.eu/trac/ticket/3722
135 134
    @OrderColumn(name="sortIndex")
136 135
    @OrderBy("sortIndex")
137
	@OneToMany(fetch = FetchType.LAZY, mappedBy="parent")
136
	@OneToMany(fetch = FetchType.LAZY, mappedBy="parent", targetEntity=FeatureNode.class)
138 137
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
139
	private List<FeatureNode> children = new ArrayList<FeatureNode>();
138
	private List<FeatureNode<T>> children = new ArrayList<>();
140 139

  
141 140
    //see https://dev.e-taxonomy.eu/trac/ticket/3722
142 141
    private Integer sortIndex;
......
166 165
     *
167 166
     * @see #NewInstance(Feature)
168 167
     */
169
    public static FeatureNode NewInstance(TermType termType){
170
        return new FeatureNode(termType);
168
    public static <T extends DefinedTermBase<T>> FeatureNode<T> NewInstance(TermType termType){
169
        return new FeatureNode<>(termType);
171 170
    }
172 171

  
173 172
	/**
......
175 174
	 *
176 175
	 * @see #NewInstance(Feature)
177 176
	 */
178
	public static FeatureNode NewInstance(){
179
		return new FeatureNode(TermType.Feature);
180
	}
181

  
182
	/**
183
	 * Creates a new feature node instance only with the given {@link Feature feature}
184
	 * (without parent and children).
185
	 *
186
	 * @param	feature	the feature assigned to the new feature node
187
	 * @see 			#NewInstance()
188
	 */
189
	public static FeatureNode NewInstance(Feature feature){
190
		FeatureNode result = new FeatureNode(TermType.Feature);
191
		result.setTerm(feature);
192
		return result;
177
	public static FeatureNode<Feature> NewInstance(){
178
		return new FeatureNode<>(TermType.Feature);
193 179
	}
194 180

  
195 181
	/**
......
200 186
	 * @param	term	the term assigned to the new feature node
201 187
	 * @see 			#NewInstance()
202 188
	 */
203
	public static FeatureNode NewInstance(DefinedTermBase term){
204
	    FeatureNode result = new FeatureNode(term.getTermType());
189
	public static <T extends DefinedTermBase<T>> FeatureNode<T> NewInstance(T term){
190
	    FeatureNode<T> result = new FeatureNode<>(term.getTermType());
205 191
	    result.setTerm(term);
206 192
	    return result;
207 193
	}
......
227 213

  
228 214
//*************************** TREE ************************************/
229 215

  
230
	public FeatureTree getFeatureTree() {
216
	public FeatureTree<T> getFeatureTree() {
231 217
		return featureTree;
232 218
	}
233 219

  
234
	protected void setFeatureTree(FeatureTree featureTree) {
220
	protected void setFeatureTree(FeatureTree<T> featureTree) {
235 221
		checkTermType(featureTree);
236 222
	    this.featureTree = featureTree;
237 223
	}
......
239 225
//** ********************** FEATURE ******************************/
240 226

  
241 227
	/**
242
	 * Returns the {@link Feature feature} <i>this</i> feature node is based on.
243
	 */
244
	@Deprecated
245
	public Feature getFeature() {
246
		return CdmBase.deproxy(feature, Feature.class);
247
	}
248
	/**
249
	 * @see	#getFeature()
250
	 */
251
	@Deprecated
252
	public void setFeature(Feature feature) {
253
	    checkTermType(feature);
254
		this.feature = feature;
255
	}
256

  
257
	   /**
258 228
     * Returns the {@link Feature feature} <i>this</i> feature node is based on.
259 229
     */
260
    public DefinedTermBase getTerm() {
230
    public T getTerm() {
261 231
        return feature;
262 232
    }
263 233
    /**
264 234
     * @see #getFeature()
265 235
     */
266
    public void setTerm(DefinedTermBase term) {
236
    public void setTerm(T term) {
267 237
        checkTermType(term);
268 238
        this.feature = term;
269 239
    }
......
276 246
	 * @see	#getChildNodes()
277 247
	 */
278 248
	@Override
279
    public FeatureNode getParent() {
249
    public FeatureNode<T> getParent() {
280 250
		return parent;
281 251
	}
282 252
	/**
......
287 257
	 * @param	parent	the feature node to be set as parent
288 258
	 * @see				#getParent()
289 259
	 */
290
	protected void setParent(FeatureNode parent) {
260
	protected void setParent(FeatureNode<T> parent) {
291 261
		checkTermType(parent);
292 262
	    this.parent = parent;
293 263
	}
......
309 279
	 * <i>this</i> feature node.
310 280
	 */
311 281
	@Override
312
    public List<FeatureNode> getChildNodes() {
282
    public List<FeatureNode<T>> getChildNodes() {
313 283
	    return children;
314 284
	}
315 285

  
......
325 295
	 * @see				#removeChild(FeatureNode)
326 296
	 * @see				#removeChild(int)
327 297
	 */
328
	public void addChild(FeatureNode child){
298
	public void addChild(FeatureNode<T> child){
329 299
		addChild(child, children.size());
330 300
	}
331 301
	/**
......
344 314
	 * @see				#removeChild(FeatureNode)
345 315
	 * @see				#removeChild(int)
346 316
	 */
347
	public void addChild(FeatureNode child, int index){
317
	public void addChild(FeatureNode<T> child, int index){
348 318
	    checkTermType(child);
349
	    List<FeatureNode> children = this.getChildNodes();
319
	    List<FeatureNode<T>> children = this.getChildNodes();
350 320
		if (index < 0 || index > children.size() + 1){
351 321
			throw new IndexOutOfBoundsException("Wrong index: " + index);
352 322
		}
......
374 344
	 * @see				#addChild(FeatureNode)
375 345
	 * @see				#removeChild(int)
376 346
	 */
377
	public void removeChild(FeatureNode child){
347
	public void removeChild(FeatureNode<T> child){
378 348

  
379 349
	    int index = children.indexOf(child);
380 350
		if (index >= 0){
......
394 364
	 * @see				#removeChild(FeatureNode)
395 365
	 */
396 366
	public void removeChild(int index){
397
	   FeatureNode child = children.get(index);
367
	   FeatureNode<T> child = children.get(index);
398 368
	   if (child != null){
399 369
			children.remove(index);
400 370
			child.setParent(null);
401 371
			child.setFeatureTree(null);
402 372
			//TODO workaround (see sortIndex doc)
403 373
			for(int i = 0; i < children.size(); i++){
404
				FeatureNode childAt = children.get(i);
374
				FeatureNode<T> childAt = children.get(i);
405 375
				childAt.setSortIndex(i);
406 376
			}
407 377
			child.setSortIndex(null);
......
418 388
	 * @see					#addChild(FeatureNode, int)
419 389
	 * @see					#removeChild(int)
420 390
	 */
421
	public FeatureNode getChildAt(int childIndex) {
391
	public FeatureNode<T> getChildAt(int childIndex) {
422 392
	    return children.get(childIndex);
423 393
	}
424 394

  
......
441 411
	 * @see			#addChild(FeatureNode, int)
442 412
	 * @see			#removeChild(int)
443 413
	 */
444
	public int getIndex(FeatureNode node) {
414
	public int getIndex(FeatureNode<T> node) {
445 415
	    if (! children.contains(node)){
446 416
			return -1;
447 417
		}else{
......
603 573
    }
604 574

  
605 575
	/**
606
	 * Returns all features that are contained in this node or a child node
576
	 * Returns all terms that are contained in this node or a child node
607 577
	 *
608 578
	 * @param featureNode
609 579
	 * @param features
610 580
	 * @return
611 581
	 */
612 582
	@Transient
613
	public Set<Feature> getDistinctFeaturesRecursive(Set<Feature> features){
614
		Feature feature = this.getFeature();
583
	public Set<T> getDistinctFeaturesRecursive(Set<T> features){
584
		T term = this.getTerm();
615 585

  
616
		if(feature!=null){
617
		    features.add(feature);
586
		if(term!=null){
587
		    features.add(term);
618 588
		}
619 589

  
620
		for(FeatureNode childNode : this.getChildNodes()){
590
		for(FeatureNode<T> childNode : this.getChildNodes()){
621 591
			features.addAll(childNode.getDistinctFeaturesRecursive(features));
622 592
		}
623 593

  
624 594
		return features;
625 595
	}
626 596

  
627
	public FeatureNode cloneDescendants(){
628
		FeatureNode clone = (FeatureNode)this.clone();
629
		FeatureNode childClone;
597
	public FeatureNode<T> cloneDescendants(){
598
		FeatureNode<T> clone = (FeatureNode<T>)this.clone();
599
		FeatureNode<T> childClone;
630 600

  
631
		for(FeatureNode childNode : this.getChildNodes()){
632
			childClone = (FeatureNode) childNode.clone();
633
			for (FeatureNode childChild:childNode.getChildNodes()){
601
		for(FeatureNode<T> childNode : this.getChildNodes()){
602
			childClone = (FeatureNode<T>) childNode.clone();
603
			for (FeatureNode<T> childChild:childNode.getChildNodes()){
634 604
				childClone.addChild(childChild.cloneDescendants());
635 605
			}
636 606
			clone.addChild(childClone);
......
653 623
	 */
654 624
	@Override
655 625
	public Object clone() {
656
		FeatureNode result;
626
		FeatureNode<T> result;
657 627
		try {
658
			result = (FeatureNode)super.clone();
628
			result = (FeatureNode<T>)super.clone();
659 629
			result.children = new ArrayList<>();
660 630
			return result;
661 631
		}catch (CloneNotSupportedException e) {
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/description/FeatureTree.java
37 37
import org.hibernate.annotations.Type;
38 38
import org.hibernate.envers.Audited;
39 39

  
40
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
40 41
import eu.etaxonomy.cdm.model.common.IHasTermType;
41 42
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
42 43
import eu.etaxonomy.cdm.model.common.Representation;
......
76 77
//@Indexed disabled to reduce clutter in indexes, since this type is not used by any search
77 78
//@Indexed(index = "eu.etaxonomy.cdm.model.description.FeatureTree")
78 79
@Audited
79
public class FeatureTree
80
public class FeatureTree <T extends DefinedTermBase>
80 81
            extends IdentifiableEntity<IIdentifiableEntityCacheStrategy>
81 82
            implements IHasTermType, Cloneable{
82 83

  
......
84 85
	private static final Logger logger = Logger.getLogger(FeatureTree.class);
85 86

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

  
91 92
    /**
92 93
     * The {@link TermType type} of this term collection. All nodes in the graph must refer to a term of the same type.
......
126 127
     * with an empty {@link #getRoot() root node}.
127 128
     * @param termType the {@link TermType term type}, must not be null
128 129
     */
129
    public static FeatureTree NewInstance(@NotNull TermType termType){
130
        return new FeatureTree(termType);
130
    public static <T extends DefinedTermBase<T>> FeatureTree<T> NewInstance(@NotNull TermType termType){
131
        return new FeatureTree<>(termType);
131 132
    }
132 133

  
133 134
    /**
......
136 137
	 * @see #NewInstance(UUID)
137 138
	 * @see #NewInstance(List)
138 139
	 */
139
	public static FeatureTree NewInstance(){
140
		return new FeatureTree(TermType.Feature);
140
	public static FeatureTree<Feature> NewInstance(){
141
		return new FeatureTree<>(TermType.Feature);
141 142
	}
142 143

  
143 144
	/**
......
149 150
	 * @see 			#NewInstance()
150 151
	 * @see 			#NewInstance(List)
151 152
	 */
152
	public static FeatureTree NewInstance(UUID uuid){
153
		FeatureTree result =  new FeatureTree(TermType.Feature);
153
	public static <T extends DefinedTermBase<T>> FeatureTree<T> NewInstance(UUID uuid){
154
		FeatureTree<T> result =  new FeatureTree<>(TermType.Feature);
154 155
		result.setUuid(uuid);
155 156
		return result;
156 157
	}
......
166 167
	 * @see 				#NewInstance()
167 168
	 * @see 				#NewInstance(UUID)
168 169
	 */
169
	public static FeatureTree NewInstance(List<Feature> featureList){
170
		FeatureTree result =  new FeatureTree(TermType.Feature);
171
		FeatureNode root = result.getRoot();
170
	public static FeatureTree<Feature> NewInstance(List<Feature> featureList){
171
		FeatureTree<Feature> result =  new FeatureTree<>(TermType.Feature);
172
		FeatureNode<Feature> root = result.getRoot();
172 173

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

  
......
208 209
	 * recursively point to their child nodes the complete feature tree is
209 210
	 * defined by its root node.
210 211
	 */
211
	public FeatureNode getRoot() {
212
	public FeatureNode<T> getRoot() {
212 213
		return root;
213 214
	}
214 215

  
......
226 227
	 * children of the root node of <i>this</i> feature tree.
227 228
	 */
228 229
	@Transient
229
	public List<FeatureNode> getRootChildren(){
230
		List<FeatureNode> result = new ArrayList<>();
230
	public List<FeatureNode<T>> getRootChildren(){
231
		List<FeatureNode<T>> result = new ArrayList<>();
231 232
		result.addAll(root.getChildNodes());
232 233
		return result;
233 234
	}
......
251 252
//******************** METHODS ***********************************************/
252 253

  
253 254
	/**
254
	 * Computes a set of distinct features that are present in this feature tree
255
	 * Computes a set of distinct terms that are present in this feature tree
255 256
	 *
256 257
	 * @return
257 258
	 */
258 259
	@Transient
259
	public Set<Feature> getDistinctFeatures(){
260
	public Set<T> getDistinctFeatures(){
260 261
	    if(termType.equals(TermType.Feature) || termType.isKindOf(TermType.Feature)){
261
	        Set<Feature> features = new HashSet<>();
262
	        Set<T> features = new HashSet<>();
262 263
	        return root.getDistinctFeaturesRecursive(features);
263 264
	    }
264 265
	    String message = "FeatureTree is not of type FEATURE.";
......
281 282
	 */
282 283
	@Override
283 284
	public Object clone() {
284
		FeatureTree result;
285
		FeatureTree<T> result;
285 286
		try {
286
			result = (FeatureTree)super.clone();
287
			result = (FeatureTree<T>)super.clone();
287 288
		}catch (CloneNotSupportedException e) {
288 289
			logger.warn("Object does not implement cloneable");
289 290
			e.printStackTrace();
290 291
			return null;
291 292
		}
292
		FeatureNode rootClone = this.getRoot().cloneDescendants();
293
		FeatureNode<T> rootClone = this.getRoot().cloneDescendants();
293 294
		result.root = rootClone;
294 295

  
295 296
		return result;
cdmlib-model/src/main/java/eu/etaxonomy/cdm/strategy/generate/PolytomousKeyGenerator.java
806 806
	 *
807 807
	 * @param node
808 808
	 */
809
	private void checkDependencies(FeatureNode node){
809
	private void checkDependencies(FeatureNode<Feature> node){
810 810
		if (node.getOnlyApplicableIf()!=null){
811 811
			Set<State> addToOAI = node.getOnlyApplicableIf();
812 812
			for (State state : addToOAI){
813 813
				if (oAIdependencies.containsKey(state)) {
814 814
                    oAIdependencies.put(state, new HashSet<Feature>());
815 815
                }
816
				oAIdependencies.get(state).add(node.getFeature());
816
				oAIdependencies.get(state).add(node.getTerm());
817 817
			}
818 818
		}
819 819
		if (node.getInapplicableIf()!=null){
......
822 822
				if (iIdependencies.containsKey(state)) {
823 823
                    iIdependencies.put(state, new HashSet<Feature>());
824 824
                }
825
				iIdependencies.get(state).add(node.getFeature());
825
				iIdependencies.get(state).add(node.getTerm());
826 826
			}
827 827
		}
828 828
		if (node.getChildNodes()!=null) {
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/PostMergeEntityListener.java
102 102

  
103 103
            }   else if(FeatureTree.class.isAssignableFrom(entityClazz)){
104 104

  
105
                FeatureTree tree = (FeatureTree)entity;
106
                for (FeatureNode node:tree.getRootChildren()){
105
                FeatureTree<?> tree = (FeatureTree)entity;
106
                for (FeatureNode<?> node:tree.getRootChildren()){
107 107
                    node.removeNullValueFromChildren();
108 108
                    if (node.getChildNodes() != null){
109 109
                        for (FeatureNode childNode: node.getChildNodes()){
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/DescriptiveDataSetService.java
452 452
        DescriptiveDataSet dataSet = load(descriptiveDataSetUuid);
453 453
        SpecimenOrObservationBase specimen = occurrenceService.load(specimenUuid);
454 454

  
455
        Set<Feature> datasetFeatures = dataSet.getDescriptiveSystem().getDistinctFeatures();
455
        Set<Character> datasetFeatures = dataSet.getDescriptiveSystem().getDistinctFeatures();
456 456
        List<DescriptionElementBase> matchingDescriptionElements = new ArrayList<>();
457 457

  
458 458
        for (SpecimenDescription specimenDescription : (Set<SpecimenDescription>) specimen.getDescriptions()) {
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/NaturalLanguageGenerator.java
11 11
import org.apache.log4j.Logger;
12 12
import org.springframework.stereotype.Component;
13 13

  
14
import eu.etaxonomy.cdm.model.common.Annotation;
15
import eu.etaxonomy.cdm.model.common.AnnotationType;
16
import eu.etaxonomy.cdm.model.common.Language;
14 17
import eu.etaxonomy.cdm.model.description.CategoricalData;
15 18
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
16 19
import eu.etaxonomy.cdm.model.description.Feature;
......
20 23
import eu.etaxonomy.cdm.model.description.TaxonDescription;
21 24
import eu.etaxonomy.cdm.model.description.TextData;
22 25
import eu.etaxonomy.cdm.model.description.TextFormat;
23
import eu.etaxonomy.cdm.model.common.Annotation;
24
import eu.etaxonomy.cdm.model.common.AnnotationType;
25
import eu.etaxonomy.cdm.model.common.Language;
26 26

  
27 27

  
28 28
/**
29 29
 * Generator of natural language descriptions from TaxonDescriptions.
30
 * 
30
 *
31 31
 * @author m.venin
32 32
 * @since 13.04.2010
33 33
 * @version 1.0
......
45 45
	private DescriptionBuilder<CategoricalData> categoricalDescriptionBuilder = new DefaultCategoricalDescriptionBuilder();
46 46

  
47 47
	private TextData previousTextData;
48
	
48

  
49 49
	DeltaTextDataProcessor deltaTextDataProcessor = new DeltaTextDataProcessor();
50 50

  
51 51
	private Map<String, INaturalLanguageTextDataProcessor> elementProcessors;
......
54 54

  
55 55
	/**
56 56
	 * Change the first separator used by generateSingleTextData. By default ",".
57
	 * 
57
	 *
58 58
	 * @param separator
59 59
	 */
60 60
	public void setFirstSeparator(String separator){
......
67 67

  
68 68
	/**
69 69
	 * Change the second separator used by generateSingleTextData. By default ".".
70
	 * 
70
	 *
71 71
	 * @param separator
72 72
	 */
73 73
	public void setSecondSeparator(String separator){
......
103 103
	 * The keys of the elementProcessors map are regular expressions which are
104 104
	 * being used to identify the those Descriptions to which the mapped
105 105
	 * NaturalLanguageTextDataProcessor is applicable.
106
	 * 
106
	 *
107 107
	 * @param elementProcessors
108 108
	 */
109 109
	public void setElementProcessors(
......
115 115
	 * Looks for technical annotations, if one matches a regular expression of the element processors
116 116
	 * the associated processor is added to the applicable element processors which will then be applied
117 117
	 * when generating the description.
118
	 * 
118
	 *
119 119
	 * @param annotations the set of annotations of the description
120 120
	 */
121 121
	private void initNaturalLanguageDescriptionElementProcessors(Set<Annotation> annotations) {
......
138 138

  
139 139
	/**
140 140
	 * Applies the list of applicable processors to a TextData.
141
	 * 
141
	 *
142 142
	 * @param textData the TextData to be modified
143 143
	 * @param previousTextData the TextData corresponding to the feature of the previous level in the tree
144 144
	 */
......
151 151

  
152 152
	/**
153 153
	 * The most simple function to generate a description. The language used is the default one.
154
	 * 
154
	 *
155 155
	 * @param featureTree the FeatureTree holding the order in which features and their states must be printed
156 156
	 * @param description the TaxonDescription with all the data
157
	 * 
157
	 *
158 158
	 * @return a list of TextData, each one being a basic element of the natural language description
159 159
	 */
160
	public List<TextData> generateNaturalLanguageDescription(FeatureTree featureTree,TaxonDescription description) {
160
	@Override
161
    public List<TextData> generateNaturalLanguageDescription(FeatureTree featureTree,TaxonDescription description) {
161 162
		return generateNaturalLanguageDescription(featureTree,description,Language.DEFAULT());
162 163
	}
163 164

  
......
165 166

  
166 167
	/**
167 168
	 * Generate a description in a specified language.
168
	 * 
169
	 *
169 170
	 * @param featureTree the FeatureTree holding the order in which features and their states must be printed
170 171
	 * @param description the TaxonDescription with all the data
171 172
	 * @param language the language in which the description has to be printed
172
	 * 
173
	 *
173 174
	 * @return a list of TextData, each one being a basic element of the natural language description
174 175
	 */
175
	public List<TextData> generateNaturalLanguageDescription(FeatureTree featureTree, TaxonDescription description,	Language language) {
176
	@Override
177
    public List<TextData> generateNaturalLanguageDescription(FeatureTree featureTree, TaxonDescription description,	Language language) {
176 178
		List<Language> languages = new ArrayList<Language>();
177 179
		languages.add(language);
178 180
		initNaturalLanguageDescriptionElementProcessors(description.getAnnotations());
......
181 183

  
182 184
	/**
183 185
	 * Generate a description with a specified list of preferred languages.
184
	 * 
186
	 *
185 187
	 * @param featureTree the FeatureTree holding the order in which features and their states must be printed
186 188
	 * @param description the TaxonDescription with all the data
187 189
	 * @param languages the ordered list of languages preferred for printing the description
188
	 * 
190
	 *
189 191
	 * @return a list of TextData, each one being a basic element of the natural language description
190 192
	 */
191
	public List<TextData> generatePreferredNaturalLanguageDescription(FeatureTree featureTree,TaxonDescription description, List<Language> languages) {
193
	@Override
194
    public List<TextData> generatePreferredNaturalLanguageDescription(FeatureTree featureTree,TaxonDescription description, List<Language> languages) {
192 195
		initNaturalLanguageDescriptionElementProcessors(description.getAnnotations());
193 196
		return buildBranchesDescr(featureTree.getRootChildren(), featureTree.getRoot(), description, languages,0);
194 197
	}
195 198

  
196 199
	/**
197 200
	 * Generate a description as a single paragraph in a TextData.
198
	 * 
201
	 *
199 202
	 * @param featureTree the FeatureTree holding the order in which features and their states must be printed
200 203
	 * @param description the TaxonDescription with all the data
201
	 * 
204
	 *
202 205
	 * @return a TextData in the default language.
203 206
	 */
204
	public TextData generateSingleTextData(FeatureTree featureTree, TaxonDescription description) {
207
	@Override
208
    public TextData generateSingleTextData(FeatureTree featureTree, TaxonDescription description) {
205 209
		return generateSingleTextData(featureTree,description,Language.DEFAULT());
206 210
	}
207 211

  
208 212
	/**
209 213
	 * Generate a description as a single paragraph in a TextData.
210
	 * 
214
	 *
211 215
	 * @param featureTree the FeatureTree holding the order in which features and their states must be printed
212 216
	 * @param description the TaxonDescription with all the data
213 217
	 * @param language the language in which the description has to be printed
214
	 * 
218
	 *
215 219
	 * @return a TextData in the specified language.
216 220
	 */
217
	public TextData generateSingleTextData(FeatureTree featureTree, TaxonDescription description, Language language) {
221
	@Override
222
    public TextData generateSingleTextData(FeatureTree featureTree, TaxonDescription description, Language language) {
218 223
		List<Language> languages = new ArrayList<Language>();
219 224
		languages.add(language);
220 225
		return generatePreferredSingleTextData(featureTree,description,languages);
......
222 227

  
223 228
	/**
224 229
	 * Generate a description with a specified list of preferred languages.
225
	 * 
230
	 *
226 231
	 * @param featureTree the FeatureTree holding the order in which features and their states must be printed
227 232
	 * @param description the TaxonDescription with all the data
228 233
	 * @param languages the ordered list of languages preferred for printing the description
229
	 * 
234
	 *
230 235
	 * @return a TextData using the languages (in the given order of preference)
231 236
	 */
232
	public TextData generatePreferredSingleTextData(FeatureTree featureTree, TaxonDescription description, List<Language> languages) {
237
	@Override
238
    public TextData generatePreferredSingleTextData(FeatureTree featureTree, TaxonDescription description, List<Language> languages) {
233 239
		levels.clear(); // before the start, the table containing the levels of each node must be cleared
234 240
		// Note: this is not the most efficient way to keep track of the levels of the nodes but it allows some flexibility
235 241
		List<TextData> texts = generatePreferredNaturalLanguageDescription(featureTree,description, languages);// first get the description as a raw list of TextData
......
246 252
					startSentence=true;
247 253
					firstOne=false;
248 254
					String asString = texts.get(i).getText(Language.DEFAULT()).toString();
249
					if (asString.length()>1) descriptionStringBuilder.append(asString.substring(0,1).toUpperCase() + asString.substring(1));
255
					if (asString.length()>1) {
256
                        descriptionStringBuilder.append(asString.substring(0,1).toUpperCase() + asString.substring(1));
257
                    }
250 258
				}
251 259
				i++;
252 260
			}
253 261
			else if (level==0) { // if this node is a leaf
254
				if (startSentence) descriptionStringBuilder.append(texts.get(i).getText(Language.DEFAULT()));
255
				else descriptionStringBuilder.append(firstSeparator + texts.get(i).getText(Language.DEFAULT()));
262
				if (startSentence) {
263
                    descriptionStringBuilder.append(texts.get(i).getText(Language.DEFAULT()));
264
                } else {
265
                    descriptionStringBuilder.append(firstSeparator + texts.get(i).getText(Language.DEFAULT()));
266
                }
256 267
				startSentence=false;
257 268
				i++;
258 269
			}
259 270
			else {
260 271
				if (!firstOne && levels.get(j-1).equals(0)){ // if this node corresponds to the states linked to the previous leaf
261
					if (i<texts.size()) descriptionStringBuilder.append(texts.get(i).getText(Language.DEFAULT()));
272
					if (i<texts.size()) {
273
                        descriptionStringBuilder.append(texts.get(i).getText(Language.DEFAULT()));
274
                    }
262 275
					i++;
263 276
				}
264 277
			}
......
274 287

  
275 288
	/** recursive function that goes through a tree containing the order in which the description has to be generated,
276 289
	 *  if an element of this tree matches one of the TaxonDescription, a DescriptionBuilder is called which returns a TextData with the corresponding description.
277
	 * 
290
	 *
278 291
	 * @param children the children of the feature node considered
279 292
	 * @param parent the feature node considered
280 293
	 * @param description the TaxonDescription element for which we want a natural language output
......
282 295
	 * @param floor integer to keep track of the level in the tree
283 296
	 * @return a list of TextData elements containing the part of description corresponding to the feature node considered
284 297
	 */
285
	private List<TextData> buildBranchesDescr(List<FeatureNode> children, FeatureNode parent, TaxonDescription description, List<Language> languages, int floor) {
298
	private List<TextData> buildBranchesDescr(List<FeatureNode> children, FeatureNode<Feature> parent, TaxonDescription description, List<Language> languages, int floor) {
286 299
		List<TextData> listTextData = new ArrayList<TextData>();
287 300
		floor++; // counter to know the current level in the tree
288 301

  
289 302
		if (!parent.isLeaf()){ // if this node is not a leaf, continue recursively (only the leaves of a FeatureTree contain states)
290 303
			levels.add(new Integer(floor)); // the level of the different nodes in the tree are kept, thus it is easier to build a structured text out of the List<TextData>
291
			Feature feature = parent.getFeature();
304
			Feature feature = parent.getTerm();
292 305
			TextData featureName;
293 306
			if (feature!=null && feature.getLabel()!=null){ // if a node is associated to a feature
294 307
				featureName = categoricalDescriptionBuilder.buildTextDataFeature(feature, languages);
295 308
				levels.add(new Integer(-1)); // it is indicated by a '-1' after its level
296 309
				listTextData.add(featureName); // the TextData representing the name of the feature is concatenated to the list
297 310
			}
298
			else featureName = new TextData(); // else an empty TextData is created (because we keep track of the features, it is useful to inform when the upper node has no feature attached)
311
            else {
312
                featureName = new TextData(); // else an empty TextData is created (because we keep track of the features, it is useful to inform when the upper node has no feature attached)
313
            }
299 314

  
300 315
			for (Iterator<FeatureNode> ifn = children.iterator() ; ifn.hasNext() ;){
301 316
				previousTextData = featureName; // this allows to keep track of the name of the feature one level up in the tree
......
304 319
			}
305 320
		}
306 321
		else { //once a leaf is reached
307
			Feature feature = parent.getFeature();
322
			Feature feature = parent.getTerm();
308 323
			if (feature!=null && (feature.isSupportsQuantitativeData() || feature.isSupportsCategoricalData())) {
309 324
				Set<DescriptionElementBase> elements = description.getElements();
310 325
				for (Iterator<DescriptionElementBase> deb = elements.iterator() ; deb.hasNext() ;){ // iterates over all the descriptions enclosed in the TaxonDescription
......
334 349
			}
335 350
		}
336 351
		return listTextData;
337
	}	
352
	}
338 353

  
339 354
}

Also available in: Unified diff