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(org.opencastproject.mediapackage.MediaPackageElement.Type
92     *      , org.opencastproject.mediapackage.MediaPackageElementFlavor)
93     */
94    @Override
95    public boolean accept(MediaPackageElement.Type type, MediaPackageElementFlavor flavor) {
96      if (this.flavor != null && !this.flavor.equals(flavor))
97        return false;
98      return type == null || MediaPackageElement.Type.Attachment.toString().equalsIgnoreCase(type.toString());
99    }
100 
101   /**
102    * This implementation of <code>accept</code> tests for the correct node type (attachment).
103    *
104    * @see org.opencastproject.mediapackage.elementbuilder.MediaPackageElementBuilderPlugin#accept(org.w3c.dom.Node)
105    */
106   @Override
107   public boolean accept(Node elementNode) {
108     try {
109       // Test for attachment
110       String nodeName = elementNode.getNodeName();
111       if (nodeName.contains(":")) {
112         nodeName = nodeName.substring(nodeName.indexOf(":") + 1);
113       }
114       if (!MediaPackageElement.Type.Attachment.toString().equalsIgnoreCase(nodeName))
115         return false;
116       // Check flavor
117       if (this.flavor != null) {
118         String nodeFlavor = (String) xpath.evaluate("@type", elementNode, XPathConstants.STRING);
119         if (!flavor.eq(nodeFlavor))
120           return false;
121       }
122       // Check mime type
123       if (mimeTypes != null && mimeTypes.size() > 0) {
124         String nodeMimeType = (String) xpath.evaluate("mimetype", elementNode, XPathConstants.STRING);
125         MimeType mimeType = MimeTypes.parseMimeType(nodeMimeType);
126         if (!mimeTypes.contains(mimeType))
127           return false;
128       }
129 
130       return true;
131     } catch (XPathExpressionException e) {
132       logger.warn("Error while reading attachment flavor from manifest: " + e.getMessage());
133       return false;
134     }
135   }
136 
137   /**
138    * @see org.opencastproject.mediapackage.MediaPackageElementBuilder#newElement(org.opencastproject.mediapackage.MediaPackageElement.Type
139    *      , org.opencastproject.mediapackage.MediaPackageElementFlavor)
140    */
141   @Override
142   public MediaPackageElement newElement(MediaPackageElement.Type type, MediaPackageElementFlavor flavor) {
143     Attachment attachment = new AttachmentImpl();
144     attachment.setFlavor(flavor);
145     return attachment;
146   }
147 
148   /**
149    * @see org.opencastproject.mediapackage.elementbuilder.MediaPackageElementBuilderPlugin#elementFromManifest(org.w3c.dom.Node,
150    *      org.opencastproject.mediapackage.MediaPackageSerializer)
151    */
152   @Override
153   public MediaPackageElement elementFromManifest(Node elementNode, MediaPackageSerializer serializer)
154           throws UnsupportedElementException {
155 
156     String id = null;
157     String attachmentFlavor = null;
158     String reference = null;
159     URI uri = null;
160     long size = -1;
161     Checksum checksum = null;
162     MimeType mimeType = null;
163 
164     try {
165       // id
166       id = (String) xpath.evaluate("@id", elementNode, XPathConstants.STRING);
167 
168       // flavor
169       attachmentFlavor = (String) xpath.evaluate("@type", elementNode, XPathConstants.STRING);
170 
171       // reference
172       reference = (String) xpath.evaluate("@ref", elementNode, XPathConstants.STRING);
173 
174       // url
175       uri = serializer.decodeURI(new URI(xpath.evaluate("url/text()", elementNode).trim()));
176 
177       // size
178       String attachmentSize = xpath.evaluate("size/text()", elementNode).trim();
179       if (!"".equals(attachmentSize))
180         size = Long.parseLong(attachmentSize);
181 
182       // checksum
183       String checksumValue = (String) xpath.evaluate("checksum/text()", elementNode, XPathConstants.STRING);
184       String checksumType = (String) xpath.evaluate("checksum/@type", elementNode, XPathConstants.STRING);
185       if (StringUtils.isNotEmpty(checksumValue) && checksumType != null)
186         checksum = Checksum.create(checksumType.trim(), checksumValue.trim());
187 
188       // mimetype
189       String mimeTypeValue = (String) xpath.evaluate("mimetype/text()", elementNode, XPathConstants.STRING);
190       if (StringUtils.isNotEmpty(mimeTypeValue))
191         mimeType = MimeTypes.parseMimeType(mimeTypeValue);
192 
193       // create the attachment
194       AttachmentImpl attachment = (AttachmentImpl) AttachmentImpl.fromURI(uri);
195 
196       if (StringUtils.isNotEmpty(id))
197         attachment.setIdentifier(id);
198 
199       // Add url
200       attachment.setURI(uri);
201 
202       // Add reference
203       if (StringUtils.isNotEmpty(reference))
204         attachment.referTo(MediaPackageReferenceImpl.fromString(reference));
205 
206       // Add type/flavor information
207       if (StringUtils.isNotEmpty(attachmentFlavor)) {
208         try {
209           MediaPackageElementFlavor flavor = MediaPackageElementFlavor.parseFlavor(attachmentFlavor);
210           attachment.setFlavor(flavor);
211         } catch (IllegalArgumentException e) {
212           logger.warn("Unable to read attachment flavor: " + e.getMessage());
213         }
214       }
215 
216       // Set the size
217       if (size > 0)
218         attachment.setSize(size);
219 
220       // Set checksum
221       if (checksum != null)
222         attachment.setChecksum(checksum);
223 
224       // Set mimetype
225       if (mimeType != null)
226         attachment.setMimeType(mimeType);
227 
228       // Set the description
229       String description = xpath.evaluate("description/text()", elementNode);
230       if (StringUtils.isNotEmpty(description))
231         attachment.setElementDescription(description.trim());
232 
233       // Set tags
234       NodeList tagNodes = (NodeList) xpath.evaluate("tags/tag", elementNode, XPathConstants.NODESET);
235       for (int i = 0; i < tagNodes.getLength(); i++) {
236         attachment.addTag(tagNodes.item(i).getTextContent());
237       }
238 
239       return specializeAttachment(attachment);
240     } catch (XPathExpressionException e) {
241       throw new UnsupportedElementException("Error while reading attachment from manifest: " + e.getMessage());
242     } catch (NoSuchAlgorithmException e) {
243       throw new UnsupportedElementException("Unsupported digest algorithm: " + e.getMessage());
244     } catch (URISyntaxException e) {
245       throw new UnsupportedElementException("Error while reading attachment file " + uri + ": " + e.getMessage());
246     }
247   }
248 
249   /**
250    * Utility method that returns an attachment object from the given url.
251    *
252    * @param uri
253    *          the element location
254    * @return an attachment object
255    * @throws UnsupportedElementException
256    *           if the attachment cannto be read
257    */
258   @Override
259   public MediaPackageElement elementFromURI(URI uri) throws UnsupportedElementException {
260     logger.trace("Creating attachment from " + uri);
261     return specializeAttachment(AttachmentImpl.fromURI(uri));
262   }
263 
264   /**
265    * @see org.opencastproject.mediapackage.MediaPackageElementBuilder#elementFromURI(URI,
266    *      org.opencastproject.mediapackage.MediaPackageElement.Type ,
267    *      org.opencastproject.mediapackage.MediaPackageElementFlavor)
268    */
269   public MediaPackageElement elementFromURI(URI uri, MediaPackageElement.Type type, MediaPackageElementFlavor flavor)
270           throws UnsupportedElementException {
271     return elementFromURI(uri);
272   }
273 
274   /**
275    * Overwrite this method in order to return a specialization of the attachment. This implementation just returns the
276    * attachment that is was given.
277    *
278    * @param attachment
279    *          the general attachment representation
280    * @return a specialized attachment
281    * @throws UnsupportedElementException
282    *           if the attachment fails to be specialized
283    */
284   protected Attachment specializeAttachment(Attachment attachment) throws UnsupportedElementException {
285     return attachment;
286   }
287 
288   /**
289    * @see java.lang.Object#toString()
290    */
291   @Override
292   public String toString() {
293     return "Attachment Builder Plugin";
294   }
295 
296 }