Project

General

Profile

Download (13.8 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.Basic;
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.commons.lang.StringUtils;
40
import org.apache.log4j.Logger;
41
import org.hibernate.annotations.Cascade;
42
import org.hibernate.annotations.CascadeType;
43
import org.hibernate.annotations.Type;
44
import org.hibernate.envers.Audited;
45
import org.hibernate.search.annotations.Indexed;
46
import org.hibernate.search.annotations.IndexedEmbedded;
47
import org.hibernate.validator.constraints.NotEmpty;
48
import org.joda.time.DateTime;
49

    
50
import eu.etaxonomy.cdm.jaxb.DateTimeAdapter;
51
import eu.etaxonomy.cdm.jaxb.MultilanguageTextAdapter;
52
import eu.etaxonomy.cdm.model.agent.AgentBase;
53
import eu.etaxonomy.cdm.model.common.IMultiLanguageTextHolder;
54
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
55
import eu.etaxonomy.cdm.model.common.Language;
56
import eu.etaxonomy.cdm.model.common.LanguageString;
57
import eu.etaxonomy.cdm.model.common.MultilanguageText;
58
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
59
import eu.etaxonomy.cdm.strategy.cache.media.MediaDefaultCacheStrategy;
60
import eu.etaxonomy.cdm.validation.Level2;
61

    
62
/**
63
 * A {@link Media media} is any kind of media that represents a media object.
64
 * This media object can have multiple {@link MediaRepresentation media representations} that differ in MIME-type
65
 * and/or quality.
66
 * E.g.
67
 * (1) an image can have a tiff and a jpg media representation.
68
 * (2) an formatted text can have a text/html or an application/pdf representation.
69
 * @author m.doering
70
 * @version 1.0
71
 * @created 08-Nov-2007 13:06:34
72
 */
73
@XmlAccessorType(XmlAccessType.FIELD)
74
@XmlType(name = "Media", propOrder = {
75
    "title",
76
    "mediaCreated",
77
    "description",
78
    "representations",
79
    "artist"
80
})
81
@XmlRootElement(name = "Media")
82
@Entity
83
@Indexed
84
@Audited
85
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
86
public class Media extends IdentifiableEntity<IIdentifiableEntityCacheStrategy> implements Cloneable, IMultiLanguageTextHolder {
87
    private static final long serialVersionUID = -1927421567263473658L;
88
    @SuppressWarnings("unused")
89
    private static final Logger logger = Logger.getLogger(Media.class);
90

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

    
103
    //creation date of the media (not of the record)
104
    @XmlElement(name = "MediaCreated", type= String.class)
105
    @XmlJavaTypeAdapter(DateTimeAdapter.class)
106
    @Type(type="dateTimeUserType")
107
    @Basic(fetch = FetchType.LAZY)
108
    private DateTime mediaCreated;
109

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

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

    
132
    @XmlElement(name = "Artist")
133
    @XmlIDREF
134
    @XmlSchemaType(name = "IDREF")
135
    @ManyToOne(fetch = FetchType.LAZY)
136
    @IndexedEmbedded
137
    @Cascade(CascadeType.SAVE_UPDATE)
138
    private AgentBase<?> artist;
139

    
140

    
141
    /**
142
     * Factory method
143
     * @return
144
     */
145
    public static Media NewInstance(){
146
        return new Media();
147
    }
148

    
149

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

    
182
    /**
183
     * Constructor
184
     */
185
    protected Media() {
186
        super();
187
        setMediaCacheStrategy();
188
    }
189

    
190
    private void setMediaCacheStrategy() {
191
//      if (getClass() == Media.class){
192
    	this.cacheStrategy = MediaDefaultCacheStrategy.NewInstance();
193
//      }
194
    }
195

    
196

    
197
    public Set<MediaRepresentation> getRepresentations(){
198
        if(representations == null) {
199
            this.representations = new HashSet<MediaRepresentation>();
200
        }
201
        return this.representations;
202
    }
203

    
204
    @SuppressWarnings("deprecation")
205
    public void addRepresentation(MediaRepresentation representation){
206
        if (representation != null){
207
            this.getRepresentations().add(representation);
208
            representation.setMedia(this);
209
        }
210
    }
211

    
212
    @SuppressWarnings("deprecation")
213
    public void removeRepresentation(MediaRepresentation representation){
214
        this.getRepresentations().remove(representation);
215
        if (representation != null){
216
            representation.setMedia(null);
217
        }
218

    
219
    }
220

    
221
    public AgentBase getArtist(){
222
        return this.artist;
223
    }
224

    
225
    public void setArtist(AgentBase artist){
226
        this.artist = artist;
227
    }
228

    
229
//************************ title / title cache *********************************
230

    
231
    public LanguageString getTitle(){
232
        return getTitle(Language.DEFAULT());
233
    }
234

    
235
    public LanguageString getTitle(Language language){
236
        return title.get(language);
237
    }
238

    
239
    @Transient
240
    public Map<Language,LanguageString> getAllTitles(){
241
        if(title == null) {
242
            this.title = new HashMap<Language,LanguageString>();
243
        }
244
        return this.title;
245
    }
246
    /**
247
     * Adds the languageString to the {@link MultilanguageText multilanguage text}
248
     * used to be the title of <i>this</i> media.
249
     *
250
     * @param title		the languageString with the title in a particular language
251
     * @see    	   		#getTitle()
252
     * @see    	   		#putTitle(Language String)
253
     * @deprecated		should follow the put semantic of maps, this method will be removed in v4.0
254
     * 					Use the {@link #putTitle(LanguageString) putTitle} method instead
255
     */
256
    @Deprecated
257
    public void addTitle(LanguageString title){
258
        this.putTitle(title);
259
    }
260
    public void putTitle(LanguageString title){
261
        this.title.put(title.getLanguage(), title);
262
    }
263

    
264
    /**
265
     * Creates a {@link LanguageString language string} based on the given text string
266
     * and the given {@link Language language} and adds it to the {@link MultilanguageText multilanguage text}
267
     * used to be the title of <i>this</i> media.
268
     *
269
     * @param text		the title in a particular language
270
     * @param language	the language in which the title string is formulated
271
     * @see    	   		#getTitle()
272
     * @see    	   		#putTitle(LanguageString)
273
     * @deprecated		should follow the put semantic of maps, this method will be removed in v4.0
274
     * 					Use the {@link #putTitle(Language, String) putTitle} method instead
275
     */
276
    @Deprecated
277
    public void addTitle(String title, Language language){
278
        this.putTitle(language, title);
279
    }
280
    /**
281
     * Creates a {@link LanguageString language string} based on the given text string
282
     * and the given {@link Language language} and adds it to the {@link MultilanguageText multilanguage text}
283
     * used to be the title of <i>this</i> media.
284
     *
285
     * @param language	the language in which the title string is formulated
286
     * @param text		the title in a particular language
287
     *
288
     * @see    	   		#getTitle()
289
     * @see    	   		#putTitle(LanguageString)
290
     */
291
    public void putTitle(Language language, String title){
292
        this.title.put(language, LanguageString.NewInstance(title, language));
293
    }
294

    
295
    public void removeTitle(Language language){
296
        this.title.remove(language);
297
    }
298

    
299

    
300
    @Transient
301
    public String getTitleCacheByLanguage(Language lang){
302
        if (cacheStrategy != null){
303
            return ((MediaDefaultCacheStrategy)cacheStrategy).getTitleCacheByLanguage(this, lang);
304
        }else{
305
            return null;
306
        }
307

    
308
    }
309

    
310

    
311
    /*
312
     * (non-Javadoc)
313
     * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#setTitleCache(java.lang.String)
314
     */
315
    @Override
316
    public void setTitleCache(String titleCache) {
317
        putTitle(LanguageString.NewInstance(titleCache, Language.DEFAULT()));
318
    }
319

    
320
    /* (non-Javadoc)
321
     * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getTitleCache()
322
     */
323
    @Override
324
    public String getTitleCache(){
325
        if (protectedTitleCache){
326
            return this.titleCache;
327
        }
328
        // is title dirty, i.e. equal NULL?
329
        if (titleCache == null){
330
            this.titleCache = generateTitle();
331
            this.titleCache = getTruncatedCache(this.titleCache) ;
332
        }else{
333
            //do the same as listeners on dependend objects like representations parts
334
            //are not yet installed
335
            this.titleCache = generateTitle();
336
            this.titleCache = getTruncatedCache(this.titleCache) ;
337
        }
338
        return titleCache;
339
    }
340

    
341

    
342

    
343

    
344
    public DateTime getMediaCreated(){
345
        return this.mediaCreated;
346
    }
347

    
348
    public void setMediaCreated(DateTime mediaCreated){
349
        this.mediaCreated = mediaCreated;
350
    }
351

    
352
    //************* Descriptions
353

    
354
    public Map<Language,LanguageString> getAllDescriptions(){
355
        if(this.description == null) {
356
            this.description = new HashMap<Language,LanguageString>();
357
        }
358
        return this.description;
359
    }
360

    
361
    public LanguageString getDescription(Language language){
362
        return getAllDescriptions().get(language);
363
    }
364

    
365
    public void addDescription(LanguageString description){
366
        this.description.put(description.getLanguage(), description);
367
    }
368

    
369
    public void putDescription(Language language, String text){
370
        this.description.put(language, LanguageString.NewInstance(text, language));
371
    }
372
    
373
    public void removeDescription(Language language){
374
        this.description.remove(language);
375
    }
376

    
377
//************************* CLONE **************************/
378

    
379

    
380
    /* (non-Javadoc)
381
     * @see java.lang.Object#clone()
382
     */
383
    @Override
384
    public Object clone() throws CloneNotSupportedException{
385
        Media result = (Media)super.clone();
386
        //description
387
        result.description = new HashMap<Language, LanguageString>();
388
        for (Language language: this.description.keySet()){
389
            result.description.put(language, this.description.get(language));
390
        }
391
        //title
392
        result.title = new HashMap<Language, LanguageString>();
393
        for (Language language: this.title.keySet()){
394
            result.title.put(language, this.title.get(language));
395
        }
396
        //media representations
397
        result.representations = new HashSet<MediaRepresentation>();
398
        for (MediaRepresentation mediaRepresentation: this.representations){
399
            result.representations.add((MediaRepresentation)mediaRepresentation.clone());
400
        }
401
        //no changes to: artist
402
        return result;
403
    }
404

    
405
    public int compareTo(Object o) {
406
        return 0;
407
    }
408

    
409

    
410

    
411
}
(6-6/13)