001 /*
002 * @(#)$Id: JAXBSource.java,v 1.9 2003/03/05 23:22:53 kk122374 Exp $
003 *
004 * Copyright 2002 Sun Microsystems, Inc. All Rights Reserved.
005 *
006 * This software is the proprietary information of Sun Microsystems, Inc.
007 * Use is subject to license terms.
008 *
009 */
010 package javax.xml.bind.util;
011
012 import java.io.IOException;
013 import javax.xml.bind.JAXBContext;
014 import javax.xml.bind.JAXBException;
015 import javax.xml.bind.Marshaller;
016 import javax.xml.transform.sax.SAXSource;
017
018 import org.xml.sax.ContentHandler;
019 import org.xml.sax.DTDHandler;
020 import org.xml.sax.EntityResolver;
021 import org.xml.sax.ErrorHandler;
022 import org.xml.sax.InputSource;
023 import org.xml.sax.SAXException;
024 import org.xml.sax.SAXNotRecognizedException;
025 import org.xml.sax.SAXParseException;
026 import org.xml.sax.XMLReader;
027 import org.xml.sax.ext.LexicalHandler;
028 import org.xml.sax.helpers.XMLFilterImpl;
029
030 /**
031 * JAXP {@link javax.xml.transform.Source} implementation
032 * that marshals a JAXB-generated object.
033 *
034 * <p>
035 * This utility class is useful to combine JAXB with
036 * other Java/XML technologies.
037 *
038 * <p>
039 * The following example shows how to use JAXB to marshal a document
040 * for transformation by XSLT.
041 *
042 * <blockquote>
043 * <pre>
044 * MyObject o = // get JAXB content tree
045 *
046 * // jaxbContext is a JAXBContext object from which 'o' is created.
047 * JAXBSource source = new JAXBSource( jaxbContext, o );
048 *
049 * // set up XSLT transformation
050 * TransformerFactory tf = TransformerFactory.newInstance();
051 * Transformer t = tf.newTransformer(new StreamSource("test.xsl"));
052 *
053 * // run transformation
054 * t.transform(source,new StreamResult(System.out));
055 * </pre>
056 * </blockquote>
057 *
058 * @author
059 * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
060 */
061 public class JAXBSource extends SAXSource {
062
063 /**
064 * Creates a new {@link javax.xml.transform.Source} for the given content object.
065 *
066 * @param context
067 * JAXBContext that was used to create
068 * <code>contentObject</code>. This context is used
069 * to create a new instance of marshaller and must not be null.
070 * @param contentObject
071 * An instance of a JAXB-generated class, which will be
072 * used as a {@link javax.xml.transform.Source} (by marshalling it into XML). It must
073 * not be null.
074 * @throws JAXBException if an error is encountered while creating the
075 * JAXBSource or if either of the parameters are null.
076 */
077 public JAXBSource( JAXBContext context, Object contentObject )
078 throws JAXBException {
079
080 this(
081 ( context == null ) ?
082 assertionFailed( Messages.format( Messages.SOURCE_NULL_CONTEXT ) ) :
083 context.createMarshaller(),
084
085 ( contentObject == null ) ?
086 assertionFailed( Messages.format( Messages.SOURCE_NULL_CONTENT ) ) :
087 contentObject);
088 }
089
090 /**
091 * Creates a new {@link javax.xml.transform.Source} for the given content object.
092 *
093 * @param marshaller
094 * A marshaller instance that will be used to marshal
095 * <code>contentObject</code> into XML. This must be
096 * created from a JAXBContext that was used to build
097 * <code>contentObject</code> and must not be null.
098 * @param contentObject
099 * An instance of a JAXB-generated class, which will be
100 * used as a {@link javax.xml.transform.Source} (by marshalling it into XML). It must
101 * not be null.
102 * @throws JAXBException if an error is encountered while creating the
103 * JAXBSource or if either of the parameters are null.
104 */
105 public JAXBSource( Marshaller marshaller, Object contentObject )
106 throws JAXBException {
107
108 if( marshaller == null )
109 throw new JAXBException(
110 Messages.format( Messages.SOURCE_NULL_MARSHALLER ) );
111
112 if( contentObject == null )
113 throw new JAXBException(
114 Messages.format( Messages.SOURCE_NULL_CONTENT ) );
115
116 this.marshaller = marshaller;
117 this.contentObject = contentObject;
118
119 super.setXMLReader(pseudoParser);
120 // pass a dummy InputSource. We don't care
121 super.setInputSource(new InputSource());
122 }
123
124 private final Marshaller marshaller;
125 private final Object contentObject;
126
127 // this object will pretend as an XMLReader.
128 // no matter what parameter is specified to the parse method,
129 // it just parse the contentObject.
130 private final XMLReader pseudoParser = new XMLReader() {
131 public boolean getFeature(String name) throws SAXNotRecognizedException {
132 throw new SAXNotRecognizedException(name);
133 }
134
135 public void setFeature(String name, boolean value) throws SAXNotRecognizedException {
136 throw new SAXNotRecognizedException(name);
137 }
138
139 public Object getProperty(String name) throws SAXNotRecognizedException {
140 if( "http://xml.org/sax/properties/lexical-handler".equals(name) ) {
141 return lexicalHandler;
142 }
143 throw new SAXNotRecognizedException(name);
144 }
145
146 public void setProperty(String name, Object value) throws SAXNotRecognizedException {
147 if( "http://xml.org/sax/properties/lexical-handler".equals(name) ) {
148 this.lexicalHandler = (LexicalHandler)value;
149 return;
150 }
151 throw new SAXNotRecognizedException(name);
152 }
153
154 private LexicalHandler lexicalHandler;
155
156 // we will store this value but never use it by ourselves.
157 private EntityResolver entityResolver;
158 public void setEntityResolver(EntityResolver resolver) {
159 this.entityResolver = resolver;
160 }
161 public EntityResolver getEntityResolver() {
162 return entityResolver;
163 }
164
165 private DTDHandler dtdHandler;
166 public void setDTDHandler(DTDHandler handler) {
167 this.dtdHandler = handler;
168 }
169 public DTDHandler getDTDHandler() {
170 return dtdHandler;
171 }
172
173 // SAX allows ContentHandler to be changed during the parsing,
174 // but JAXB doesn't. So this repeater will sit between those
175 // two components.
176 private XMLFilterImpl repeater = new XMLFilterImpl();
177
178 public void setContentHandler(ContentHandler handler) {
179 repeater.setContentHandler(handler);
180 }
181 public ContentHandler getContentHandler() {
182 return repeater.getContentHandler();
183 }
184
185 private ErrorHandler errorHandler;
186 public void setErrorHandler(ErrorHandler handler) {
187 this.errorHandler = handler;
188 }
189 public ErrorHandler getErrorHandler() {
190 return errorHandler;
191 }
192
193 public void parse(InputSource input) throws IOException, SAXException {
194 parse();
195 }
196
197 public void parse(String systemId) throws IOException, SAXException {
198 parse();
199 }
200
201 public void parse() throws SAXException {
202 // parses a content object by using the given marshaller
203 // SAX events will be sent to the repeater, and the repeater
204 // will further forward it to an appropriate component.
205 try {
206 marshaller.marshal( contentObject, repeater );
207 } catch( JAXBException e ) {
208 // wrap it to a SAXException
209 SAXParseException se =
210 new SAXParseException( e.getMessage(),
211 null, null, -1, -1, e );
212
213 // if the consumer sets an error handler, it is our responsibility
214 // to notify it.
215 if(errorHandler!=null)
216 errorHandler.fatalError(se);
217
218 // this is a fatal error. Even if the error handler
219 // returns, we will abort anyway.
220 throw se;
221 }
222 }
223 };
224
225 /**
226 * Hook to throw exception from the middle of a contructor chained call
227 * to this
228 */
229 private static Marshaller assertionFailed( String message )
230 throws JAXBException {
231
232 throw new JAXBException( message );
233 }
234 }