View Javadoc
1   /*
2    * Licensed to The Apereo Foundation under one or more contributor license
3    * agreements. See the NOTICE file distributed with this work for additional
4    * information regarding copyright ownership.
5    *
6    *
7    * The Apereo Foundation licenses this file to you under the Educational
8    * Community License, Version 2.0 (the "License"); you may not use this file
9    * except in compliance with the License. You may obtain a copy of the License
10   * at:
11   *
12   *   http://opensource.org/licenses/ecl2.txt
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
17   * License for the specific language governing permissions and limitations under
18   * the License.
19   *
20   */
21  
22  
23  package org.opencastproject.mediapackage.elementbuilder;
24  
25  import org.opencastproject.mediapackage.Attachment;
26  import org.opencastproject.mediapackage.MediaPackageElement;
27  import org.opencastproject.mediapackage.MediaPackageElementFlavor;
28  import org.opencastproject.mediapackage.MediaPackageReferenceImpl;
29  import org.opencastproject.mediapackage.MediaPackageSerializer;
30  import org.opencastproject.mediapackage.UnsupportedElementException;
31  import org.opencastproject.mediapackage.attachment.AttachmentImpl;
32  import org.opencastproject.util.Checksum;
33  import org.opencastproject.util.MimeType;
34  import org.opencastproject.util.MimeTypes;
35  
36  import org.apache.commons.lang3.StringUtils;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  import org.w3c.dom.Node;
40  import org.w3c.dom.NodeList;
41  
42  import java.net.URI;
43  import java.net.URISyntaxException;
44  import java.security.NoSuchAlgorithmException;
45  
46  import javax.xml.xpath.XPathConstants;
47  import javax.xml.xpath.XPathExpressionException;
48  
49  /**
50   * This implementation of the {@link MediaPackageElementBuilderPlugin} recognizes attachments and provides utility
51   * methods for creating media package element representations for them.
52   */
53  public abstract class AbstractAttachmentBuilderPlugin extends AbstractElementBuilderPlugin {
54  
55    /** the logging facility provided by log4j */
56    private static final Logger logger = LoggerFactory.getLogger(AbstractAttachmentBuilderPlugin.class);
57  
58    /** The flavor to look for */
59    protected MediaPackageElementFlavor flavor = null;
60  
61    /**
62     * Creates a new attachment plugin builder that will accept attachments with any flavor.
63     */
64    public AbstractAttachmentBuilderPlugin() {
65      this(null);
66    }
67  
68    /**
69     * Creates a new attachment plugin builder that will accept attachments with the given flavor.
70     *
71     * @param flavor
72     *          the attachment flavor
73     */
74    public AbstractAttachmentBuilderPlugin(MediaPackageElementFlavor flavor) {
75      this.flavor = flavor;
76    }
77  
78    /**
79     * @see org.opencastproject.mediapackage.elementbuilder.MediaPackageElementBuilderPlugin#accept(URI,
80     *      org.opencastproject.mediapackage.MediaPackageElement.Type ,
81     *      org.opencastproject.mediapackage.MediaPackageElementFlavor)
82     */
83    @Override
84    public boolean accept(URI uri, MediaPackageElement.Type type, MediaPackageElementFlavor flavor) {
85      return accept(type, flavor);
86    }
87  
88    /**
89     * This implementation of <code>accept</code> tests for the element type (attachment).
90     *
91     * @see org.opencastproject.mediapackage.elementbuilder.MediaPackageElementBuilderPlugin#accept(
92     *      org.opencastproject.mediapackage.MediaPackageElement.Type
93     *      , org.opencastproject.mediapackage.MediaPackageElementFlavor)
94     */
95    @Override
96    public boolean accept(MediaPackageElement.Type type, MediaPackageElementFlavor flavor) {
97      if (this.flavor != null && !this.flavor.equals(flavor)) {
98        return false;
99      }
100     return type == null || MediaPackageElement.Type.Attachment.toString().equalsIgnoreCase(type.toString());
101   }
102 
103   /**
104    * This implementation of <code>accept</code> tests for the correct node type (attachment).
105    *
106    * @see org.opencastproject.mediapackage.elementbuilder.MediaPackageElementBuilderPlugin#accept(org.w3c.dom.Node)
107    */
108   @Override
109   public boolean accept(Node elementNode) {
110     try {
111       // Test for attachment
112       String nodeName = elementNode.getNodeName();
113       if (nodeName.contains(":")) {
114         nodeName = nodeName.substring(nodeName.indexOf(":") + 1);
115       }
116       if (!MediaPackageElement.Type.Attachment.toString().equalsIgnoreCase(nodeName)) {
117         return false;
118       }
119       // Check flavor
120       if (this.flavor != null) {
121         String nodeFlavor = (String) xpath.evaluate("@type", elementNode, XPathConstants.STRING);
122         if (!flavor.eq(nodeFlavor)) {
123           return false;
124         }
125       }
126       // Check mime type
127       if (mimeTypes != null && mimeTypes.size() > 0) {
128         String nodeMimeType = (String) xpath.evaluate("mimetype", elementNode, XPathConstants.STRING);
129         MimeType mimeType = MimeTypes.parseMimeType(nodeMimeType);
130         if (!mimeTypes.contains(mimeType)) {
131           return false;
132         }
133       }
134 
135       return true;
136     } catch (XPathExpressionException e) {
137       logger.warn("Error while reading attachment flavor from manifest: " + e.getMessage());
138       return false;
139     }
140   }
141 
142   /**
143    * @see org.opencastproject.mediapackage.MediaPackageElementBuilder#newElement(
144    *      org.opencastproject.mediapackage.MediaPackageElement.Type
145    *      , org.opencastproject.mediapackage.MediaPackageElementFlavor)
146    */
147   @Override
148   public MediaPackageElement newElement(MediaPackageElement.Type type, MediaPackageElementFlavor flavor) {
149     Attachment attachment = new AttachmentImpl();
150     attachment.setFlavor(flavor);
151     return attachment;
152   }
153 
154   /**
155    * @see org.opencastproject.mediapackage.elementbuilder.MediaPackageElementBuilderPlugin#elementFromManifest(
156    *      org.w3c.dom.Node,
157    *      org.opencastproject.mediapackage.MediaPackageSerializer)
158    */
159   @Override
160   public MediaPackageElement elementFromManifest(Node elementNode, MediaPackageSerializer serializer)
161           throws UnsupportedElementException {
162 
163     String id = null;
164     String attachmentFlavor = null;
165     String reference = null;
166     URI uri = null;
167     long size = -1;
168     Checksum checksum = null;
169     MimeType mimeType = null;
170 
171     try {
172       // id
173       id = (String) xpath.evaluate("@id", elementNode, XPathConstants.STRING);
174 
175       // flavor
176       attachmentFlavor = (String) xpath.evaluate("@type", elementNode, XPathConstants.STRING);
177 
178       // reference
179       reference = (String) xpath.evaluate("@ref", elementNode, XPathConstants.STRING);
180 
181       // url
182       uri = serializer.decodeURI(new URI(xpath.evaluate("url/text()", elementNode).trim()));
183 
184       // size
185       String attachmentSize = xpath.evaluate("size/text()", elementNode).trim();
186       if (!"".equals(attachmentSize)) {
187         size = Long.parseLong(attachmentSize);
188       }
189 
190       // checksum
191       String checksumValue = (String) xpath.evaluate("checksum/text()", elementNode, XPathConstants.STRING);
192       String checksumType = (String) xpath.evaluate("checksum/@type", elementNode, XPathConstants.STRING);
193       if (StringUtils.isNotEmpty(checksumValue) && checksumType != null) {
194         checksum = Checksum.create(checksumType.trim(), checksumValue.trim());
195       }
196 
197       // mimetype
198       String mimeTypeValue = (String) xpath.evaluate("mimetype/text()", elementNode, XPathConstants.STRING);
199       if (StringUtils.isNotEmpty(mimeTypeValue)) {
200         mimeType = MimeTypes.parseMimeType(mimeTypeValue);
201       }
202 
203       // create the attachment
204       AttachmentImpl attachment = (AttachmentImpl) AttachmentImpl.fromURI(uri);
205 
206       if (StringUtils.isNotEmpty(id)) {
207         attachment.setIdentifier(id);
208       }
209 
210       // Add url
211       attachment.setURI(uri);
212 
213       // Add reference
214       if (StringUtils.isNotEmpty(reference)) {
215         attachment.referTo(MediaPackageReferenceImpl.fromString(reference));
216       }
217 
218       // Add type/flavor information
219       if (StringUtils.isNotEmpty(attachmentFlavor)) {
220         try {
221           MediaPackageElementFlavor flavor = MediaPackageElementFlavor.parseFlavor(attachmentFlavor);
222           attachment.setFlavor(flavor);
223         } catch (IllegalArgumentException e) {
224           logger.warn("Unable to read attachment flavor: " + e.getMessage());
225         }
226       }
227 
228       // Set the size
229       if (size > 0) {
230         attachment.setSize(size);
231       }
232 
233       // Set checksum
234       if (checksum != null) {
235         attachment.setChecksum(checksum);
236       }
237 
238       // Set mimetype
239       if (mimeType != null) {
240         attachment.setMimeType(mimeType);
241       }
242 
243       // Set the description
244       String description = xpath.evaluate("description/text()", elementNode);
245       if (StringUtils.isNotEmpty(description)) {
246         attachment.setElementDescription(description.trim());
247       }
248 
249       // Set tags
250       NodeList tagNodes = (NodeList) xpath.evaluate("tags/tag", elementNode, XPathConstants.NODESET);
251       for (int i = 0; i < tagNodes.getLength(); i++) {
252         attachment.addTag(tagNodes.item(i).getTextContent());
253       }
254 
255       return specializeAttachment(attachment);
256     } catch (XPathExpressionException e) {
257       throw new UnsupportedElementException("Error while reading attachment from manifest: " + e.getMessage());
258     } catch (NoSuchAlgorithmException e) {
259       throw new UnsupportedElementException("Unsupported digest algorithm: " + e.getMessage());
260     } catch (URISyntaxException e) {
261       throw new UnsupportedElementException("Error while reading attachment file " + uri + ": " + e.getMessage());
262     }
263   }
264 
265   /**
266    * Utility method that returns an attachment object from the given url.
267    *
268    * @param uri
269    *          the element location
270    * @return an attachment object
271    * @throws UnsupportedElementException
272    *           if the attachment cannto be read
273    */
274   @Override
275   public MediaPackageElement elementFromURI(URI uri) throws UnsupportedElementException {
276     logger.trace("Creating attachment from " + uri);
277     return specializeAttachment(AttachmentImpl.fromURI(uri));
278   }
279 
280   /**
281    * @see org.opencastproject.mediapackage.MediaPackageElementBuilder#elementFromURI(URI,
282    *      org.opencastproject.mediapackage.MediaPackageElement.Type ,
283    *      org.opencastproject.mediapackage.MediaPackageElementFlavor)
284    */
285   public MediaPackageElement elementFromURI(URI uri, MediaPackageElement.Type type, MediaPackageElementFlavor flavor)
286           throws UnsupportedElementException {
287     return elementFromURI(uri);
288   }
289 
290   /**
291    * Overwrite this method in order to return a specialization of the attachment. This implementation just returns the
292    * attachment that is was given.
293    *
294    * @param attachment
295    *          the general attachment representation
296    * @return a specialized attachment
297    * @throws UnsupportedElementException
298    *           if the attachment fails to be specialized
299    */
300   protected Attachment specializeAttachment(Attachment attachment) throws UnsupportedElementException {
301     return attachment;
302   }
303 
304   /**
305    * @see java.lang.Object#toString()
306    */
307   @Override
308   public String toString() {
309     return "Attachment Builder Plugin";
310   }
311 
312 }