package org.cagrid.core.common;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URL;
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.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchema;
import javax.xml.bind.annotation.XmlType;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.cagrid.core.cache.WeakValueConcurrentCache;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
public class JAXBUtils {
public final static String DEFAULT_NAMESPACE_VALUE = "##default";
private final static WeakValueConcurrentCache<String, JAXBContext> jaxbCache = new WeakValueConcurrentCache<String, JAXBContext>();
private final static DocumentBuilderFactory dbf = DocumentBuilderFactory
.newInstance();
static {
dbf.setNamespaceAware(true);
}
public static JAXBContext getJAXBContext(Class<?> klass)
throws JAXBException {
String pkg = klass.getPackage().getName();
JAXBContext jaxb = jaxbCache.get(pkg);
if (jaxb == null) {
jaxb = JAXBContext.newInstance(pkg);
JAXBContext oldJAXB = jaxbCache.putIfAbsent(pkg, jaxb);
if (oldJAXB != null) {
jaxb = oldJAXB;
}
}
return jaxb;
}
public static String getNamespace(Class<?> klass) {
String namespace = null;
XmlType xmlType = klass.getAnnotation(XmlType.class);
if (xmlType != null) {
String ns = xmlType.namespace();
if (!DEFAULT_NAMESPACE_VALUE.equals(ns)) {
namespace = ns;
}
}
if (namespace == null) {
namespace = DEFAULT_NAMESPACE_VALUE;
Package pkg = klass.getPackage();
XmlSchema xmlSchema = pkg.getAnnotation(XmlSchema.class);
if (xmlSchema != null) {
namespace = xmlSchema.namespace();
}
}
return namespace;
}
public static QName getQName(Class<?> klass) {
XmlType xmlType = klass.getAnnotation(XmlType.class);
if (xmlType == null)
return null;
String namespace = getNamespace(klass);
String name = xmlType.name();
return new QName(namespace, name);
}
public static <T> String marshal(T t) throws JAXBException {
return marshal(t, null);
}
public static <T> String marshal(T t, QName qName) throws JAXBException {
@SuppressWarnings("unchecked")
Class<T> klass = (Class<T>) t.getClass();
Marshaller marshaller = getMarshaller(klass);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter sw = new StringWriter();
marshaller.marshal(wrap(t, qName), sw);
return sw.toString();
}
public static <T> String marshalRaw(T t, QName qName) throws JAXBException {
@SuppressWarnings("unchecked")
Class<T> klass = (Class<T>) t.getClass();
Marshaller marshaller = getMarshaller(klass);
StringWriter sw = new StringWriter();
marshaller.marshal(wrap(t, qName), sw);
return sw.toString();
}
public static <T> Element marshalToElement(T t) throws JAXBException,
ParserConfigurationException {
return marshalToElement(t, null);
}
public static <T> Element marshalToElement(T t, QName qName)
throws JAXBException, ParserConfigurationException {
@SuppressWarnings("unchecked")
Class<T> klass = (Class<T>) t.getClass();
Marshaller marshaller = getMarshaller(klass);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.newDocument();
marshaller.marshal(wrap(t, qName), doc);
return doc.getDocumentElement();
}
public static <T> T unmarshal(Class<T> klass, URL url) throws JAXBException {
Unmarshaller unmarshaller = getUnmarshaller(klass);
Object obj = unmarshaller.unmarshal(url);
return castT(klass, obj);
}
public static <T> T unmarshal(Class<T> klass, String s)
throws JAXBException {
return unmarshal(klass, new StringReader(s));
}
public static <T> T unmarshal(Class<T> klass, Reader r)
throws JAXBException {
Unmarshaller unmarshaller = getUnmarshaller(klass);
Object obj = unmarshaller.unmarshal(r);
return castT(klass, obj);
}
public static <T> T unmarshal(Class<T> klass, Node node)
throws JAXBException {
Unmarshaller unmarshaller = getUnmarshaller(klass);
Object obj = unmarshaller.unmarshal(node);
return castT(klass, obj);
}
public static <T> Object wrap(T t) {
return wrap(t, null);
}
public static <T> Object wrap(T t, QName qName) {
Object o = t;
@SuppressWarnings("unchecked")
Class<T> klass = (Class<T>) t.getClass();
if (!klass.isAnnotationPresent(XmlRootElement.class)) {
if (qName == null)
qName = getQName(klass);
JAXBElement<T> je = new JAXBElement<T>(qName, klass, t);
o = je;
}
return o;
}
public static <T> Marshaller getMarshaller(Class<T> klass)
throws JAXBException {
JAXBContext jaxb = getJAXBContext(klass);
Marshaller marshaller = jaxb.createMarshaller();
if (!klass.isAnnotationPresent(XmlRootElement.class)) {
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
}
return marshaller;
}
public static Unmarshaller getUnmarshaller(Class<?> klass)
throws JAXBException {
JAXBContext jaxb = getJAXBContext(klass);
Unmarshaller unmarshaller = jaxb.createUnmarshaller();
return unmarshaller;
}
@SuppressWarnings("unchecked")
private static <T> T castT(Class<T> klass, Object obj) {
T t = null;
if (obj instanceof JAXBElement<?>) {
JAXBElement<T> tElement = (JAXBElement<T>) obj;
t = tElement.getValue();
} else {
t = (T) obj;
}
return t;
}
}