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