1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.opencastproject.mediapackage.elementbuilder;
24
25 import org.opencastproject.mediapackage.MediaPackageElement;
26 import org.opencastproject.mediapackage.MediaPackageElementFlavor;
27 import org.opencastproject.mediapackage.MediaPackageReferenceImpl;
28 import org.opencastproject.mediapackage.MediaPackageSerializer;
29 import org.opencastproject.mediapackage.Track;
30 import org.opencastproject.mediapackage.UnsupportedElementException;
31 import org.opencastproject.mediapackage.track.AudioStreamImpl;
32 import org.opencastproject.mediapackage.track.SubtitleStreamImpl;
33 import org.opencastproject.mediapackage.track.TrackImpl;
34 import org.opencastproject.mediapackage.track.VideoStreamImpl;
35 import org.opencastproject.util.Checksum;
36 import org.opencastproject.util.MimeType;
37 import org.opencastproject.util.MimeTypes;
38
39 import org.apache.commons.lang3.StringUtils;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42 import org.w3c.dom.Node;
43 import org.w3c.dom.NodeList;
44
45 import java.net.URI;
46 import java.net.URISyntaxException;
47 import java.security.NoSuchAlgorithmException;
48
49 import javax.xml.xpath.XPathConstants;
50 import javax.xml.xpath.XPathException;
51 import javax.xml.xpath.XPathExpressionException;
52
53
54
55
56
57 public class TrackBuilderPlugin extends AbstractElementBuilderPlugin {
58
59
60
61
62 private static final Logger logger = LoggerFactory.getLogger(TrackBuilderPlugin.class);
63
64
65
66
67
68 @Override
69 public boolean accept(MediaPackageElement.Type type, MediaPackageElementFlavor flavor) {
70 return type.equals(MediaPackageElement.Type.Track);
71 }
72
73
74
75
76 @Override
77 public boolean accept(Node elementNode) {
78 String name = elementNode.getNodeName();
79 if (name.contains(":")) {
80 name = name.substring(name.indexOf(":") + 1);
81 }
82 return name.equalsIgnoreCase(MediaPackageElement.Type.Track.toString());
83 }
84
85
86
87
88
89
90 @Override
91 public boolean accept(URI uri, MediaPackageElement.Type type, MediaPackageElementFlavor flavor) {
92 return MediaPackageElement.Type.Track.equals(type);
93 }
94
95
96
97
98 @Override
99 public MediaPackageElement elementFromURI(URI uri) throws UnsupportedElementException {
100 logger.trace("Creating track from " + uri);
101 Track track = TrackImpl.fromURI(uri);
102 return track;
103 }
104
105
106
107
108
109 @Override
110 public MediaPackageElement newElement(MediaPackageElement.Type type, MediaPackageElementFlavor flavor) {
111 Track track = new TrackImpl();
112 track.setFlavor(flavor);
113 return track;
114 }
115
116
117
118
119
120 @Override
121 public MediaPackageElement elementFromManifest(Node elementNode, MediaPackageSerializer serializer)
122 throws UnsupportedElementException {
123
124 String id = null;
125 MimeType mimeType = null;
126 MediaPackageElementFlavor flavor = null;
127 TrackImpl.StreamingProtocol transport = null;
128 String reference = null;
129 URI url = null;
130 long size = -1;
131 Checksum checksum = null;
132
133 try {
134
135 id = (String) xpath.evaluate("@id", elementNode, XPathConstants.STRING);
136
137
138 url = serializer.decodeURI(new URI(xpath.evaluate("url/text()", elementNode).trim()));
139
140
141 reference = (String) xpath.evaluate("@ref", elementNode, XPathConstants.STRING);
142
143
144 String trackSize = xpath.evaluate("size/text()", elementNode).trim();
145 if (!"".equals(trackSize))
146 size = Long.parseLong(trackSize);
147
148
149 String flavorValue = (String) xpath.evaluate("@type", elementNode, XPathConstants.STRING);
150 if (StringUtils.isNotEmpty(flavorValue))
151 flavor = MediaPackageElementFlavor.parseFlavor(flavorValue);
152
153
154 String transportValue = (String) xpath.evaluate("@transport", elementNode, XPathConstants.STRING);
155 if (StringUtils.isNotEmpty(transportValue))
156 transport = TrackImpl.StreamingProtocol.valueOf(transportValue);
157
158
159 String checksumValue = (String) xpath.evaluate("checksum/text()", elementNode, XPathConstants.STRING);
160 String checksumType = (String) xpath.evaluate("checksum/@type", elementNode, XPathConstants.STRING);
161 if (StringUtils.isNotEmpty(checksumValue) && checksumType != null)
162 checksum = Checksum.create(checksumType.trim(), checksumValue.trim());
163
164
165 String mimeTypeValue = (String) xpath.evaluate("mimetype/text()", elementNode, XPathConstants.STRING);
166 if (StringUtils.isNotEmpty(mimeTypeValue))
167 mimeType = MimeTypes.parseMimeType(mimeTypeValue);
168
169
170
171
172 TrackImpl track = TrackImpl.fromURI(url);
173
174 if (StringUtils.isNotBlank(id))
175 track.setIdentifier(id);
176
177
178 track.setURI(url);
179
180
181 if (StringUtils.isNotEmpty(reference))
182 track.referTo(MediaPackageReferenceImpl.fromString(reference));
183
184
185 if (size > 0)
186 track.setSize(size);
187
188
189 if (checksum != null)
190 track.setChecksum(checksum);
191
192
193 if (mimeType != null)
194 track.setMimeType(mimeType);
195
196 if (flavor != null)
197 track.setFlavor(flavor);
198
199
200 if (transport != null)
201 track.setTransport(transport);
202
203
204 String description = (String) xpath.evaluate("description/text()", elementNode, XPathConstants.STRING);
205 if (StringUtils.isNotBlank(description))
206 track.setElementDescription(description.trim());
207
208
209 NodeList tagNodes = (NodeList) xpath.evaluate("tags/tag", elementNode, XPathConstants.NODESET);
210 for (int i = 0; i < tagNodes.getLength(); i++) {
211 track.addTag(tagNodes.item(i).getTextContent());
212 }
213
214
215 try {
216 String strDuration = (String) xpath.evaluate("duration/text()", elementNode, XPathConstants.STRING);
217 if (StringUtils.isNotEmpty(strDuration)) {
218 long duration = Long.parseLong(strDuration.trim());
219 track.setDuration(duration);
220 }
221 } catch (NumberFormatException e) {
222 throw new UnsupportedElementException("Duration of track " + url + " is malformatted");
223 }
224
225
226 String strLive = (String) xpath.evaluate("live/text()", elementNode, XPathConstants.STRING);
227 if (StringUtils.isNotEmpty(strLive)) {
228 boolean live = Boolean.parseBoolean(strLive.trim());
229 track.setLive(live);
230 }
231
232
233 String strMaster = (String) xpath.evaluate("master/text()", elementNode, XPathConstants.STRING);
234 if (StringUtils.isNotEmpty(strMaster)) {
235 track.setMaster(Boolean.parseBoolean(strMaster.trim()));
236 }
237
238
239 String strLogicalname = (String) xpath.evaluate("logicalname/text()", elementNode, XPathConstants.STRING);
240 if (StringUtils.isNotEmpty(strLogicalname)) {
241 track.setLogicalName(strLogicalname.trim());
242 }
243
244
245 Node audioSettingsNode = (Node) xpath.evaluate("audio", elementNode, XPathConstants.NODE);
246 if (audioSettingsNode != null && audioSettingsNode.hasChildNodes()) {
247 try {
248 AudioStreamImpl as = AudioStreamImpl.fromManifest(createStreamID(track), audioSettingsNode, xpath);
249 track.addStream(as);
250 } catch (IllegalStateException e) {
251 throw new UnsupportedElementException("Illegal state encountered while reading audio settings from " + url
252 + ": " + e.getMessage());
253 } catch (XPathException e) {
254 throw new UnsupportedElementException("Error while parsing audio settings from " + url + ": "
255 + e.getMessage());
256 }
257 }
258
259
260 Node videoSettingsNode = (Node) xpath.evaluate("video", elementNode, XPathConstants.NODE);
261 if (videoSettingsNode != null && videoSettingsNode.hasChildNodes()) {
262 try {
263 VideoStreamImpl vs = VideoStreamImpl.fromManifest(createStreamID(track), videoSettingsNode, xpath);
264 track.addStream(vs);
265 } catch (IllegalStateException e) {
266 throw new UnsupportedElementException("Illegal state encountered while reading video settings from " + url
267 + ": " + e.getMessage());
268 } catch (XPathException e) {
269 throw new UnsupportedElementException("Error while parsing video settings from " + url + ": "
270 + e.getMessage());
271 }
272 }
273
274
275 Node subtitleSettingsNode = (Node) xpath.evaluate("subtitle", elementNode, XPathConstants.NODE);
276 if (subtitleSettingsNode != null && subtitleSettingsNode.hasChildNodes()) {
277 try {
278 SubtitleStreamImpl ss = SubtitleStreamImpl.fromManifest(createStreamID(track), subtitleSettingsNode, xpath);
279 track.addStream(ss);
280 } catch (IllegalStateException e) {
281 throw new UnsupportedElementException("Illegal state encountered while reading subtitle settings from " + url
282 + ": " + e.getMessage());
283 } catch (XPathException e) {
284 throw new UnsupportedElementException("Error while parsing subtitle settings from " + url + ": "
285 + e.getMessage());
286 }
287 }
288
289 return track;
290 } catch (XPathExpressionException e) {
291 throw new UnsupportedElementException("Error while reading track information from manifest: " + e.getMessage());
292 } catch (NoSuchAlgorithmException e) {
293 throw new UnsupportedElementException("Unsupported digest algorithm: " + e.getMessage());
294 } catch (URISyntaxException e) {
295 throw new UnsupportedElementException("Error while reading presenter track " + url + ": " + e.getMessage());
296 }
297 }
298
299 private String createStreamID(Track track) {
300 return "stream-" + (track.getStreams().length + 1);
301 }
302
303 @Override
304 public String toString() {
305 return "Track Builder Plugin";
306 }
307
308 }