Project

General

Profile

Download (11 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.util.ArrayList;
13
import java.util.HashMap;
14
import java.util.HashSet;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.NoSuchElementException;
18
import java.util.Set;
19
import java.util.SortedMap;
20
import java.util.TreeMap;
21
import java.util.Map.Entry;
22
import java.util.regex.Matcher;
23
import java.util.regex.Pattern;
24

    
25
import javax.persistence.Basic;
26
import javax.persistence.Entity;
27
import javax.persistence.FetchType;
28
import javax.persistence.Inheritance;
29
import javax.persistence.InheritanceType;
30
import javax.persistence.JoinTable;
31
import javax.persistence.ManyToOne;
32
import javax.persistence.OneToMany;
33
import javax.validation.constraints.NotNull;
34
import javax.xml.bind.annotation.XmlAccessType;
35
import javax.xml.bind.annotation.XmlAccessorType;
36
import javax.xml.bind.annotation.XmlElement;
37
import javax.xml.bind.annotation.XmlElementWrapper;
38
import javax.xml.bind.annotation.XmlIDREF;
39
import javax.xml.bind.annotation.XmlRootElement;
40
import javax.xml.bind.annotation.XmlSchemaType;
41
import javax.xml.bind.annotation.XmlType;
42
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
43

    
44
import org.apache.log4j.Logger;
45
import org.hibernate.annotations.Cascade;
46
import org.hibernate.annotations.CascadeType;
47
import org.hibernate.annotations.Type;
48
import org.hibernate.envers.Audited;
49
import org.hibernate.search.annotations.Indexed;
50
import org.hibernate.search.annotations.IndexedEmbedded;
51
import org.hibernate.validator.constraints.NotEmpty;
52
import org.joda.time.DateTime;
53

    
54
import eu.etaxonomy.cdm.jaxb.DateTimeAdapter;
55
import eu.etaxonomy.cdm.jaxb.MultilanguageTextAdapter;
56
import eu.etaxonomy.cdm.model.agent.AgentBase;
57
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
58
import eu.etaxonomy.cdm.model.common.Language;
59
import eu.etaxonomy.cdm.model.common.LanguageString;
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 implements Cloneable {
87
	private static final long serialVersionUID = -1927421567263473658L;
88
	private static final Logger logger = Logger.getLogger(Media.class);
89

    
90
    // TODO once hibernate annotations support custom collection type
91
	// private MultilanguageText title = new MultilanguageText();
92
	@XmlElement(name = "MediaTitle")
93
    @XmlJavaTypeAdapter(MultilanguageTextAdapter.class)
94
    @OneToMany(fetch = FetchType.LAZY)
95
    @IndexedEmbedded
96
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE,CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
97
    @NotNull
98
    @NotEmpty(groups = Level2.class)
99
	private Map<Language,LanguageString> title = new HashMap<Language,LanguageString>();
100
	
101
	//creation date of the media (not of the record) 
102
	@XmlElement(name = "MediaCreated", type= String.class)
103
	@XmlJavaTypeAdapter(DateTimeAdapter.class)
104
	@Type(type="dateTimeUserType")
105
	@Basic(fetch = FetchType.LAZY)
106
	private DateTime mediaCreated;
107
	
108
	 // TODO once hibernate annotations support custom collection type
109
	// private MultilanguageText description = new MultilanguageText();
110
	@XmlElement(name = "MediaDescription")
111
    @XmlJavaTypeAdapter(MultilanguageTextAdapter.class)
112
    @OneToMany(fetch = FetchType.LAZY)
113
    @IndexedEmbedded
114
    @JoinTable(name = "Media_Description")
115
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE,CascadeType.DELETE,CascadeType.DELETE_ORPHAN})
116
    @NotNull
117
	private Map<Language,LanguageString> description = new HashMap<Language,LanguageString>();
118
	
119
	//A single medium such as a picture can have multiple representations in files. 
120
	//Common are multiple resolutions or file formats for images for example
121
	@XmlElementWrapper(name = "MediaRepresentations")
122
	@XmlElement(name = "MediaRepresentation")
123
	@OneToMany(mappedBy="media",fetch = FetchType.LAZY)
124
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
125
	@NotNull
126
	@NotEmpty(groups = Level2.class)
127
	private Set<MediaRepresentation> representations = new HashSet<MediaRepresentation>();
128
	
129
	@XmlElement(name = "Artist")
130
	@XmlIDREF
131
	@XmlSchemaType(name = "IDREF")
132
	@ManyToOne(fetch = FetchType.LAZY)
133
	@IndexedEmbedded
134
	@Cascade(CascadeType.SAVE_UPDATE)
135
	private AgentBase artist;
136

    
137
	/**
138
	 * Factory method
139
	 * @return
140
	 */
141
	public static Media NewInstance(){
142
		logger.debug("NewInstance");
143
		return new Media();
144
	}
145
	
146
	/**
147
	 * Constructor
148
	 */
149
	protected Media() {
150
		super();
151
	}
152

    
153
	public Set<MediaRepresentation> getRepresentations(){
154
		if(representations == null) {
155
			this.representations = new HashSet<MediaRepresentation>();
156
		}
157
		return this.representations;
158
	}
159

    
160
	@SuppressWarnings("deprecation")
161
	public void addRepresentation(MediaRepresentation representation){
162
		if (representation != null){
163
			this.getRepresentations().add(representation);
164
			representation.setMedia(this);
165
		}
166
	}
167
	
168
	@SuppressWarnings("deprecation")
169
	public void removeRepresentation(MediaRepresentation representation){
170
		this.getRepresentations().remove(representation);
171
		if (representation != null){
172
			representation.setMedia(null);
173
		}
174

    
175
	}
176

    
177
	public AgentBase getArtist(){
178
		return this.artist;
179
	}
180
	
181
	public void setArtist(AgentBase artist){
182
		this.artist = artist;
183
	}
184

    
185
	public Map<Language,LanguageString> getTitle(){
186
		if(title == null) {
187
			this.title = new HashMap<Language,LanguageString>();
188
		}
189
		return this.title;
190
	}
191
	
192
	public void addTitle(LanguageString title){
193
		this.title.put(title.getLanguage(), title);
194
	}
195
	
196
	public void removeTitle(Language language){
197
		this.title.remove(language);
198
	}
199

    
200
	public DateTime getMediaCreated(){
201
		return this.mediaCreated;
202
	}
203
	
204
	public void setMediaCreated(DateTime mediaCreated){
205
		this.mediaCreated = mediaCreated;
206
	}
207

    
208
	public Map<Language,LanguageString> getDescription(){
209
		if(this.description == null) {
210
			this.description = new HashMap<Language,LanguageString>();
211
		}
212
		return this.description;
213
	}
214
	
215
	public void addDescription(LanguageString description){
216
		this.description.put(description.getLanguage(),description);
217
	}
218
	
219
	public void addDescription(String text, Language language){
220
		this.description.put(language, LanguageString.NewInstance(text, language));
221
	}
222
	
223
	public void removeDescription(Language language){
224
		this.description.remove(language);
225
	}
226
	
227
//************************* CLONE **************************/
228
	
229
	
230
	/* (non-Javadoc)
231
	 * @see java.lang.Object#clone()
232
	 */
233
	@Override
234
	public Object clone() throws CloneNotSupportedException{
235
		Media result = (Media)super.clone();
236
		//description
237
		result.description = new HashMap<Language, LanguageString>();
238
		for (Language language: this.description.keySet()){
239
			result.description.put(language, this.description.get(language));
240
		}
241
		//title
242
		result.title = new HashMap<Language, LanguageString>();
243
		for (Language language: this.title.keySet()){
244
			result.title.put(language, this.title.get(language));
245
		}
246
		//media representations
247
		result.representations = new HashSet<MediaRepresentation>();
248
		for (MediaRepresentation mediaRepresentation: this.representations){
249
			result.representations.add((MediaRepresentation)mediaRepresentation.clone());
250
		}
251
		//no changes to: artist
252
		return result;
253
	}
254
	
255
	public int compareTo(Object o) {
256
		return 0;
257
	}
258
	/**
259
	 * @param mimeTypeRegexes
260
	 * @param size
261
	 * @param widthOrDuration
262
	 * @param height
263
	 * @return
264
	 * 
265
	 * 
266
	 */
267
	public MediaRepresentation findBestMatchingRepresentation(Integer size, Integer height, Integer widthOrDuration, String[] mimeTypes){
268
		// find best matching representations of each media
269
		Set<MediaRepresentation> reps = this.getRepresentations();
270
				
271
		List<Media> returnMedia = new ArrayList<Media>(reps.size());
272
		SortedMap<Integer, MediaRepresentation> prefRepresentations 
273
				= orderMediaRepresentations(mimeTypes, size, widthOrDuration, height);
274
			try {
275
				// take first one and remove all other representations
276
				MediaRepresentation prefOne = prefRepresentations.get(prefRepresentations.firstKey());
277
				
278
				return prefOne;
279
				
280
			} catch (NoSuchElementException nse) {
281
				/* IGNORE */
282
			}
283
			return null;
284
		}
285
	
286
	
287
	/**
288
	 * @param mimeTypeRegexes
289
	 * @param size
290
	 * @param widthOrDuration
291
	 * @param height
292
	 * @return
293
	 * 
294
	 * 
295
	 */
296
	private SortedMap<Integer, MediaRepresentation> orderMediaRepresentations(String[] mimeTypeRegexes,
297
			Integer size, Integer widthOrDuration, Integer height) {
298
		SortedMap<Integer, MediaRepresentation> prefRepr = new TreeMap<Integer, MediaRepresentation>();
299
		SortedMap<String, MediaRepresentation> sortedForSizeDistance = new TreeMap<String, MediaRepresentation>();		
300
		String keyString = "";
301
		for (String mimeTypeRegex : mimeTypeRegexes) {
302
			// getRepresentationByMimeType
303
			Pattern mimeTypePattern = Pattern.compile(mimeTypeRegex);
304
			int representationCnt = 0;
305
			for (MediaRepresentation representation : getRepresentations()) {
306
				
307
				Matcher mather = mimeTypePattern.matcher(representation.getMimeType());
308
				if (mather.matches()) {
309
					int dwa = 0;
310
					
311
					//first the size is used for comparison
312
					for (MediaRepresentationPart part : representation.getParts()) {
313
						if (part.getSize()!= null){
314
							int sizeOfPart = part.getSize();
315
							int distance = sizeOfPart - size;
316
							if (distance < 0) {
317
								distance*= -1;
318
							}
319
							dwa += distance;
320
						}
321
						//if height and width/duration is defined, add this information, too
322
						if (height != 0 && widthOrDuration != 0){
323
							int dw = 0;
324
							
325
							if (part instanceof ImageFile) {
326
								ImageFile image = (ImageFile) part;
327
								dw = image.getWidth() * image.getHeight() - height * widthOrDuration;
328
							}
329
							else if (part instanceof MovieFile){
330
								MovieFile movie = (MovieFile) part;
331
								dw = movie.getDuration() - widthOrDuration;
332
										
333
							}else if (part instanceof AudioFile){
334
								AudioFile audio = (AudioFile) part;
335
								dw = audio.getDuration() - widthOrDuration;
336
								
337
							}
338
							if (dw < 0) {
339
								dw *= -1;
340
							}
341
							dwa += dw;
342
							
343
						}
344
					}
345
					dwa = (representation.getParts().size() > 0 ? dwa / representation.getParts().size() : 0);
346
					
347
					//keyString =(dwa + representationCnt++) + '_' + representation.getMimeType();
348
					
349
					prefRepr.put((dwa + representationCnt++), representation);
350
					System.out.println(prefRepr.get(prefRepr.firstKey()) + " --- " + prefRepr.firstKey());
351
				}
352
					
353
			}				
354
						
355
		}
356
		return prefRepr;
357
	}
358
	
359
}
(6-6/13)