001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.camel.converter.jaxp;
018
019import javax.xml.stream.XMLStreamConstants;
020import javax.xml.stream.XMLStreamException;
021import javax.xml.stream.XMLStreamReader;
022import javax.xml.transform.sax.SAXSource;
023
024import org.xml.sax.Attributes;
025import org.xml.sax.ContentHandler;
026import org.xml.sax.DTDHandler;
027import org.xml.sax.EntityResolver;
028import org.xml.sax.ErrorHandler;
029import org.xml.sax.InputSource;
030import org.xml.sax.SAXException;
031import org.xml.sax.SAXNotRecognizedException;
032import org.xml.sax.SAXNotSupportedException;
033import org.xml.sax.SAXParseException;
034import org.xml.sax.XMLReader;
035import org.xml.sax.ext.LexicalHandler;
036
037/**
038 * Adapter to turn a StAX {@link XMLStreamReader} into a {@link SAXSource}.
039 */
040public class StAX2SAXSource extends SAXSource implements XMLReader {
041
042    private XMLStreamReader streamReader;
043
044    private ContentHandler contentHandler;
045
046    private LexicalHandler lexicalHandler;
047
048    public StAX2SAXSource(XMLStreamReader streamReader) {
049        this.streamReader = streamReader;
050        setInputSource(new InputSource());
051    }
052
053    public XMLReader getXMLReader() {
054        return this;
055    }
056
057    public XMLStreamReader getXMLStreamReader() {
058        return streamReader;
059    }
060
061    protected void parse() throws SAXException {
062        final StAX2SAXAttributes attributes = new StAX2SAXAttributes();
063        try {
064            while (true) {
065                switch (streamReader.getEventType()) {
066                // Attributes are handled in START_ELEMENT
067                case XMLStreamConstants.ATTRIBUTE:
068                    break;
069                case XMLStreamConstants.CDATA:
070                {
071                    if (lexicalHandler != null) {
072                        lexicalHandler.startCDATA();
073                    }
074                    int length = streamReader.getTextLength();
075                    int start = streamReader.getTextStart();
076                    char[] chars = streamReader.getTextCharacters();
077                    contentHandler.characters(chars, start, length);
078                    if (lexicalHandler != null) {
079                        lexicalHandler.endCDATA();
080                    }
081                    break;
082                }
083                case XMLStreamConstants.CHARACTERS:
084                {
085                    int length = streamReader.getTextLength();
086                    int start = streamReader.getTextStart();
087                    char[] chars = streamReader.getTextCharacters();
088                    contentHandler.characters(chars, start, length);
089                    break;
090                }
091                case XMLStreamConstants.SPACE:
092                {
093                    int length = streamReader.getTextLength();
094                    int start = streamReader.getTextStart();
095                    char[] chars = streamReader.getTextCharacters();
096                    contentHandler.ignorableWhitespace(chars, start, length);
097                    break;
098                }
099                case XMLStreamConstants.COMMENT:
100                    if (lexicalHandler != null) {
101                        int length = streamReader.getTextLength();
102                        int start = streamReader.getTextStart();
103                        char[] chars = streamReader.getTextCharacters();
104                        lexicalHandler.comment(chars, start, length);
105                    }
106                    break;
107                case XMLStreamConstants.DTD:
108                    break;
109                case XMLStreamConstants.END_DOCUMENT:
110                    contentHandler.endDocument();
111                    return;
112                case XMLStreamConstants.END_ELEMENT: {
113                    String uri = nullToEmpty(streamReader.getNamespaceURI());
114                    String localName = streamReader.getLocalName();
115                    String qname = getPrefixedName(streamReader.getPrefix(), localName);
116                    contentHandler.endElement(uri, localName, qname);
117
118                    // namespaces
119                    for (int i = 0; i < streamReader.getNamespaceCount(); i++) {
120                        String nsPrefix = streamReader.getNamespacePrefix(i);
121                        contentHandler.endPrefixMapping(nsPrefix);
122                    }
123                    break;
124                }
125                case XMLStreamConstants.ENTITY_DECLARATION:
126                case XMLStreamConstants.ENTITY_REFERENCE:
127                case XMLStreamConstants.NAMESPACE:
128                case XMLStreamConstants.NOTATION_DECLARATION:
129                    break;
130                case XMLStreamConstants.PROCESSING_INSTRUCTION:
131                    break;
132                case XMLStreamConstants.START_DOCUMENT:
133                    contentHandler.startDocument();
134                    break;
135                case XMLStreamConstants.START_ELEMENT: {
136                    // namespaces
137                    for (int i = 0; i < streamReader.getNamespaceCount(); i++) {
138                        String nsPrefix = nullToEmpty(streamReader.getNamespacePrefix(i));
139                        String nsUri = nullToEmpty(streamReader.getNamespaceURI(i));
140                        contentHandler.startPrefixMapping(nsPrefix, nsUri);
141                    }
142
143                    String uri = nullToEmpty(streamReader.getNamespaceURI());
144                    String localName = streamReader.getLocalName();
145                    String qname = getPrefixedName(streamReader.getPrefix(), localName);
146                    attributes.init();
147                    contentHandler.startElement(uri, localName, qname, attributes);
148                    attributes.reset();
149                    break;
150                }
151                default:
152                    break;
153                }
154                if (!streamReader.hasNext()) {
155                    return;
156                }
157                streamReader.next();
158            }
159        } catch (XMLStreamException e) {
160            SAXParseException spe;
161            if (e.getLocation() != null) {
162                spe = new SAXParseException(e.getMessage(), null, null,
163                                            e.getLocation().getLineNumber(),
164                                            e.getLocation().getColumnNumber(), e);
165            } else {
166                spe = new SAXParseException(e.getMessage(), null, null, -1, -1, e);
167            }
168            spe.initCause(e);
169            throw spe;
170        }
171    }
172
173    private String getPrefixedName(String prefix, String localName) {
174        if (prefix == null || prefix.length() == 0) {
175            return localName;
176        }
177        return prefix + ":" + localName;
178    }
179
180    private String nullToEmpty(String s) {
181        return s == null ? "" : s;
182    }
183
184    class StAX2SAXAttributes implements Attributes {
185
186        private int attributeCount;
187
188        void init() {
189            attributeCount = streamReader.getAttributeCount();
190        }
191
192        void reset() {
193            attributeCount = 0;
194        }
195
196        @Override
197        public int getLength() {
198            return attributeCount;
199        }
200
201        private boolean checkIndex(int index) {
202            return index >= 0 && index < attributeCount;
203        }
204
205        @Override
206        public String getURI(int index) {
207            if (!checkIndex(index)) {
208                return null;
209            }
210            return nullToEmpty(streamReader.getAttributeNamespace(index));
211        }
212
213        @Override
214        public String getLocalName(int index) {
215            if (!checkIndex(index)) {
216                return null;
217            }
218            return streamReader.getAttributeLocalName(index);
219        }
220
221        @Override
222        public String getQName(int index) {
223            if (!checkIndex(index)) {
224                return null;
225            }
226            String localName = streamReader.getAttributeLocalName(index);
227            String prefix = streamReader.getAttributePrefix(index);
228            return getPrefixedName(prefix, localName);
229        }
230
231        @Override
232        public String getType(int index) {
233            if (!checkIndex(index)) {
234                return null;
235            }
236            return streamReader.getAttributeType(index);
237        }
238
239        @Override
240        public String getValue(int index) {
241            if (!checkIndex(index)) {
242                return null;
243            }
244            return nullToEmpty(streamReader.getAttributeValue(index));
245        }
246
247        @Override
248        public int getIndex(String searchUri, String searchLocalName) {
249            for (int i = 0; i < attributeCount; i++) {
250                if (getURI(i).equals(searchUri) && getLocalName(i).equals(searchLocalName)) {
251                    return i;
252                }
253            }
254            return -1;
255        }
256
257        @Override
258        public int getIndex(String searchQName) {
259            for (int i = 0; i < attributeCount; i++) {
260                if (getQName(i).equals(searchQName)) {
261                    return i;
262                }
263            }
264            return -1;
265        }
266
267        @Override
268        public String getType(String uri, String localName) {
269            return getType(getIndex(uri, localName));
270        }
271
272        @Override
273        public String getType(String qName) {
274            return getType(getIndex(qName));
275        }
276
277        @Override
278        public String getValue(String uri, String localName) {
279            return getValue(getIndex(uri, localName));
280        }
281
282        @Override
283        public String getValue(String qName) {
284            return getValue(getIndex(qName));
285        }
286    }
287
288    public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
289        return false;
290    }
291
292    public void setFeature(String name, boolean value)
293        throws SAXNotRecognizedException, SAXNotSupportedException {
294    }
295
296    public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
297        return null;
298    }
299
300    public void setProperty(String name, Object value)
301        throws SAXNotRecognizedException, SAXNotSupportedException {
302        if ("http://xml.org/sax/properties/lexical-handler".equals(name)) {
303            lexicalHandler = (LexicalHandler) value;
304        } else {
305            throw new SAXNotRecognizedException(name);
306        }
307    }
308
309    public void setEntityResolver(EntityResolver resolver) {
310    }
311
312    public EntityResolver getEntityResolver() {
313        return null;
314    }
315
316    public void setDTDHandler(DTDHandler handler) {
317    }
318
319    public DTDHandler getDTDHandler() {
320        return null;
321    }
322
323    public void setContentHandler(ContentHandler handler) {
324        this.contentHandler = handler;
325        if (handler instanceof LexicalHandler
326            && lexicalHandler == null) {
327            lexicalHandler = (LexicalHandler)handler;
328        }
329    }
330
331    public ContentHandler getContentHandler() {
332        return this.contentHandler;
333    }
334
335    public void setErrorHandler(ErrorHandler handler) {
336    }
337
338    public ErrorHandler getErrorHandler() {
339        return null;
340    }
341
342    public void parse(InputSource input) throws SAXException {
343        StAX2SAXSource.this.parse();
344    }
345
346    public void parse(String systemId) throws SAXException {
347        StAX2SAXSource.this.parse();
348    }
349
350}