/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2003-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
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 JAXBSource( JAXBContext context, Object contentObject )
throws JAXBException {
this(
( context == null ) ?
assertionFailed( Messages.format( Messages.SOURCE_NULL_CONTEXT ) ) :
context.createMarshaller(),
( contentObject == null ) ?
assertionFailed( Messages.format( Messages.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 JAXBSource( Marshaller marshaller, Object contentObject )
throws JAXBException {
if( marshaller == null )
throw new JAXBException(
Messages.format( Messages.SOURCE_NULL_MARSHALLER ) );
if( contentObject == null )
throw new JAXBException(
Messages.format( Messages.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 name) throws 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 value) throws 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 name) throws SAXNotRecognizedException {
if( "http://xml.org/sax/properties/lexical-handler".equals(name) ) {
return lexicalHandler;
}
throw new SAXNotRecognizedException(name);
}
public void setProperty(String name, Object value) throws 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 input) throws SAXException {
parse();
}
public void parse(String systemId) throws 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.marshal( contentObject, repeater );
} catch( JAXBException e ) {
// wrap it to a SAXException
SAXParseException se =
new SAXParseException( e.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 assertionFailed( String message )
throws JAXBException {
throw new JAXBException( message );
}
}
|