package com.sun.xml.internal.bind.v2.runtime;
import java.io.BufferedWriter;
import java.io.Closeable;
import java.io.FileOutputStream;
import java.io.Flushable;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URI;
import javax.xml.bind.JAXBException;
import javax.xml.bind.MarshalException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.attachment.AttachmentMarshaller;
import javax.xml.bind.helpers.AbstractMarshallerImpl;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Result;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.validation.Schema;
import javax.xml.validation.ValidatorHandler;
import javax.xml.namespace.NamespaceContext;
import com.sun.xml.internal.bind.api.JAXBRIContext;
import com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler;
import com.sun.xml.internal.bind.marshaller.DataWriter;
import com.sun.xml.internal.bind.marshaller.DumbEscapeHandler;
import com.sun.xml.internal.bind.marshaller.MinimumEscapeHandler;
import com.sun.xml.internal.bind.marshaller.NamespacePrefixMapper;
import com.sun.xml.internal.bind.marshaller.NioEscapeHandler;
import com.sun.xml.internal.bind.marshaller.SAX2DOMEx;
import com.sun.xml.internal.bind.marshaller.XMLWriter;
import com.sun.xml.internal.bind.v2.runtime.output.C14nXmlOutput;
import com.sun.xml.internal.bind.v2.runtime.output.Encoded;
import com.sun.xml.internal.bind.v2.runtime.output.ForkXmlOutput;
import com.sun.xml.internal.bind.v2.runtime.output.IndentingUTF8XmlOutput;
import com.sun.xml.internal.bind.v2.runtime.output.NamespaceContextImpl;
import com.sun.xml.internal.bind.v2.runtime.output.SAXOutput;
import com.sun.xml.internal.bind.v2.runtime.output.UTF8XmlOutput;
import com.sun.xml.internal.bind.v2.runtime.output.XMLEventWriterOutput;
import com.sun.xml.internal.bind.v2.runtime.output.XMLStreamWriterOutput;
import com.sun.xml.internal.bind.v2.runtime.output.XmlOutput;
import com.sun.xml.internal.bind.v2.util.FatalAdapter;
import java.net.URISyntaxException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.XMLFilterImpl;
public final class MarshallerImpl extends AbstractMarshallerImpl implements ValidationEventHandler
{
private static final Logger LOGGER = Logger.getLogger(MarshallerImpl.class.getName());
private String indent = " ";
private NamespacePrefixMapper prefixMapper = null;
private CharacterEscapeHandler escapeHandler = null;
private String =null;
final JAXBContextImpl context;
protected final XMLSerializer serializer;
private Schema schema;
private Listener externalListener = null;
private boolean c14nSupport;
private Flushable toBeFlushed;
private Closeable toBeClosed;
public MarshallerImpl( JAXBContextImpl c, AssociationMap assoc ) {
context = c;
serializer = new XMLSerializer(this);
c14nSupport = context.c14nSupport;
try {
setEventHandler(this);
} catch (JAXBException e) {
throw new AssertionError(e);
}
}
public JAXBContextImpl getContext() {
return context;
}
public void marshal(Object obj, OutputStream out, NamespaceContext inscopeNamespace) throws JAXBException {
write(obj, createWriter(out), new StAXPostInitAction(inscopeNamespace,serializer));
}
@Override
public void marshal(Object obj, XMLStreamWriter writer) throws JAXBException {
write(obj, XMLStreamWriterOutput.create(writer,context, escapeHandler), new StAXPostInitAction(writer,serializer));
}
@Override
public void marshal(Object obj, XMLEventWriter writer) throws JAXBException {
write(obj, new XMLEventWriterOutput(writer), new StAXPostInitAction(writer,serializer));
}
public void marshal(Object obj, XmlOutput output) throws JAXBException {
write(obj, output, null );
}
final XmlOutput createXmlOutput(Result result) throws JAXBException {
if (result instanceof SAXResult)
return new SAXOutput(((SAXResult) result).getHandler());
if (result instanceof DOMResult) {
final Node node = ((DOMResult) result).getNode();
if (node == null) {
Document doc = JAXBContextImpl.createDom(getContext().disableSecurityProcessing);
((DOMResult) result).setNode(doc);
return new SAXOutput(new SAX2DOMEx(doc));
} else {
return new SAXOutput(new SAX2DOMEx(node));
}
}
if (result instanceof StreamResult) {
StreamResult sr = (StreamResult) result;
if (sr.getWriter() != null)
return createWriter(sr.getWriter());
else if (sr.getOutputStream() != null)
return createWriter(sr.getOutputStream());
else if (sr.getSystemId() != null) {
String fileURL = sr.getSystemId();
try {
fileURL = new URI(fileURL).getPath();
} catch (URISyntaxException use) {
}
try {
FileOutputStream fos = new FileOutputStream(fileURL);
assert toBeClosed==null;
toBeClosed = fos;
return createWriter(fos);
} catch (IOException e) {
throw new MarshalException(e);
}
}
}
throw new MarshalException(Messages.UNSUPPORTED_RESULT.format());
}
final Runnable createPostInitAction(Result result) {
if (result instanceof DOMResult) {
Node node = ((DOMResult) result).getNode();
return new DomPostInitAction(node,serializer);
}
return null;
}
public void marshal(Object target,Result result) throws JAXBException {
write(target, createXmlOutput(result), createPostInitAction(result));
}
protected final <T> void write(Name rootTagName, JaxBeanInfo<T> bi, T obj, XmlOutput out,Runnable postInitAction) throws JAXBException {
try {
try {
prewrite(out, true, postInitAction);
serializer.startElement(rootTagName,null);
if(bi.jaxbType==Void.class || bi.jaxbType==void.class) {
serializer.endNamespaceDecls(null);
serializer.endAttributes();
} else {
if(obj==null)
serializer.writeXsiNilTrue();
else
serializer.childAsXsiType(obj,"root",bi, false);
}
serializer.endElement();
postwrite();
} catch( SAXException e ) {
throw new MarshalException(e);
} catch (IOException e) {
throw new MarshalException(e);
} catch (XMLStreamException e) {
throw new MarshalException(e);
} finally {
serializer.close();
}
} finally {
cleanUp();
}
}
private void write(Object obj, XmlOutput out, Runnable postInitAction) throws JAXBException {
try {
if( obj == null )
throw new IllegalArgumentException(Messages.NOT_MARSHALLABLE.format());
if( schema!=null ) {
ValidatorHandler validator = schema.newValidatorHandler();
validator.setErrorHandler(new FatalAdapter(serializer));
XMLFilterImpl f = new XMLFilterImpl() {
@Override
public void startPrefixMapping(String prefix, String uri) throws SAXException {
super.startPrefixMapping(prefix.intern(), uri.intern());
}
};
f.setContentHandler(validator);
out = new ForkXmlOutput( new SAXOutput(f) {
@Override
public void startDocument(XMLSerializer serializer, boolean fragment, int[] nsUriIndex2prefixIndex, NamespaceContextImpl nsContext) throws SAXException, IOException, XMLStreamException {
super.startDocument(serializer, false, nsUriIndex2prefixIndex, nsContext);
}
@Override
public void endDocument(boolean fragment) throws SAXException, IOException, XMLStreamException {
super.endDocument(false);
}
}, out );
}
try {
prewrite(out,isFragment(),postInitAction);
serializer.childAsRoot(obj);
postwrite();
} catch( SAXException e ) {
throw new MarshalException(e);
} catch (IOException e) {
throw new MarshalException(e);
} catch (XMLStreamException e) {
throw new MarshalException(e);
} finally {
serializer.close();
}
} finally {
cleanUp();
}
}
private void cleanUp() {
if(toBeFlushed!=null)
try {
toBeFlushed.flush();
} catch (IOException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
}
if(toBeClosed!=null)
try {
toBeClosed.close();
} catch (IOException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
}
toBeFlushed = null;
toBeClosed = null;
}
private void prewrite(XmlOutput out, boolean fragment, Runnable postInitAction) throws IOException, SAXException, XMLStreamException {
serializer.startDocument(out,fragment,getSchemaLocation(),getNoNSSchemaLocation());
if(postInitAction!=null) postInitAction.run();
if(prefixMapper!=null) {
String[] decls = prefixMapper.getContextualNamespaceDecls();
if(decls!=null) {
for( int i=0; i<decls.length; i+=2 ) {
String prefix = decls[i];
String nsUri = decls[i+1];
if(nsUri!=null && prefix!=null)
serializer.addInscopeBinding(nsUri,prefix);
}
}
}
serializer.setPrefixMapper(prefixMapper);
}
private void postwrite() throws IOException, SAXException, XMLStreamException {
serializer.endDocument();
serializer.reconcileID();
}
CharacterEscapeHandler getEscapeHandler() {
return escapeHandler;
}
protected CharacterEscapeHandler createEscapeHandler( String encoding ) {
if( escapeHandler!=null )
return escapeHandler;
if( encoding.startsWith("UTF") )
return MinimumEscapeHandler.theInstance;
try {
return new NioEscapeHandler( getJavaEncoding(encoding) );
} catch( Throwable e ) {
return DumbEscapeHandler.theInstance;
}
}
public XmlOutput createWriter( Writer w, String encoding ) {
if(!(w instanceof BufferedWriter))
w = new BufferedWriter(w);
assert toBeFlushed==null;
toBeFlushed = w;
CharacterEscapeHandler ceh = createEscapeHandler(encoding);
XMLWriter xw;
if(isFormattedOutput()) {
DataWriter d = new DataWriter(w,encoding,ceh);
d.setIndentStep(indent);
xw=d;
} else
xw = new XMLWriter(w,encoding,ceh);
xw.setXmlDecl(!isFragment());
xw.setHeader(header);
return new SAXOutput(xw);
}
public XmlOutput createWriter(Writer w) {
return createWriter(w, getEncoding());
}
public XmlOutput createWriter( OutputStream os ) throws JAXBException {
return createWriter(os, getEncoding());
}
public XmlOutput createWriter( OutputStream os, String encoding ) throws JAXBException {
if(encoding.equals("UTF-8")) {
Encoded[] table = context.getUTF8NameTable();
final UTF8XmlOutput out;
CharacterEscapeHandler ceh = createEscapeHandler(encoding);
if(isFormattedOutput())
out = new IndentingUTF8XmlOutput(os, indent, table, ceh);
else {
if(c14nSupport)
out = new C14nXmlOutput(os, table, context.c14nSupport, ceh);
else
out = new UTF8XmlOutput(os, table, ceh);
}
if(header!=null)
out.setHeader(header);
return out;
}
try {
return createWriter(
new OutputStreamWriter(os,getJavaEncoding(encoding)),
encoding );
} catch( UnsupportedEncodingException e ) {
throw new MarshalException(
Messages.UNSUPPORTED_ENCODING.format(encoding),
e );
}
}
@Override
public Object getProperty(String name) throws PropertyException {
if( INDENT_STRING.equals(name) )
return indent;
if( ENCODING_HANDLER.equals(name) || ENCODING_HANDLER2.equals(name) )
return escapeHandler;
if( PREFIX_MAPPER.equals(name) )
return prefixMapper;
if( XMLDECLARATION.equals(name) )
return !isFragment();
if( XML_HEADERS.equals(name) )
return header;
if( C14N.equals(name) )
return c14nSupport;
if ( OBJECT_IDENTITY_CYCLE_DETECTION.equals(name))
return serializer.getObjectIdentityCycleDetection();
return super.getProperty(name);
}
@Override
public void setProperty(String name, Object value) throws PropertyException {
if( INDENT_STRING.equals(name) ) {
checkString(name, value);
indent = (String)value;
return;
}
if( ENCODING_HANDLER.equals(name) || ENCODING_HANDLER2.equals(name)) {
if(!(value instanceof CharacterEscapeHandler))
throw new PropertyException(
Messages.MUST_BE_X.format(
name,
CharacterEscapeHandler.class.getName(),
value.getClass().getName() ) );
escapeHandler = (CharacterEscapeHandler)value;
return;
}
if( PREFIX_MAPPER.equals(name) ) {
if(!(value instanceof NamespacePrefixMapper))
throw new PropertyException(
Messages.MUST_BE_X.format(
name,
NamespacePrefixMapper.class.getName(),
value.getClass().getName() ) );
prefixMapper = (NamespacePrefixMapper)value;
return;
}
if( XMLDECLARATION.equals(name) ) {
checkBoolean(name, value);
super.setProperty(JAXB_FRAGMENT, !(Boolean)value);
return;
}
if( XML_HEADERS.equals(name) ) {
checkString(name, value);
header = (String)value;
return;
}
if( C14N.equals(name) ) {
checkBoolean(name,value);
c14nSupport = (Boolean)value;
return;
}
if (OBJECT_IDENTITY_CYCLE_DETECTION.equals(name)) {
checkBoolean(name,value);
serializer.setObjectIdentityCycleDetection((Boolean)value);
return;
}
super.setProperty(name, value);
}
private void checkBoolean( String name, Object value ) throws PropertyException {
if(!(value instanceof Boolean))
throw new PropertyException(
Messages.MUST_BE_X.format(
name,
Boolean.class.getName(),
value.getClass().getName() ) );
}
private void checkString( String name, Object value ) throws PropertyException {
if(!(value instanceof String))
throw new PropertyException(
Messages.MUST_BE_X.format(
name,
String.class.getName(),
value.getClass().getName() ) );
}
@Override
public <A extends XmlAdapter> void setAdapter(Class<A> type, A adapter) {
if(type==null)
throw new IllegalArgumentException();
serializer.putAdapter(type,adapter);
}
@Override
public <A extends XmlAdapter> A getAdapter(Class<A> type) {
if(type==null)
throw new IllegalArgumentException();
if(serializer.containsAdapter(type))
return serializer.getAdapter(type);
else
return null;
}
@Override
public void setAttachmentMarshaller(AttachmentMarshaller am) {
serializer.attachmentMarshaller = am;
}
@Override
public AttachmentMarshaller getAttachmentMarshaller() {
return serializer.attachmentMarshaller;
}
@Override
public Schema getSchema() {
return schema;
}
@Override
public void setSchema(Schema s) {
this.schema = s;
}
public boolean handleEvent(ValidationEvent event) {
return false;
}
@Override
public Listener getListener() {
return externalListener;
}
@Override
public void setListener(Listener listener) {
externalListener = listener;
}
protected static final String INDENT_STRING = "com.sun.xml.internal.bind.indentString";
protected static final String PREFIX_MAPPER = "com.sun.xml.internal.bind.namespacePrefixMapper";
protected static final String ENCODING_HANDLER = "com.sun.xml.internal.bind.characterEscapeHandler";
protected static final String ENCODING_HANDLER2 = "com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler";
protected static final String XMLDECLARATION = "com.sun.xml.internal.bind.xmlDeclaration";
protected static final String = "com.sun.xml.internal.bind.xmlHeaders";
protected static final String C14N = JAXBRIContext.CANONICALIZATION_SUPPORT;
protected static final String OBJECT_IDENTITY_CYCLE_DETECTION = "com.sun.xml.internal.bind.objectIdentitityCycleDetection";
}