1 /*
2 * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25 package javax.xml.bind.util;
26
27 import org.xml.sax.ContentHandler;
28 import org.xml.sax.DTDHandler;
29 import org.xml.sax.EntityResolver;
30 import org.xml.sax.ErrorHandler;
31 import org.xml.sax.InputSource;
32 import org.xml.sax.SAXException;
33 import org.xml.sax.SAXNotRecognizedException;
34 import org.xml.sax.SAXParseException;
35 import org.xml.sax.XMLReader;
36 import org.xml.sax.ext.LexicalHandler;
37 import org.xml.sax.helpers.XMLFilterImpl;
38
39 import javax.xml.bind.JAXBContext;
40 import javax.xml.bind.JAXBException;
41 import javax.xml.bind.Marshaller;
42 import javax.xml.transform.sax.SAXSource;
43
44 /**
45 * JAXP {@link javax.xml.transform.Source} implementation
46 * that marshals a JAXB-generated object.
47 *
48 * <p>
49 * This utility class is useful to combine JAXB with
50 * other Java/XML technologies.
51 *
52 * <p>
53 * The following example shows how to use JAXB to marshal a document
54 * for transformation by XSLT.
55 *
56 * <blockquote>
57 * <pre>
58 * MyObject o = // get JAXB content tree
59 *
60 * // jaxbContext is a JAXBContext object from which 'o' is created.
61 * JAXBSource source = new JAXBSource( jaxbContext, o );
62 *
63 * // set up XSLT transformation
64 * TransformerFactory tf = TransformerFactory.newInstance();
65 * Transformer t = tf.newTransformer(new StreamSource("test.xsl"));
66 *
67 * // run transformation
68 * t.transform(source,new StreamResult(System.out));
69 * </pre>
70 * </blockquote>
71 *
72 * <p>
73 * The fact that JAXBSource derives from SAXSource is an implementation
74 * detail. Thus in general applications are strongly discouraged from
75 * accessing methods defined on SAXSource. In particular,
76 * the setXMLReader and setInputSource methods shall never be called.
77 * The XMLReader object obtained by the getXMLReader method shall
78 * be used only for parsing the InputSource object returned by
79 * the getInputSource method.
80 *
81 * <p>
82 * Similarly the InputSource object obtained by the getInputSource
83 * method shall be used only for being parsed by the XMLReader object
84 * returned by the getXMLReader.
85 *
86 * @author
87 * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
88 */
89 public class JAXBSource extends SAXSource {
90
91 /**
92 * Creates a new {@link javax.xml.transform.Source} for the given content object.
93 *
94 * @param context
95 * JAXBContext that was used to create
96 * <code>contentObject</code>. This context is used
97 * to create a new instance of marshaller and must not be null.
98 * @param contentObject
99 * 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( JAXBContext context, Object contentObject )
106 throws JAXBException {
107
108 this(
109 ( context == null ) ?
110 assertionFailed( Messages.format( Messages.SOURCE_NULL_CONTEXT ) ) :
111 context.createMarshaller(),
112
113 ( contentObject == null ) ?
114 assertionFailed( Messages.format( Messages.SOURCE_NULL_CONTENT ) ) :
115 contentObject);
116 }
117
118 /**
119 * Creates a new {@link javax.xml.transform.Source} for the given content object.
120 *
121 * @param marshaller
122 * A marshaller instance that will be used to marshal
123 * <code>contentObject</code> into XML. This must be
124 * created from a JAXBContext that was used to build
125 * <code>contentObject</code> and must not be null.
126 * @param contentObject
127 * An instance of a JAXB-generated class, which will be
128 * used as a {@link javax.xml.transform.Source} (by marshalling it into XML). It must
129 * not be null.
130 * @throws JAXBException if an error is encountered while creating the
131 * JAXBSource or if either of the parameters are null.
132 */
133 public JAXBSource( Marshaller marshaller, Object contentObject )
134 throws JAXBException {
135
136 if( marshaller == null )
137 throw new JAXBException(
138 Messages.format( Messages.SOURCE_NULL_MARSHALLER ) );
139
140 if( contentObject == null )
141 throw new JAXBException(
142 Messages.format( Messages.SOURCE_NULL_CONTENT ) );
143
144 this.marshaller = marshaller;
145 this.contentObject = contentObject;
146
147 super.setXMLReader(pseudoParser);
148 // pass a dummy InputSource. We don't care
149 super.setInputSource(new InputSource());
150 }
151
152 private final Marshaller marshaller;
153 private final Object contentObject;
154
155 // this object will pretend as an XMLReader.
156 // no matter what parameter is specified to the parse method,
157 // it just parse the contentObject.
158 private final XMLReader pseudoParser = new XMLReader() {
159 public boolean getFeature(String name) throws SAXNotRecognizedException {
160 if(name.equals("http://xml.org/sax/features/namespaces"))
161 return true;
162 if(name.equals("http://xml.org/sax/features/namespace-prefixes"))
163 return false;
164 throw new SAXNotRecognizedException(name);
165 }
166
167 public void setFeature(String name, boolean value) throws SAXNotRecognizedException {
168 if(name.equals("http://xml.org/sax/features/namespaces") && value)
169 return;
170 if(name.equals("http://xml.org/sax/features/namespace-prefixes") && !value)
171 return;
172 throw new SAXNotRecognizedException(name);
173 }
174
175 public Object getProperty(String name) throws SAXNotRecognizedException {
176 if( "http://xml.org/sax/properties/lexical-handler".equals(name) ) {
177 return lexicalHandler;
178 }
179 throw new SAXNotRecognizedException(name);
180 }
181
182 public void setProperty(String name, Object value) throws SAXNotRecognizedException {
183 if( "http://xml.org/sax/properties/lexical-handler".equals(name) ) {
184 this.lexicalHandler = (LexicalHandler)value;
185 return;
186 }
187 throw new SAXNotRecognizedException(name);
188 }
189
190 private LexicalHandler lexicalHandler;
191
192 // we will store this value but never use it by ourselves.
193 private EntityResolver entityResolver;
194 public void setEntityResolver(EntityResolver resolver) {
195 this.entityResolver = resolver;
196 }
197 public EntityResolver getEntityResolver() {
198 return entityResolver;
199 }
200
201 private DTDHandler dtdHandler;
202 public void setDTDHandler(DTDHandler handler) {
203 this.dtdHandler = handler;
204 }
205 public DTDHandler getDTDHandler() {
206 return dtdHandler;
207 }
208
209 // SAX allows ContentHandler to be changed during the parsing,
210 // but JAXB doesn't. So this repeater will sit between those
211 // two components.
212 private XMLFilterImpl repeater = new XMLFilterImpl();
213
214 public void setContentHandler(ContentHandler handler) {
215 repeater.setContentHandler(handler);
216 }
217 public ContentHandler getContentHandler() {
218 return repeater.getContentHandler();
219 }
220
221 private ErrorHandler errorHandler;
222 public void setErrorHandler(ErrorHandler handler) {
223 this.errorHandler = handler;
224 }
225 public ErrorHandler getErrorHandler() {
226 return errorHandler;
227 }
228
229 public void parse(InputSource input) throws SAXException {
230 parse();
231 }
232
233 public void parse(String systemId) throws SAXException {
234 parse();
235 }
236
237 public void parse() throws SAXException {
238 // parses a content object by using the given marshaller
239 // SAX events will be sent to the repeater, and the repeater
240 // will further forward it to an appropriate component.
241 try {
242 marshaller.marshal( contentObject, repeater );
243 } catch( JAXBException e ) {
244 // wrap it to a SAXException
245 SAXParseException se =
246 new SAXParseException( e.getMessage(),
247 null, null, -1, -1, e );
248
249 // if the consumer sets an error handler, it is our responsibility
250 // to notify it.
251 if(errorHandler!=null)
252 errorHandler.fatalError(se);
253
254 // this is a fatal error. Even if the error handler
255 // returns, we will abort anyway.
256 throw se;
257 }
258 }
259 };
260
261 /**
262 * Hook to throw exception from the middle of a contructor chained call
263 * to this
264 */
265 private static Marshaller assertionFailed( String message )
266 throws JAXBException {
267
268 throw new JAXBException( message );
269 }
270 }