Project

General

Profile

Download (15.3 KB) Statistics
| Branch: | Tag: | Revision:
1 9479da48 Andreas Müller
/**
2
* Copyright (C) 2007 EDIT
3 ad190552 Andreas Kohlbecker
* European Distributed Institute of Taxonomy
4 9479da48 Andreas Müller
* http://www.e-taxonomy.eu
5 ad190552 Andreas Kohlbecker
*
6 9479da48 Andreas Müller
* 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 533cbb43 Andreas Müller
import java.lang.reflect.Constructor;
13 f7f4a80d Andreas Müller
import java.net.URI;
14 ee91bcd9 ben.clark
import java.util.HashSet;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.Set;
18
import java.util.UUID;
19 9479da48 Andreas Müller
20 ee91bcd9 ben.clark
import javax.persistence.Entity;
21
import javax.persistence.FetchType;
22
import javax.persistence.Inheritance;
23
import javax.persistence.InheritanceType;
24 0a6f2f53 Andreas Müller
import javax.persistence.ManyToMany;
25 ee91bcd9 ben.clark
import javax.persistence.ManyToOne;
26
import javax.persistence.OneToMany;
27 b70a7f94 Andreas Kohlbecker
import javax.persistence.Transient;
28 70440a7d a.babadshanjan
import javax.xml.bind.annotation.XmlAccessType;
29
import javax.xml.bind.annotation.XmlAccessorType;
30
import javax.xml.bind.annotation.XmlElement;
31
import javax.xml.bind.annotation.XmlElementWrapper;
32 c4c118de a.babadshanjan
import javax.xml.bind.annotation.XmlIDREF;
33 70440a7d a.babadshanjan
import javax.xml.bind.annotation.XmlRootElement;
34 c4c118de a.babadshanjan
import javax.xml.bind.annotation.XmlSchemaType;
35 c9866164 ben.clark
import javax.xml.bind.annotation.XmlSeeAlso;
36
import javax.xml.bind.annotation.XmlTransient;
37 70440a7d a.babadshanjan
import javax.xml.bind.annotation.XmlType;
38 9479da48 Andreas Müller
39 ee91bcd9 ben.clark
import org.apache.log4j.Logger;
40 1631c353 Andreas Müller
import org.codehaus.plexus.util.StringUtils;
41 ee91bcd9 ben.clark
import org.hibernate.annotations.Cascade;
42
import org.hibernate.annotations.CascadeType;
43
import org.hibernate.envers.Audited;
44 c7f65649 Andreas Kohlbecker
import org.hibernate.proxy.HibernateProxy;
45
import org.hibernate.proxy.LazyInitializer;
46 ad190552 Andreas Kohlbecker
import org.hibernate.search.annotations.ClassBridge;
47 a5b11b44 Andreas Müller
import org.hibernate.validator.constraints.Length;
48 ee91bcd9 ben.clark
49
import au.com.bytecode.opencsv.CSVWriter;
50 ad190552 Andreas Kohlbecker
import eu.etaxonomy.cdm.hibernate.search.DefinedTermBaseClassBridge;
51 93f50b5e Cherian Mathew
import eu.etaxonomy.cdm.model.ICdmCacher;
52 c9866164 ben.clark
import eu.etaxonomy.cdm.model.description.Feature;
53
import eu.etaxonomy.cdm.model.description.MeasurementUnit;
54
import eu.etaxonomy.cdm.model.description.StatisticalMeasure;
55
import eu.etaxonomy.cdm.model.description.TextFormat;
56
import eu.etaxonomy.cdm.model.location.NamedAreaType;
57
import eu.etaxonomy.cdm.model.location.ReferenceSystem;
58 ee91bcd9 ben.clark
import eu.etaxonomy.cdm.model.media.Media;
59 ff3882c8 Andreas Müller
import eu.etaxonomy.cdm.model.media.RightsType;
60 c9866164 ben.clark
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
61
import eu.etaxonomy.cdm.model.occurrence.DerivationEventType;
62
import eu.etaxonomy.cdm.model.occurrence.PreservationMethod;
63 ee91bcd9 ben.clark
64 fbd23d1d Andreas Müller
65 9479da48 Andreas Müller
/**
66 02dc229b Andreas Kohlbecker
 * workaround for enumerations, base type according to TDWG.  For linear ordering
67 9479da48 Andreas Müller
 * use partOf relation and BreadthFirst. Default iterator order should therefore
68
 * be BreadthFirst (not DepthFirst)
69
 * @author m.doering
70
 * @created 08-Nov-2007 13:06:19
71
 */
72 70440a7d a.babadshanjan
@XmlAccessorType(XmlAccessType.FIELD)
73
@XmlType(name = "DefinedTermBase", propOrder = {
74
    "media",
75 efa9828a Andreas Müller
    "vocabulary",
76
    "idInVocabulary"
77 70440a7d a.babadshanjan
})
78
@XmlRootElement(name = "DefinedTermBase")
79 c9866164 ben.clark
@XmlSeeAlso({
80 ad190552 Andreas Kohlbecker
    AnnotationType.class,
81
    DerivationEventType.class,
82 533cbb43 Andreas Müller
    DefinedTerm.class,
83 ad190552 Andreas Kohlbecker
    ExtensionType.class,
84 c9866164 ben.clark
    Feature.class,
85
    Language.class,
86
    MarkerType.class,
87
    MeasurementUnit.class,
88
    NamedAreaType.class,
89
    NomenclaturalCode.class,
90
    PreservationMethod.class,
91
    ReferenceSystem.class,
92 ff3882c8 Andreas Müller
    RightsType.class,
93 c9866164 ben.clark
    StatisticalMeasure.class,
94 828f8b96 a.babadshanjan
    TextFormat.class
95 c9866164 ben.clark
})
96 9479da48 Andreas Müller
@Entity
97 ee91bcd9 ben.clark
@Audited
98 9479da48 Andreas Müller
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
99 ad190552 Andreas Kohlbecker
@ClassBridge(impl=DefinedTermBaseClassBridge.class)
100 589ecf52 Andreas Müller
//TODO Comparable implemented only for fixing failing JAXB import, may be removed when this is fixed
101
public abstract class DefinedTermBase<T extends DefinedTermBase> extends TermBase implements ILoadableTerm<T>, IDefinedTerm<T>, Comparable<T> {
102 ad190552 Andreas Kohlbecker
    private static final long serialVersionUID = 2931811562248571531L;
103
    private static final Logger logger = Logger.getLogger(DefinedTermBase.class);
104
105 c9866164 ben.clark
//	@XmlElement(name = "KindOf")
106
//    @XmlIDREF
107
//    @XmlSchemaType(name = "IDREF")
108 ad190552 Andreas Kohlbecker
    @XmlTransient
109 ee91bcd9 ben.clark
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = DefinedTermBase.class)
110
    @Cascade(CascadeType.SAVE_UPDATE)
111 ad190552 Andreas Kohlbecker
    private T kindOf;
112
    /**
113 ee91b8fd Andreas Kohlbecker
     * FIXME - Hibernate returns this as a collection of CGLibProxy$$DefinedTermBase objects
114 ad190552 Andreas Kohlbecker
     * which can't be cast to instances of T - can we explicitly initialize these terms using
115
     * Hibernate.initialize(), does this imply a distinct load, and find methods in the dao?
116
     */
117 c9866164 ben.clark
//	@XmlElementWrapper(name = "Generalizations")
118
//	@XmlElement(name = "GeneralizationOf")
119
//    @XmlIDREF
120
//    @XmlSchemaType(name = "IDREF")
121 ad190552 Andreas Kohlbecker
    @XmlTransient
122 ee91bcd9 ben.clark
    @OneToMany(fetch=FetchType.LAZY, mappedBy = "kindOf", targetEntity = DefinedTermBase.class)
123 ad190552 Andreas Kohlbecker
    @Cascade({CascadeType.SAVE_UPDATE})
124
    private Set<T> generalizationOf = new HashSet<T>();
125
126 c9866164 ben.clark
//	@XmlElement(name = "PartOf")
127
//	@XmlIDREF
128
//  @XmlSchemaType(name = "IDREF")
129 ad190552 Andreas Kohlbecker
    @XmlTransient
130
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = DefinedTermBase.class)
131
    @Cascade(CascadeType.SAVE_UPDATE)
132
    protected T partOf;
133
134
    /**
135
     * FIXME - Hibernate retuns this as a collection of CGLibProxy$$DefinedTermBase objects
136
     * which can't be cast to instances of T - can we explicitly initialize these terms using
137
     * Hibernate.initialize(), does this imply a distinct load, and find methods in the dao?
138
     */
139 c9866164 ben.clark
//	@XmlElementWrapper(name = "Includes")
140
//	@XmlElement(name = "Include")
141
//	@XmlIDREF
142
//    @XmlSchemaType(name = "IDREF")
143 ad190552 Andreas Kohlbecker
    @XmlTransient
144
    @OneToMany(fetch=FetchType.LAZY, mappedBy = "partOf", targetEntity = DefinedTermBase.class)
145
    @Cascade({CascadeType.SAVE_UPDATE})
146
    private Set<T> includes = new HashSet<T>();
147
148
    @XmlElementWrapper(name = "Media")
149
    @XmlElement(name = "Medium")
150 0ae18eec a.babadshanjan
    @XmlIDREF
151
    @XmlSchemaType(name = "IDREF")
152 0a6f2f53 Andreas Müller
    @ManyToMany(fetch = FetchType.LAZY)
153 ad190552 Andreas Kohlbecker
    @Cascade({CascadeType.SAVE_UPDATE})
154
    private Set<Media> media = new HashSet<Media>();
155
156
    @XmlElement(name = "TermVocabulary")
157
    @XmlIDREF
158
    @XmlSchemaType(name = "IDREF")
159
    @ManyToOne(fetch=FetchType.LAZY)
160
    @Cascade(CascadeType.SAVE_UPDATE)
161
    protected TermVocabulary<T> vocabulary;
162 ee91b8fd Andreas Kohlbecker
163 ed0e00d0 Andreas Müller
  //the unique iedentifier/name this term uses in its given vocabulary #3479
164 efa9828a Andreas Müller
   //open issues: is null allowed? If not, implement unique constraint
165 ee91b8fd Andreas Kohlbecker
166 efa9828a Andreas Müller
    @XmlElement(name = "idInVocabulary")
167 a5b11b44 Andreas Müller
    @Length(max=255)
168 ed0e00d0 Andreas Müller
    private String idInVocabulary;  //the unique identifier/name this term uses in its given vocabulary #3479
169 93f50b5e Cherian Mathew
    
170
171 ad190552 Andreas Kohlbecker
172
//***************************** CONSTRUCTOR *******************************************/
173
174 93f50b5e Cherian Mathew
175
176
	//for javassit only
177 9e3239f6 Andreas Müller
    @Deprecated
178
    protected DefinedTermBase(){};
179 ee91b8fd Andreas Kohlbecker
180 9e3239f6 Andreas Müller
    protected DefinedTermBase(TermType type) {
181
        super(type);
182 ad190552 Andreas Kohlbecker
    }
183 533cbb43 Andreas Müller
    public DefinedTermBase(TermType type, String description, String label, String labelAbbrev) {
184
        super(type, description, label, labelAbbrev);
185 ad190552 Andreas Kohlbecker
    }
186 9479da48 Andreas Müller
187 ad190552 Andreas Kohlbecker
188 ee91b8fd Andreas Kohlbecker
//********************** GETTER /SETTER *************************************
189
190
      @Override
191
      public String getIdInVocabulary() {
192
          return idInVocabulary;
193
      }
194
195
      @Override
196
      public void setIdInVocabulary(String idInVocabulary) {
197
          this.idInVocabulary = idInVocabulary;
198
      }
199
200
      @Override
201 221619fa Andreas Müller
      public T getKindOf(){
202 c7f65649 Andreas Kohlbecker
203
          if (this instanceof HibernateProxy) {
204
              HibernateProxy proxy = (HibernateProxy) this;
205
              LazyInitializer li = proxy.getHibernateLazyInitializer();
206
              return (T) ((T)li.getImplementation()).getKindOf();
207
          } else {
208
              return (T)DefinedTermBase.deproxy(this.kindOf, this.getClass());
209
          }
210 efa9828a Andreas Müller
      }
211
212
      public void setKindOf(T kindOf){
213
          this.kindOf = kindOf;
214
      }
215
216 42414138 Andreas Müller
217
      @Override
218 efa9828a Andreas Müller
      public Set<T> getGeneralizationOf(){
219
          return this.generalizationOf;
220
      }
221
222
      protected void setGeneralizationOf(Set<T> value) {
223
          this.generalizationOf = value;
224
      }
225
226
      public void addGeneralizationOf(T generalization) {
227
          generalization.setKindOf(this);
228
          this.generalizationOf.add(generalization);
229
      }
230
231 221619fa Andreas Müller
232 efa9828a Andreas Müller
      public void removeGeneralization(T generalization) {
233
          if(generalizationOf.contains(generalization)){
234
              generalization.setKindOf(null);
235
              this.generalizationOf.remove(generalization);
236
          }
237
      }
238
239 42414138 Andreas Müller
      @Override
240 efa9828a Andreas Müller
      public T getPartOf(){
241 c7f65649 Andreas Kohlbecker
          if (this instanceof HibernateProxy) {
242
              HibernateProxy proxy = (HibernateProxy) this;
243
              LazyInitializer li = proxy.getHibernateLazyInitializer();
244
              return (T) ((T)li.getImplementation()).getPartOf();
245
          } else {
246
              return (T)DefinedTermBase.deproxy(this.partOf, this.getClass());
247
          }
248 efa9828a Andreas Müller
      }
249
250 42414138 Andreas Müller
      /**
251
       * @see #getPartOf()
252
      */
253 efa9828a Andreas Müller
      public void setPartOf(T partOf){
254
          this.partOf = partOf;
255
      }
256 589ecf52 Andreas Müller
      
257
      
258
    //TODO Comparable implemented only for fixing failing JAXB imports, may be removed when this is fixed
259
  	@Override
260
  	@Deprecated //for inner use only
261
  	public int compareTo(T other) {
262
		return ((Integer)this.getId()).compareTo(other.getId());
263
	}
264
265
	@Override
266 efa9828a Andreas Müller
      public Set<T> getIncludes(){
267
          return this.includes;
268
      }
269
270 42414138 Andreas Müller
      /**
271
       * @see #getIncludes()
272
      */
273 efa9828a Andreas Müller
      protected void setIncludes(Set<T> includes) {
274
          this.includes = includes;
275
      }
276
277 42414138 Andreas Müller
      /**
278
       * @see #getIncludes()
279 efa9828a Andreas Müller
       */
280
      public void addIncludes(T includes) {
281
          includes.setPartOf(this);
282
          this.includes.add(includes);
283
      }
284 ee91b8fd Andreas Kohlbecker
285 42414138 Andreas Müller
      /**
286
       * @see #getIncludes()
287 efa9828a Andreas Müller
       */
288
      public void removeIncludes(T includes) {
289
          if(this.includes.contains(includes)) {
290
              includes.setPartOf(null);
291
              this.includes.remove(includes);
292
          }
293
      }
294
295 42414138 Andreas Müller
      @Override
296 efa9828a Andreas Müller
      public Set<Media> getMedia(){
297
          return this.media;
298
      }
299
300
      public void addMedia(Media media) {
301
          this.media.add(media);
302
      }
303
      public void removeMedia(Media media) {
304
          this.media.remove(media);
305
      }
306
307
      /**
308
       * @return
309
       */
310
      public TermVocabulary<T> getVocabulary() {
311
          return this.vocabulary;
312
      }
313
314
      //for bedirectional use only, use vocabulary.addTerm instead
315
      /**
316
       * @param newVocabulary
317
       */
318
      protected void setVocabulary(TermVocabulary<T> newVocabulary) {
319
          this.vocabulary = newVocabulary;
320 42414138 Andreas Müller
    }
321 efa9828a Andreas Müller
322
//******************************* METHODS ******************************************************/
323 ee91b8fd Andreas Kohlbecker
324
325
      @Override
326
      public boolean isKindOf(T ancestor) {
327
          if (kindOf == null || ancestor == null){
328
            return false;
329
        }else if (kindOf.equals(ancestor)){
330
            return true;
331
        }else{
332
            return kindOf.isKindOf(ancestor);
333
        }
334
      }
335
336
      @Override
337
      public Set<T> getGeneralizationOf(boolean recursive) {
338
          Set<T> result = new HashSet<T>();
339
        result.addAll(this.generalizationOf);
340
        if (recursive){
341
            for (T child : this.generalizationOf){
342
                result.addAll(child.getGeneralizationOf());
343
            }
344
        }
345
        return result;
346
      }
347
348
349
350 ad190552 Andreas Kohlbecker
    public abstract void resetTerms();
351
352
    protected abstract void setDefaultTerms(TermVocabulary<T> termVocabulary);
353
354
355 9e3239f6 Andreas Müller
    @Override
356
    public T readCsvLine(Class<T> termClass, List<String> csvLine, Map<UUID,DefinedTermBase> terms, boolean abbrevAsId) {
357 ad190552 Andreas Kohlbecker
        try {
358 533cbb43 Andreas Müller
            T newInstance = getInstance(termClass);
359 14149f73 Andreas Müller
            readCsvLine(newInstance, csvLine, Language.CSV_LANGUAGE(), abbrevAsId);
360
            readIsPartOf(newInstance, csvLine, terms);
361
            return newInstance;
362 ad190552 Andreas Kohlbecker
        } catch (Exception e) {
363
            logger.error(e);
364
            for(StackTraceElement ste : e.getStackTrace()) {
365
                logger.error(ste);
366
            }
367 14149f73 Andreas Müller
            throw new RuntimeException(e);
368 ad190552 Andreas Kohlbecker
        }
369
    }
370 ee91b8fd Andreas Kohlbecker
371
    protected static <TERM extends DefinedTermBase> TERM readCsvLine(TERM newInstance, List<String> csvLine, Language lang, boolean abbrevAsId) {
372 54ccc2d6 Andreas Müller
        newInstance.setUuid(UUID.fromString(csvLine.get(0)));
373
        newInstance.setUri( URI.create(csvLine.get(1)));
374
        String label = csvLine.get(2).trim();
375
        String description = csvLine.get(3);
376
        String abbreviatedLabel = csvLine.get(4);
377
        if (StringUtils.isBlank(abbreviatedLabel)){
378 ee91b8fd Andreas Kohlbecker
            abbreviatedLabel = null;
379 54ccc2d6 Andreas Müller
        }
380
        if (abbrevAsId){
381 ee91b8fd Andreas Kohlbecker
            newInstance.setIdInVocabulary(abbreviatedLabel);  //new in 3.3
382 54ccc2d6 Andreas Müller
        }
383
        newInstance.addRepresentation(Representation.NewInstance(description, label, abbreviatedLabel, lang) );
384 ee91b8fd Andreas Kohlbecker
385 54ccc2d6 Andreas Müller
        return newInstance;
386
    }
387 ee91b8fd Andreas Kohlbecker
388 14149f73 Andreas Müller
    protected void readIsPartOf(T newInstance, List<String> csvLine, Map<UUID, DefinedTermBase> terms){
389
        int index = partOfCsvLineIndex();
390 ee91b8fd Andreas Kohlbecker
         if (index != -1){
391
            String partOfString = csvLine.get(index);
392
             if(StringUtils.isNotBlank(partOfString)) {
393
                 UUID partOfUuid = UUID.fromString(partOfString);
394
                 DefinedTermBase partOf = terms.get(partOfUuid);
395
                 partOf.addIncludes(newInstance);
396
             }
397
         }
398
399
    }
400
401
    /**
402
     * Get the
403
     * @return
404
     */
405
    protected int partOfCsvLineIndex() {
406
        return -1;
407
    }
408
409
410
    private  <T extends DefinedTermBase> T getInstance(Class<? extends DefinedTermBase> termClass) {
411
        try {
412
            Constructor<T> c = ((Class<T>)termClass).getDeclaredConstructor();
413
            c.setAccessible(true);
414
            T termInstance = c.newInstance();
415
            return termInstance;
416
        } catch (Exception e) {
417
            throw new RuntimeException(e);
418
        }
419 14149f73 Andreas Müller
    }
420
421 639679e0 Andreas Müller
    @Override
422 ad190552 Andreas Kohlbecker
    public void writeCsvLine(CSVWriter writer, T term) {
423
        String [] line = new String[4];
424
        line[0] = term.getUuid().toString();
425
        line[1] = term.getUri().toString();
426
        line[2] = term.getLabel();
427
        line[3] = term.getDescription();
428
        writer.writeNext(line);
429
    }
430
431
    @Transient
432
    public T getByUuid(UUID uuid){
433
        return this.vocabulary.findTermByUuid(uuid);
434
    }
435
436
437 2e8b8e21 Katja Luther
//*********************** CLONE ********************************************************/
438 ad190552 Andreas Kohlbecker
439
    /**
440
     * Clones <i>this</i> DefinedTermBase. This is a shortcut that enables to create
441
     * a new instance that differs only slightly from <i>this</i> defined term base by
442
     * modifying only some of the attributes.
443
     *
444
     * @see eu.etaxonomy.cdm.model.common.TermBase#clone()
445
     * @see java.lang.Object#clone()
446
     */
447
    @Override
448
    public Object clone() {
449
        DefinedTermBase result;
450
        try {
451
            result = (DefinedTermBase) super.clone();
452
        }catch (CloneNotSupportedException e) {
453
            logger.warn("Object does not implement cloneable");
454
            e.printStackTrace();
455
            return null;
456
        }
457
458
        result.generalizationOf = new HashSet<DefinedTermBase>();
459
        for (DefinedTermBase generalizationOf : this.generalizationOf){
460 ee91b8fd Andreas Kohlbecker
            result.generalizationOf.add(generalizationOf.clone());
461 ad190552 Andreas Kohlbecker
        }
462
463
        result.includes = new HashSet<DefinedTermBase>();
464
465
        for (DefinedTermBase include: this.includes){
466 ee91b8fd Andreas Kohlbecker
            result.includes.add(include.clone());
467 ad190552 Andreas Kohlbecker
        }
468
469
        result.media = new HashSet<Media>();
470
471
        for (Media media: this.media){
472
            result.addMedia(media);
473
        }
474
475
        return result;
476
    }
477 efa9828a Andreas Müller
478 93f50b5e Cherian Mathew
    // Currently the CDM Caching mechanism is only used for caching terms
479
    private static ICdmCacher cacher;
480
    
481
    /**
482
     * Gets the CDM cacher object
483
     *      
484
     * @return the CDM cacher object
485
     */
486
    public static ICdmCacher getCacher() {
487
		return cacher;
488
	}
489
490
	/**
491
	 * Sets the CDM cacher object
492
	 * 
493
	 * @param cacher the CDM cacher object
494
	 */
495
	public static void setCacher(ICdmCacher cacher) {
496
		DefinedTermBase.cacher = cacher;
497
	}
498 9479da48 Andreas Müller
}