Project

General

Profile

Download (13.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.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.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.envers.Audited;
44
import org.hibernate.search.annotations.IndexedEmbedded;
45
import org.hibernate.validator.constraints.NotEmpty;
46

    
47
import eu.etaxonomy.cdm.jaxb.MultilanguageTextAdapter;
48
import eu.etaxonomy.cdm.model.agent.AgentBase;
49
import eu.etaxonomy.cdm.model.common.IIntextReferenceTarget;
50
import eu.etaxonomy.cdm.model.common.IMultiLanguageTextHolder;
51
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
52
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
53
import eu.etaxonomy.cdm.model.common.Language;
54
import eu.etaxonomy.cdm.model.common.LanguageString;
55
import eu.etaxonomy.cdm.model.common.MultilanguageText;
56
import eu.etaxonomy.cdm.model.common.TimePeriod;
57
import eu.etaxonomy.cdm.model.reference.Reference;
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
 *
70
 * @author m.doering
71
 * @since 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
    "link"
81
})
82
@XmlRootElement(name = "Media")
83
@Entity
84
//@Indexed disabled to reduce clutter in indexes, since this type is not used by any search
85
//@Indexed
86
@Audited
87
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
88
public class Media
89
        extends IdentifiableEntity<IIdentifiableEntityCacheStrategy>
90
        implements IMultiLanguageTextHolder, IIntextReferenceTarget {
91

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

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

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

    
114

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

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

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

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

    
153
//************************* FACTORY METHODS *******************************/
154

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

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

    
191
//********************************* CONSTRUCTOR **************************/
192

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

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

    
207
// ********************* GETTER / SETTER    **************************/
208

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

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

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

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

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

    
246
//************************ title / title cache *********************************
247

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

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

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

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

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

    
294

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

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

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

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

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

    
339
    //************* Descriptions  *********************/
340

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

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

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

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

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

    
364
// ************************ SOURCE ***************************/
365

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

    
375
//************************* CLONE **************************/
376

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

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

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

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

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

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

    
402

    
403

    
404
}
(8-8/16)