Project

General

Profile

Download (13.2 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.media;
11

    
12
import java.net.URI;
13
import java.util.HashMap;
14
import java.util.HashSet;
15
import java.util.Map;
16
import java.util.Set;
17

    
18
import javax.persistence.Embedded;
19
import javax.persistence.Entity;
20
import javax.persistence.FetchType;
21
import javax.persistence.Inheritance;
22
import javax.persistence.InheritanceType;
23
import javax.persistence.JoinTable;
24
import javax.persistence.ManyToOne;
25
import javax.persistence.MapKeyJoinColumn;
26
import javax.persistence.OneToMany;
27
import javax.persistence.Transient;
28
import javax.validation.constraints.NotNull;
29
import javax.xml.bind.annotation.XmlAccessType;
30
import javax.xml.bind.annotation.XmlAccessorType;
31
import javax.xml.bind.annotation.XmlElement;
32
import javax.xml.bind.annotation.XmlElementWrapper;
33
import javax.xml.bind.annotation.XmlIDREF;
34
import javax.xml.bind.annotation.XmlRootElement;
35
import javax.xml.bind.annotation.XmlSchemaType;
36
import javax.xml.bind.annotation.XmlType;
37
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
38

    
39
import org.apache.log4j.Logger;
40
import org.hibernate.annotations.Cascade;
41
import org.hibernate.annotations.CascadeType;
42
import org.hibernate.envers.Audited;
43
import org.hibernate.search.annotations.IndexedEmbedded;
44
import org.hibernate.validator.constraints.NotEmpty;
45

    
46
import eu.etaxonomy.cdm.jaxb.MultilanguageTextAdapter;
47
import eu.etaxonomy.cdm.model.agent.AgentBase;
48
import eu.etaxonomy.cdm.model.common.IIntextReferenceTarget;
49
import eu.etaxonomy.cdm.model.common.IMultiLanguageTextHolder;
50
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
51
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
52
import eu.etaxonomy.cdm.model.common.Language;
53
import eu.etaxonomy.cdm.model.common.LanguageString;
54
import eu.etaxonomy.cdm.model.common.MultilanguageText;
55
import eu.etaxonomy.cdm.model.common.TimePeriod;
56
import eu.etaxonomy.cdm.model.reference.Reference;
57
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
58
import eu.etaxonomy.cdm.strategy.cache.media.MediaDefaultCacheStrategy;
59
import eu.etaxonomy.cdm.validation.Level2;
60

    
61
/**
62
 * A {@link Media media} is any kind of media that represents a media object.
63
 * This media object can have multiple {@link MediaRepresentation media representations} that differ in MIME-type
64
 * and/or quality.
65
 * E.g.
66
 * (1) an image can have a tiff and a jpg media representation.
67
 * (2) an formatted text can have a text/html or an application/pdf representation.
68
 *
69
 * @author m.doering
70
 * @since 08-Nov-2007 13:06:34
71
 */
72
@XmlAccessorType(XmlAccessType.FIELD)
73
@XmlType(name = "Media", propOrder = {
74
    "title",
75
    "mediaCreated",
76
    "description",
77
    "representations",
78
    "artist",
79
    "link"
80
})
81
@XmlRootElement(name = "Media")
82
@Entity
83
//@Indexed disabled to reduce clutter in indexes, since this type is not used by any search
84
//@Indexed
85
@Audited
86
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
87
public class Media
88
        extends IdentifiableEntity<IIdentifiableEntityCacheStrategy>
89
        implements IMultiLanguageTextHolder, IIntextReferenceTarget {
90

    
91
    private static final long serialVersionUID = -1927421567263473658L;
92
    @SuppressWarnings("unused")
93
    private static final Logger logger = Logger.getLogger(Media.class);
94

    
95
    // TODO once hibernate annotations support custom collection type
96
    // private MultilanguageText title = new MultilanguageText();
97
    @XmlElement(name = "MediaTitle")
98
    @XmlJavaTypeAdapter(MultilanguageTextAdapter.class)
99
    @OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
100
    @MapKeyJoinColumn(name="title_mapkey_id")
101
    @IndexedEmbedded
102
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE,CascadeType.DELETE, CascadeType.REFRESH})
103
    @NotNull
104
    @NotEmpty(groups = Level2.class)
105
    private Map<Language,LanguageString> title = new HashMap<>();
106

    
107
    //creation date of the media (not of the record)
108
    @XmlElement(name ="MediaCreated" )
109
    @Embedded
110
    @IndexedEmbedded
111
    private TimePeriod mediaCreated;
112

    
113

    
114
    // TODO once hibernate annotations support custom collection type
115
    // private MultilanguageText description = new MultilanguageText();
116
    @XmlElement(name = "MediaDescription")
117
    @XmlJavaTypeAdapter(MultilanguageTextAdapter.class)
118
    @OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
119
    @MapKeyJoinColumn(name="description_mapkey_id")
120
    @JoinTable(name = "Media_Description")
121
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE,CascadeType.DELETE, CascadeType.REFRESH})
122
    @IndexedEmbedded
123
    @NotNull
124
    private Map<Language,LanguageString> description = new HashMap<>();
125

    
126
    //A single medium such as a picture can have multiple representations in files.
127
    //Common are multiple resolutions or file formats for images for example
128
    @XmlElementWrapper(name = "MediaRepresentations")
129
    @XmlElement(name = "MediaRepresentation")
130
    @OneToMany(mappedBy="media",fetch = FetchType.LAZY, orphanRemoval=true)
131
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.REFRESH})
132
    @NotNull
133
    @NotEmpty(groups = Level2.class)
134
    private Set<MediaRepresentation> representations = new HashSet<>();
135

    
136
    @XmlElement(name = "Artist")
137
    @XmlIDREF
138
    @XmlSchemaType(name = "IDREF")
139
    @ManyToOne(fetch = FetchType.LAZY)
140
    @IndexedEmbedded
141
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
142
    private AgentBase<?> artist;
143

    
144
    @XmlElement(name = "Link")
145
    @XmlIDREF
146
    @XmlSchemaType(name = "IDREF")
147
    @ManyToOne(fetch = FetchType.LAZY)
148
    @IndexedEmbedded
149
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE, CascadeType.DELETE})
150
    private ExternalLink link;
151

    
152
//************************* FACTORY METHODS *******************************/
153

    
154
    public static Media NewInstance(){
155
        return new Media();
156
    }
157

    
158
    /**
159
     * Factory method which creates a new media, adds a reprsentation including mime type and suffix information
160
     * and adds to the later a representation part for a given uri and size
161
     * Returns <code>null</code> if uri is empty
162
     * @return Media
163
     */
164
    public static Media NewInstance(URI uri, Integer size, String mimeType, String suffix){
165
    	//TODO improve type recognition
166
    	Class<? extends MediaRepresentationPart> clazz = null;
167
    	if (isNotBlank(mimeType)){
168
    		if (mimeType.matches("image.*")){
169
    			clazz = ImageFile.class;
170
    		}
171
    	}
172
    	if (isNotBlank(suffix)){
173
    		if (suffix.matches("\\.(gif|jpe?g|tiff?)")){
174
    			clazz = ImageFile.class;
175
    		}
176
    	}else if (uri != null){
177
    		if (uri.toString().matches("\\.(gif|jpe?g|tiff?)")){
178
    			clazz = ImageFile.class;
179
    		}
180
    	}
181
    	MediaRepresentation representation = MediaRepresentation.NewInstance(mimeType, suffix, uri, size,clazz);
182
        if (representation == null){
183
            return null;
184
        }
185
        Media media = new Media();
186
        media.addRepresentation(representation);
187
        return media;
188
    }
189

    
190
//********************************* CONSTRUCTOR **************************/
191

    
192
    /**
193
     * Constructor
194
     */
195
    protected Media() {
196
        super();
197
        setMediaCacheStrategy();
198
    }
199

    
200
    private void setMediaCacheStrategy() {
201
//      if (getClass() == Media.class){
202
    	this.cacheStrategy = MediaDefaultCacheStrategy.NewInstance();
203
//      }
204
    }
205

    
206
// ********************* GETTER / SETTER    **************************/
207

    
208
    public Set<MediaRepresentation> getRepresentations(){
209
        if(representations == null) {
210
            this.representations = new HashSet<>();
211
        }
212
        return this.representations;
213
    }
214

    
215
    @SuppressWarnings("deprecation")
216
    public void addRepresentation(MediaRepresentation representation){
217
        if (representation != null){
218
            this.getRepresentations().add(representation);
219
            representation.setMedia(this);
220
        }
221
    }
222

    
223
    @SuppressWarnings("deprecation")
224
    public void removeRepresentation(MediaRepresentation representation){
225
        this.getRepresentations().remove(representation);
226
        if (representation != null){
227
            representation.setMedia(null);
228
        }
229
    }
230

    
231
    public AgentBase getArtist(){
232
        return this.artist;
233
    }
234
    public void setArtist(AgentBase artist){
235
        this.artist = artist;
236
    }
237

    
238
    public ExternalLink getLink() {
239
        return link;
240
    }
241
    public void setLink(ExternalLink link) {
242
        this.link = link;
243
    }
244

    
245
//************************ title / title cache *********************************
246

    
247
    public LanguageString getTitle(){
248
        return getTitle(Language.DEFAULT());
249
    }
250

    
251
    public LanguageString getTitle(Language language){
252
        return title.get(language);
253
    }
254

    
255
    @Transient
256
    public Map<Language,LanguageString> getAllTitles(){
257
        if(title == null) {
258
            this.title = new HashMap<>();
259
        }
260
        return this.title;
261
    }
262
    /**
263
     * Adds the languageString to the {@link MultilanguageText multilanguage text}
264
     * used to be the title of <i>this</i> media.
265
     *
266
     * @param title		the languageString with the title in a particular language
267
     * @see    	   		#getTitle()
268
     * @see    	   		#putTitle(Language String)
269
    */
270
    public void putTitle(LanguageString title){
271
        this.title.put(title.getLanguage(), title);
272
    }
273

    
274
    /**
275
     * Creates a {@link LanguageString language string} based on the given text string
276
     * and the given {@link Language language} and adds it to the {@link MultilanguageText multilanguage text}
277
     * used to be the title of <i>this</i> media.
278
     *
279
     * @param language	the language in which the title string is formulated
280
     * @param text		the title in a particular language
281
     *
282
     * @see    	   		#getTitle()
283
     * @see    	   		#putTitle(LanguageString)
284
     */
285
    public void putTitle(Language language, String title){
286
        this.title.put(language, LanguageString.NewInstance(title, language));
287
    }
288

    
289
    public void removeTitle(Language language){
290
        this.title.remove(language);
291
    }
292

    
293

    
294
    @Transient
295
    public String getTitleCacheByLanguage(Language lang){
296
        if (cacheStrategy != null){
297
            return ((MediaDefaultCacheStrategy)cacheStrategy).getTitleCacheByLanguage(this, lang);
298
        }else{
299
            return null;
300
        }
301
    }
302

    
303
    /**
304
     * Puts the title into the title field which is a multi-language string
305
     * with default language as language
306
     */
307
    @Override
308
    public void setTitleCache(String titleCache) {
309
        putTitle(LanguageString.NewInstance(titleCache, Language.DEFAULT()));
310
    }
311

    
312
    @Override
313
    public String getTitleCache(){
314
        if (protectedTitleCache){
315
            return this.titleCache;
316
        }
317
        // is title dirty, i.e. equal NULL?
318
        if (titleCache == null){
319
            this.titleCache = generateTitle();
320
            this.titleCache = getTruncatedCache(this.titleCache) ;
321
        }else{
322
            //do the same as listeners on dependend objects like representations parts
323
            //are not yet installed
324
            this.titleCache = generateTitle();
325
            this.titleCache = getTruncatedCache(this.titleCache) ;
326
        }
327
        return titleCache;
328
    }
329

    
330
    public TimePeriod getMediaCreated(){
331
        return this.mediaCreated;
332
    }
333

    
334
    public void setMediaCreated(TimePeriod mediaCreated){
335
        this.mediaCreated = mediaCreated;
336
    }
337

    
338
    //************* Descriptions  *********************/
339

    
340
    public Map<Language,LanguageString> getAllDescriptions(){
341
        if(this.description == null) {
342
            this.description = new HashMap<>();
343
        }
344
        return this.description;
345
    }
346

    
347
    public LanguageString getDescription(Language language){
348
        return getAllDescriptions().get(language);
349
    }
350

    
351
    public void addDescription(LanguageString description){
352
        this.description.put(description.getLanguage(), description);
353
    }
354

    
355
    public void putDescription(Language language, String text){
356
        this.description.put(language, LanguageString.NewInstance(text, language));
357
    }
358

    
359
    public void removeDescription(Language language){
360
        this.description.remove(language);
361
    }
362

    
363
// ************************ SOURCE ***************************/
364

    
365
    public IdentifiableSource addPrimaryMediaSource(Reference citation, String microCitation) {
366
        if (citation == null && microCitation == null){
367
            return null;
368
        }
369
        IdentifiableSource source = IdentifiableSource.NewPrimaryMediaSourceInstance(citation, microCitation);
370
        addSource(source);
371
        return source;
372
    }
373

    
374
//************************* CLONE **************************/
375

    
376
    @Override
377
    public Object clone() throws CloneNotSupportedException{
378
        Media result = (Media)super.clone();
379
        //description
380
        result.description = cloneLanguageString(this.description);
381

    
382
        //title
383
        result.title = cloneLanguageString(this.title);
384

    
385
        //media representations
386
        result.representations = new HashSet<>();
387
        for (MediaRepresentation mediaRepresentation: this.representations){
388
            result.representations.add((MediaRepresentation)mediaRepresentation.clone());
389
        }
390

    
391
        result.link = this.link != null ? this.link.clone(): null;
392

    
393
        //no changes to: artist
394
        return result;
395
    }
396

    
397
    public int compareTo(Object o) {
398
        return 0;
399
    }
400

    
401

    
402

    
403
}
(8-8/16)