1/*
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.xml.internal.ws.message.source;
27
28import com.sun.xml.internal.ws.message.RootElementSniffer;
29import com.sun.xml.internal.ws.streaming.SourceReaderFactory;
30import com.sun.xml.internal.ws.util.xml.XmlUtil;
31import org.w3c.dom.Document;
32import org.w3c.dom.Node;
33
34import javax.xml.namespace.QName;
35import javax.xml.stream.XMLStreamConstants;
36import javax.xml.stream.XMLStreamException;
37import javax.xml.stream.XMLStreamReader;
38import javax.xml.stream.XMLStreamWriter;
39import javax.xml.transform.Source;
40import javax.xml.transform.Transformer;
41import javax.xml.transform.TransformerConfigurationException;
42import javax.xml.transform.TransformerException;
43import javax.xml.transform.dom.DOMSource;
44import javax.xml.transform.sax.SAXResult;
45import javax.xml.transform.sax.SAXSource;
46import javax.xml.transform.stream.StreamSource;
47import javax.xml.ws.WebServiceException;
48
49/**
50 *
51 * @author Vivek Pandey
52 */
53final class SourceUtils {
54
55    int srcType;
56
57    private static final int domSource = 1;
58    private static final int streamSource = 2;
59    private static final int saxSource=4;
60
61    public SourceUtils(Source src) {
62        if(src instanceof StreamSource){
63            srcType = streamSource;
64        }else if(src instanceof DOMSource){
65            srcType = domSource;
66        }else if(src instanceof SAXSource){
67            srcType = saxSource;
68        }
69    }
70
71    public boolean isDOMSource(){
72        return (srcType&domSource) == domSource;
73    }
74
75    public boolean isStreamSource(){
76        return (srcType&streamSource) == streamSource;
77    }
78
79    public boolean isSaxSource(){
80        return (srcType&saxSource) == saxSource;
81    }
82
83    /**
84     * This would peek into the Source (DOMSource and SAXSource) for the localName and NamespaceURI
85     * of the top-level element.
86     * @param src
87     * @return QName of the payload
88     */
89    public QName sniff(Source src) {
90        return sniff(src, new RootElementSniffer());
91    }
92
93    public QName sniff(Source src, RootElementSniffer sniffer){
94        String localName = null;
95        String namespaceUri = null;
96
97        if(isDOMSource()){
98            DOMSource domSrc = (DOMSource)src;
99            Node n = domSrc.getNode();
100            if(n.getNodeType()== Node.DOCUMENT_NODE) {
101                n = ((Document)n).getDocumentElement();
102            }
103            localName = n.getLocalName();
104            namespaceUri = n.getNamespaceURI();
105        }else if(isSaxSource()){
106            SAXSource saxSrc = (SAXSource)src;
107            SAXResult saxResult = new SAXResult(sniffer);
108            try {
109                Transformer tr = XmlUtil.newTransformer();
110                tr.transform(saxSrc, saxResult);
111            } catch (TransformerConfigurationException e) {
112                throw new WebServiceException(e);
113            } catch (TransformerException e) {
114                // if it's due to aborting the processing after the first element,
115                // we can safely ignore this exception.
116                //
117                // if it's due to error in the object, the same error will be reported
118                // when the readHeader() method is used, so we don't have to report
119                // an error right now.
120                localName = sniffer.getLocalName();
121                namespaceUri = sniffer.getNsUri();
122            }
123        }
124        return new QName(namespaceUri, localName);
125    }
126
127    public static void serializeSource(Source src, XMLStreamWriter writer) throws XMLStreamException {
128        XMLStreamReader reader = SourceReaderFactory.createSourceReader(src, true);
129        int state;
130        do {
131            state = reader.next();
132            switch (state) {
133                case XMLStreamConstants.START_ELEMENT:
134                    /*
135                     * TODO: Is this necessary, shouldn't zephyr return "" instead of
136                     * null for getNamespaceURI() and getPrefix()?
137                     */
138                    String uri = reader.getNamespaceURI();
139                    String prefix = reader.getPrefix();
140                    String localName = reader.getLocalName();
141
142                    if (prefix == null) {
143                        if (uri == null) {
144                            writer.writeStartElement(localName);
145                        } else {
146                            writer.writeStartElement(uri, localName);
147                        }
148                    } else {
149//                        assert uri != null;
150
151                        if(prefix.length() > 0){
152                            /**
153                             * Before we write the
154                             */
155                            String writerURI = null;
156                            if (writer.getNamespaceContext() != null) {
157                                writerURI = writer.getNamespaceContext().getNamespaceURI(prefix);
158                            }
159                            String writerPrefix = writer.getPrefix(uri);
160                            if(declarePrefix(prefix, uri, writerPrefix, writerURI)){
161                                writer.writeStartElement(prefix, localName, uri);
162                                writer.setPrefix(prefix, uri != null ? uri : "");
163                                writer.writeNamespace(prefix, uri);
164                            }else{
165                                writer.writeStartElement(prefix, localName, uri);
166                            }
167                        }else{
168                            writer.writeStartElement(prefix, localName, uri);
169                        }
170                    }
171
172                    int n = reader.getNamespaceCount();
173                    // Write namespace declarations
174                    for (int i = 0; i < n; i++) {
175                        String nsPrefix = reader.getNamespacePrefix(i);
176                        if (nsPrefix == null) {
177                            nsPrefix = "";
178                        }
179                        // StAX returns null for default ns
180                        String writerURI = null;
181                        if (writer.getNamespaceContext() != null) {
182                            writerURI = writer.getNamespaceContext().getNamespaceURI(nsPrefix);
183                        }
184
185                        // Zephyr: Why is this returning null?
186                        // Compare nsPrefix with prefix because of [1] (above)
187                        String readerURI = reader.getNamespaceURI(i);
188
189                        /**
190                         * write the namespace in 3 conditions
191                         *  - when the namespace URI is not bound to the prefix in writer(writerURI == 0)
192                         *  - when the readerPrefix and writerPrefix are ""
193                         *  - when readerPrefix and writerPrefix are not equal and the URI bound to them
194                         *    are different
195                         */
196                        if (writerURI == null || ((nsPrefix.length() == 0) || (prefix.length() == 0)) ||
197                                (!nsPrefix.equals(prefix) && !writerURI.equals(readerURI))) {
198                            writer.setPrefix(nsPrefix, readerURI != null ? readerURI : "");
199                            writer.writeNamespace(nsPrefix, readerURI != null ? readerURI : "");
200                        }
201                    }
202
203                    // Write attributes
204                    n = reader.getAttributeCount();
205                    for (int i = 0; i < n; i++) {
206                        String attrPrefix = reader.getAttributePrefix(i);
207                        String attrURI = reader.getAttributeNamespace(i);
208
209                        writer.writeAttribute(attrPrefix != null ? attrPrefix : "",
210                            attrURI != null ? attrURI : "",
211                            reader.getAttributeLocalName(i),
212                            reader.getAttributeValue(i));
213                        // if the attribute prefix is undeclared in current writer scope then declare it
214                        setUndeclaredPrefix(attrPrefix, attrURI, writer);
215                    }
216                    break;
217                case XMLStreamConstants.END_ELEMENT:
218                    writer.writeEndElement();
219                    break;
220                case XMLStreamConstants.CHARACTERS:
221                    writer.writeCharacters(reader.getText());
222                    break;
223                default:
224                    break;
225            }
226        } while (state != XMLStreamConstants.END_DOCUMENT);
227        reader.close();
228    }
229
230    /**
231     * sets undeclared prefixes on the writer
232     * @param prefix
233     * @param writer
234     * @throws XMLStreamException
235     */
236    private static void setUndeclaredPrefix(String prefix, String readerURI, XMLStreamWriter writer) throws XMLStreamException {
237        String writerURI = null;
238        if (writer.getNamespaceContext() != null) {
239            writerURI = writer.getNamespaceContext().getNamespaceURI(prefix);
240        }
241
242        if (writerURI == null) {
243            writer.setPrefix(prefix, readerURI != null ? readerURI : "");
244            writer.writeNamespace(prefix, readerURI != null ? readerURI : "");
245        }
246    }
247
248    /**
249     * check if we need to declare
250     * @param rPrefix
251     * @param rUri
252     * @param wPrefix
253     * @param wUri
254     */
255    private static boolean declarePrefix(String rPrefix, String rUri, String wPrefix, String wUri){
256        if (wUri == null ||((wPrefix != null) && !rPrefix.equals(wPrefix))||
257                (rUri != null && !wUri.equals(rUri))) {
258            return true;
259        }
260        return false;
261    }
262}
263