Resolved #465 - Implemented relationships between terms and added relationships betwe...
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / common / DefinedTermBase.java
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.common;
11
12 import org.apache.log4j.Logger;
13 import org.hibernate.annotations.Cascade;
14 import org.hibernate.annotations.CascadeType;
15 import org.hibernate.collection.AbstractPersistentCollection;
16
17 import au.com.bytecode.opencsv.CSVWriter;
18 import eu.etaxonomy.cdm.model.common.init.DefaultVocabularyStore;
19 import eu.etaxonomy.cdm.model.common.init.IVocabularyStore;
20 import eu.etaxonomy.cdm.model.media.Media;
21 import java.lang.reflect.Field;
22 import java.util.*;
23
24 import javax.persistence.*;
25 import javax.xml.bind.annotation.XmlAccessType;
26 import javax.xml.bind.annotation.XmlAccessorType;
27 import javax.xml.bind.annotation.XmlElement;
28 import javax.xml.bind.annotation.XmlElementWrapper;
29 import javax.xml.bind.annotation.XmlIDREF;
30 import javax.xml.bind.annotation.XmlRootElement;
31 import javax.xml.bind.annotation.XmlSchemaType;
32 import javax.xml.bind.annotation.XmlTransient;
33 import javax.xml.bind.annotation.XmlType;
34
35
36 /**
37 * walkaround for enumerations, base type according to TDWG. For linear ordering
38 * use partOf relation and BreadthFirst. Default iterator order should therefore
39 * be BreadthFirst (not DepthFirst)
40 * @author m.doering
41 * @version 1.0
42 * @created 08-Nov-2007 13:06:19
43 */
44 @XmlAccessorType(XmlAccessType.FIELD)
45 @XmlType(name = "DefinedTermBase", propOrder = {
46 "kindOf",
47 "generalizationOf",
48 "partOf",
49 "includes",
50 "media",
51 "vocabulary"
52 })
53 @XmlRootElement(name = "DefinedTermBase")
54 @Entity
55 @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
56 public abstract class DefinedTermBase<T extends DefinedTermBase> extends TermBase implements ILoadableTerm<T> {
57 private static final long serialVersionUID = 2931811562248571531L;
58 @SuppressWarnings("unused")
59 private static final Logger logger = Logger.getLogger(DefinedTermBase.class);
60
61 static protected IVocabularyStore vocabularyStore = new DefaultVocabularyStore();
62
63 public static void setVocabularyStore(IVocabularyStore vocabularyStore){
64 DefinedTermBase.vocabularyStore = vocabularyStore;
65 }
66
67 @XmlElement(name = "KindOf")
68 private DefinedTermBase<T> kindOf;
69
70 @XmlElement(name = "GeneralizationOf")
71 private Set<DefinedTermBase<T>> generalizationOf = new HashSet<DefinedTermBase<T>>();
72
73 @XmlElement(name = "PartOf")
74 private DefinedTermBase<T> partOf;
75
76 @XmlElementWrapper(name = "Includes")
77 @XmlElement(name = "Include")
78 private Set<DefinedTermBase<T>> includes = new HashSet<DefinedTermBase<T>>();
79
80 @XmlElementWrapper(name = "Media")
81 @XmlElement(name = "Medium")
82 @XmlIDREF
83 @XmlSchemaType(name = "IDREF")
84 private Set<Media> media = new HashSet<Media>();
85
86 @XmlElement(name = "TermVocabulary")
87 @XmlIDREF
88 @XmlSchemaType(name = "IDREF")
89 protected TermVocabulary<T> vocabulary;
90
91
92 public static DefinedTermBase findByUuid(UUID uuid){
93 return vocabularyStore.getTermByUuid(uuid);
94 }
95
96 public DefinedTermBase() {
97 super();
98 }
99 public DefinedTermBase(String term, String label, String labelAbbrev) {
100 super(term, label, labelAbbrev);
101 }
102
103
104 /* (non-Javadoc)
105 * @see eu.etaxonomy.cdm.model.common.ILoadableTerm#readCsvLine(java.util.List)
106 */
107 public ILoadableTerm readCsvLine(List<String> csvLine) {
108 return readCsvLine(csvLine, Language.ENGLISH());
109 }
110
111 public ILoadableTerm readCsvLine(List<String> csvLine, Language lang) {
112 this.setUuid(UUID.fromString(csvLine.get(0)));
113 this.setUri(csvLine.get(1));
114 String label = csvLine.get(2).trim();
115 String text = csvLine.get(3);
116 String abbreviatedLabel = null;
117 this.addRepresentation(Representation.NewInstance(text, label, abbreviatedLabel, lang) );
118 return this;
119 }
120
121 /* (non-Javadoc)
122 * @see eu.etaxonomy.cdm.model.common.ILoadableTerm#writeCsvLine(au.com.bytecode.opencsv.CSVWriter)
123 */
124 public void writeCsvLine(CSVWriter writer) {
125 String [] line = new String[4];
126 line[0] = getUuid().toString();
127 line[1] = getUri();
128 line[2] = getLabel();
129 line[3] = getDescription();
130 writer.writeNext(line);
131 }
132
133
134 @ManyToOne(fetch = FetchType.LAZY)
135 @Cascade({CascadeType.SAVE_UPDATE})
136 public DefinedTermBase<T> getKindOf(){
137 return this.kindOf;
138 }
139 public void setKindOf(DefinedTermBase<T> kindOf){
140 this.kindOf = kindOf;
141 }
142
143 @OneToMany(fetch=FetchType.LAZY, mappedBy = "kindOf")
144 @Cascade({CascadeType.SAVE_UPDATE})
145 public Set<DefinedTermBase<T>> getGeneralizationOf(){
146 return this.generalizationOf;
147 }
148
149 public void setGeneralizationOf(Set<DefinedTermBase<T>> generalizationOf) {
150 this.generalizationOf = generalizationOf;
151 }
152
153 public void addGeneralizationOf(DefinedTermBase<T> generalization) {
154 generalization.setKindOf(this);
155 this.generalizationOf.add(generalization);
156 }
157
158 public void removeGeneralization(DefinedTermBase<T> generalization) {
159 if(generalizationOf.contains(generalization)){
160 generalization.setKindOf(null);
161 this.generalizationOf.remove(generalization);
162 }
163 }
164
165
166 @ManyToOne
167 @Cascade({CascadeType.SAVE_UPDATE})
168 public DefinedTermBase<T> getPartOf(){
169 return this.partOf;
170 }
171 public void setPartOf(DefinedTermBase<T> partOf){
172 this.partOf = partOf;
173 }
174
175
176 @OneToMany(fetch=FetchType.LAZY, mappedBy = "partOf")
177 @Cascade({CascadeType.SAVE_UPDATE})
178 public Set<DefinedTermBase<T>> getIncludes(){
179 return this.includes;
180 }
181 public void setIncludes(Set<DefinedTermBase<T>> includes) {
182 this.includes = includes;
183 }
184 public void addIncludes(DefinedTermBase<T> includes) {
185 includes.setPartOf(this);
186 this.includes.add(includes);
187 }
188 public void removeIncludes(DefinedTermBase<T> includes) {
189 if(this.includes.contains(includes)) {
190 includes.setPartOf(null);
191 this.includes.remove(includes);
192 }
193 }
194
195
196 @OneToMany
197 @Cascade({CascadeType.SAVE_UPDATE})
198 public Set<Media> getMedia(){
199 return this.media;
200 }
201 public void setMedia(Set<Media> media) {
202 this.media = media;
203 }
204 public void addMedia(Media media) {
205 this.media.add(media);
206 }
207 public void removeMedia(Media media) {
208 this.media.remove(media);
209 }
210
211 /* (non-Javadoc)
212 * @see eu.etaxonomy.cdm.model.common.IDefTerm#getVocabulary()
213 */
214 @Transient
215 @XmlTransient
216 public TermVocabulary getVocabulary() {
217 return this.vocabulary;
218 }
219 /* (non-Javadoc)
220 * @see eu.etaxonomy.cdm.model.common.IDefTerm#setVocabulary(eu.etaxonomy.cdm.model.common.TermVocabulary)
221 */
222 public void setVocabulary(TermVocabulary newVocabulary) {
223 // Hibernate bidirectional cascade hack:
224 // http://opensource.atlassian.com/projects/hibernate/browse/HHH-1054
225 if(this.vocabulary == newVocabulary){ return;}
226 if (this.vocabulary != null) {
227 this.vocabulary.terms.remove(this);
228 }
229 if (newVocabulary!= null) {
230 newVocabulary.terms.add(this);
231 }
232 this.vocabulary = newVocabulary;
233 }
234
235
236 /* (non-Javadoc)
237 * @see eu.etaxonomy.cdm.model.common.IDefTerm#getVocabulary()
238 */
239 @ManyToOne(fetch=FetchType.LAZY)
240 @Cascade( { CascadeType.SAVE_UPDATE })
241 protected TermVocabulary getPersistentVocabulary() {
242 return this.vocabulary;
243 }
244 /* (non-Javadoc)
245 * @see eu.etaxonomy.cdm.model.common.IDefTerm#setVocabulary(eu.etaxonomy.cdm.model.common.TermVocabulary)
246 */
247 protected void setPersistentVocabulary(TermVocabulary newVocabulary) {
248 // Hibernate bidirectional cascade hack:
249 // http://opensource.atlassian.com/projects/hibernate/browse/HHH-1054
250 if(this.vocabulary == newVocabulary){ return;}
251 if (this.vocabulary != null) {
252 this.vocabulary.terms.remove(this);
253 }
254 if (newVocabulary!= null) {
255 try {
256 Field fieldInitializing = AbstractPersistentCollection.class.getDeclaredField("initializing");
257 fieldInitializing.setAccessible(true);
258 if (AbstractPersistentCollection.class.isAssignableFrom(newVocabulary.terms.getClass())){
259 boolean initValue = fieldInitializing.getBoolean(newVocabulary.terms);
260 if (initValue == false){
261 newVocabulary.terms.add(this);
262 }else{
263 //nothing
264 }
265 }else{
266 newVocabulary.terms.add(this);
267 }
268 } catch (SecurityException e) {
269 e.printStackTrace();
270 } catch (IllegalArgumentException e) {
271 e.printStackTrace();
272 } catch (NoSuchFieldException e) {
273 e.printStackTrace();
274 } catch (IllegalAccessException e) {
275 e.printStackTrace();
276 }
277 }
278 this.vocabulary = newVocabulary;
279 }
280
281 }