1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.opencastproject.mediapackage;
23
24 import static org.apache.commons.lang3.StringUtils.isNotBlank;
25 import static org.opencastproject.util.IoSupport.withResource;
26 import static org.opencastproject.util.data.Collections.list;
27 import static org.opencastproject.util.data.functions.Booleans.not;
28 import static org.opencastproject.util.data.functions.Options.sequenceOpt;
29 import static org.opencastproject.util.data.functions.Options.toOption;
30
31 import org.opencastproject.util.data.Effect;
32 import org.opencastproject.util.data.Function;
33 import org.opencastproject.util.data.Option;
34
35 import com.entwinemedia.fn.data.Opt;
36 import com.entwinemedia.fn.fns.Strings;
37
38 import org.apache.commons.io.FilenameUtils;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 import java.io.InputStream;
43 import java.net.URI;
44 import java.util.Collections;
45 import java.util.List;
46
47
48 public final class MediaPackageSupport {
49
50 private MediaPackageSupport() {
51 }
52
53 private static final List NIL = java.util.Collections.EMPTY_LIST;
54
55
56
57
58
59
60
61
62
63
64
65 public enum MergeMode {
66 Merge, Replace, Skip, Fail
67 }
68
69
70 private static final Logger logger = LoggerFactory.getLogger(MediaPackageSupport.class.getName());
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 public static MediaPackage merge(MediaPackage dest, MediaPackage src, MergeMode mode) throws MediaPackageException {
90 try {
91 for (MediaPackageElement e : src.elements()) {
92 if (dest.getElementById(e.getIdentifier()) == null)
93 dest.add(e);
94 else {
95 if (MergeMode.Replace == mode) {
96 logger.debug("Replacing element " + e.getIdentifier() + " while merging " + dest + " with " + src);
97 dest.remove(dest.getElementById(e.getIdentifier()));
98 dest.add(e);
99 } else if (MergeMode.Skip == mode) {
100 logger.debug("Skipping element " + e.getIdentifier() + " while merging " + dest + " with " + src);
101 continue;
102 } else if (MergeMode.Merge == mode) {
103 logger.debug("Renaming element " + e.getIdentifier() + " while merging " + dest + " with " + src);
104 e.setIdentifier(null);
105 dest.add(e);
106 } else if (MergeMode.Fail == mode) {
107 throw new MediaPackageException("Target media package " + dest + " already contains element with id "
108 + e.getIdentifier());
109 }
110 }
111 }
112 } catch (UnsupportedElementException e) {
113 throw new MediaPackageException(e);
114 }
115 return dest;
116 }
117
118
119
120
121
122
123
124
125 public static boolean contains(String identifier, MediaPackage mp) {
126 for (MediaPackageElement element : mp.getElements()) {
127 if (element.getIdentifier().equals(identifier))
128 return true;
129 }
130 return false;
131 }
132
133
134
135
136
137
138 public static Opt<String> getFileName(MediaPackageElement mpe) {
139 final URI uri = mpe.getURI();
140 if (uri != null) {
141 return Opt.nul(FilenameUtils.getName(uri.toString())).bind(Strings.blankToNone);
142 } else {
143 return Opt.none();
144 }
145 }
146
147
148
149
150
151
152
153 public static MediaPackage copy(MediaPackage mp) {
154 return (MediaPackage) mp.clone();
155 }
156
157
158 public static void updateElement(MediaPackage mp, MediaPackageElement e) {
159 mp.removeElementById(e.getIdentifier());
160 mp.add(e);
161 }
162
163
164 public static Effect<MediaPackageElement> updateElement(final MediaPackage mp) {
165 return new Effect<MediaPackageElement>() {
166 @Override
167 protected void run(MediaPackageElement e) {
168 updateElement(mp, e);
169 }
170 };
171 }
172
173 public static final Function<MediaPackageElement, String> getMediaPackageElementId = new Function<MediaPackageElement, String>() {
174 @Override
175 public String apply(MediaPackageElement mediaPackageElement) {
176 return mediaPackageElement.getIdentifier();
177 }
178 };
179
180
181 public static final class Filters {
182 private Filters() {
183 }
184
185
186
187 public static <A extends MediaPackageElement> Function<MediaPackageElement, List<A>> byType(final Class<A> type) {
188 return new Function<MediaPackageElement, List<A>>() {
189 @Override
190 public List<A> apply(MediaPackageElement mpe) {
191 return type.isAssignableFrom(mpe.getClass()) ? list((A) mpe) : (List<A>) NIL;
192 }
193 };
194 }
195
196 public static Function<MediaPackageElement, List<MediaPackageElement>> byFlavor(
197 final MediaPackageElementFlavor flavor) {
198 return new Function<MediaPackageElement, List<MediaPackageElement>>() {
199 @Override
200 public List<MediaPackageElement> apply(MediaPackageElement mpe) {
201
202 return flavor.matches(mpe.getFlavor()) ? Collections.singletonList(mpe) : Collections.emptyList();
203 }
204 };
205 }
206
207 public static <A extends MediaPackageElement> Function<MediaPackageElement, Boolean> ofType(final Class<A> type) {
208 return new Function<MediaPackageElement, Boolean>() {
209 @Override
210 public Boolean apply(MediaPackageElement mpe) {
211 return type.isAssignableFrom(mpe.getClass());
212 }
213 };
214 }
215
216 public static final Function<MediaPackageElement, List<Publication>> presentations = byType(Publication.class);
217
218 public static final Function<MediaPackageElement, List<Attachment>> attachments = byType(Attachment.class);
219
220 public static final Function<MediaPackageElement, List<Track>> tracks = byType(Track.class);
221
222 public static final Function<MediaPackageElement, List<Catalog>> catalogs = byType(Catalog.class);
223
224 public static final Function<MediaPackageElement, Boolean> isPublication = ofType(Publication.class);
225
226 public static final Function<MediaPackageElement, Boolean> isNotPublication = not(isPublication);
227
228 public static final Function<MediaPackageElement, Boolean> hasChecksum = new Function<MediaPackageElement, Boolean>() {
229 @Override
230 public Boolean apply(MediaPackageElement e) {
231 return e.getChecksum() != null;
232 }
233 };
234
235 public static final Function<MediaPackageElement, Boolean> hasNoChecksum = not(hasChecksum);
236
237 public static final Function<Track, Boolean> hasVideo = new Function<Track, Boolean>() {
238 @Override
239 public Boolean apply(Track track) {
240 return track.hasVideo();
241 }
242 };
243
244 public static final Function<Track, Boolean> hasAudio = new Function<Track, Boolean>() {
245 @Override
246 public Boolean apply(Track track) {
247 return track.hasAudio();
248 }
249 };
250
251 public static final Function<Track, Boolean> hasNoVideo = not(hasVideo);
252
253 public static final Function<Track, Boolean> hasNoAudio = not(hasAudio);
254
255
256 public static Function<Publication, Boolean> ofChannel(final String channelId) {
257 return new Function<Publication, Boolean>() {
258 @Override
259 public Boolean apply(Publication p) {
260 return p.getChannel().equals(channelId);
261 }
262 };
263 }
264
265
266 public static Function<MediaPackageElement, Boolean> hasTagAny(final List<String> tags) {
267 return new Function<MediaPackageElement, Boolean>() {
268 @Override
269 public Boolean apply(MediaPackageElement mpe) {
270 return mpe.containsTag(tags);
271 }
272 };
273 }
274
275
276
277
278
279
280 public static Function<MediaPackageElement, Boolean> matchesFlavor(final MediaPackageElementFlavor flavor) {
281 return new Function<MediaPackageElement, Boolean>() {
282 @Override
283 public Boolean apply(MediaPackageElement mpe) {
284
285 return flavor.matches(mpe.getFlavor());
286 }
287 };
288 }
289
290 public static final Function<MediaPackageElementFlavor, Function<MediaPackageElement, Boolean>> matchesFlavor = new Function<MediaPackageElementFlavor, Function<MediaPackageElement, Boolean>>() {
291 @Override
292 public Function<MediaPackageElement, Boolean> apply(final MediaPackageElementFlavor flavor) {
293 return matchesFlavor(flavor);
294 }
295 };
296
297 public static final Function<MediaPackageElement, Boolean> isEpisodeDublinCore = new Function<MediaPackageElement, Boolean>() {
298 @Override
299 public Boolean apply(MediaPackageElement mpe) {
300
301 return MediaPackageElements.EPISODE.matches(mpe.getFlavor());
302 }
303 };
304
305 public static final Function<MediaPackageElement, Boolean> isSmilCatalog = new Function<MediaPackageElement, Boolean>() {
306 @Override
307 public Boolean apply(MediaPackageElement mpe) {
308
309 return MediaPackageElements.SMIL.matches(mpe.getFlavor());
310 }
311 };
312 }
313
314
315
316
317
318
319
320
321
322
323
324 public static Option<List<String>> sanityCheck(MediaPackage mp) {
325 final Option<List<String>> errors = sequenceOpt(list(toOption(mp.getIdentifier() != null, "no ID"),
326 toOption(mp.getIdentifier() != null && isNotBlank(mp.getIdentifier().toString()), "blank ID")));
327 return errors.getOrElse(NIL).size() == 0 ? Option.<List<String>> none() : errors;
328 }
329
330
331 public static MediaPackage loadFromClassPath(String path) {
332 return withResource(MediaPackageSupport.class.getResourceAsStream(path),
333 new Function.X<InputStream, MediaPackage>() {
334 @Override
335 public MediaPackage xapply(InputStream is) throws MediaPackageException {
336 return MediaPackageBuilderFactory.newInstance().newMediaPackageBuilder().loadFromXml(is);
337 }
338 });
339 }
340
341
342
343
344 @Deprecated
345 public static final Function<MediaPackage, String> getId = new Function<MediaPackage, String>() {
346 @Override
347 public String apply(MediaPackage mp) {
348 return mp.getIdentifier().toString();
349 }
350 };
351
352
353 public static final class Fn {
354 private Fn() {
355 }
356
357 }
358 }