/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The name "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package org.apache.ws.jaxme.impl;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import javax.xml.bind.JAXBException;
import javax.xml.bind.MarshalException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import javax.xml.transform.Result;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import org.apache.ws.jaxme.*;
import org.apache.ws.jaxme.JMElement;
import org.apache.ws.jaxme.JMMarshaller;
import org.apache.ws.jaxme.JMXmlSerializer;
import org.apache.ws.jaxme.util.DOMBuilder;
import org.w3c.dom.Node;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
/**
* @author <a href="mailto:joe@ispsoft.de">Jochen Wiedmann</a>
* @version $Id: JMMarshallerImpl.java 231712 2004-01-24 22:14:39Z jochen $
*/
public class JMMarshallerImpl extends JMControllerImpl implements JMMarshaller {
/** <p>Default value for {@link Marshaller#JAXB_ENCODING}: UTF-8.</p>
*/
public static final String DEFAULT_JAXB_ENCODING = "UTF-8";
/** <p>Default value for {@link #JAXME_INDENTATION_STRING}: " "
*(two blanks)</p>
*/
public static final String DEFAULT_JAXME_INDENTATION_STRING = " ";
/** <p>Default value for {@link #JAXME_INDENTATION_SEPARATOR}: "\n"
* (Line Feed)</p>
*/
public static final String DEFAULT_JAXME_INDENTATION_SEPARATOR = "\n";
/** <p>Property name for setting the String used to indent
* the formatted output by one level: "jaxme.indentation.string".
* Defaults to {@link #DEFAULT_JAXME_INDENTATION_STRING}.</p>
*
* @see #setIndentationString
* @see #getIndentationString
*/
public static final String JAXME_INDENTATION_STRING = "jaxme.indentation.string";
/** <p>Property name for setting the String used as a
* line separator in the formatted output. "jaxme.indentation.separator"</p>
*
* @see #setIndentationSeparator
* @see #getIndentationSeparator
*/
public static final String JAXME_INDENTATION_SEPARATOR = "jaxme.indentation.separator";
/** <p>Property name for choosing whether the marshalled
* output should contain an XML declaration. The methods
* {@link #marshal(Object, OutputStream)} and
* {@link #marshal(Object, Writer)} recognize
* requests for XML declarations.</p>
*
* @see #setXmlDeclaration(boolean)
* @see #getXmlDeclaration
*/
public static final String JAXME_XML_DECLARATION = "jaxme.xml.declaration";
/** <p>Property name for a SAX {@link ContentHandler} which is able to
* marshal a SAX stream into a character stream. The property value is
* an instance of {@link Class} implementing {@link XMLWriter}.</p>
*/
public static final String JAXME_XML_WRITER = "jaxme.xml.writer";
private static final Class xmlWriterClassDefault;
static {
boolean haveCharset = false;
try {
Class.forName("java.nio.charset.Charset");
haveCharset = true;
} catch (Exception e) {
}
xmlWriterClassDefault = haveCharset ? CharSetXMLWriter.class : XMLWriterImpl.class;
}
private String encoding = DEFAULT_JAXB_ENCODING;
private boolean indentation = true;
private String indentationString = DEFAULT_JAXME_INDENTATION_STRING;
private String indentationSeparator = DEFAULT_JAXME_INDENTATION_SEPARATOR;
private boolean xmlDeclaration;
private Class xmlWriterClass;
/** <p>Sets the controllers encoding; to be used in
* marshalling. Defaults to {@link #DEFAULT_JAXB_ENCODING}.</p>
*
* @param pEncoding Suggested encoding or null to restore
* the default
*/
public void setEncoding(String pEncoding) throws PropertyException {
encoding = pEncoding;
}
/** <p>Returns the controllers encoding; to be used in
* marshalling. Defaults to {@link #DEFAULT_JAXB_ENCODING}.</p>
*/
public String getEncoding() { return encoding; }
/** <p>Sets the controllers class implementing {@link XMLWriter}.
* Defaults to {@link XMLWriterImpl}.</p>
*
* @param pClass A class implementing {@link XMLWriterImpl} or
* null to restore the default.
*/
public void setXMLWriterClass(Class pClass) throws PropertyException {
if (pClass == null) {
// Restore
xmlWriterClass = null;
} else if (XMLWriter.class.isAssignableFrom(pClass) && !pClass.isInterface()) {
xmlWriterClass = pClass;
} else {
throw new PropertyException("The class " + pClass.getName() + " is not implementing " + XMLWriter.class.getName());
}
}
/** <p>Returns the controllers class implementing {@link XMLWriter}.
* Defaults to {@link XMLWriterImpl}.</p>
*/
public Class getXMLWriterClass() {
return xmlWriterClass == null ? xmlWriterClassDefault : xmlWriterClass;
}
/** <p>Sets whether XML documents generated by the controller
* ought to be formatted. Defaults to true.</p>
*/
public void setIndentation(boolean pIndentation) {
indentation = pIndentation;
}
/** <p>Returns whether XML documents generated by the controller
* ought to be formatted. Defaults to true.</p>
*/
public boolean getIndentation() {
return indentation;
}
/** <p>Sets whether the methods <code>marshal(Object, Writer)</code>
* and <code>marshal(Object, OutputStream)</code> ought to emit an
* XML declaration.</p>
*/
public void setXmlDeclaration(boolean pDeclaration) {
xmlDeclaration = pDeclaration;
}
/** <p>Returns whether the methods <code>marshal(Object, Writer)</code>
* and <code>marshal(Object, OutputStream)</code> ought to emit an
* XML declaration.</p>
*/
public boolean getXmlDeclaration() { return xmlDeclaration; }
/** <p>Sets the string used to indent one level. Defaults to
* {@link #DEFAULT_JAXME_INDENTATION_STRING}. Equivalent to
* <code>setProperty(JAXME_INDENTATION_STRING, pStr)</code>.</p>
*
* @see #DEFAULT_JAXME_INDENTATION_STRING
* @see #setProperty
* @see #getProperty
*/
public void setIndentationString(String pStr) { indentationString = pStr; }
/** <p>Returns the string used to indent one level. Defaults to
* {@link #DEFAULT_JAXME_INDENTATION_STRING}. Equivalent to
* <code>getProperty(JAXME_INDENTATION_STRING)</code>.</p>
*
* @see #DEFAULT_JAXME_INDENTATION_STRING
* @see #setProperty
* @see #getProperty
*/
public String getIndentationString() { return indentationString; }
/** <p>Sets the string used as a line separator. Defaults to
* {@link #DEFAULT_JAXME_INDENTATION_SEPARATOR}. Equivalent to
* <code>setProperty(JAXME_INDENTATION_SEPARATOR, pStr)</code>.</p>
*
* @see #DEFAULT_JAXME_INDENTATION_SEPARATOR
* @see #setProperty
* @see #getProperty
*/
public void setIndentationSeparator(String pStr) { indentationSeparator = pStr; }
/** <p>Returns the string used as a line separator. Defaults to
* {@link #DEFAULT_JAXME_INDENTATION_SEPARATOR}. Equivalent to
* <code>getProperty(JAXME_INDENTATION_SEPARATOR)</code>.</p>
*
* @see #DEFAULT_JAXME_INDENTATION_SEPARATOR
* @see #setProperty
* @see #getProperty
*/
public String getIndentationSeparator() { return indentationSeparator; }
public void setProperty(String pProperty, Object pValue)
throws PropertyException {
if (pProperty.startsWith("jaxb.")) {
if (Marshaller.JAXB_ENCODING.equals(pProperty)) {
setEncoding((String) pValue);
return;
} else if (Marshaller.JAXB_FORMATTED_OUTPUT.equals(pProperty)) {
setIndentation(((Boolean) pValue).booleanValue());
return;
}
} else if (pProperty.startsWith("jaxme.")) {
if (JAXME_XML_WRITER.equals(pProperty)) {
setXMLWriterClass((Class) pValue);
return;
} else if (JAXME_XML_DECLARATION.equals(pProperty)) {
setEncoding((String) pValue);
return;
} else if (JAXME_INDENTATION_SEPARATOR.equals(pProperty)) {
setIndentationSeparator((String) pValue);
return;
} else if (JAXME_INDENTATION_STRING.equals(pProperty)) {
setIndentationString((String) pValue);
return;
}
}
super.setProperty(pProperty, pValue);
}
public Object getProperty(String pProperty) throws PropertyException {
if (pProperty.startsWith("jaxb.")) {
if (Marshaller.JAXB_ENCODING.equals(pProperty)) {
return getEncoding();
} else if (Marshaller.JAXB_FORMATTED_OUTPUT.equals(pProperty)) {
return new Boolean(getIndentation());
}
} else if (pProperty.startsWith("jaxme.")) {
if (JAXME_INDENTATION_STRING.equals(pProperty)) {
return getIndentationString();
} else if (JAXME_XML_WRITER.equals(pProperty)) {
return getXMLWriterClass();
} else if (JAXME_XML_DECLARATION.equals(pProperty)) {
return getEncoding();
} else if (JAXME_INDENTATION_SEPARATOR.equals(pProperty)) {
return getIndentationSeparator();
}
}
return super.getProperty(pProperty);
}
/* Marshaller methods
*/
public void marshal(Object pObject, OutputStream pStream) throws JAXBException {
Writer writer;
try {
writer = new OutputStreamWriter(pStream, getEncoding());
} catch(UnsupportedEncodingException e) {
throw new MarshalException("Unsupported encoding: " + getEncoding(), e);
}
marshal(pObject, writer);
try {
writer.close();
} catch (IOException e) {
throw new MarshalException(e);
}
}
public void marshal(Object pObject, ContentHandler pHandler) throws JAXBException {
JMElement element = (JMElement) pObject;
try {
JMXmlSerializer serializer = getJAXBContextImpl().getJMXmlSerializer(element.getQName());
serializer.marshal(serializer.getData(this, pHandler), element.getQName(), element);
} catch (SAXException e) {
throw new MarshalException(e);
}
}
public void marshal(Object pObject, Writer pWriter) throws JAXBException {
if (getXmlDeclaration()) {
try {
pWriter.write("<?xml version='1.0' encoding='" + getEncoding() + "'?>");
if (getIndentation()) {
pWriter.write(getIndentationSeparator());
}
} catch (IOException e) {
throw new MarshalException(e);
}
}
XMLWriter w;
Class c = getXMLWriterClass();
try {
w = (XMLWriter) c.newInstance();
} catch (Exception e) {
throw new JAXBException("Failed to instantiate XMLWriter class " + c.getName(), e);
}
w.init(this);
w.setWriter(pWriter);
marshal(pObject, w);
}
public void marshal(Object pObject, Node pNode) throws JAXBException {
DOMBuilder db = new DOMBuilder();
db.setTarget(pNode);
marshal(pObject, db);
}
public void marshal(Object pObject, Result pResult) throws JAXBException {
if (pResult instanceof SAXResult) {
ContentHandler ch = ((SAXResult) pResult).getHandler();
if (ch == null) {
throw new MarshalException("The SAXResult doesn't have its ContentHandler set.");
}
marshal(pObject, ch);
} else if (pResult instanceof StreamResult) {
StreamResult sr = (StreamResult) pResult;
Writer w = sr.getWriter();
if (w == null) {
OutputStream s = sr.getOutputStream();
if (s == null) {
throw new MarshalException("The StreamResult doesn't have its Writer or OutputStream set.");
}
marshal(pObject, s);
} else {
marshal(pObject, w);
}
} else if (pResult instanceof DOMResult) {
Node node = ((DOMResult) pResult).getNode();
if (node == null) {
throw new MarshalException("The DOMResult doesn't have its Node set.");
}
marshal(pObject, node);
} else {
throw new MarshalException("Unknown type of Result: " + pResult.getClass().getName() +
", only SAXResult, StreamResult and DOMResult are supported.");
}
}
public Node getNode(java.lang.Object contentTree) throws JAXBException {
throw new UnsupportedOperationException("JaxMe doesn't support live DOM views");
}
}