Open Source Repository

Home /jaxb/jaxb-api-2.2.2 | Repository Home



javax/xml/bind/util/JAXBSource.java
/*
 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package javax.xml.bind.util;

import org.xml.sax.ContentHandler;
import org.xml.sax.DTDHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.helpers.XMLFilterImpl;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.transform.sax.SAXSource;

/**
 * JAXP {@link javax.xml.transform.Source} implementation
 * that marshals a JAXB-generated object.
 
 <p>
 * This utility class is useful to combine JAXB with
 * other Java/XML technologies.
 
 <p>
 * The following example shows how to use JAXB to marshal a document
 * for transformation by XSLT.
 
 <blockquote>
 *    <pre>
 *       MyObject o = // get JAXB content tree
 *       
 *       // jaxbContext is a JAXBContext object from which 'o' is created.
 *       JAXBSource source = new JAXBSource( jaxbContext, o );
 *       
 *       // set up XSLT transformation
 *       TransformerFactory tf = TransformerFactory.newInstance();
 *       Transformer t = tf.newTransformer(new StreamSource("test.xsl"));
 *       
 *       // run transformation
 *       t.transform(source,new StreamResult(System.out));
 *    </pre>
 </blockquote>
 
 <p>
 * The fact that JAXBSource derives from SAXSource is an implementation
 * detail. Thus in general applications are strongly discouraged from
 * accessing methods defined on SAXSource. In particular,
 * the setXMLReader and setInputSource methods shall never be called.
 * The XMLReader object obtained by the getXMLReader method shall
 * be used only for parsing the InputSource object returned by
 * the getInputSource method.
 
 <p>
 * Similarly the InputSource object obtained by the getInputSource
 * method shall be used only for being parsed by the XMLReader object
 * returned by the getXMLReader.
 *
 @author
 *   Kohsuke Kawaguchi ([email protected])
 */
public class JAXBSource extends SAXSource {

    /**
     * Creates a new {@link javax.xml.transform.Source} for the given content object.
     
     @param   context
     *      JAXBContext that was used to create
     *      <code>contentObject</code>. This context is used
     *      to create a new instance of marshaller and must not be null.
     @param   contentObject
     *      An instance of a JAXB-generated class, which will be
     *      used as a {@link javax.xml.transform.Source} (by marshalling it into XML).  It must
     *      not be null.
     @throws JAXBException if an error is encountered while creating the
     * JAXBSource or if either of the parameters are null.
     */
    public JAXBSourceJAXBContext context, Object contentObject 
        throws JAXBException {
            
        this
            context == null 
                assertionFailedMessages.formatMessages.SOURCE_NULL_CONTEXT ) ) 
                context.createMarshaller(),
                
            contentObject == null 
                assertionFailedMessages.formatMessages.SOURCE_NULL_CONTENT ) ) 
                contentObject);
    }
    
    /**
     * Creates a new {@link javax.xml.transform.Source} for the given content object.
     
     @param   marshaller
     *      A marshaller instance that will be used to marshal
     *      <code>contentObject</code> into XML. This must be
     *      created from a JAXBContext that was used to build
     *      <code>contentObject</code> and must not be null.
     @param   contentObject
     *      An instance of a JAXB-generated class, which will be
     *      used as a {@link javax.xml.transform.Source} (by marshalling it into XML).  It must
     *      not be null.
     @throws JAXBException if an error is encountered while creating the
     * JAXBSource or if either of the parameters are null.
     */
    public JAXBSourceMarshaller marshaller, Object contentObject 
        throws JAXBException {
            
        ifmarshaller == null )
            throw new JAXBException
                Messages.formatMessages.SOURCE_NULL_MARSHALLER ) );
                
        ifcontentObject == null )
            throw new JAXBException
                Messages.formatMessages.SOURCE_NULL_CONTENT ) );
            
        this.marshaller = marshaller;
        this.contentObject = contentObject;
        
        super.setXMLReader(pseudoParser);
        // pass a dummy InputSource. We don't care
        super.setInputSource(new InputSource());
    }
    
    private final Marshaller marshaller;
    private final Object contentObject;
    
    // this object will pretend as an XMLReader.
    // no matter what parameter is specified to the parse method,
    // it just parse the contentObject.
    private final XMLReader pseudoParser = new XMLReader() {
        public boolean getFeature(String namethrows SAXNotRecognizedException {
            if(name.equals("http://xml.org/sax/features/namespaces"))
                return true;
            if(name.equals("http://xml.org/sax/features/namespace-prefixes"))
                return false;
            throw new SAXNotRecognizedException(name);
        }

        public void setFeature(String name, boolean valuethrows SAXNotRecognizedException {
            if(name.equals("http://xml.org/sax/features/namespaces"&& value)
                return;
            if(name.equals("http://xml.org/sax/features/namespace-prefixes"&& !value)
                return;
            throw new SAXNotRecognizedException(name);
        }

        public Object getProperty(String namethrows SAXNotRecognizedException {
            if"http://xml.org/sax/properties/lexical-handler".equals(name) ) {
                return lexicalHandler;
            }
            throw new SAXNotRecognizedException(name);
        }

        public void setProperty(String name, Object valuethrows SAXNotRecognizedException {
            if"http://xml.org/sax/properties/lexical-handler".equals(name) ) {
                this.lexicalHandler = (LexicalHandler)value;
                return;
            }
            throw new SAXNotRecognizedException(name);
        }

        private LexicalHandler lexicalHandler;

        // we will store this value but never use it by ourselves.
        private EntityResolver entityResolver;
        public void setEntityResolver(EntityResolver resolver) {
            this.entityResolver = resolver;
        }
        public EntityResolver getEntityResolver() {
            return entityResolver;
        }

        private DTDHandler dtdHandler;
        public void setDTDHandler(DTDHandler handler) {
            this.dtdHandler = handler;
        }
        public DTDHandler getDTDHandler() {
            return dtdHandler;
        }

        // SAX allows ContentHandler to be changed during the parsing,
        // but JAXB doesn't. So this repeater will sit between those
        // two components.
        private XMLFilterImpl repeater = new XMLFilterImpl();

        public void setContentHandler(ContentHandler handler) {
            repeater.setContentHandler(handler);
        }
        public ContentHandler getContentHandler() {
            return repeater.getContentHandler();
        }

        private ErrorHandler errorHandler;
        public void setErrorHandler(ErrorHandler handler) {
            this.errorHandler = handler;
        }
        public ErrorHandler getErrorHandler() {
            return errorHandler;
        }

        public void parse(InputSource inputthrows SAXException {
            parse();
        }

        public void parse(String systemIdthrows SAXException {
            parse();
        }

        public void parse() throws SAXException {
            // parses a content object by using the given marshaller
            // SAX events will be sent to the repeater, and the repeater
            // will further forward it to an appropriate component.
            try {
                marshaller.marshalcontentObject, repeater );
            catchJAXBException e ) {
                // wrap it to a SAXException
                SAXParseException se =
                    new SAXParseExceptione.getMessage(),
                        null, null, -1, -1, e );

                // if the consumer sets an error handler, it is our responsibility
                // to notify it.
                if(errorHandler!=null)
                    errorHandler.fatalError(se);

                // this is a fatal error. Even if the error handler
                // returns, we will abort anyway.
                throw se;
            }
        }
    };

    /**
     * Hook to throw exception from the middle of a contructor chained call
     * to this
     */
    private static Marshaller assertionFailedString message 
        throws JAXBException {
            
        throw new JAXBExceptionmessage );
    }
}