Project

General

Profile

Download (14.9 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
public abstract class DefinedTermBase<T extends DefinedTermBase> extends TermBase implements ILoadableTerm<T>, IDefinedTerm<T> {
101
    private static final long serialVersionUID = 2931811562248571531L;
102
    private static final Logger logger = Logger.getLogger(DefinedTermBase.class);
103

    
104
//	@XmlElement(name = "KindOf")
105
//    @XmlIDREF
106
//    @XmlSchemaType(name = "IDREF")
107
    @XmlTransient
108
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = DefinedTermBase.class)
109
    @Cascade(CascadeType.SAVE_UPDATE)
110
    private T kindOf;
111
    /**
112
     * FIXME - Hibernate returns this as a collection of CGLibProxy$$DefinedTermBase objects
113
     * which can't be cast to instances of T - can we explicitly initialize these terms using
114
     * Hibernate.initialize(), does this imply a distinct load, and find methods in the dao?
115
     */
116
//	@XmlElementWrapper(name = "Generalizations")
117
//	@XmlElement(name = "GeneralizationOf")
118
//    @XmlIDREF
119
//    @XmlSchemaType(name = "IDREF")
120
    @XmlTransient
121
    @OneToMany(fetch=FetchType.LAZY, mappedBy = "kindOf", targetEntity = DefinedTermBase.class)
122
    @Cascade({CascadeType.SAVE_UPDATE})
123
    private Set<T> generalizationOf = new HashSet<T>();
124

    
125
//	@XmlElement(name = "PartOf")
126
//	@XmlIDREF
127
//  @XmlSchemaType(name = "IDREF")
128
    @XmlTransient
129
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = DefinedTermBase.class)
130
    @Cascade(CascadeType.SAVE_UPDATE)
131
    protected T partOf;
132

    
133
    /**
134
     * FIXME - Hibernate retuns this as a collection of CGLibProxy$$DefinedTermBase objects
135
     * which can't be cast to instances of T - can we explicitly initialize these terms using
136
     * Hibernate.initialize(), does this imply a distinct load, and find methods in the dao?
137
     */
138
//	@XmlElementWrapper(name = "Includes")
139
//	@XmlElement(name = "Include")
140
//	@XmlIDREF
141
//    @XmlSchemaType(name = "IDREF")
142
    @XmlTransient
143
    @OneToMany(fetch=FetchType.LAZY, mappedBy = "partOf", targetEntity = DefinedTermBase.class)
144
    @Cascade({CascadeType.SAVE_UPDATE})
145
    private Set<T> includes = new HashSet<T>();
146

    
147
    @XmlElementWrapper(name = "Media")
148
    @XmlElement(name = "Medium")
149
    @XmlIDREF
150
    @XmlSchemaType(name = "IDREF")
151
    @ManyToMany(fetch = FetchType.LAZY)
152
    @Cascade({CascadeType.SAVE_UPDATE})
153
    private Set<Media> media = new HashSet<Media>();
154

    
155
    @XmlElement(name = "TermVocabulary")
156
    @XmlIDREF
157
    @XmlSchemaType(name = "IDREF")
158
    @ManyToOne(fetch=FetchType.LAZY)
159
    @Cascade(CascadeType.SAVE_UPDATE)
160
    protected TermVocabulary<T> vocabulary;
161

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

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

    
170

    
171
//***************************** CONSTRUCTOR *******************************************/
172

    
173

    
174

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

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

    
186

    
187
//********************** GETTER /SETTER *************************************
188

    
189
      @Override
190
      public String getIdInVocabulary() {
191
          return idInVocabulary;
192
      }
193

    
194
      @Override
195
      public void setIdInVocabulary(String idInVocabulary) {
196
          this.idInVocabulary = idInVocabulary;
197
      }
198

    
199
      @Override
200
      public T getKindOf(){
201

    
202
          if (this instanceof HibernateProxy) {
203
              HibernateProxy proxy = (HibernateProxy) this;
204
              LazyInitializer li = proxy.getHibernateLazyInitializer();
205
              return (T) ((T)li.getImplementation()).getKindOf();
206
          } else {
207
              return (T)DefinedTermBase.deproxy(this.kindOf, this.getClass());
208
          }
209
      }
210

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

    
215

    
216
      @Override
217
      public Set<T> getGeneralizationOf(){
218
          return this.generalizationOf;
219
      }
220

    
221
      protected void setGeneralizationOf(Set<T> value) {
222
          this.generalizationOf = value;
223
      }
224

    
225
      public void addGeneralizationOf(T generalization) {
226
          generalization.setKindOf(this);
227
          this.generalizationOf.add(generalization);
228
      }
229

    
230

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

    
238
      @Override
239
      public T getPartOf(){
240
          if (this instanceof HibernateProxy) {
241
              HibernateProxy proxy = (HibernateProxy) this;
242
              LazyInitializer li = proxy.getHibernateLazyInitializer();
243
              return (T) ((T)li.getImplementation()).getPartOf();
244
          } else {
245
              return (T)DefinedTermBase.deproxy(this.partOf, this.getClass());
246
          }
247
      }
248

    
249
      /**
250
       * @see #getPartOf()
251
      */
252
      public void setPartOf(T partOf){
253
          this.partOf = partOf;
254
      }
255

    
256
      @Override
257
      public Set<T> getIncludes(){
258
          return this.includes;
259
      }
260

    
261
      /**
262
       * @see #getIncludes()
263
      */
264
      protected void setIncludes(Set<T> includes) {
265
          this.includes = includes;
266
      }
267

    
268
      /**
269
       * @see #getIncludes()
270
       */
271
      public void addIncludes(T includes) {
272
          includes.setPartOf(this);
273
          this.includes.add(includes);
274
      }
275

    
276
      /**
277
       * @see #getIncludes()
278
       */
279
      public void removeIncludes(T includes) {
280
          if(this.includes.contains(includes)) {
281
              includes.setPartOf(null);
282
              this.includes.remove(includes);
283
          }
284
      }
285

    
286
      @Override
287
      public Set<Media> getMedia(){
288
          return this.media;
289
      }
290

    
291
      public void addMedia(Media media) {
292
          this.media.add(media);
293
      }
294
      public void removeMedia(Media media) {
295
          this.media.remove(media);
296
      }
297

    
298
      /**
299
       * @return
300
       */
301
      public TermVocabulary<T> getVocabulary() {
302
          return this.vocabulary;
303
      }
304

    
305
      //for bedirectional use only, use vocabulary.addTerm instead
306
      /**
307
       * @param newVocabulary
308
       */
309
      protected void setVocabulary(TermVocabulary<T> newVocabulary) {
310
          this.vocabulary = newVocabulary;
311
    }
312

    
313
//******************************* METHODS ******************************************************/
314

    
315

    
316
      @Override
317
      public boolean isKindOf(T ancestor) {
318
          if (kindOf == null || ancestor == null){
319
            return false;
320
        }else if (kindOf.equals(ancestor)){
321
            return true;
322
        }else{
323
            return kindOf.isKindOf(ancestor);
324
        }
325
      }
326

    
327
      @Override
328
      public Set<T> getGeneralizationOf(boolean recursive) {
329
          Set<T> result = new HashSet<T>();
330
        result.addAll(this.generalizationOf);
331
        if (recursive){
332
            for (T child : this.generalizationOf){
333
                result.addAll(child.getGeneralizationOf());
334
            }
335
        }
336
        return result;
337
      }
338

    
339

    
340

    
341
    public abstract void resetTerms();
342

    
343
    protected abstract void setDefaultTerms(TermVocabulary<T> termVocabulary);
344

    
345

    
346
    @Override
347
    public T readCsvLine(Class<T> termClass, List<String> csvLine, Map<UUID,DefinedTermBase> terms, boolean abbrevAsId) {
348
        try {
349
            T newInstance = getInstance(termClass);
350
            readCsvLine(newInstance, csvLine, Language.CSV_LANGUAGE(), abbrevAsId);
351
            readIsPartOf(newInstance, csvLine, terms);
352
            return newInstance;
353
        } catch (Exception e) {
354
            logger.error(e);
355
            for(StackTraceElement ste : e.getStackTrace()) {
356
                logger.error(ste);
357
            }
358
            throw new RuntimeException(e);
359
        }
360
    }
361

    
362
    protected static <TERM extends DefinedTermBase> TERM readCsvLine(TERM newInstance, List<String> csvLine, Language lang, boolean abbrevAsId) {
363
        newInstance.setUuid(UUID.fromString(csvLine.get(0)));
364
        newInstance.setUri( URI.create(csvLine.get(1)));
365
        String label = csvLine.get(2).trim();
366
        String description = csvLine.get(3);
367
        String abbreviatedLabel = csvLine.get(4);
368
        if (StringUtils.isBlank(abbreviatedLabel)){
369
            abbreviatedLabel = null;
370
        }
371
        if (abbrevAsId){
372
            newInstance.setIdInVocabulary(abbreviatedLabel);  //new in 3.3
373
        }
374
        newInstance.addRepresentation(Representation.NewInstance(description, label, abbreviatedLabel, lang) );
375

    
376
        return newInstance;
377
    }
378

    
379
    protected void readIsPartOf(T newInstance, List<String> csvLine, Map<UUID, DefinedTermBase> terms){
380
        int index = partOfCsvLineIndex();
381
         if (index != -1){
382
            String partOfString = csvLine.get(index);
383
             if(StringUtils.isNotBlank(partOfString)) {
384
                 UUID partOfUuid = UUID.fromString(partOfString);
385
                 DefinedTermBase partOf = terms.get(partOfUuid);
386
                 partOf.addIncludes(newInstance);
387
             }
388
         }
389

    
390
    }
391

    
392
    /**
393
     * Get the
394
     * @return
395
     */
396
    protected int partOfCsvLineIndex() {
397
        return -1;
398
    }
399

    
400

    
401
    private  <T extends DefinedTermBase> T getInstance(Class<? extends DefinedTermBase> termClass) {
402
        try {
403
            Constructor<T> c = ((Class<T>)termClass).getDeclaredConstructor();
404
            c.setAccessible(true);
405
            T termInstance = c.newInstance();
406
            return termInstance;
407
        } catch (Exception e) {
408
            throw new RuntimeException(e);
409
        }
410
    }
411

    
412
    @Override
413
    public void writeCsvLine(CSVWriter writer, T term) {
414
        String [] line = new String[4];
415
        line[0] = term.getUuid().toString();
416
        line[1] = term.getUri().toString();
417
        line[2] = term.getLabel();
418
        line[3] = term.getDescription();
419
        writer.writeNext(line);
420
    }
421

    
422
    @Transient
423
    public T getByUuid(UUID uuid){
424
        return this.vocabulary.findTermByUuid(uuid);
425
    }
426

    
427

    
428
//*********************** CLONE ********************************************************/
429

    
430
    /**
431
     * Clones <i>this</i> DefinedTermBase. This is a shortcut that enables to create
432
     * a new instance that differs only slightly from <i>this</i> defined term base by
433
     * modifying only some of the attributes.
434
     *
435
     * @see eu.etaxonomy.cdm.model.common.TermBase#clone()
436
     * @see java.lang.Object#clone()
437
     */
438
    @Override
439
    public Object clone() {
440
        DefinedTermBase result;
441
        try {
442
            result = (DefinedTermBase) super.clone();
443
        }catch (CloneNotSupportedException e) {
444
            logger.warn("Object does not implement cloneable");
445
            e.printStackTrace();
446
            return null;
447
        }
448

    
449
        result.generalizationOf = new HashSet<DefinedTermBase>();
450
        for (DefinedTermBase generalizationOf : this.generalizationOf){
451
            result.generalizationOf.add(generalizationOf.clone());
452
        }
453

    
454
        result.includes = new HashSet<DefinedTermBase>();
455

    
456
        for (DefinedTermBase include: this.includes){
457
            result.includes.add(include.clone());
458
        }
459

    
460
        result.media = new HashSet<Media>();
461

    
462
        for (Media media: this.media){
463
            result.addMedia(media);
464
        }
465

    
466
        return result;
467
    }
468

    
469
    // Currently the CDM Caching mechanism is only used for caching terms
470
    private static ICdmCacher cacher;
471
    
472
    /**
473
     * Gets the CDM cacher object
474
     *      
475
     * @return the CDM cacher object
476
     */
477
    public static ICdmCacher getCacher() {
478
		return cacher;
479
	}
480

    
481
	/**
482
	 * Sets the CDM cacher object
483
	 * 
484
	 * @param cacher the CDM cacher object
485
	 */
486
	public static void setCacher(ICdmCacher cacher) {
487
		DefinedTermBase.cacher = cacher;
488
	}
489
}
(8-8/69)