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.functions.Misc.chuck;
27
28 import org.apache.commons.io.FilenameUtils;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 import java.io.InputStream;
33 import java.net.URI;
34 import java.util.List;
35 import java.util.Objects;
36 import java.util.Optional;
37 import java.util.function.Consumer;
38 import java.util.function.Function;
39 import java.util.function.Predicate;
40 import java.util.stream.Collectors;
41
42
43 public final class MediaPackageSupport {
44
45 private MediaPackageSupport() {
46 }
47
48 private static final List NIL = java.util.Collections.EMPTY_LIST;
49
50
51
52
53
54
55
56
57
58
59
60 public enum MergeMode {
61 Merge, Replace, Skip, Fail
62 }
63
64
65 private static final Logger logger = LoggerFactory.getLogger(MediaPackageSupport.class.getName());
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 public static MediaPackage merge(MediaPackage dest, MediaPackage src, MergeMode mode) throws MediaPackageException {
85 try {
86 for (MediaPackageElement e : src.elements()) {
87 if (dest.getElementById(e.getIdentifier()) == null) {
88 dest.add(e);
89 } else {
90 if (MergeMode.Replace == mode) {
91 logger.debug("Replacing element " + e.getIdentifier() + " while merging " + dest + " with " + src);
92 dest.remove(dest.getElementById(e.getIdentifier()));
93 dest.add(e);
94 } else if (MergeMode.Skip == mode) {
95 logger.debug("Skipping element " + e.getIdentifier() + " while merging " + dest + " with " + src);
96 continue;
97 } else if (MergeMode.Merge == mode) {
98 logger.debug("Renaming element " + e.getIdentifier() + " while merging " + dest + " with " + src);
99 e.setIdentifier(null);
100 dest.add(e);
101 } else if (MergeMode.Fail == mode) {
102 throw new MediaPackageException("Target media package " + dest + " already contains element with id "
103 + e.getIdentifier());
104 }
105 }
106 }
107 } catch (UnsupportedElementException e) {
108 throw new MediaPackageException(e);
109 }
110 return dest;
111 }
112
113
114
115
116
117
118
119
120 public static boolean contains(String identifier, MediaPackage mp) {
121 for (MediaPackageElement element : mp.getElements()) {
122 if (element.getIdentifier().equals(identifier)) {
123 return true;
124 }
125 }
126 return false;
127 }
128
129
130
131
132
133
134 public static Optional<String> getFileName(MediaPackageElement mpe) {
135 URI uri = mpe.getURI();
136 if (uri == null) {
137 return Optional.empty();
138 }
139 String name = FilenameUtils.getName(uri.toString());
140 if (name == null || name.isBlank()) {
141 return Optional.empty();
142 }
143 return Optional.of(name);
144 }
145
146
147
148
149
150
151
152 public static MediaPackage copy(MediaPackage mp) {
153 return (MediaPackage) mp.clone();
154 }
155
156
157 public static void updateElement(MediaPackage mp, MediaPackageElement e) {
158 mp.removeElementById(e.getIdentifier());
159 mp.add(e);
160 }
161
162
163 public static Consumer<MediaPackageElement> updateElement(final MediaPackage mp) {
164 return e -> updateElement(mp, e);
165 }
166
167
168 public static final class Filters {
169 private Filters() {
170 }
171
172
173 public static final Predicate<MediaPackageElement> isPublication = Publication.class::isInstance;
174 public static final Predicate<MediaPackageElement> isNotPublication = isPublication.negate();
175
176 public static final Predicate<MediaPackageElement> hasChecksum = e -> e.getChecksum() != null;
177
178 public static final Predicate<MediaPackageElement> hasNoChecksum = hasChecksum.negate();
179
180
181 public static boolean ofChannel(Publication p, String channelId) {
182 return p.getChannel().equals(channelId);
183 }
184
185
186 public static boolean hasTagAny(MediaPackageElement mpe, List<String> tags) {
187 return mpe.containsTag(tags);
188 }
189
190
191
192
193
194
195 public static Function<MediaPackageElement, Boolean> matchesFlavor(final MediaPackageElementFlavor flavor) {
196 return mpe -> flavor.matches(mpe.getFlavor());
197 }
198
199 public static boolean isEpisodeDublinCore(MediaPackageElement mpe) {
200
201 return MediaPackageElements.EPISODE.matches(mpe.getFlavor());
202 }
203
204 public static boolean isSmilCatalog(MediaPackageElement mpe) {
205
206 return MediaPackageElements.SMIL.matches(mpe.getFlavor());
207 }
208 }
209
210
211
212
213
214
215
216
217
218
219
220 public static Optional<List<String>> sanityCheck(MediaPackage mp) {
221 List<String> errors = java.util.stream.Stream.of(
222 mp.getIdentifier() == null ? "no ID" : null,
223 (mp.getIdentifier() != null && isNotBlank(mp.getIdentifier().toString())) ? null : "blank ID"
224 )
225 .filter(Objects::nonNull)
226 .collect(Collectors.toList());
227
228 return errors.isEmpty() ? Optional.empty() : Optional.of(errors);
229 }
230
231
232 public static MediaPackage loadFromClassPath(String path) {
233 return withResource(
234 MediaPackageSupport.class.getResourceAsStream(path),
235 (InputStream is) -> {
236 try {
237 return MediaPackageBuilderFactory.newInstance()
238 .newMediaPackageBuilder()
239 .loadFromXml(is);
240 } catch (Exception e) {
241 return chuck(e);
242 }
243 }
244 );
245 }
246 }