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 d6fcdafc Andreas M��ller
    //TODO Val #3379, #4245
169
//  @NullOrNotEmpty
170 ed0e00d0 Andreas Müller
    private String idInVocabulary;  //the unique identifier/name this term uses in its given vocabulary #3479
171 d6fcdafc Andreas M��ller
172 93f50b5e Cherian Mathew
173 ad190552 Andreas Kohlbecker
174
//***************************** CONSTRUCTOR *******************************************/
175
176 93f50b5e Cherian Mathew
177
178
	//for javassit only
179 9e3239f6 Andreas Müller
    @Deprecated
180
    protected DefinedTermBase(){};
181 ee91b8fd Andreas Kohlbecker
182 9e3239f6 Andreas Müller
    protected DefinedTermBase(TermType type) {
183
        super(type);
184 ad190552 Andreas Kohlbecker
    }
185 533cbb43 Andreas Müller
    public DefinedTermBase(TermType type, String description, String label, String labelAbbrev) {
186
        super(type, description, label, labelAbbrev);
187 ad190552 Andreas Kohlbecker
    }
188 9479da48 Andreas Müller
189 ad190552 Andreas Kohlbecker
190 ee91b8fd Andreas Kohlbecker
//********************** GETTER /SETTER *************************************
191
192
      @Override
193
      public String getIdInVocabulary() {
194
          return idInVocabulary;
195
      }
196
197
      @Override
198
      public void setIdInVocabulary(String idInVocabulary) {
199 d6fcdafc Andreas M��ller
200 85147fc2 Katja Luther
          this.idInVocabulary = StringUtils.isBlank(idInVocabulary)? null : idInVocabulary;
201 ee91b8fd Andreas Kohlbecker
      }
202
203
      @Override
204 221619fa Andreas Müller
      public T getKindOf(){
205 c7f65649 Andreas Kohlbecker
206
          if (this instanceof HibernateProxy) {
207
              HibernateProxy proxy = (HibernateProxy) this;
208
              LazyInitializer li = proxy.getHibernateLazyInitializer();
209
              return (T) ((T)li.getImplementation()).getKindOf();
210
          } else {
211
              return (T)DefinedTermBase.deproxy(this.kindOf, this.getClass());
212
          }
213 efa9828a Andreas Müller
      }
214
215
      public void setKindOf(T kindOf){
216
          this.kindOf = kindOf;
217
      }
218
219 42414138 Andreas Müller
220
      @Override
221 efa9828a Andreas Müller
      public Set<T> getGeneralizationOf(){
222
          return this.generalizationOf;
223
      }
224
225
      protected void setGeneralizationOf(Set<T> value) {
226
          this.generalizationOf = value;
227
      }
228
229
      public void addGeneralizationOf(T generalization) {
230
          generalization.setKindOf(this);
231
          this.generalizationOf.add(generalization);
232
      }
233
234 221619fa Andreas Müller
235 efa9828a Andreas Müller
      public void removeGeneralization(T generalization) {
236
          if(generalizationOf.contains(generalization)){
237
              generalization.setKindOf(null);
238
              this.generalizationOf.remove(generalization);
239
          }
240
      }
241
242 42414138 Andreas Müller
      @Override
243 efa9828a Andreas Müller
      public T getPartOf(){
244 c7f65649 Andreas Kohlbecker
          if (this instanceof HibernateProxy) {
245
              HibernateProxy proxy = (HibernateProxy) this;
246
              LazyInitializer li = proxy.getHibernateLazyInitializer();
247
              return (T) ((T)li.getImplementation()).getPartOf();
248
          } else {
249
              return (T)DefinedTermBase.deproxy(this.partOf, this.getClass());
250
          }
251 efa9828a Andreas Müller
      }
252
253 42414138 Andreas Müller
      /**
254
       * @see #getPartOf()
255
      */
256 efa9828a Andreas Müller
      public void setPartOf(T partOf){
257
          this.partOf = partOf;
258
      }
259 d6fcdafc Andreas M��ller
260
261 589ecf52 Andreas Müller
    //TODO Comparable implemented only for fixing failing JAXB imports, may be removed when this is fixed
262
  	@Override
263
  	@Deprecated //for inner use only
264
  	public int compareTo(T other) {
265
		return ((Integer)this.getId()).compareTo(other.getId());
266
	}
267
268
	@Override
269 efa9828a Andreas Müller
      public Set<T> getIncludes(){
270
          return this.includes;
271
      }
272
273 42414138 Andreas Müller
      /**
274
       * @see #getIncludes()
275
      */
276 efa9828a Andreas Müller
      protected void setIncludes(Set<T> includes) {
277
          this.includes = includes;
278
      }
279
280 42414138 Andreas Müller
      /**
281
       * @see #getIncludes()
282 efa9828a Andreas Müller
       */
283
      public void addIncludes(T includes) {
284
          includes.setPartOf(this);
285
          this.includes.add(includes);
286
      }
287 ee91b8fd Andreas Kohlbecker
288 42414138 Andreas Müller
      /**
289
       * @see #getIncludes()
290 efa9828a Andreas Müller
       */
291
      public void removeIncludes(T includes) {
292
          if(this.includes.contains(includes)) {
293
              includes.setPartOf(null);
294
              this.includes.remove(includes);
295
          }
296
      }
297
298 42414138 Andreas Müller
      @Override
299 efa9828a Andreas Müller
      public Set<Media> getMedia(){
300
          return this.media;
301
      }
302
303
      public void addMedia(Media media) {
304
          this.media.add(media);
305
      }
306
      public void removeMedia(Media media) {
307
          this.media.remove(media);
308
      }
309
310
      /**
311
       * @return
312
       */
313
      public TermVocabulary<T> getVocabulary() {
314
          return this.vocabulary;
315
      }
316
317
      //for bedirectional use only, use vocabulary.addTerm instead
318
      /**
319
       * @param newVocabulary
320
       */
321
      protected void setVocabulary(TermVocabulary<T> newVocabulary) {
322
          this.vocabulary = newVocabulary;
323 42414138 Andreas Müller
    }
324 efa9828a Andreas Müller
325
//******************************* METHODS ******************************************************/
326 ee91b8fd Andreas Kohlbecker
327
328
      @Override
329
      public boolean isKindOf(T ancestor) {
330
          if (kindOf == null || ancestor == null){
331
            return false;
332
        }else if (kindOf.equals(ancestor)){
333
            return true;
334
        }else{
335
            return kindOf.isKindOf(ancestor);
336
        }
337
      }
338
339
      @Override
340
      public Set<T> getGeneralizationOf(boolean recursive) {
341
          Set<T> result = new HashSet<T>();
342
        result.addAll(this.generalizationOf);
343
        if (recursive){
344
            for (T child : this.generalizationOf){
345
                result.addAll(child.getGeneralizationOf());
346
            }
347
        }
348
        return result;
349
      }
350
351
352
353 ad190552 Andreas Kohlbecker
    public abstract void resetTerms();
354
355
    protected abstract void setDefaultTerms(TermVocabulary<T> termVocabulary);
356
357
358 9e3239f6 Andreas Müller
    @Override
359
    public T readCsvLine(Class<T> termClass, List<String> csvLine, Map<UUID,DefinedTermBase> terms, boolean abbrevAsId) {
360 ad190552 Andreas Kohlbecker
        try {
361 533cbb43 Andreas Müller
            T newInstance = getInstance(termClass);
362 14149f73 Andreas Müller
            readCsvLine(newInstance, csvLine, Language.CSV_LANGUAGE(), abbrevAsId);
363
            readIsPartOf(newInstance, csvLine, terms);
364
            return newInstance;
365 ad190552 Andreas Kohlbecker
        } catch (Exception e) {
366
            logger.error(e);
367
            for(StackTraceElement ste : e.getStackTrace()) {
368
                logger.error(ste);
369
            }
370 14149f73 Andreas Müller
            throw new RuntimeException(e);
371 ad190552 Andreas Kohlbecker
        }
372
    }
373 ee91b8fd Andreas Kohlbecker
374
    protected static <TERM extends DefinedTermBase> TERM readCsvLine(TERM newInstance, List<String> csvLine, Language lang, boolean abbrevAsId) {
375 54ccc2d6 Andreas Müller
        newInstance.setUuid(UUID.fromString(csvLine.get(0)));
376
        newInstance.setUri( URI.create(csvLine.get(1)));
377
        String label = csvLine.get(2).trim();
378
        String description = csvLine.get(3);
379
        String abbreviatedLabel = csvLine.get(4);
380
        if (StringUtils.isBlank(abbreviatedLabel)){
381 ee91b8fd Andreas Kohlbecker
            abbreviatedLabel = null;
382 54ccc2d6 Andreas Müller
        }
383
        if (abbrevAsId){
384 ee91b8fd Andreas Kohlbecker
            newInstance.setIdInVocabulary(abbreviatedLabel);  //new in 3.3
385 54ccc2d6 Andreas Müller
        }
386
        newInstance.addRepresentation(Representation.NewInstance(description, label, abbreviatedLabel, lang) );
387 ee91b8fd Andreas Kohlbecker
388 54ccc2d6 Andreas Müller
        return newInstance;
389
    }
390 ee91b8fd Andreas Kohlbecker
391 14149f73 Andreas Müller
    protected void readIsPartOf(T newInstance, List<String> csvLine, Map<UUID, DefinedTermBase> terms){
392
        int index = partOfCsvLineIndex();
393 ee91b8fd Andreas Kohlbecker
         if (index != -1){
394
            String partOfString = csvLine.get(index);
395
             if(StringUtils.isNotBlank(partOfString)) {
396
                 UUID partOfUuid = UUID.fromString(partOfString);
397
                 DefinedTermBase partOf = terms.get(partOfUuid);
398
                 partOf.addIncludes(newInstance);
399
             }
400
         }
401
402
    }
403
404
    /**
405
     * Get the
406
     * @return
407
     */
408
    protected int partOfCsvLineIndex() {
409
        return -1;
410
    }
411
412
413
    private  <T extends DefinedTermBase> T getInstance(Class<? extends DefinedTermBase> termClass) {
414
        try {
415
            Constructor<T> c = ((Class<T>)termClass).getDeclaredConstructor();
416
            c.setAccessible(true);
417
            T termInstance = c.newInstance();
418
            return termInstance;
419
        } catch (Exception e) {
420
            throw new RuntimeException(e);
421
        }
422 14149f73 Andreas Müller
    }
423
424 639679e0 Andreas Müller
    @Override
425 ad190552 Andreas Kohlbecker
    public void writeCsvLine(CSVWriter writer, T term) {
426
        String [] line = new String[4];
427
        line[0] = term.getUuid().toString();
428
        line[1] = term.getUri().toString();
429
        line[2] = term.getLabel();
430
        line[3] = term.getDescription();
431
        writer.writeNext(line);
432
    }
433
434
    @Transient
435
    public T getByUuid(UUID uuid){
436
        return this.vocabulary.findTermByUuid(uuid);
437
    }
438
439
440 2e8b8e21 Katja Luther
//*********************** CLONE ********************************************************/
441 ad190552 Andreas Kohlbecker
442
    /**
443
     * Clones <i>this</i> DefinedTermBase. This is a shortcut that enables to create
444
     * a new instance that differs only slightly from <i>this</i> defined term base by
445
     * modifying only some of the attributes.
446
     *
447
     * @see eu.etaxonomy.cdm.model.common.TermBase#clone()
448
     * @see java.lang.Object#clone()
449
     */
450
    @Override
451
    public Object clone() {
452
        DefinedTermBase result;
453
        try {
454
            result = (DefinedTermBase) super.clone();
455
        }catch (CloneNotSupportedException e) {
456
            logger.warn("Object does not implement cloneable");
457
            e.printStackTrace();
458
            return null;
459
        }
460
461
        result.generalizationOf = new HashSet<DefinedTermBase>();
462
        for (DefinedTermBase generalizationOf : this.generalizationOf){
463 ee91b8fd Andreas Kohlbecker
            result.generalizationOf.add(generalizationOf.clone());
464 ad190552 Andreas Kohlbecker
        }
465
466
        result.includes = new HashSet<DefinedTermBase>();
467
468
        for (DefinedTermBase include: this.includes){
469 ee91b8fd Andreas Kohlbecker
            result.includes.add(include.clone());
470 ad190552 Andreas Kohlbecker
        }
471
472
        result.media = new HashSet<Media>();
473
474
        for (Media media: this.media){
475
            result.addMedia(media);
476
        }
477
478
        return result;
479
    }
480 efa9828a Andreas Müller
481 93f50b5e Cherian Mathew
    // Currently the CDM Caching mechanism is only used for caching terms
482
    private static ICdmCacher cacher;
483 d6fcdafc Andreas M��ller
484 93f50b5e Cherian Mathew
    /**
485
     * Gets the CDM cacher object
486 d6fcdafc Andreas M��ller
     *
487 93f50b5e Cherian Mathew
     * @return the CDM cacher object
488
     */
489
    public static ICdmCacher getCacher() {
490
		return cacher;
491
	}
492
493
	/**
494
	 * Sets the CDM cacher object
495 d6fcdafc Andreas M��ller
	 *
496 93f50b5e Cherian Mathew
	 * @param cacher the CDM cacher object
497
	 */
498
	public static void setCacher(ICdmCacher cacher) {
499
		DefinedTermBase.cacher = cacher;
500
	}
501 9479da48 Andreas Müller
}