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 8186441 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 35 import com.sun.xml.internal.ws.api.SOAPVersion; 36 import com.sun.xml.internal.ws.api.message.saaj.SAAJFactory; 37 import com.sun.xml.internal.ws.message.stream.StreamMessage; 38 import java.io.ByteArrayInputStream; 39 import java.io.StringReader; 40 import java.io.StringWriter; 41 import java.io.UnsupportedEncodingException; 42 import javax.xml.namespace.QName; 43 import javax.xml.soap.MessageFactory; 44 import javax.xml.soap.SOAPBody; 45 import javax.xml.soap.SOAPElement; 46 import javax.xml.soap.SOAPException; 47 import javax.xml.soap.SOAPMessage; 48 import javax.xml.stream.XMLInputFactory; 49 import javax.xml.stream.XMLStreamReader; 50 import javax.xml.transform.OutputKeys; 51 import javax.xml.transform.Transformer; 52 import javax.xml.transform.TransformerException; 53 import javax.xml.transform.TransformerFactory; 54 import javax.xml.transform.dom.DOMSource; 55 import javax.xml.transform.stream.StreamResult; 56 import javax.xml.transform.stream.StreamSource; 57 import org.testng.Assert; 58 import org.testng.annotations.Test; 59 import org.w3c.dom.Node; 60 61 public class SaajEmptyNamespaceTest { 62 63 /* 64 * Test that SOAP reader doesn't move namespaces declarations to SOAP body element 65 * as reported in JDK-8186441 66 */ 67 @Test 68 public void testPreserveNamespacesPosition() 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_2)); 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 //Get SOAP body and convert it to string representation 78 SOAPBody body = soapMessage.getSOAPBody(); 79 String bodyAsString = nodeToText(body); 80 Assert.assertEquals(bodyAsString, PRESERVE_NAMESPACES_EXPECTED_RESULT); 81 } 82 83 /* 84 * Test that SOAP message with default namespace declaration that contains empty 85 * string is properly processed by SAAJ reader. 86 */ 87 @Test 88 public void testResetDefaultNamespaceSAAJ() throws Exception { 89 // Create SOAP message from XML string and process it with SAAJ reader 90 XMLStreamReader envelope = XMLInputFactory.newFactory().createXMLStreamReader( 91 new StringReader(INPUT_SOAP_MESSAGE)); 92 StreamMessage streamMessage = new StreamMessage(SOAPVersion.SOAP_11, 93 envelope, null); 94 SAAJFactory saajFact = new SAAJFactory(); 95 SOAPMessage soapMessage = saajFact.readAsSOAPMessage(SOAPVersion.SOAP_11, streamMessage); 96 97 // Check if constructed object model meets local names and namespace expectations 98 SOAPElement request = (SOAPElement) soapMessage.getSOAPBody().getFirstChild(); 99 // Check top body element name 100 Assert.assertEquals(request.getLocalName(), "SampleServiceRequest"); 101 // Check top body element namespace 102 Assert.assertEquals(request.getNamespaceURI(), TEST_NS); 103 SOAPElement params = (SOAPElement) request.getFirstChild(); 104 // Check first child name 105 Assert.assertEquals(params.getLocalName(), "RequestParams"); 106 // Check if first child namespace is null 107 Assert.assertNull(params.getNamespaceURI()); 108 109 // Check inner elements of the first child 110 SOAPElement param1 = (SOAPElement) params.getFirstChild(); 111 Assert.assertEquals(param1.getLocalName(), "Param1"); 112 Assert.assertNull(param1.getNamespaceURI()); 113 SOAPElement param2 = (SOAPElement) params.getChildNodes().item(1); 114 Assert.assertEquals(param2.getLocalName(), "Param2"); 115 Assert.assertNull(param2.getNamespaceURI()); 116 // Check full content of SOAP body 117 Assert.assertEquals(nodeToText(request), EXPECTED_RESULT); 118 } 119 120 /* 121 * Test that adding element with explicitly null namespace URI shall put the 122 * element into global namespace. Namespace declarations are not added explicitly. 123 */ 124 @Test 125 public void testAddElementToNullNsNoDeclarations() throws Exception { 126 // Create empty SOAP message 127 SOAPMessage msg = createSoapMessage(); 128 SOAPBody body = msg.getSOAPPart().getEnvelope().getBody(); 129 130 // Add elements 131 SOAPElement parentExplicitNS = body.addChildElement("content", "", TEST_NS); 132 SOAPElement childGlobalNS = parentExplicitNS.addChildElement("global-child", "", null); 133 SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child"); 134 135 // Check namespace URIs 136 Assert.assertNull(childGlobalNS.getNamespaceURI()); 137 Assert.assertEquals(childDefaultNS.getNamespaceURI(), TEST_NS); 138 } 139 140 /* 141 * Test that adding element with explicitly empty namespace URI shall put 142 * the element into global namespace. Namespace declarations are not added 143 * explicitly. 144 */ 145 @Test 146 public void testAddElementToGlobalNsNoDeclarations() 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 SOAPElement childGlobalNS = parentExplicitNS.addChildElement("global-child", "", ""); 154 SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child"); 155 156 // Check namespace URIs 157 Assert.assertNull(childGlobalNS.getNamespaceURI()); 158 Assert.assertEquals(childDefaultNS.getNamespaceURI(), TEST_NS); 159 } 160 161 /* 162 * Test that adding element with explicitly empty namespace URI set via QName 163 * shall put the element into global namespace. 164 */ 165 @Test 166 public void testAddElementToNullNsQName() throws Exception { 167 // Create empty SOAP message 168 SOAPMessage msg = createSoapMessage(); 169 SOAPBody body = msg.getSOAPPart().getEnvelope().getBody(); 170 171 // Add elements 172 SOAPElement parentExplicitNS = body.addChildElement("content", "", TEST_NS); 173 parentExplicitNS.addNamespaceDeclaration("", TEST_NS); 174 SOAPElement childGlobalNS = parentExplicitNS.addChildElement(new QName(null, "global-child")); 175 childGlobalNS.addNamespaceDeclaration("", ""); 176 SOAPElement grandChildGlobalNS = childGlobalNS.addChildElement("global-grand-child"); 177 SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child"); 178 179 // Check namespace URIs 180 Assert.assertNull(childGlobalNS.getNamespaceURI()); 181 Assert.assertNull(grandChildGlobalNS.getNamespaceURI()); 182 Assert.assertEquals(childDefaultNS.getNamespaceURI(), TEST_NS); 183 } 184 185 /* 186 * Test that adding element with explicitly empty namespace URI shall put 187 * the element into global namespace. 188 */ 189 @Test 190 public void testAddElementToGlobalNs() throws Exception { 191 // Create empty SOAP message 192 SOAPMessage msg = createSoapMessage(); 193 SOAPBody body = msg.getSOAPPart().getEnvelope().getBody(); 194 195 // Add elements 196 SOAPElement parentExplicitNS = body.addChildElement("content", "", TEST_NS); 197 parentExplicitNS.addNamespaceDeclaration("", TEST_NS); 198 SOAPElement childGlobalNS = parentExplicitNS.addChildElement("global-child", "", ""); 199 childGlobalNS.addNamespaceDeclaration("", ""); 200 SOAPElement grandChildGlobalNS = childGlobalNS.addChildElement("global-grand-child"); 201 SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child"); 202 203 // Check namespace URIs 204 Assert.assertNull(childGlobalNS.getNamespaceURI()); 205 Assert.assertNull(grandChildGlobalNS.getNamespaceURI()); 206 Assert.assertEquals(childDefaultNS.getNamespaceURI(), TEST_NS); 207 } 208 209 /* 210 * Test that adding element with explicitly null namespace URI shall put 211 * the element into global namespace. 212 */ 213 @Test 214 public void testAddElementToNullNs() throws Exception { 215 // Create empty SOAP message 216 SOAPMessage msg = createSoapMessage(); 217 SOAPBody body = msg.getSOAPPart().getEnvelope().getBody(); 218 219 // Add elements 220 SOAPElement parentExplicitNS = body.addChildElement("content", "", TEST_NS); 221 parentExplicitNS.addNamespaceDeclaration("", TEST_NS); 222 SOAPElement childGlobalNS = parentExplicitNS.addChildElement("global-child", "", null); 223 childGlobalNS.addNamespaceDeclaration("", null); 224 SOAPElement grandChildGlobalNS = childGlobalNS.addChildElement("global-grand-child"); 225 SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child"); 226 227 // Check namespace URIs 228 Assert.assertNull(childGlobalNS.getNamespaceURI()); 229 Assert.assertNull(grandChildGlobalNS.getNamespaceURI()); 230 Assert.assertEquals(TEST_NS, childDefaultNS.getNamespaceURI()); 231 } 232 233 /* 234 * Test that adding element with explicitly empty namespace URI via QName 235 * shall put the element in global namespace. 236 */ 237 @Test 238 public void testAddElementToGlobalNsQName() throws Exception { 239 // Create empty SOAP message 240 SOAPMessage msg = createSoapMessage(); 241 SOAPBody body = msg.getSOAPPart().getEnvelope().getBody(); 242 243 // Add elements 244 SOAPElement parentExplicitNS = body.addChildElement("content", "", TEST_NS); 245 parentExplicitNS.addNamespaceDeclaration("", TEST_NS); 246 SOAPElement childGlobalNS = parentExplicitNS.addChildElement(new QName("", "global-child")); 247 childGlobalNS.addNamespaceDeclaration("", ""); 248 SOAPElement grandChildGlobalNS = childGlobalNS.addChildElement("global-grand-child"); 249 SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child"); 250 251 // Check namespace URIs 252 Assert.assertNull(childGlobalNS.getNamespaceURI()); 253 Assert.assertNull(grandChildGlobalNS.getNamespaceURI()); 254 Assert.assertEquals(childDefaultNS.getNamespaceURI(),TEST_NS); 255 } 256 257 // Convert DOM node to text representation 258 private String nodeToText(Node node) throws TransformerException { 259 Transformer trans = TransformerFactory.newInstance().newTransformer(); 260 trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); 261 StringWriter writer = new StringWriter(); 262 StreamResult result = new StreamResult(writer); 263 trans.transform(new DOMSource(node), result); 264 String bodyContent = writer.toString(); 265 System.out.println("SOAP body content read by SAAJ:"+bodyContent); 266 return bodyContent; 267 } 268 269 // Create SOAP message with empty body 270 private static SOAPMessage createSoapMessage() throws SOAPException, UnsupportedEncodingException { 271 String xml = "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">" 272 +"<SOAP-ENV:Body/></SOAP-ENV:Envelope>"; 273 MessageFactory mFactory = MessageFactory.newInstance(); 274 SOAPMessage msg = mFactory.createMessage(); 275 msg.getSOAPPart().setContent(new StreamSource(new ByteArrayInputStream(xml.getBytes("utf-8")))); 276 return msg; 277 } 278 279 // Namespace value used in tests 280 private static String TEST_NS = "http://example.org/test"; 281 282 // Content of SOAP message passed to SAAJ factory 283 private static String INPUT_SOAP_MESSAGE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" 284 + "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">" 285 + "<s:Body>" 286 + "<SampleServiceRequest xmlns=\"http://example.org/test\"" 287 + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" 288 + "<RequestParams xmlns=\"\">" 289 + "<Param1>hogehoge</Param1>" 290 + "<Param2>fugafuga</Param2>" 291 + "</RequestParams>" 292 + "</SampleServiceRequest>" 293 + "</s:Body>" 294 + "</s:Envelope>"; 295 296 // Expected body content after SAAJ processing 297 private static String EXPECTED_RESULT = "<SampleServiceRequest" 298 + " xmlns=\"http://example.org/test\"" 299 + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" 300 + "<RequestParams xmlns=\"\">" 301 + "<Param1>hogehoge</Param1>" 302 + "<Param2>fugafuga</Param2>" 303 + "</RequestParams>" 304 + "</SampleServiceRequest>"; 305 306 private static String PRESERVE_NAMESPACES_EXPECTED_RESULT = 307 "<s:Body xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">" 308 +"<Request xmlns=\"http://example.org/NS_1\">" 309 +"<Item><Contact xmlns=\"http://example.org/NS_2\">Test_Contact</Contact>" 310 +"</Item></Request></s:Body>"; 311 312 private static String INPUT_SOAP_MESSAGE_2 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" 313 + "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">" 314 + "<s:Body>" 315 + "<Request xmlns=\"http://example.org/NS_1\">" 316 + "<Item>" 317 + "<Contact xmlns=\"http://example.org/NS_2\">Test_Contact</Contact>" 318 + "</Item>" 319 + "</Request>" 320 + "</s:Body>" 321 + "</s:Envelope>"; 322 }