001 /*
002 * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025 package javax.xml.bind.util;
026
027 import org.xml.sax.ContentHandler;
028 import org.xml.sax.DTDHandler;
029 import org.xml.sax.EntityResolver;
030 import org.xml.sax.ErrorHandler;
031 import org.xml.sax.InputSource;
032 import org.xml.sax.SAXException;
033 import org.xml.sax.SAXNotRecognizedException;
034 import org.xml.sax.SAXParseException;
035 import org.xml.sax.XMLReader;
036 import org.xml.sax.ext.LexicalHandler;
037 import org.xml.sax.helpers.XMLFilterImpl;
038
039 import javax.xml.bind.JAXBContext;
040 import javax.xml.bind.JAXBException;
041 import javax.xml.bind.Marshaller;
042 import javax.xml.transform.sax.SAXSource;
043
044 /**
045 * JAXP {@link javax.xml.transform.Source} implementation
046 * that marshals a JAXB-generated object.
047 *
048 * <p>
049 * This utility class is useful to combine JAXB with
050 * other Java/XML technologies.
051 *
052 * <p>
053 * The following example shows how to use JAXB to marshal a document
054 * for transformation by XSLT.
055 *
056 * <blockquote>
057 * <pre>
058 * MyObject o = // get JAXB content tree
059 *
060 * // jaxbContext is a JAXBContext object from which 'o' is created.
061 * JAXBSource source = new JAXBSource( jaxbContext, o );
062 *
063 * // set up XSLT transformation
064 * TransformerFactory tf = TransformerFactory.newInstance();
065 * Transformer t = tf.newTransformer(new StreamSource("test.xsl"));
066 *
067 * // run transformation
068 * t.transform(source,new StreamResult(System.out));
069 * </pre>
070 * </blockquote>
071 *
072 * <p>
073 * The fact that JAXBSource derives from SAXSource is an implementation
074 * detail. Thus in general applications are strongly discouraged from
075 * accessing methods defined on SAXSource. In particular,
076 * the setXMLReader and setInputSource methods shall never be called.
077 * The XMLReader object obtained by the getXMLReader method shall
078 * be used only for parsing the InputSource object returned by
079 * the getInputSource method.
080 *
081 * <p>
082 * Similarly the InputSource object obtained by the getInputSource
083 * method shall be used only for being parsed by the XMLReader object
084 * returned by the getXMLReader.
085 *
086 * @author
087 * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
088 */
089 public class JAXBSource extends SAXSource {
090
091 /**
092 * Creates a new {@link javax.xml.transform.Source} for the given content object.
093 *
094 * @param context
095 * JAXBContext that was used to create
096 * <code>contentObject</code>. This context is used
097 * to create a new instance of marshaller 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(JAXBContext context, Object contentObject)
106 throws JAXBException {
107
108 this ((context == null) ? assertionFailed(Messages
109 .format(Messages.SOURCE_NULL_CONTEXT)) : context
110 .createMarshaller(),
111
112 (contentObject == null) ? assertionFailed(Messages
113 .format(Messages.SOURCE_NULL_CONTENT)) : contentObject);
114 }
115
116 /**
117 * Creates a new {@link javax.xml.transform.Source} for the given content object.
118 *
119 * @param marshaller
120 * A marshaller instance that will be used to marshal
121 * <code>contentObject</code> into XML. This must be
122 * created from a JAXBContext that was used to build
123 * <code>contentObject</code> and must not be null.
124 * @param contentObject
125 * An instance of a JAXB-generated class, which will be
126 * used as a {@link javax.xml.transform.Source} (by marshalling it into XML). It must
127 * not be null.
128 * @throws JAXBException if an error is encountered while creating the
129 * JAXBSource or if either of the parameters are null.
130 */
131 public JAXBSource(Marshaller marshaller, Object contentObject)
132 throws JAXBException {
133
134 if (marshaller == null)
135 throw new JAXBException(Messages
136 .format(Messages.SOURCE_NULL_MARSHALLER));
137
138 if (contentObject == null)
139 throw new JAXBException(Messages
140 .format(Messages.SOURCE_NULL_CONTENT));
141
142 this .marshaller = marshaller;
143 this .contentObject = contentObject;
144
145 super .setXMLReader(pseudoParser);
146 // pass a dummy InputSource. We don't care
147 super .setInputSource(new InputSource());
148 }
149
150 private final Marshaller marshaller;
151 private final Object contentObject;
152
153 // this object will pretend as an XMLReader.
154 // no matter what parameter is specified to the parse method,
155 // it just parse the contentObject.
156 private final XMLReader pseudoParser = new XMLReader() {
157 public boolean getFeature(String name)
158 throws SAXNotRecognizedException {
159 if (name.equals("http://xml.org/sax/features/namespaces"))
160 return true;
161 if (name
162 .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)
168 throws SAXNotRecognizedException {
169 if (name.equals("http://xml.org/sax/features/namespaces")
170 && value)
171 return;
172 if (name
173 .equals("http://xml.org/sax/features/namespace-prefixes")
174 && !value)
175 return;
176 throw new SAXNotRecognizedException(name);
177 }
178
179 public Object getProperty(String name)
180 throws SAXNotRecognizedException {
181 if ("http://xml.org/sax/properties/lexical-handler"
182 .equals(name)) {
183 return lexicalHandler;
184 }
185 throw new SAXNotRecognizedException(name);
186 }
187
188 public void setProperty(String name, Object value)
189 throws SAXNotRecognizedException {
190 if ("http://xml.org/sax/properties/lexical-handler"
191 .equals(name)) {
192 this .lexicalHandler = (LexicalHandler) value;
193 return;
194 }
195 throw new SAXNotRecognizedException(name);
196 }
197
198 private LexicalHandler lexicalHandler;
199
200 // we will store this value but never use it by ourselves.
201 private EntityResolver entityResolver;
202
203 public void setEntityResolver(EntityResolver resolver) {
204 this .entityResolver = resolver;
205 }
206
207 public EntityResolver getEntityResolver() {
208 return entityResolver;
209 }
210
211 private DTDHandler dtdHandler;
212
213 public void setDTDHandler(DTDHandler handler) {
214 this .dtdHandler = handler;
215 }
216
217 public DTDHandler getDTDHandler() {
218 return dtdHandler;
219 }
220
221 // SAX allows ContentHandler to be changed during the parsing,
222 // but JAXB doesn't. So this repeater will sit between those
223 // two components.
224 private XMLFilterImpl repeater = new XMLFilterImpl();
225
226 public void setContentHandler(ContentHandler handler) {
227 repeater.setContentHandler(handler);
228 }
229
230 public ContentHandler getContentHandler() {
231 return repeater.getContentHandler();
232 }
233
234 private ErrorHandler errorHandler;
235
236 public void setErrorHandler(ErrorHandler handler) {
237 this .errorHandler = handler;
238 }
239
240 public ErrorHandler getErrorHandler() {
241 return errorHandler;
242 }
243
244 public void parse(InputSource input) throws SAXException {
245 parse();
246 }
247
248 public void parse(String systemId) throws SAXException {
249 parse();
250 }
251
252 public void parse() throws SAXException {
253 // parses a content object by using the given marshaller
254 // SAX events will be sent to the repeater, and the repeater
255 // will further forward it to an appropriate component.
256 try {
257 marshaller.marshal(contentObject, repeater);
258 } catch (JAXBException e) {
259 // wrap it to a SAXException
260 SAXParseException se = new SAXParseException(e
261 .getMessage(), null, null, -1, -1, e);
262
263 // if the consumer sets an error handler, it is our responsibility
264 // to notify it.
265 if (errorHandler != null)
266 errorHandler.fatalError(se);
267
268 // this is a fatal error. Even if the error handler
269 // returns, we will abort anyway.
270 throw se;
271 }
272 }
273 };
274
275 /**
276 * Hook to throw exception from the middle of a contructor chained call
277 * to this
278 */
279 private static Marshaller assertionFailed(String message)
280 throws JAXBException {
281
282 throw new JAXBException(message);
283 }
284 }
|