/**
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License
* at:
*
* http://opensource.org/licenses/ecl2.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
*/
package org.opencastproject.metadata.dublincore;
import static java.util.UUID.randomUUID;
import static javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI;
import static org.opencastproject.mediapackage.XMLCatalogImpl.XSI_NS_PREFIX;
import static org.opencastproject.metadata.dublincore.DublinCore.ELEMENTS_1_1_NS_PREFIX;
import static org.opencastproject.metadata.dublincore.DublinCore.ELEMENTS_1_1_NS_URI;
import static org.opencastproject.metadata.dublincore.DublinCore.TERMS_NS_PREFIX;
import static org.opencastproject.metadata.dublincore.DublinCore.TERMS_NS_URI;
import org.opencastproject.mediapackage.EName;
import org.opencastproject.mediapackage.MediaPackageElementFlavor;
import org.opencastproject.mediapackage.MediaPackageElements;
import org.opencastproject.metadata.dublincore.OpencastDctermsDublinCore.Episode;
import org.opencastproject.metadata.dublincore.OpencastDctermsDublinCore.Series;
import org.opencastproject.util.XmlNamespaceBinding;
import org.opencastproject.util.XmlNamespaceContext;
import com.entwinemedia.fn.data.Opt;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import javax.xml.XMLConstants;
/**
* Factory for metadata catalogs following the DublinCore standard.
*/
@ParametersAreNonnullByDefault
public final class DublinCores {
/**
* Namespace name of Dublin Core metadata generated by matterhorn. By default this namespace is the default namespace
* of xml documents generated by this class.
*/
public static final String OC_DC_CATALOG_NS_URI = "http://www.opencastproject.org/xsd/1.0/dublincore/";
/** The dc root element of Opencast DublinCore catalogs. */
public static final EName OC_DC_CATALOG_ROOT_ELEMENT = new EName(OC_DC_CATALOG_NS_URI, "dublincore");
/** Namespace URI for Opencast properties. */
public static final String OC_PROPERTY_NS_URI = "http://www.opencastproject.org/matterhorn/";
/** Prefix for Opencast properties. */
public static final String OC_PROPERTY_NS_PREFIX = "oc";
/**
* Opencast property: The timezone of the agent specified to be scheduled with an event. IE: "America/Chicago"
*/
public static final EName OC_PROPERTY_AGENT_TIMEZONE = new EName(OC_PROPERTY_NS_URI, "agentTimezone");
/**
* This is a string defining a recurrence pattern as specified in RFC 2445. See <a
* href="http://tools.ietf.org/html/rfc2445#section-4.8.5.4">http://tools.ietf.org/html/rfc2445#section-4.8.5.4</a>
*/
public static final EName OC_PROPERTY_RECURRENCE = new EName(OC_PROPERTY_NS_URI, "recurrence");
public static final EName OC_PROPERTY_ANNOTATION = new EName(OC_PROPERTY_NS_URI, "annotation");
public static final EName OC_PROPERTY_ADVERTISED = new EName(OC_PROPERTY_NS_URI, "advertised");
public static final EName OC_PROPERTY_PROMOTED = new EName(OC_PROPERTY_NS_URI, "promoted");
public static final EName OC_PROPERTY_DURATION = new EName(OC_PROPERTY_NS_URI, "duration");
private DublinCores() {
}
/**
* Create a new Opencast DublinCore metadata catalog for episodes.
* <ul>
* <li>Set flavor to {@link org.opencastproject.mediapackage.MediaPackageElements#EPISODE}.
* <li>Register all necessary namespaces and set the root tag to {@link #OC_DC_CATALOG_ROOT_ELEMENT}.
* <li>The catalog does not have an {@linkplain DublinCoreCatalog#getIdentifier() identifier} and the
* {@link DublinCore#PROPERTY_IDENTIFIER identifier} property is not set.
* </ul>
*
* @deprecated use {@link #mkOpencastEpisode()} instead
*/
@Nonnull
@Deprecated
public static Episode mkOpencast() {
return mkOpencastEpisode();
}
/**
* Create a new Opencast DublinCore metadata catalog for episodes.
* <ul>
* <li>Set flavor to {@link org.opencastproject.mediapackage.MediaPackageElements#EPISODE}.
* <li>Register all necessary namespaces and set the root tag to {@link #OC_DC_CATALOG_ROOT_ELEMENT}.
* <li>The catalog does not have an {@linkplain DublinCoreCatalog#getIdentifier() identifier} and the
* {@link DublinCore#PROPERTY_IDENTIFIER identifier} property is not set.
* </ul>
*/
@Nonnull
public static Episode mkOpencastEpisode() {
return new Episode(mkOpencast(MediaPackageElements.EPISODE));
}
/**
* Create a new Opencast DublinCore metadata catalog for episodes.
* <ul>
* <li>Set flavor to {@link org.opencastproject.mediapackage.MediaPackageElements#EPISODE}.
* <li>Register all necessary namespaces and set the root tag to {@link #OC_DC_CATALOG_ROOT_ELEMENT}.
* <li>Set the {@link DublinCore#PROPERTY_IDENTIFIER dcterms:identifier} to {@code id}
* <li>The catalog does not have an {@linkplain DublinCoreCatalog#getIdentifier() identifier}
* </ul>
*/
@Nonnull
public static Episode mkOpencastEpisode(String id) {
final Episode dc = mkOpencastEpisode();
dc.setDcIdentifier(id);
return dc;
}
/**
* Create a new Opencast DublinCore metadata catalog for episodes.
* <ul>
* <li>Set flavor to {@link org.opencastproject.mediapackage.MediaPackageElements#EPISODE}.
* <li>Register all necessary namespaces and set the root tag to {@link #OC_DC_CATALOG_ROOT_ELEMENT}.
* <li>Set the {@link DublinCore#PROPERTY_IDENTIFIER dcterms:identifier} to {@code id} if some, or create a random
* UUID otherwise
* <li>The catalog does not have an {@linkplain DublinCoreCatalog#getIdentifier() identifier}
* </ul>
*/
@Nonnull
public static Episode mkOpencastEpisode(Opt<String> id) {
final Episode dc = mkOpencastEpisode();
dc.setDcIdentifier(id.getOr(randomUUID().toString()));
return dc;
}
/**
* Create a new Opencast DublinCore metadata catalog for episodes.
* <ul>
* <li>Set flavor to {@link org.opencastproject.mediapackage.MediaPackageElements#EPISODE}.
* <li>Register all necessary namespaces and set the root tag to {@link #OC_DC_CATALOG_ROOT_ELEMENT}.
* <li>Set the {@link DublinCore#PROPERTY_IDENTIFIER dcterms:identifier} to {@code id}
* <li>Link to series {@code seriesId} setting the {@link DublinCore#PROPERTY_IS_PART_OF} property.
* <li>The catalog does not have an {@linkplain DublinCoreCatalog#getIdentifier() identifier}
* </ul>
*/
@Nonnull
public static Episode mkOpencastEpisode(String id, String seriesId) {
final Episode dc = mkOpencastEpisode(id);
dc.setIsPartOf(seriesId);
return dc;
}
/**
* Create an Opencast episode DublinCore accessor for a {@link DublinCoreCatalog}.
* Read and write operations access and modify the wrapped catalog.
*/
@Nonnull
public static Episode mkOpencastEpisode(DublinCoreCatalog dc) {
return new Episode(dc);
}
/**
* Create a new Opencast DublinCore metadata catalog for series.
* <ul>
* <li>Set flavor to {@link org.opencastproject.mediapackage.MediaPackageElements#SERIES}.
* <li>Register all necessary namespaces and set the root tag to {@link #OC_DC_CATALOG_ROOT_ELEMENT}.
* <li>The catalog does not have an {@linkplain DublinCoreCatalog#getIdentifier() identifier} and the
* {@link DublinCore#PROPERTY_IDENTIFIER identifier} property is not set.
* </ul>
*/
@Nonnull
public static Series mkOpencastSeries() {
return new Series(mkOpencast(MediaPackageElements.SERIES));
}
/**
* Create a new Opencast DublinCore metadata catalog for series.
* <ul>
* <li>Set flavor to {@link org.opencastproject.mediapackage.MediaPackageElements#SERIES}.
* <li>Register all necessary namespaces and set the root tag to {@link #OC_DC_CATALOG_ROOT_ELEMENT}.
* <li>Set the {@link DublinCore#PROPERTY_IDENTIFIER dcterms:identifier} to {@code id}
* <li>The catalog does not have an {@linkplain DublinCoreCatalog#getIdentifier() identifier}
* </ul>
*/
@Nonnull
public static Series mkOpencastSeries(String id) {
final Series dc = mkOpencastSeries();
dc.setDcIdentifier(id);
return dc;
}
/**
* Create an Opencast series DublinCore accessor for a {@link DublinCoreCatalog}.
* Read and write operations access and modify the wrapped catalog.
*/
@Nonnull
public static Series mkOpencastSeries(DublinCoreCatalog dc) {
return new Series(dc);
}
/**
* Create a new empty catalog suitable to take properties from the standard DublinCore
* namespaces {@link DublinCore#ELEMENTS_1_1_NS_URI} and {@link DublinCore#TERMS_NS_URI}.
* <p>
* Please note that neither a flavor nor a root tag is set.
*/
@Nonnull
public static DublinCoreCatalog mkStandard() {
final DublinCoreCatalog dc = new DublinCoreCatalog();
dc.addBindings(XmlNamespaceContext.mk(
XmlNamespaceBinding.mk(ELEMENTS_1_1_NS_PREFIX, ELEMENTS_1_1_NS_URI),
XmlNamespaceBinding.mk(TERMS_NS_PREFIX, TERMS_NS_URI)));
return dc;
}
/** Create a new empty catalog with no special namespace registered, no root tag and no flavor. */
@Nonnull
public static DublinCoreCatalog mkSimple() {
return new DublinCoreCatalog();
}
/**
* Read a DublinCore catalog from a stream containing either JSON or XML. The method is
* capable of detecting the used format.
* <p>
* The reader is not capable of determining the catalog's flavor.
* <p>
* <strong>Implementation note:</strong> In order to detect the format the whole stream is read into memory first. If you
* know upfront whether JSON or XML is used you may want to choose {@link DublinCoreJsonFormat#read(java.io.InputStream)}
* or {@link DublinCoreXmlFormat#read(java.io.InputStream)} for performance reasons.
*/
@Nonnull
public static DublinCoreCatalog read(InputStream in) {
final String ser;
try {
ser = IOUtils.toString(in, "UTF-8");
} catch (IOException e) {
throw new RuntimeException("Unable to read DublinCore from stream", e);
}
if (ser.startsWith("{")) {
try {
return DublinCoreJsonFormat.read(ser);
} catch (Exception e) {
throw new RuntimeException("Unable to read DublinCore catalog, JSON parsing failed.", e);
}
} else {
try {
return DublinCoreXmlFormat.read(ser);
} catch (Exception e) {
throw new RuntimeException("Unable to read DublinCore catalog, XML parsing failed.", e);
}
}
}
private static DublinCoreCatalog mkOpencast(MediaPackageElementFlavor flavor) {
final DublinCoreCatalog dc = mkStandard();
dc.setFlavor(flavor);
dc.addBindings(XmlNamespaceContext.mk(
// Opencast property namespace
XmlNamespaceBinding.mk(OC_PROPERTY_NS_PREFIX, OC_PROPERTY_NS_URI),
// Opencast root tag
XmlNamespaceBinding.mk(XMLConstants.DEFAULT_NS_PREFIX, OC_DC_CATALOG_NS_URI)));
//XMLSchema-instance namespace xsi
XmlNamespaceBinding.mk(XSI_NS_PREFIX, W3C_XML_SCHEMA_INSTANCE_NS_URI);
dc.setRootTag(OC_DC_CATALOG_ROOT_ELEMENT);
return dc;
}
}