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  package org.opencastproject.metadata.dublincore;
23  
24  import static javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI;
25  import static org.opencastproject.mediapackage.XMLCatalogImpl.XSI_NS_PREFIX;
26  import static org.opencastproject.metadata.dublincore.DublinCore.ELEMENTS_1_1_NS_PREFIX;
27  import static org.opencastproject.metadata.dublincore.DublinCore.ELEMENTS_1_1_NS_URI;
28  import static org.opencastproject.metadata.dublincore.DublinCore.TERMS_NS_PREFIX;
29  import static org.opencastproject.metadata.dublincore.DublinCore.TERMS_NS_URI;
30  
31  import org.opencastproject.mediapackage.EName;
32  import org.opencastproject.mediapackage.MediaPackageElementFlavor;
33  import org.opencastproject.mediapackage.MediaPackageElements;
34  import org.opencastproject.metadata.dublincore.OpencastDctermsDublinCore.Episode;
35  import org.opencastproject.metadata.dublincore.OpencastDctermsDublinCore.Series;
36  import org.opencastproject.util.XmlNamespaceBinding;
37  import org.opencastproject.util.XmlNamespaceContext;
38  
39  import org.apache.commons.io.IOUtils;
40  
41  import java.io.IOException;
42  import java.io.InputStream;
43  import java.nio.charset.StandardCharsets;
44  
45  import javax.annotation.Nonnull;
46  import javax.annotation.ParametersAreNonnullByDefault;
47  import javax.xml.XMLConstants;
48  
49  /**
50   * Factory for metadata catalogs following the DublinCore standard.
51   */
52  @ParametersAreNonnullByDefault
53  public final class DublinCores {
54    /**
55     * Namespace name of Dublin Core metadata generated by Opencast. By default this namespace is the default namespace
56     * of xml documents generated by this class.
57     */
58    public static final String OC_DC_CATALOG_NS_URI = "http://www.opencastproject.org/xsd/1.0/dublincore/";
59  
60    /** The dc root element of Opencast DublinCore catalogs. */
61    public static final EName OC_DC_CATALOG_ROOT_ELEMENT = new EName(OC_DC_CATALOG_NS_URI, "dublincore");
62  
63    /** Namespace URI for Opencast properties. */
64    public static final String OC_PROPERTY_NS_URI = "http://www.opencastproject.org/matterhorn/";
65  
66    /** Prefix for Opencast properties. */
67    public static final String OC_PROPERTY_NS_PREFIX = "oc";
68  
69    /**
70     * Opencast property: The timezone of the agent specified to be scheduled with an event. IE: "America/Chicago"
71     */
72    public static final EName OC_PROPERTY_AGENT_TIMEZONE = new EName(OC_PROPERTY_NS_URI, "agentTimezone");
73  
74    /**
75     * This is a string defining a recurrence pattern as specified in RFC 2445. See <a
76     * href="http://tools.ietf.org/html/rfc2445#section-4.8.5.4">http://tools.ietf.org/html/rfc2445#section-4.8.5.4</a>
77     */
78    public static final EName OC_PROPERTY_RECURRENCE = new EName(OC_PROPERTY_NS_URI, "recurrence");
79    public static final EName OC_PROPERTY_ANNOTATION = new EName(OC_PROPERTY_NS_URI, "annotation");
80    public static final EName OC_PROPERTY_ADVERTISED = new EName(OC_PROPERTY_NS_URI, "advertised");
81    public static final EName OC_PROPERTY_PROMOTED = new EName(OC_PROPERTY_NS_URI, "promoted");
82    public static final EName OC_PROPERTY_DURATION = new EName(OC_PROPERTY_NS_URI, "duration");
83  
84    private DublinCores() {
85    }
86  
87    /**
88     * Create a new Opencast DublinCore metadata catalog for episodes.
89     * <ul>
90     * <li>Set flavor to {@link org.opencastproject.mediapackage.MediaPackageElements#EPISODE}.
91     * <li>Register all necessary namespaces and set the root tag to {@link #OC_DC_CATALOG_ROOT_ELEMENT}.
92     * <li>The catalog does not have an {@linkplain DublinCoreCatalog#getIdentifier() identifier} and the
93     *   {@link DublinCore#PROPERTY_IDENTIFIER identifier} property is not set.
94     * </ul>
95     *
96     * @deprecated use {@link #mkOpencastEpisode()} instead
97     */
98    @Nonnull
99    @Deprecated
100   public static Episode mkOpencast() {
101     return mkOpencastEpisode();
102   }
103 
104   /**
105    * Create a new Opencast DublinCore metadata catalog for episodes.
106    * <ul>
107    * <li>Set flavor to {@link org.opencastproject.mediapackage.MediaPackageElements#EPISODE}.
108    * <li>Register all necessary namespaces and set the root tag to {@link #OC_DC_CATALOG_ROOT_ELEMENT}.
109    * <li>The catalog does not have an {@linkplain DublinCoreCatalog#getIdentifier() identifier} and the
110    *   {@link DublinCore#PROPERTY_IDENTIFIER identifier} property is not set.
111    * </ul>
112    */
113   @Nonnull
114   public static Episode mkOpencastEpisode() {
115     return new Episode(mkOpencast(MediaPackageElements.EPISODE));
116   }
117 
118   /**
119    * Create an Opencast episode DublinCore accessor for a {@link DublinCoreCatalog}.
120    * Read and write operations access and modify the wrapped catalog.
121    */
122   @Nonnull
123   public static Episode mkOpencastEpisode(DublinCoreCatalog dc) {
124     return new Episode(dc);
125   }
126 
127   /**
128    * Create a new Opencast DublinCore metadata catalog for series.
129    * <ul>
130    * <li>Set flavor to {@link org.opencastproject.mediapackage.MediaPackageElements#SERIES}.
131    * <li>Register all necessary namespaces and set the root tag to {@link #OC_DC_CATALOG_ROOT_ELEMENT}.
132    * <li>The catalog does not have an {@linkplain DublinCoreCatalog#getIdentifier() identifier} and the
133    *   {@link DublinCore#PROPERTY_IDENTIFIER identifier} property is not set.
134    * </ul>
135    */
136   @Nonnull
137   public static Series mkOpencastSeries() {
138     return new Series(mkOpencast(MediaPackageElements.SERIES));
139   }
140 
141   /**
142    * Create a new empty catalog suitable to take properties from the standard DublinCore
143    * namespaces {@link DublinCore#ELEMENTS_1_1_NS_URI} and {@link DublinCore#TERMS_NS_URI}.
144    * <p>
145    * Please note that neither a flavor nor a root tag is set.
146    */
147   @Nonnull
148   public static DublinCoreCatalog mkStandard() {
149     final DublinCoreCatalog dc = new DublinCoreCatalog();
150     dc.addBindings(XmlNamespaceContext.mk(
151             XmlNamespaceBinding.mk(ELEMENTS_1_1_NS_PREFIX, ELEMENTS_1_1_NS_URI),
152             XmlNamespaceBinding.mk(TERMS_NS_PREFIX, TERMS_NS_URI)));
153     return dc;
154   }
155 
156   /** Create a new empty catalog with no special namespace registered, no root tag and no flavor. */
157   @Nonnull
158   public static DublinCoreCatalog mkSimple() {
159     return new DublinCoreCatalog();
160   }
161 
162   /**
163    * Read a DublinCore catalog from a stream containing either JSON or XML. The method is
164    * capable of detecting the used format.
165    * <p>
166    * The reader is not capable of determining the catalog's flavor.
167    * <p>
168    * <strong>Implementation note:</strong> In order to detect the format the whole stream is read into memory first.
169    */
170   @Nonnull
171   public static DublinCoreCatalog read(InputStream in) {
172     final String ser;
173     try {
174       ser = IOUtils.toString(in, StandardCharsets.UTF_8);
175     } catch (IOException e) {
176       throw new RuntimeException("Unable to read DublinCore from stream", e);
177     }
178     if (DublinCoreJsonFormat.isJson(ser)) {
179       try {
180         return DublinCoreJsonFormat.read(ser);
181       } catch (Exception e) {
182         throw new RuntimeException("Unable to read DublinCore catalog, JSON parsing failed.", e);
183       }
184     } else {
185       try {
186         return DublinCoreXmlFormat.read(ser);
187       } catch (Exception e) {
188         throw new RuntimeException("Unable to read DublinCore catalog, XML parsing failed.", e);
189       }
190     }
191   }
192 
193   private static DublinCoreCatalog mkOpencast(MediaPackageElementFlavor flavor) {
194     final DublinCoreCatalog dc = mkStandard();
195     dc.setFlavor(flavor);
196     dc.addBindings(XmlNamespaceContext.mk(
197             // Opencast property namespace
198             XmlNamespaceBinding.mk(OC_PROPERTY_NS_PREFIX, OC_PROPERTY_NS_URI),
199             // Opencast root tag
200             XmlNamespaceBinding.mk(XMLConstants.DEFAULT_NS_PREFIX, OC_DC_CATALOG_NS_URI)));
201             //XMLSchema-instance namespace xsi
202             XmlNamespaceBinding.mk(XSI_NS_PREFIX, W3C_XML_SCHEMA_INSTANCE_NS_URI);
203     dc.setRootTag(OC_DC_CATALOG_ROOT_ELEMENT);
204     return dc;
205   }
206 }