jaxws/src/share/jaxws_classes/com/sun/istack/internal/XMLStreamReaderToContentHandler.java
changeset 12009 4abb694f273a
child 16791 fe5141eabb0e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxws/src/share/jaxws_classes/com/sun/istack/internal/XMLStreamReaderToContentHandler.java	Tue Mar 06 16:09:35 2012 -0800
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.istack.internal;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.Locator;
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.AttributesImpl;
+
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.namespace.QName;
+
+/**
+ * This is a simple utility class that adapts StAX events from an
+ * {@link XMLStreamReader} to SAX events on a
+ * {@link ContentHandler}, bridging between the two
+ * parser technologies.
+ *
+ * @author Ryan.Shoemaker@Sun.COM
+ * @version 1.0
+ */
+public class XMLStreamReaderToContentHandler {
+
+    // StAX event source
+    private final XMLStreamReader staxStreamReader;
+
+    // SAX event sink
+    private final ContentHandler saxHandler;
+
+    // if true, when the conversion is completed, leave the cursor to the last
+    // event that was fired (such as end element)
+    private final boolean eagerQuit;
+
+    /**
+     * If true, not start/endDocument event.
+     */
+    private final boolean fragment;
+
+    // array of the even length of the form { prefix0, uri0, prefix1, uri1, ... }
+    private final String[] inscopeNamespaces;
+
+    /**
+     * @see #XMLStreamReaderToContentHandler(XMLStreamReader, ContentHandler, boolean, boolean, String[])
+     */
+    public XMLStreamReaderToContentHandler(XMLStreamReader staxCore, ContentHandler saxCore, boolean eagerQuit, boolean fragment) {
+        this(staxCore, saxCore, eagerQuit, fragment, new String[0]);
+    }
+
+    /**
+     * Construct a new StAX to SAX adapter that will convert a StAX event
+     * stream into a SAX event stream.
+     *
+     * @param staxCore
+     *                StAX event source
+     * @param saxCore
+     *                SAXevent sink
+     * @param eagerQuit
+     * @param fragment
+     * @param inscopeNamespaces
+     *                array of the even length of the form { prefix0, uri0, prefix1, uri1, ... }
+     */
+    public XMLStreamReaderToContentHandler(XMLStreamReader staxCore, ContentHandler saxCore,
+            boolean eagerQuit, boolean fragment, String[] inscopeNamespaces) {
+        this.staxStreamReader = staxCore;
+        this.saxHandler = saxCore;
+        this.eagerQuit = eagerQuit;
+        this.fragment = fragment;
+        this.inscopeNamespaces = inscopeNamespaces;
+        assert inscopeNamespaces.length%2 == 0;
+    }
+
+
+    /*
+     * @see StAXReaderToContentHandler#bridge()
+     */
+    public void bridge() throws XMLStreamException {
+
+        try {
+            // remembers the nest level of elements to know when we are done.
+            int depth=0;
+
+            // if the parser is at the start tag, proceed to the first element
+            int event = staxStreamReader.getEventType();
+            if(event == XMLStreamConstants.START_DOCUMENT) {
+                // nextTag doesn't correctly handle DTDs
+                while( !staxStreamReader.isStartElement() )
+                    event = staxStreamReader.next();
+            }
+
+
+            if( event!=XMLStreamConstants.START_ELEMENT)
+                throw new IllegalStateException("The current event is not START_ELEMENT\n but " + event);
+
+            handleStartDocument();
+
+            for(int i=0; i < inscopeNamespaces.length; i+=2) {
+                saxHandler.startPrefixMapping(inscopeNamespaces[i], inscopeNamespaces[i+1]);
+            }
+
+            OUTER:
+            do {
+                // These are all of the events listed in the javadoc for
+                // XMLEvent.
+                // The spec only really describes 11 of them.
+                switch (event) {
+                    case XMLStreamConstants.START_ELEMENT :
+                        depth++;
+                        handleStartElement();
+                        break;
+                    case XMLStreamConstants.END_ELEMENT :
+                        handleEndElement();
+                        depth--;
+                        if(depth==0 && eagerQuit)
+                            break OUTER;
+                        break;
+                    case XMLStreamConstants.CHARACTERS :
+                        handleCharacters();
+                        break;
+                    case XMLStreamConstants.ENTITY_REFERENCE :
+                        handleEntityReference();
+                        break;
+                    case XMLStreamConstants.PROCESSING_INSTRUCTION :
+                        handlePI();
+                        break;
+                    case XMLStreamConstants.COMMENT :
+                        handleComment();
+                        break;
+                    case XMLStreamConstants.DTD :
+                        handleDTD();
+                        break;
+                    case XMLStreamConstants.ATTRIBUTE :
+                        handleAttribute();
+                        break;
+                    case XMLStreamConstants.NAMESPACE :
+                        handleNamespace();
+                        break;
+                    case XMLStreamConstants.CDATA :
+                        handleCDATA();
+                        break;
+                    case XMLStreamConstants.ENTITY_DECLARATION :
+                        handleEntityDecl();
+                        break;
+                    case XMLStreamConstants.NOTATION_DECLARATION :
+                        handleNotationDecl();
+                        break;
+                    case XMLStreamConstants.SPACE :
+                        handleSpace();
+                        break;
+                    default :
+                        throw new InternalError("processing event: " + event);
+                }
+
+                event=staxStreamReader.next();
+            } while (depth!=0);
+
+            for(int i=0; i < inscopeNamespaces.length; i+=2) {
+                saxHandler.endPrefixMapping(inscopeNamespaces[i]);
+            }
+
+            handleEndDocument();
+        } catch (SAXException e) {
+            throw new XMLStreamException2(e);
+        }
+    }
+
+    private void handleEndDocument() throws SAXException {
+        if(fragment)
+            return;
+
+        saxHandler.endDocument();
+    }
+
+    private void handleStartDocument() throws SAXException {
+        if(fragment)
+            return;
+
+        saxHandler.setDocumentLocator(new Locator() {
+            public int getColumnNumber() {
+                return staxStreamReader.getLocation().getColumnNumber();
+            }
+            public int getLineNumber() {
+                return staxStreamReader.getLocation().getLineNumber();
+            }
+            public String getPublicId() {
+                return staxStreamReader.getLocation().getPublicId();
+            }
+            public String getSystemId() {
+                return staxStreamReader.getLocation().getSystemId();
+            }
+        });
+        saxHandler.startDocument();
+    }
+
+    private void handlePI() throws XMLStreamException {
+        try {
+            saxHandler.processingInstruction(
+                staxStreamReader.getPITarget(),
+                staxStreamReader.getPIData());
+        } catch (SAXException e) {
+            throw new XMLStreamException2(e);
+        }
+    }
+
+    private void handleCharacters() throws XMLStreamException {
+        try {
+            saxHandler.characters(
+                staxStreamReader.getTextCharacters(),
+                staxStreamReader.getTextStart(),
+                staxStreamReader.getTextLength() );
+        } catch (SAXException e) {
+            throw new XMLStreamException2(e);
+        }
+    }
+
+    private void handleEndElement() throws XMLStreamException {
+        QName qName = staxStreamReader.getName();
+
+        try {
+            String pfix = qName.getPrefix();
+            String rawname = (pfix == null || pfix.length() == 0)
+                    ? qName.getLocalPart()
+                    : pfix + ':' + qName.getLocalPart();
+            // fire endElement
+            saxHandler.endElement(
+                qName.getNamespaceURI(),
+                qName.getLocalPart(),
+                rawname);
+
+            // end namespace bindings
+            int nsCount = staxStreamReader.getNamespaceCount();
+            for (int i = nsCount - 1; i >= 0; i--) {
+                String prefix = staxStreamReader.getNamespacePrefix(i);
+                if (prefix == null) { // true for default namespace
+                    prefix = "";
+                }
+                saxHandler.endPrefixMapping(prefix);
+            }
+        } catch (SAXException e) {
+            throw new XMLStreamException2(e);
+        }
+    }
+
+    private void handleStartElement() throws XMLStreamException {
+
+        try {
+            // start namespace bindings
+            int nsCount = staxStreamReader.getNamespaceCount();
+            for (int i = 0; i < nsCount; i++) {
+                saxHandler.startPrefixMapping(
+                    fixNull(staxStreamReader.getNamespacePrefix(i)),
+                    fixNull(staxStreamReader.getNamespaceURI(i)));
+            }
+
+            // fire startElement
+            QName qName = staxStreamReader.getName();
+            String prefix = qName.getPrefix();
+            String rawname;
+            if(prefix==null || prefix.length()==0)
+                rawname = qName.getLocalPart();
+            else
+                rawname = prefix + ':' + qName.getLocalPart();
+            Attributes attrs = getAttributes();
+            saxHandler.startElement(
+                qName.getNamespaceURI(),
+                qName.getLocalPart(),
+                rawname,
+                attrs);
+        } catch (SAXException e) {
+            throw new XMLStreamException2(e);
+        }
+    }
+
+    private static String fixNull(String s) {
+        if(s==null)     return "";
+        else            return s;
+    }
+
+    /**
+     * Get the attributes associated with the given START_ELEMENT or ATTRIBUTE
+     * StAXevent.
+     *
+     * @return the StAX attributes converted to an org.xml.sax.Attributes
+     */
+    private Attributes getAttributes() {
+        AttributesImpl attrs = new AttributesImpl();
+
+        int eventType = staxStreamReader.getEventType();
+        if (eventType != XMLStreamConstants.ATTRIBUTE
+            && eventType != XMLStreamConstants.START_ELEMENT) {
+            throw new InternalError(
+                "getAttributes() attempting to process: " + eventType);
+        }
+
+        // in SAX, namespace declarations are not part of attributes by default.
+        // (there's a property to control that, but as far as we are concerned
+        // we don't use it.) So don't add xmlns:* to attributes.
+
+        // gather non-namespace attrs
+        for (int i = 0; i < staxStreamReader.getAttributeCount(); i++) {
+            String uri = staxStreamReader.getAttributeNamespace(i);
+            if(uri==null)   uri="";
+            String localName = staxStreamReader.getAttributeLocalName(i);
+            String prefix = staxStreamReader.getAttributePrefix(i);
+            String qName;
+            if(prefix==null || prefix.length()==0)
+                qName = localName;
+            else
+                qName = prefix + ':' + localName;
+            String type = staxStreamReader.getAttributeType(i);
+            String value = staxStreamReader.getAttributeValue(i);
+
+            attrs.addAttribute(uri, localName, qName, type, value);
+        }
+
+        return attrs;
+    }
+
+    private void handleNamespace() {
+        // no-op ???
+        // namespace events don't normally occur outside of a startElement
+        // or endElement
+    }
+
+    private void handleAttribute() {
+        // no-op ???
+        // attribute events don't normally occur outside of a startElement
+        // or endElement
+    }
+
+    private void handleDTD() {
+        // no-op ???
+        // it seems like we need to pass this info along, but how?
+    }
+
+    private void handleComment() {
+        // no-op ???
+    }
+
+    private void handleEntityReference() {
+        // no-op ???
+    }
+
+    private void handleSpace() {
+        // no-op ???
+        // this event is listed in the javadoc, but not in the spec.
+    }
+
+    private void handleNotationDecl() {
+        // no-op ???
+        // this event is listed in the javadoc, but not in the spec.
+    }
+
+    private void handleEntityDecl() {
+        // no-op ???
+        // this event is listed in the javadoc, but not in the spec.
+    }
+
+    private void handleCDATA() {
+        // no-op ???
+        // this event is listed in the javadoc, but not in the spec.
+    }
+}