Project

General

Profile

Download (15.3 KB) Statistics
| Branch: | Tag: | Revision:
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 java.lang.reflect.Constructor;
13
import java.net.URI;
14
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

    
20
import javax.persistence.Entity;
21
import javax.persistence.FetchType;
22
import javax.persistence.Inheritance;
23
import javax.persistence.InheritanceType;
24
import javax.persistence.ManyToMany;
25
import javax.persistence.ManyToOne;
26
import javax.persistence.OneToMany;
27
import javax.persistence.Transient;
28
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
import javax.xml.bind.annotation.XmlIDREF;
33
import javax.xml.bind.annotation.XmlRootElement;
34
import javax.xml.bind.annotation.XmlSchemaType;
35
import javax.xml.bind.annotation.XmlSeeAlso;
36
import javax.xml.bind.annotation.XmlTransient;
37
import javax.xml.bind.annotation.XmlType;
38

    
39
import org.apache.log4j.Logger;
40
import org.codehaus.plexus.util.StringUtils;
41
import org.hibernate.annotations.Cascade;
42
import org.hibernate.annotations.CascadeType;
43
import org.hibernate.envers.Audited;
44
import org.hibernate.proxy.HibernateProxy;
45
import org.hibernate.proxy.LazyInitializer;
46
import org.hibernate.search.annotations.ClassBridge;
47
import org.hibernate.validator.constraints.Length;
48

    
49
import au.com.bytecode.opencsv.CSVWriter;
50
import eu.etaxonomy.cdm.hibernate.search.DefinedTermBaseClassBridge;
51
import eu.etaxonomy.cdm.model.ICdmCacher;
52
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
import eu.etaxonomy.cdm.model.media.Media;
59
import eu.etaxonomy.cdm.model.media.RightsType;
60
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
61
import eu.etaxonomy.cdm.model.occurrence.DerivationEventType;
62
import eu.etaxonomy.cdm.model.occurrence.PreservationMethod;
63

    
64

    
65
/**
66
 * workaround for enumerations, base type according to TDWG.  For linear ordering
67
 * 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
@XmlAccessorType(XmlAccessType.FIELD)
73
@XmlType(name = "DefinedTermBase", propOrder = {
74
    "media",
75
    "vocabulary",
76
    "idInVocabulary"
77
})
78
@XmlRootElement(name = "DefinedTermBase")
79
@XmlSeeAlso({
80
    AnnotationType.class,
81
    DerivationEventType.class,
82
    DefinedTerm.class,
83
    ExtensionType.class,
84
    Feature.class,
85
    Language.class,
86
    MarkerType.class,
87
    MeasurementUnit.class,
88
    NamedAreaType.class,
89
    NomenclaturalCode.class,
90
    PreservationMethod.class,
91
    ReferenceSystem.class,
92
    RightsType.class,
93
    StatisticalMeasure.class,
94
    TextFormat.class
95
})
96
@Entity
97
@Audited
98
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
99
@ClassBridge(impl=DefinedTermBaseClassBridge.class)
100
//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
    private static final long serialVersionUID = 2931811562248571531L;
103
    private static final Logger logger = Logger.getLogger(DefinedTermBase.class);
104

    
105
//	@XmlElement(name = "KindOf")
106
//    @XmlIDREF
107
//    @XmlSchemaType(name = "IDREF")
108
    @XmlTransient
109
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = DefinedTermBase.class)
110
    @Cascade(CascadeType.SAVE_UPDATE)
111
    private T kindOf;
112
    /**
113
     * FIXME - Hibernate returns this as a collection of CGLibProxy$$DefinedTermBase objects
114
     * 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
//	@XmlElementWrapper(name = "Generalizations")
118
//	@XmlElement(name = "GeneralizationOf")
119
//    @XmlIDREF
120
//    @XmlSchemaType(name = "IDREF")
121
    @XmlTransient
122
    @OneToMany(fetch=FetchType.LAZY, mappedBy = "kindOf", targetEntity = DefinedTermBase.class)
123
    @Cascade({CascadeType.SAVE_UPDATE})
124
    private Set<T> generalizationOf = new HashSet<T>();
125

    
126
//	@XmlElement(name = "PartOf")
127
//	@XmlIDREF
128
//  @XmlSchemaType(name = "IDREF")
129
    @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
//	@XmlElementWrapper(name = "Includes")
140
//	@XmlElement(name = "Include")
141
//	@XmlIDREF
142
//    @XmlSchemaType(name = "IDREF")
143
    @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
    @XmlIDREF
151
    @XmlSchemaType(name = "IDREF")
152
    @ManyToMany(fetch = FetchType.LAZY)
153
    @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

    
163
  //the unique iedentifier/name this term uses in its given vocabulary #3479
164
   //open issues: is null allowed? If not, implement unique constraint
165

    
166
    @XmlElement(name = "idInVocabulary")
167
    @Length(max=255)
168
    private String idInVocabulary;  //the unique identifier/name this term uses in its given vocabulary #3479
169
    
170

    
171

    
172
//***************************** CONSTRUCTOR *******************************************/
173

    
174

    
175

    
176
	//for javassit only
177
    @Deprecated
178
    protected DefinedTermBase(){};
179

    
180
    protected DefinedTermBase(TermType type) {
181
        super(type);
182
    }
183
    public DefinedTermBase(TermType type, String description, String label, String labelAbbrev) {
184
        super(type, description, label, labelAbbrev);
185
    }
186

    
187

    
188
//********************** 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
      public T getKindOf(){
202

    
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
      }
211

    
212
      public void setKindOf(T kindOf){
213
          this.kindOf = kindOf;
214
      }
215

    
216

    
217
      @Override
218
      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

    
232
      public void removeGeneralization(T generalization) {
233
          if(generalizationOf.contains(generalization)){
234
              generalization.setKindOf(null);
235
              this.generalizationOf.remove(generalization);
236
          }
237
      }
238

    
239
      @Override
240
      public T getPartOf(){
241
          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
      }
249

    
250
      /**
251
       * @see #getPartOf()
252
      */
253
      public void setPartOf(T partOf){
254
          this.partOf = partOf;
255
      }
256
      
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
      public Set<T> getIncludes(){
267
          return this.includes;
268
      }
269

    
270
      /**
271
       * @see #getIncludes()
272
      */
273
      protected void setIncludes(Set<T> includes) {
274
          this.includes = includes;
275
      }
276

    
277
      /**
278
       * @see #getIncludes()
279
       */
280
      public void addIncludes(T includes) {
281
          includes.setPartOf(this);
282
          this.includes.add(includes);
283
      }
284

    
285
      /**
286
       * @see #getIncludes()
287
       */
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
      @Override
296
      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
    }
321

    
322
//******************************* METHODS ******************************************************/
323

    
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
    public abstract void resetTerms();
351

    
352
    protected abstract void setDefaultTerms(TermVocabulary<T> termVocabulary);
353

    
354

    
355
    @Override
356
    public T readCsvLine(Class<T> termClass, List<String> csvLine, Map<UUID,DefinedTermBase> terms, boolean abbrevAsId) {
357
        try {
358
            T newInstance = getInstance(termClass);
359
            readCsvLine(newInstance, csvLine, Language.CSV_LANGUAGE(), abbrevAsId);
360
            readIsPartOf(newInstance, csvLine, terms);
361
            return newInstance;
362
        } catch (Exception e) {
363
            logger.error(e);
364
            for(StackTraceElement ste : e.getStackTrace()) {
365
                logger.error(ste);
366
            }
367
            throw new RuntimeException(e);
368
        }
369
    }
370

    
371
    protected static <TERM extends DefinedTermBase> TERM readCsvLine(TERM newInstance, List<String> csvLine, Language lang, boolean abbrevAsId) {
372
        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
            abbreviatedLabel = null;
379
        }
380
        if (abbrevAsId){
381
            newInstance.setIdInVocabulary(abbreviatedLabel);  //new in 3.3
382
        }
383
        newInstance.addRepresentation(Representation.NewInstance(description, label, abbreviatedLabel, lang) );
384

    
385
        return newInstance;
386
    }
387

    
388
    protected void readIsPartOf(T newInstance, List<String> csvLine, Map<UUID, DefinedTermBase> terms){
389
        int index = partOfCsvLineIndex();
390
         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
    }
420

    
421
    @Override
422
    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
//*********************** CLONE ********************************************************/
438

    
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
            result.generalizationOf.add(generalizationOf.clone());
461
        }
462

    
463
        result.includes = new HashSet<DefinedTermBase>();
464

    
465
        for (DefinedTermBase include: this.includes){
466
            result.includes.add(include.clone());
467
        }
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

    
478
    // 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
}
(8-8/70)