001: /* $Id: StAXSource.java,v 1.4 2006/01/23 18:50:02 sandoz Exp $
002: *
003: * Copyright (c) 2004, Sun Microsystems, Inc.
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are
008: * met:
009: *
010: * * Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * * Redistributions in binary form must reproduce the above
014: * copyright notice, this list of conditions and the following
015: * disclaimer in the documentation and/or other materials provided
016: * with the distribution.
017: *
018: * * Neither the name of Sun Microsystems, Inc. nor the names of its
019: * contributors may be used to endorse or promote products derived
020: * from this software without specific prior written permission.
021: *
022: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
023: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
024: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
025: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
026: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
027: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
028: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
029: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
030: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
031: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
032: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
033: */
034: package javanet.staxutils;
035:
036: import javanet.staxutils.helpers.XMLFilterImplEx;
037: import javax.xml.stream.XMLEventReader;
038: import org.xml.sax.*;
039: import org.xml.sax.ext.LexicalHandler;
040:
041: import javax.xml.stream.XMLStreamConstants;
042: import javax.xml.stream.XMLStreamException;
043: import javax.xml.stream.XMLStreamReader;
044: import javax.xml.transform.sax.SAXSource;
045:
046: /**
047: * A JAXP {@link javax.xml.transform.Source} implementation that wraps
048: * the specified {@link javax.xml.stream.XMLStreamReader} or
049: * {@link javax.xml.stream.XMLEventReader} for use by applications that
050: * expext a {@link javax.xml.transform.Source}.
051: *
052: * <p>
053: * The fact that StAXSource 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: *
057: * <ul>
058: * <li> The setXMLReader and setInputSource methods shall never be called.</li>
059: * <li> The XMLReader object obtained by the getXMLReader method shall
060: * be used only for parsing the InputSource object returned by
061: * the getInputSource method.</li>
062: * <li> The InputSource object obtained by the getInputSource method shall
063: * be used only for being parsed by the XMLReader object returned by
064: * the getXMLReader method.</li>
065: * </ul>
066: *
067: * <p>
068: * Example:
069: *
070: * <pre>
071: * // create a StAXSource
072: * XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(new FileReader(args[0]));
073: * Source staxSource = new StAXSource(reader);
074: *
075: * // createa StreamResult
076: * Result streamResult = new StreamResult(System.out);
077: *
078: * // run the transform
079: * TransformerFactory.newInstance().newTransformer().transform(staxSource, streamResult);
080: * </pre>
081: *
082: * @author Ryan.Shoemaker@Sun.COM
083: * @version 1.0
084: */
085: public class StAXSource extends SAXSource {
086:
087: // StAX to SAX converter that will read from StAX and produce SAX
088: // this object will be wrapped by the XMLReader exposed to the client
089: private final StAXReaderToContentHandler reader;
090:
091: // SAX allows ContentHandler to be changed during the parsing,
092: // but JAXB doesn't. So this repeater will sit between those
093: // two components.
094: private XMLFilterImplEx repeater = new XMLFilterImplEx();
095:
096: // this object will pretend as an XMLReader.
097: // no matter what parameter is specified to the parse method,
098: // it will just read from the StAX reader.
099: private final XMLReader pseudoParser = new XMLReader() {
100: public boolean getFeature(String name)
101: throws SAXNotRecognizedException {
102: if ("http://xml.org/sax/features/namespace-prefixes"
103: .equals(name)) {
104: return repeater.getNamespacePrefixes();
105: } else if ("http://xml.org/sax/features/external-general-entities"
106: .equals(name)) {
107: return true;
108: } else if ("http://xml.org/sax/features/external-parameter-entities"
109: .equals(name)) {
110: return true;
111: }
112:
113: throw new SAXNotRecognizedException(name);
114: }
115:
116: public void setFeature(String name, boolean value)
117: throws SAXNotRecognizedException {
118: if ("http://xml.org/sax/features/namespace-prefixes"
119: .equals(name)) {
120: repeater.setNamespacePrefixes(value);
121: } else if ("http://xml.org/sax/features/external-general-entities"
122: .equals(name)) {
123: // Pass over, XOM likes to get this feature
124: } else if ("http://xml.org/sax/features/external-parameter-entities"
125: .equals(name)) {
126: // Pass over, XOM likes to get this feature
127: } else {
128: throw new SAXNotRecognizedException(name);
129: }
130: }
131:
132: public Object getProperty(String name)
133: throws SAXNotRecognizedException {
134: if ("http://xml.org/sax/properties/lexical-handler"
135: .equals(name)) {
136: return repeater.getLexicalHandler();
137: }
138:
139: throw new SAXNotRecognizedException(name);
140: }
141:
142: public void setProperty(String name, Object value)
143: throws SAXNotRecognizedException {
144: if ("http://xml.org/sax/properties/lexical-handler"
145: .equals(name)) {
146: repeater.setLexicalHandler((LexicalHandler) value);
147: } else {
148: throw new SAXNotRecognizedException(name);
149: }
150: }
151:
152: // we will store this value but never use it by ourselves.
153: private EntityResolver entityResolver;
154:
155: public void setEntityResolver(EntityResolver resolver) {
156: this .entityResolver = resolver;
157: }
158:
159: public EntityResolver getEntityResolver() {
160: return entityResolver;
161: }
162:
163: private DTDHandler dtdHandler;
164:
165: public void setDTDHandler(DTDHandler handler) {
166: this .dtdHandler = handler;
167: }
168:
169: public DTDHandler getDTDHandler() {
170: return dtdHandler;
171: }
172:
173: public void setContentHandler(ContentHandler handler) {
174: repeater.setContentHandler(handler);
175: }
176:
177: public ContentHandler getContentHandler() {
178: return repeater.getContentHandler();
179: }
180:
181: private ErrorHandler errorHandler;
182:
183: public void setErrorHandler(ErrorHandler handler) {
184: this .errorHandler = handler;
185: }
186:
187: public ErrorHandler getErrorHandler() {
188: return errorHandler;
189: }
190:
191: public void parse(InputSource input) throws SAXException {
192: parse();
193: }
194:
195: public void parse(String systemId) throws SAXException {
196: parse();
197: }
198:
199: public void parse() throws SAXException {
200: // parses from a StAX reader and generates SAX events which
201: // go through the repeater and are forwarded to the appropriate
202: // component
203: try {
204: reader.bridge();
205: } catch (XMLStreamException e) {
206: // wrap it in a SAXException
207: SAXParseException se = new SAXParseException(e
208: .getMessage(), null, null, e.getLocation()
209: .getLineNumber(), e.getLocation()
210: .getColumnNumber(), e);
211:
212: // if the consumer sets an error handler, it is our responsibility
213: // to notify it.
214: if (errorHandler != null)
215: errorHandler.fatalError(se);
216:
217: // this is a fatal error. Even if the error handler
218: // returns, we will abort anyway.
219: throw se;
220:
221: }
222: }
223: };
224:
225: /**
226: * Creates a new {@link javax.xml.transform.Source} for the given
227: * {@link XMLStreamReader}.
228: *
229: * The XMLStreamReader must be pointing at either a
230: * {@link javax.xml.stream.XMLStreamConstants#START_DOCUMENT} or
231: * {@link javax.xml.stream.XMLStreamConstants#START_ELEMENT} event.
232: *
233: * @param reader XMLStreamReader that will be exposed as a Source
234: * @throws IllegalArgumentException iff the reader is null
235: * @throws IllegalStateException iff the reader is not pointing at either a
236: * START_DOCUMENT or START_ELEMENT event
237: */
238: public StAXSource(XMLStreamReader reader) {
239: if (reader == null)
240: throw new IllegalArgumentException();
241:
242: int eventType = reader.getEventType();
243: if (!(eventType == XMLStreamConstants.START_DOCUMENT)
244: && !(eventType == XMLStreamConstants.START_ELEMENT)) {
245: throw new IllegalStateException();
246: }
247:
248: this .reader = new XMLStreamReaderToContentHandler(reader,
249: repeater);
250:
251: super .setXMLReader(pseudoParser);
252: // pass a dummy InputSource. We don't care
253: super .setInputSource(new InputSource());
254: }
255:
256: /**
257: * Creates a new {@link javax.xml.transform.Source} for the given
258: * {@link XMLEventReader}.
259: *
260: * The XMLEventReader must be pointing at either a
261: * {@link javax.xml.stream.XMLStreamConstants#START_DOCUMENT} or
262: * {@link javax.xml.stream.XMLStreamConstants#START_ELEMENT} event.
263: *
264: * @param reader XMLEventReader that will be exposed as a Source
265: * @throws IllegalArgumentException iff the reader is null
266: * @throws IllegalStateException iff the reader is not pointing at either a
267: * START_DOCUEMENT or START_ELEMENT event
268: */
269: public StAXSource(XMLEventReader reader) {
270: if (reader == null)
271: throw new IllegalArgumentException();
272:
273: // TODO: detect IllegalStateException for START_ELEMENT|DOCUMENT
274: // bugid 5046340 - peek not implemented
275: // XMLEvent event = staxEventReader.peek();
276:
277: this .reader = new XMLEventReaderToContentHandler(reader,
278: repeater);
279:
280: super .setXMLReader(pseudoParser);
281: // pass a dummy InputSource. We don't care
282: super .setInputSource(new InputSource());
283: }
284:
285: }
|