Annotated fields partOf, kindOf, generalizationOf as IDREF
[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 @XmlIDREF
69 @XmlSchemaType(name = "IDREF")
70 private T kindOf;
71 /**
72 * FIXME - Hibernate retuns this as a collection of CGLibProxy$$DefinedTermBase objects
73 * which can't be cast to instances of T - can we explicitly initialize these terms using
74 * Hibernate.initialize(), does this imply a distinct load, and find methods in the dao?
75 */
76 @XmlElement(name = "GeneralizationOf")
77 @XmlIDREF
78 @XmlSchemaType(name = "IDREF")
79 private Set<T> generalizationOf = new HashSet<T>();
80
81 @XmlElement(name = "PartOf")
82 @XmlIDREF
83 @XmlSchemaType(name = "IDREF")
84 private T partOf;
85
86 /**
87 * FIXME - Hibernate retuns this as a collection of CGLibProxy$$DefinedTermBase objects
88 * which can't be cast to instances of T - can we explicitly initialize these terms using
89 * Hibernate.initialize(), does this imply a distinct load, and find methods in the dao?
90 */
91 @XmlElementWrapper(name = "Includes")
92 @XmlElement(name = "Include")
93 @XmlIDREF
94 @XmlSchemaType(name = "IDREF")
95 private Set<T> includes = new HashSet<T>();
96
97 @XmlElementWrapper(name = "Media")
98 @XmlElement(name = "Medium")
99 @XmlIDREF
100 @XmlSchemaType(name = "IDREF")
101 private Set<Media> media = new HashSet<Media>();
102
103 @XmlElement(name = "TermVocabulary")
104 @XmlIDREF
105 @XmlSchemaType(name = "IDREF")
106 protected TermVocabulary<T> vocabulary;
107
108
109 public static DefinedTermBase findByUuid(UUID uuid){
110 return vocabularyStore.getTermByUuid(uuid);
111 }
112
113 public DefinedTermBase() {
114 super();
115 }
116 public DefinedTermBase(String term, String label, String labelAbbrev) {
117 super(term, label, labelAbbrev);
118 }
119
120
121 /* (non-Javadoc)
122 * @see eu.etaxonomy.cdm.model.common.ILoadableTerm#readCsvLine(java.util.List)
123 */
124 public ILoadableTerm readCsvLine(List<String> csvLine) {
125 return readCsvLine(csvLine, Language.ENGLISH());
126 }
127
128 public ILoadableTerm readCsvLine(List<String> csvLine, Language lang) {
129 this.setUuid(UUID.fromString(csvLine.get(0)));
130 this.setUri(csvLine.get(1));
131 String label = csvLine.get(2).trim();
132 String text = csvLine.get(3);
133 String abbreviatedLabel = null;
134 this.addRepresentation(Representation.NewInstance(text, label, abbreviatedLabel, lang) );
135 return this;
136 }
137
138 /* (non-Javadoc)
139 * @see eu.etaxonomy.cdm.model.common.ILoadableTerm#writeCsvLine(au.com.bytecode.opencsv.CSVWriter)
140 */
141 public void writeCsvLine(CSVWriter writer) {
142 String [] line = new String[4];
143 line[0] = getUuid().toString();
144 line[1] = getUri();
145 line[2] = getLabel();
146 line[3] = getDescription();
147 writer.writeNext(line);
148 }
149
150
151 @ManyToOne(fetch = FetchType.LAZY, targetEntity = DefinedTermBase.class)
152 @Cascade({CascadeType.SAVE_UPDATE})
153 public T getKindOf(){
154 return this.kindOf;
155 }
156
157 public void setKindOf(T kindOf){
158 this.kindOf = kindOf;
159 }
160
161 @OneToMany(fetch=FetchType.LAZY, mappedBy = "kindOf", targetEntity = DefinedTermBase.class)
162 @Cascade({CascadeType.SAVE_UPDATE})
163 public Set<T> getGeneralizationOf(){
164 return this.generalizationOf;
165 }
166
167 public void setGeneralizationOf(Set<T> generalizationOf) {
168 this.generalizationOf = generalizationOf;
169 }
170
171 public void addGeneralizationOf(T generalization) {
172 generalization.setKindOf(this);
173 this.generalizationOf.add(generalization);
174 }
175
176 public void removeGeneralization(T generalization) {
177 if(generalizationOf.contains(generalization)){
178 generalization.setKindOf(null);
179 this.generalizationOf.remove(generalization);
180 }
181 }
182
183
184 @ManyToOne(fetch = FetchType.LAZY, targetEntity = DefinedTermBase.class)
185 @Cascade({CascadeType.SAVE_UPDATE})
186 public T getPartOf(){
187 return this.partOf;
188 }
189 public void setPartOf(T partOf){
190 this.partOf = partOf;
191 }
192
193
194 @OneToMany(fetch=FetchType.LAZY, mappedBy = "partOf", targetEntity = DefinedTermBase.class)
195 @Cascade({CascadeType.SAVE_UPDATE})
196 public Set<T> getIncludes(){
197 return this.includes;
198 }
199 public void setIncludes(Set<T> includes) {
200 this.includes = includes;
201 }
202 public void addIncludes(T includes) {
203 includes.setPartOf(this);
204 this.includes.add(includes);
205 }
206 public void removeIncludes(T includes) {
207 if(this.includes.contains(includes)) {
208 includes.setPartOf(null);
209 this.includes.remove(includes);
210 }
211 }
212
213
214 @OneToMany
215 @Cascade({CascadeType.SAVE_UPDATE})
216 public Set<Media> getMedia(){
217 return this.media;
218 }
219 public void setMedia(Set<Media> media) {
220 this.media = media;
221 }
222 public void addMedia(Media media) {
223 this.media.add(media);
224 }
225 public void removeMedia(Media media) {
226 this.media.remove(media);
227 }
228
229 /* (non-Javadoc)
230 * @see eu.etaxonomy.cdm.model.common.IDefTerm#getVocabulary()
231 */
232 @Transient
233 @XmlTransient
234 public TermVocabulary<T> getVocabulary() {
235 return this.vocabulary;
236 }
237 /* (non-Javadoc)
238 * @see eu.etaxonomy.cdm.model.common.IDefTerm#setVocabulary(eu.etaxonomy.cdm.model.common.TermVocabulary)
239 */
240 public void setVocabulary(TermVocabulary<T> newVocabulary) {
241 // Hibernate bidirectional cascade hack:
242 // http://opensource.atlassian.com/projects/hibernate/browse/HHH-1054
243 if(this.vocabulary == newVocabulary){ return;}
244 if (this.vocabulary != null) {
245 this.vocabulary.terms.remove(this);
246 }
247 if (newVocabulary!= null) {
248 newVocabulary.terms.add((T)this);
249 }
250 this.vocabulary = newVocabulary;
251 }
252
253
254 /* (non-Javadoc)
255 * @see eu.etaxonomy.cdm.model.common.IDefTerm#getVocabulary()
256 */
257 @ManyToOne(fetch=FetchType.LAZY)
258 @Cascade( { CascadeType.SAVE_UPDATE })
259 protected TermVocabulary<T> getPersistentVocabulary() {
260 return this.vocabulary;
261 }
262 /* (non-Javadoc)
263 * @see eu.etaxonomy.cdm.model.common.IDefTerm#setVocabulary(eu.etaxonomy.cdm.model.common.TermVocabulary)
264 */
265 protected void setPersistentVocabulary(TermVocabulary newVocabulary) {
266 // Hibernate bidirectional cascade hack:
267 // http://opensource.atlassian.com/projects/hibernate/browse/HHH-1054
268 if(this.vocabulary == newVocabulary){ return;}
269 if (this.vocabulary != null) {
270 this.vocabulary.terms.remove(this);
271 }
272 if (newVocabulary!= null) {
273 try {
274 Field fieldInitializing = AbstractPersistentCollection.class.getDeclaredField("initializing");
275 fieldInitializing.setAccessible(true);
276 if (AbstractPersistentCollection.class.isAssignableFrom(newVocabulary.terms.getClass())){
277 boolean initValue = fieldInitializing.getBoolean(newVocabulary.terms);
278 if (initValue == false){
279 newVocabulary.terms.add(this);
280 }else{
281 //nothing
282 }
283 }else{
284 newVocabulary.terms.add(this);
285 }
286 } catch (SecurityException e) {
287 e.printStackTrace();
288 } catch (IllegalArgumentException e) {
289 e.printStackTrace();
290 } catch (NoSuchFieldException e) {
291 e.printStackTrace();
292 } catch (IllegalAccessException e) {
293 e.printStackTrace();
294 }
295 }
296 this.vocabulary = newVocabulary;
297 }
298
299 }