/**
* Copyright 2005-2014 Restlet
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can
* select the license that you prefer but you may not use this file except in
* compliance with one of these Licenses.
*
* You can obtain a copy of the Apache 2.0 license at
* http://www.opensource.org/licenses/apache-2.0
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://restlet.com/products/restlet-framework
*
* Restlet is a registered trademark of Restlet S.A.S.
*/
package org.restlet.ext.jaxb.internal;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.logging.Level;
import javax.xml.bind.JAXBException;
import org.restlet.Context;
import org.restlet.ext.jaxb.JaxbRepresentation;
/**
* This is a utility class to assist in marshaling Java content trees into XML.
* Each {@code marshal} method takes a different target for the XML.
*
* This class is a factory that constructs an instance of itself for multiple
* uses. The created instance is thread safe and is optimized to be used for
* multiple, possibly concurrent calls.
*
* @author Overstock.com
*/
public class Marshaller<T> {
/** The JAXB classloader. */
private final ClassLoader classLoader;
/** The JAXB context path. */
private final String contextPath;
/** The parent JAXB representation. */
private final JaxbRepresentation<T> jaxbRepresentation;
/** Use thread identity to preserve safety of access to marshalers. */
private final ThreadLocal<javax.xml.bind.Marshaller> marshaller = new ThreadLocal<javax.xml.bind.Marshaller>() {
@Override
protected synchronized javax.xml.bind.Marshaller initialValue() {
javax.xml.bind.Marshaller m = null;
try {
m = JaxbRepresentation.getContext(getContextPath(),
getClassLoader()).createMarshaller();
m.setProperty("jaxb.formatted.output", getJaxbRepresentation()
.isFormattedOutput());
if (getJaxbRepresentation().getSchemaLocation() != null) {
m.setProperty("jaxb.schemaLocation",
getJaxbRepresentation().getSchemaLocation());
}
if (getJaxbRepresentation().getNoNamespaceSchemaLocation() != null) {
m.setProperty("jaxb.noNamespaceSchemaLocation",
getJaxbRepresentation()
.getNoNamespaceSchemaLocation());
}
if (Marshaller.this.jaxbRepresentation.getCharacterSet() != null) {
m.setProperty("jaxb.encoding",
Marshaller.this.jaxbRepresentation
.getCharacterSet().getName());
}
if (getJaxbRepresentation().getNamespacePrefixMapper() != null) {
m.setProperty("com.sun.xml.bind.namespacePrefixMapper",
getJaxbRepresentation().getNamespacePrefixMapper());
}
m.setProperty("jaxb.fragment", getJaxbRepresentation()
.isFragment());
} catch (Exception e) {
Context.getCurrentLogger().log(Level.WARNING,
"Problem creating Marshaller", e);
return null;
}
return m;
}
};
// This is a factory class.
public Marshaller(JaxbRepresentation<T> jaxbRepresentation) {
this(jaxbRepresentation, null, null);
}
/**
* Constructor.
*
* @param jaxbRepresentation
* The JAXB representation to marshal.
* @param contextPath
* The JAXB context path.
* @param classLoader
* The JAXB classloader.
*/
public Marshaller(JaxbRepresentation<T> jaxbRepresentation,
String contextPath, ClassLoader classLoader) {
this.jaxbRepresentation = jaxbRepresentation;
this.contextPath = contextPath;
this.classLoader = classLoader;
}
/**
* Returns the JAXB classloader.
*
* @return The JAXB classloader.
*/
public ClassLoader getClassLoader() {
return this.classLoader;
}
/**
* Returns the JAXB context path.
*
* @return The JAXB context path.
*/
public String getContextPath() {
return this.contextPath;
}
/**
* Returns the parent JAXB representation.
*
* @return The parent JAXB representation.
*/
public JaxbRepresentation<T> getJaxbRepresentation() {
return jaxbRepresentation;
}
/**
* Returns the JAXB marshaller.
*
* @return The JAXB marshaller.
* @throws JAXBException
*/
private javax.xml.bind.Marshaller getMarshaller() throws JAXBException {
final javax.xml.bind.Marshaller m = this.marshaller.get();
if (m == null) {
Context.getCurrentLogger().warning("Unable to locate marshaller.");
throw new JAXBException("Unable to locate marshaller.");
}
return m;
}
/**
* Marshals the content tree rooted at {@code jaxbElement} into an output
* stream.
*
* @param jaxbElement
* The root of the content tree to be marshalled.
* @param stream
* The target output stream write the XML to.
* @throws JAXBException
* If any unexpected problem occurs during marshalling.
*/
public void marshal(Object jaxbElement, OutputStream stream)
throws JAXBException {
marshal(jaxbElement, new OutputStreamWriter(stream));
}
/**
* Marshal the content tree rooted at {@code jaxbElement} into a writer.
*
* @param jaxbElement
* The root of the content tree to be marshaled.
* @param writer
* The target writer to write the XML to.
* @throws JAXBException
* If any unexpected problem occurs during marshaling.
*/
public void marshal(Object jaxbElement, Writer writer) throws JAXBException {
getMarshaller().setEventHandler(
getJaxbRepresentation().getValidationEventHandler());
getMarshaller().marshal(jaxbElement, writer);
}
}