/*
* Copyright (C) 2012 Jan Pokorsky
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cz.cas.lib.proarc.common.dublincore;
import cz.cas.lib.proarc.oaidublincore.ElementType;
import cz.cas.lib.proarc.oaidublincore.OaiDcType;
import cz.cas.lib.proarc.oaidublincore.ObjectFactory;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URL;
import java.util.Collection;
import java.util.List;
import javax.xml.bind.DataBindingException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
/**
*
* @author Jan Pokorsky
*/
public final class DcUtils {
private static JAXBContext defaultJaxbContext;
private static ThreadLocal<Marshaller> defaultMarshaller = new ThreadLocal<Marshaller>();
private static ThreadLocal<Unmarshaller> defaultUnmarshaller = new ThreadLocal<Unmarshaller>();
private static ThreadLocal<Transformer> defaultModsTransformer = new ThreadLocal<Transformer>();
private static final Templates MODS2DC = createMods2dcTemplate();
/**
* Default DC context. Oracle JAXB RI's context should be thread safe.
* @see <a href='http://jaxb.java.net/faq/index.html#threadSafety'>Are the JAXB runtime API's thread safe?</a>
*/
public static JAXBContext defaultJaxbContext() throws JAXBException {
if (defaultJaxbContext == null) {
defaultJaxbContext = JAXBContext.newInstance(ObjectFactory.class);
}
return defaultJaxbContext;
}
/**
* Default DC marshaller for current thread.
*/
public static Marshaller defaultMarshaller(boolean indent) throws JAXBException {
Marshaller m = defaultMarshaller.get();
if (m == null) {
// later we could use a pool to minimize Marshaller instances
m = defaultJaxbContext().createMarshaller();
m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
defaultMarshaller.set(m);
}
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, indent);
return m;
}
/**
* Default DC marshaller for current thread.
*/
public static Unmarshaller defaultUnmarshaller() throws JAXBException {
Unmarshaller m = defaultUnmarshaller.get();
if (m == null) {
m = defaultJaxbContext().createUnmarshaller();
defaultUnmarshaller.set(m);
}
return m;
}
/**
* Dumps DC object to XML string.
*/
public static String toXml(OaiDcType mods, boolean indent) {
StringWriter dump = new StringWriter();
marshal(new StreamResult(dump), mods, indent);
return dump.toString();
}
public static void marshal(Result target, OaiDcType oaidc, boolean indent) {
try {
Marshaller m = defaultMarshaller(indent);
m.marshal(new ObjectFactory().createDc(oaidc), target);
} catch (JAXBException ex) {
throw new DataBindingException(ex);
}
}
public static <T> T unmarshal(String source, Class<T> type) {
return unmarshal(new StreamSource(new StringReader(source)), type);
}
public static <T> T unmarshal(URL source, Class<T> type) {
return unmarshal(new StreamSource(source.toExternalForm()), type);
}
public static <T> T unmarshal(Source source, Class<T> type) {
try {
JAXBElement<T> item = defaultUnmarshaller().unmarshal(source, type);
return item.getValue();
} catch (JAXBException ex) {
throw new DataBindingException(ex);
}
}
/**
* MODS -> DC transformer.
*
* @param model fedora object model
* @return transformer
* @throws TransformerConfigurationException
*/
public static Transformer modsTransformer(String model) throws TransformerConfigurationException {
Transformer t = defaultModsTransformer.get();
if (t == null) {
t = MODS2DC.newTransformer();
defaultModsTransformer.set(t);
} else {
t.reset();
}
t.setParameter("MODEL", model);
return t;
}
/**
* Gets short label for DC object
* @param dc DC
* @return label
*/
public static String getLabel(OaiDcType dc) {
List<ElementType> titles = dc.getTitles();
return titles.isEmpty() ? "?" : titles.get(0).getValue();
}
public static OaiDcType merge(OaiDcType dc, OaiDcType add) {
merge(dc.getContributors(), add.getContributors());
merge(dc.getCoverages(), add.getCoverages());
merge(dc.getCreators(), add.getCreators());
merge(dc.getDates(), add.getDates());
merge(dc.getDescriptions(), add.getDescriptions());
merge(dc.getFormats(), add.getFormats());
merge(dc.getIdentifiers(), add.getIdentifiers());
merge(dc.getLanguages(), add.getLanguages());
merge(dc.getPublishers(), add.getPublishers());
merge(dc.getRelations(), add.getRelations());
merge(dc.getRights(), add.getRights());
merge(dc.getSources(), add.getSources());
merge(dc.getSubjects(), add.getSubjects());
merge(dc.getTitles(), add.getTitles());
merge(dc.getTypes(), add.getTypes());
return dc;
}
public static void merge(List<ElementType> elms, List<ElementType> add) {
if (elms == null) {
throw new NullPointerException();
}
for (ElementType elm : add) {
merge(elms, elm);
}
}
public static void merge(List<ElementType> elms, ElementType add) {
for (ElementType elm : elms) {
String value = elm.getValue();
String addValue = add.getValue();
if (value == null ? addValue == null : value.equals(addValue)) {
String lang = elm.getLang();
String addLang = add.getLang();
if (lang == null ? addLang == null : lang.equals(addLang)) {
return;
}
}
}
elms.add(add);
}
public static void addPid(OaiDcType dc, String pid) {
addElementType(dc.getIdentifiers(), pid);
}
public static void addModel(OaiDcType dc, String modelId) {
addElementType(dc.getTypes(), modelId);
}
public static void addTitle(OaiDcType dc, String title) {
addElementType(dc.getTitles(), title);
}
public static void addOwner(OaiDcType dc, Collection<String> owners) {
for (String owner : owners) {
addOwner(dc, owner);
}
}
public static void addOwner(OaiDcType dc, String owner) {
addElementType(dc.getRights(), owner);
}
public static void addElementType(List<ElementType> elms, String value) {
for (ElementType elm : elms) {
if (value.equals(elm.getValue())) {
return;
}
}
elms.add(new ElementType(value, null));
}
private static Templates createMods2dcTemplate() {
TransformerFactory tf = TransformerFactory.newInstance();
String resourcePath = "/xml/MODS3_DC_XSLT1-0.xsl";
URL resource = DcUtils.class.getResource(resourcePath);
if (resource == null) {
throw new IllegalStateException("Template not found: " + resourcePath);
}
try {
return tf.newTemplates(new StreamSource(resource.toExternalForm()));
} catch (TransformerConfigurationException ex) {
throw new IllegalStateException(resourcePath, ex);
}
}
}