1/*
2 * Copyright (c) 2017, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/*
25 * @test
26 * @bug 8159058
27 * @summary Test that empty default namespace declaration clears the
28 *          default namespace value
29 * @modules java.xml.ws/com.sun.xml.internal.ws.api
30 *          java.xml.ws/com.sun.xml.internal.ws.api.message.saaj
31 *          java.xml.ws/com.sun.xml.internal.ws.message.stream
32 * @run testng/othervm SaajEmptyNamespaceTest
33 */
34
35import com.sun.xml.internal.ws.api.SOAPVersion;
36import com.sun.xml.internal.ws.api.message.saaj.SAAJFactory;
37import com.sun.xml.internal.ws.message.stream.StreamMessage;
38import java.io.ByteArrayInputStream;
39import java.io.StringReader;
40import java.io.StringWriter;
41import java.io.UnsupportedEncodingException;
42import javax.xml.namespace.QName;
43import javax.xml.soap.MessageFactory;
44import javax.xml.soap.SOAPBody;
45import javax.xml.soap.SOAPElement;
46import javax.xml.soap.SOAPException;
47import javax.xml.soap.SOAPMessage;
48import javax.xml.stream.XMLInputFactory;
49import javax.xml.stream.XMLStreamReader;
50import javax.xml.transform.OutputKeys;
51import javax.xml.transform.Transformer;
52import javax.xml.transform.TransformerException;
53import javax.xml.transform.TransformerFactory;
54import javax.xml.transform.dom.DOMSource;
55import javax.xml.transform.stream.StreamResult;
56import javax.xml.transform.stream.StreamSource;
57import org.testng.Assert;
58import org.testng.annotations.Test;
59import org.w3c.dom.Node;
60
61public class SaajEmptyNamespaceTest {
62
63    /*
64     * Test that SOAP message with default namespace declaration that contains empty
65     * string is properly processed by SAAJ reader.
66     */
67    @Test
68    public void testResetDefaultNamespaceSAAJ() throws Exception {
69        // Create SOAP message from XML string and process it with SAAJ reader
70        XMLStreamReader envelope = XMLInputFactory.newFactory().createXMLStreamReader(
71                new StringReader(INPUT_SOAP_MESSAGE));
72        StreamMessage streamMessage = new StreamMessage(SOAPVersion.SOAP_11,
73                envelope, null);
74        SAAJFactory saajFact = new SAAJFactory();
75        SOAPMessage soapMessage = saajFact.readAsSOAPMessage(SOAPVersion.SOAP_11, streamMessage);
76
77        // Check if constructed object model meets local names and namespace expectations
78        SOAPElement request = (SOAPElement) soapMessage.getSOAPBody().getFirstChild();
79        // Check top body element name
80        Assert.assertEquals(request.getLocalName(), "SampleServiceRequest");
81        // Check top body element namespace
82        Assert.assertEquals(request.getNamespaceURI(), TEST_NS);
83        SOAPElement params = (SOAPElement) request.getFirstChild();
84        // Check first child name
85        Assert.assertEquals(params.getLocalName(), "RequestParams");
86        // Check if first child namespace is null
87        Assert.assertNull(params.getNamespaceURI());
88
89        // Check inner elements of the first child
90        SOAPElement param1 = (SOAPElement) params.getFirstChild();
91        Assert.assertEquals(param1.getLocalName(), "Param1");
92        Assert.assertNull(param1.getNamespaceURI());
93        SOAPElement param2 = (SOAPElement) params.getChildNodes().item(1);
94        Assert.assertEquals(param2.getLocalName(), "Param2");
95        Assert.assertNull(param2.getNamespaceURI());
96        // Check full content of SOAP body
97        Assert.assertEquals(nodeToText(request), EXPECTED_RESULT);
98    }
99
100    /*
101     * Test that adding element with explicitly null namespace URI shall put the
102     * element into global namespace. Namespace declarations are not added explicitly.
103     */
104    @Test
105    public void testAddElementToNullNsNoDeclarations() throws Exception {
106        // Create empty SOAP message
107        SOAPMessage msg = createSoapMessage();
108        SOAPBody body = msg.getSOAPPart().getEnvelope().getBody();
109
110        // Add elements
111        SOAPElement parentExplicitNS = body.addChildElement("content", "", TEST_NS);
112        SOAPElement childGlobalNS = parentExplicitNS.addChildElement("global-child", "", null);
113        SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child");
114
115        // Check namespace URIs
116        Assert.assertNull(childGlobalNS.getNamespaceURI());
117        Assert.assertEquals(childDefaultNS.getNamespaceURI(), TEST_NS);
118    }
119
120    /*
121     * Test that adding element with explicitly empty namespace URI shall put
122     * the element into global namespace. Namespace declarations are not added
123     * explicitly.
124     */
125    @Test
126    public void testAddElementToGlobalNsNoDeclarations() throws Exception {
127        // Create empty SOAP message
128        SOAPMessage msg = createSoapMessage();
129        SOAPBody body = msg.getSOAPPart().getEnvelope().getBody();
130
131        // Add elements
132        SOAPElement parentExplicitNS = body.addChildElement("content", "", TEST_NS);
133        SOAPElement childGlobalNS = parentExplicitNS.addChildElement("global-child", "", "");
134        SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child");
135
136        // Check namespace URIs
137        Assert.assertNull(childGlobalNS.getNamespaceURI());
138        Assert.assertEquals(childDefaultNS.getNamespaceURI(), TEST_NS);
139    }
140
141    /*
142     * Test that adding element with explicitly empty namespace URI set via QName
143     * shall put the element into global namespace.
144     */
145    @Test
146    public void testAddElementToNullNsQName() throws Exception {
147        // Create empty SOAP message
148        SOAPMessage msg = createSoapMessage();
149        SOAPBody body = msg.getSOAPPart().getEnvelope().getBody();
150
151        // Add elements
152        SOAPElement parentExplicitNS = body.addChildElement("content", "", TEST_NS);
153        parentExplicitNS.addNamespaceDeclaration("", TEST_NS);
154        SOAPElement childGlobalNS = parentExplicitNS.addChildElement(new QName(null, "global-child"));
155        childGlobalNS.addNamespaceDeclaration("", "");
156        SOAPElement grandChildGlobalNS = childGlobalNS.addChildElement("global-grand-child");
157        SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child");
158
159        // Check namespace URIs
160        Assert.assertNull(childGlobalNS.getNamespaceURI());
161        Assert.assertNull(grandChildGlobalNS.getNamespaceURI());
162        Assert.assertEquals(childDefaultNS.getNamespaceURI(), TEST_NS);
163    }
164
165    /*
166     * Test that adding element with explicitly empty namespace URI shall put
167     * the element into global namespace.
168     */
169    @Test
170    public void testAddElementToGlobalNs() throws Exception {
171        // Create empty SOAP message
172        SOAPMessage msg = createSoapMessage();
173        SOAPBody body = msg.getSOAPPart().getEnvelope().getBody();
174
175        // Add elements
176        SOAPElement parentExplicitNS = body.addChildElement("content", "", TEST_NS);
177        parentExplicitNS.addNamespaceDeclaration("", TEST_NS);
178        SOAPElement childGlobalNS = parentExplicitNS.addChildElement("global-child", "", "");
179        childGlobalNS.addNamespaceDeclaration("", "");
180        SOAPElement grandChildGlobalNS = childGlobalNS.addChildElement("global-grand-child");
181        SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child");
182
183        // Check namespace URIs
184        Assert.assertNull(childGlobalNS.getNamespaceURI());
185        Assert.assertNull(grandChildGlobalNS.getNamespaceURI());
186        Assert.assertEquals(childDefaultNS.getNamespaceURI(), TEST_NS);
187    }
188
189    /*
190     * Test that adding element with explicitly null namespace URI shall put
191     * the element into global namespace.
192     */
193    @Test
194    public void testAddElementToNullNs() throws Exception {
195        // Create empty SOAP message
196        SOAPMessage msg = createSoapMessage();
197        SOAPBody body = msg.getSOAPPart().getEnvelope().getBody();
198
199        // Add elements
200        SOAPElement parentExplicitNS = body.addChildElement("content", "", TEST_NS);
201        parentExplicitNS.addNamespaceDeclaration("", TEST_NS);
202        SOAPElement childGlobalNS = parentExplicitNS.addChildElement("global-child", "", null);
203        childGlobalNS.addNamespaceDeclaration("", null);
204        SOAPElement grandChildGlobalNS = childGlobalNS.addChildElement("global-grand-child");
205        SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child");
206
207        // Check namespace URIs
208        Assert.assertNull(childGlobalNS.getNamespaceURI());
209        Assert.assertNull(grandChildGlobalNS.getNamespaceURI());
210        Assert.assertEquals(TEST_NS, childDefaultNS.getNamespaceURI());
211    }
212
213    /*
214     * Test that adding element with explicitly empty namespace URI via QName
215     * shall put the element in global namespace.
216     */
217    @Test
218    public void testAddElementToGlobalNsQName() throws Exception {
219        // Create empty SOAP message
220        SOAPMessage msg = createSoapMessage();
221        SOAPBody body = msg.getSOAPPart().getEnvelope().getBody();
222
223        // Add elements
224        SOAPElement parentExplicitNS = body.addChildElement("content", "", TEST_NS);
225        parentExplicitNS.addNamespaceDeclaration("", TEST_NS);
226        SOAPElement childGlobalNS = parentExplicitNS.addChildElement(new QName("", "global-child"));
227        childGlobalNS.addNamespaceDeclaration("", "");
228        SOAPElement grandChildGlobalNS = childGlobalNS.addChildElement("global-grand-child");
229        SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child");
230
231        // Check namespace URIs
232        Assert.assertNull(childGlobalNS.getNamespaceURI());
233        Assert.assertNull(grandChildGlobalNS.getNamespaceURI());
234        Assert.assertEquals(childDefaultNS.getNamespaceURI(),TEST_NS);
235    }
236
237    // Convert DOM node to text representation
238    private String nodeToText(Node node) throws TransformerException {
239        Transformer trans = TransformerFactory.newInstance().newTransformer();
240        trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
241        StringWriter writer = new StringWriter();
242        StreamResult result = new StreamResult(writer);
243        trans.transform(new DOMSource(node), result);
244        String bodyContent = writer.toString();
245        System.out.println("SOAP body content read by SAAJ:"+bodyContent);
246        return bodyContent;
247    }
248
249    // Create SOAP message with empty body
250    private static SOAPMessage createSoapMessage() throws SOAPException, UnsupportedEncodingException {
251        String xml = "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">"
252                    +"<SOAP-ENV:Body/></SOAP-ENV:Envelope>";
253        MessageFactory mFactory = MessageFactory.newInstance();
254        SOAPMessage msg = mFactory.createMessage();
255        msg.getSOAPPart().setContent(new StreamSource(new ByteArrayInputStream(xml.getBytes("utf-8"))));
256        return msg;
257    }
258
259    // Namespace value used in tests
260    private static String TEST_NS = "http://example.org/test";
261
262    // Content of SOAP message passed to SAAJ factory
263    private static String INPUT_SOAP_MESSAGE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
264            + "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">"
265            + "<s:Body>"
266            + "<SampleServiceRequest xmlns=\"http://example.org/test\""
267            + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
268            + "<RequestParams xmlns=\"\">"
269            + "<Param1>hogehoge</Param1>"
270            + "<Param2>fugafuga</Param2>"
271            + "</RequestParams>"
272            + "</SampleServiceRequest>"
273            + "</s:Body>"
274            + "</s:Envelope>";
275
276    // Expected body content after SAAJ processing
277    private static String EXPECTED_RESULT = "<SampleServiceRequest"
278            +" xmlns=\"http://example.org/test\">"
279            + "<RequestParams xmlns=\"\">"
280            + "<Param1>hogehoge</Param1>"
281            + "<Param2>fugafuga</Param2>"
282            + "</RequestParams>"
283            + "</SampleServiceRequest>";
284}
285