1 /* 2 * Copyright (c) 2014, 2019, 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 package dom.ls; 25 26 import static org.w3c.dom.ls.DOMImplementationLS.MODE_SYNCHRONOUS; 27 28 import java.io.IOException; 29 import java.io.OutputStream; 30 import java.io.StringReader; 31 import java.io.Writer; 32 33 import javax.xml.parsers.DocumentBuilder; 34 import javax.xml.parsers.DocumentBuilderFactory; 35 import javax.xml.parsers.ParserConfigurationException; 36 37 import org.testng.Assert; 38 import org.testng.annotations.DataProvider; 39 import org.testng.annotations.Listeners; 40 import org.testng.annotations.Test; 41 import org.w3c.dom.DOMError; 42 import org.w3c.dom.DOMErrorHandler; 43 import org.w3c.dom.DOMImplementation; 44 import org.w3c.dom.Document; 45 import org.w3c.dom.ls.DOMImplementationLS; 46 import org.w3c.dom.ls.LSException; 47 import org.w3c.dom.ls.LSInput; 48 import org.w3c.dom.ls.LSOutput; 49 import org.w3c.dom.ls.LSParser; 50 import org.w3c.dom.ls.LSSerializer; 51 import org.xml.sax.InputSource; 52 import org.xml.sax.SAXException; 53 54 /* 55 * @test 56 * @bug 8080906 8114834 8206132 57 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest 58 * @run testng/othervm -DrunSecMngr=true dom.ls.LSSerializerTest 59 * @run testng/othervm dom.ls.LSSerializerTest 60 * @summary Test LSSerializer. 61 */ 62 @Listeners({jaxp.library.BasePolicy.class}) 63 public class LSSerializerTest { 64 65 class DOMErrorHandlerImpl implements DOMErrorHandler { 66 67 boolean NoOutputSpecifiedErrorReceived = false; 68 69 public boolean handleError(final DOMError error) { 70 // consume "no-output-specified" errors 71 if ("no-output-specified".equalsIgnoreCase(error.getType())) { 72 NoOutputSpecifiedErrorReceived = true; 73 return true; 74 } 75 76 // unexpected error 77 Assert.fail("Unexpected Error Type: " + error.getType() + " @ (" + error.getLocation().getLineNumber() + ", " 78 + error.getLocation().getColumnNumber() + ")" + ", " + error.getMessage()); 79 80 return false; 81 } 82 } 83 84 class Output implements LSOutput { 85 public OutputStream getByteStream() { 86 return null; 87 } 88 89 public void setByteStream(final OutputStream byteStream) { 90 } 91 92 public Writer getCharacterStream() { 93 return null; 94 } 95 96 public void setCharacterStream(final Writer characterStream) { 97 } 98 99 public String getSystemId() { 100 return null; 101 } 102 103 public void setSystemId(final String systemId) { 104 } 105 106 public String getEncoding() { 107 return "UTF8"; 108 } 109 110 public void setEncoding(final String encoding) { 111 } 112 } 113 114 /* 115 * @bug 8080906 116 */ 117 @Test 118 public void testDefaultLSSerializer() throws Exception { 119 DOMImplementationLS domImpl = (DOMImplementationLS) DocumentBuilderFactory.newInstance().newDocumentBuilder().getDOMImplementation(); 120 LSSerializer lsSerializer = domImpl.createLSSerializer(); 121 Assert.assertTrue(lsSerializer.getClass().getName().endsWith("dom3.LSSerializerImpl")); 122 } 123 124 @Test 125 public void testDOMErrorHandler() { 126 127 final String XML_DOCUMENT = "<?xml version=\"1.0\"?>" + "<hello>" + "world" + "</hello>"; 128 129 StringReader stringReader = new StringReader(XML_DOCUMENT); 130 InputSource inputSource = new InputSource(stringReader); 131 Document doc = null; 132 try { 133 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); 134 // LSSerializer defaults to Namespace processing 135 // so parsing must also 136 documentBuilderFactory.setNamespaceAware(true); 137 DocumentBuilder parser = documentBuilderFactory.newDocumentBuilder(); 138 doc = parser.parse(inputSource); 139 140 } catch (Throwable e) { 141 e.printStackTrace(); 142 Assert.fail(e.toString()); 143 } 144 145 DOMImplementation impl = doc.getImplementation(); 146 DOMImplementationLS implLS = (DOMImplementationLS) impl.getFeature("LS", "3.0"); 147 LSSerializer writer = implLS.createLSSerializer(); 148 149 System.out.println("Serializer is: " + implLS.getClass().getName() + " " + implLS); 150 151 DOMErrorHandlerImpl eh = new DOMErrorHandlerImpl(); 152 writer.getDomConfig().setParameter("error-handler", eh); 153 154 boolean serialized = false; 155 try { 156 serialized = writer.write(doc, new Output()); 157 158 // unexpected success 159 Assert.fail("Serialized without raising an LSException due to " + "'no-output-specified'."); 160 } catch (LSException lsException) { 161 // expected exception 162 System.out.println("Expected LSException: " + lsException.toString()); 163 // continue processing 164 } 165 166 Assert.assertFalse(serialized, "Expected writer.write(doc, new Output()) == false"); 167 168 Assert.assertTrue(eh.NoOutputSpecifiedErrorReceived, "'no-output-specified' error was expected"); 169 } 170 171 @Test 172 public void testXML11() { 173 174 /** 175 * XML 1.1 document to parse. 176 */ 177 final String XML11_DOCUMENT = "<?xml version=\"1.1\" encoding=\"UTF-16\"?>\n" + "<hello>" + "world" + "<child><children/><children/></child>" 178 + "</hello>"; 179 180 /**JDK-8035467 181 * no newline in default output 182 */ 183 final String XML11_DOCUMENT_OUTPUT = 184 "<?xml version=\"1.1\" encoding=\"UTF-16\"?>" 185 + "<hello>" 186 + "world" 187 + "<child><children/><children/></child>" 188 + "</hello>"; 189 190 // it all begins with a Document 191 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); 192 DocumentBuilder documentBuilder = null; 193 try { 194 documentBuilder = documentBuilderFactory.newDocumentBuilder(); 195 } catch (ParserConfigurationException parserConfigurationException) { 196 parserConfigurationException.printStackTrace(); 197 Assert.fail(parserConfigurationException.toString()); 198 } 199 Document document = null; 200 201 StringReader stringReader = new StringReader(XML11_DOCUMENT); 202 InputSource inputSource = new InputSource(stringReader); 203 try { 204 document = documentBuilder.parse(inputSource); 205 } catch (SAXException saxException) { 206 saxException.printStackTrace(); 207 Assert.fail(saxException.toString()); 208 } catch (IOException ioException) { 209 ioException.printStackTrace(); 210 Assert.fail(ioException.toString()); 211 } 212 213 // query DOM Interfaces to get to a LSSerializer 214 DOMImplementation domImplementation = documentBuilder.getDOMImplementation(); 215 DOMImplementationLS domImplementationLS = (DOMImplementationLS) domImplementation; 216 LSSerializer lsSerializer = domImplementationLS.createLSSerializer(); 217 218 System.out.println("Serializer is: " + lsSerializer.getClass().getName() + " " + lsSerializer); 219 220 // get default serialization 221 String defaultSerialization = lsSerializer.writeToString(document); 222 223 System.out.println("XML 1.1 serialization = \"" + defaultSerialization + "\""); 224 225 // output should == input 226 Assert.assertEquals(XML11_DOCUMENT_OUTPUT, defaultSerialization, "Invalid serialization of XML 1.1 document: "); 227 } 228 229 // XML source 230 private static final String XML = 231 "<?xml version=\"1.1\" encoding=\"UTF-16\"?>\n" + 232 "<!DOCTYPE author [\n" + 233 " <!ENTITY name \"Jo Smith\">" + 234 " <!ENTITY name1 \"&name;\">" + 235 " <!ENTITY name2 \"&name1;\">" + 236 "<!ENTITY ele \"<aa><bb>text</bb></aa>\">" + 237 " <!ENTITY ele1 \"&ele;\">" + 238 " <!ENTITY ele2 \"&ele1;\">" + 239 " ]>" + 240 " <author><a>&name1;</a>" + 241 "<b>b &name2; &name1; b</b>" + 242 "<c> &name; </c>" + 243 "<d>&ele1;d</d>" + 244 "<e> &ele2;eee </e>" + 245 "<f><att></f>" + 246 "<g> &ele; g</g>" + 247 "<h>&ele2;</h></author>" ; 248 249 // result when "entities" = true, equvalent to setting ExpandEntityReference to false 250 private static final String RESULT_TRUE = 251 "<?xml version=\"1.1\" encoding=\"UTF-16\"?><!DOCTYPE author [ \n" + 252 "<!ENTITY name 'Jo Smith'>\n" + 253 "<!ENTITY name1 '&name;'>\n" + 254 "<!ENTITY name2 '&name1;'>\n" + 255 "<!ENTITY ele '<aa><bb>text</bb></aa>'>\n" + 256 "<!ENTITY ele1 '&ele;'>\n" + 257 "<!ENTITY ele2 '&ele1;'>\n" + 258 "]>\n" + 259 "<author>\n" + 260 " <a>&name1;</a>\n" + 261 " <b>b &name2;&name1; b</b>\n" + 262 " <c>&name;</c>\n" + 263 " <d>&ele1;d</d>\n" + 264 " <e>&ele2;eee </e>\n" + 265 " <f><att></f>\n" + 266 " <g>&ele; g</g>\n" + 267 " <h>&ele2;</h>\n" + 268 "</author>\n"; 269 270 // result when "entities" = false, equvalent to setting ExpandEntityReference to true 271 private static final String RESULT_FALSE = 272 "<?xml version=\"1.1\" encoding=\"UTF-16\"?><!DOCTYPE author [ \n" + 273 "<!ENTITY name 'Jo Smith'>\n" + 274 "<!ENTITY name1 '&name;'>\n" + 275 "<!ENTITY name2 '&name1;'>\n" + 276 "<!ENTITY ele '<aa><bb>text</bb></aa>'>\n" + 277 "<!ENTITY ele1 '&ele;'>\n" + 278 "<!ENTITY ele2 '&ele1;'>\n" + 279 "]>\n" + 280 "<author>\n" + 281 " <a>Jo Smith</a>\n" + 282 " <b>b Jo Smith Jo Smith b</b>\n" + 283 " <c> Jo Smith </c>\n" + 284 " <d>\n" + 285 " <aa>\n" + 286 " <bb>text</bb>\n" + 287 " </aa>\n" + 288 " d\n" + 289 " </d>\n" + 290 " <e>\n" + 291 " <aa>\n" + 292 " <bb>text</bb>\n" + 293 " </aa>\n" + 294 " eee \n" + 295 " </e>\n" + 296 " <f><att></f>\n" + 297 " <g>\n" + 298 " <aa>\n" + 299 " <bb>text</bb>\n" + 300 " </aa>\n" + 301 " g\n" + 302 " </g>\n" + 303 " <h>\n" + 304 " <aa>\n" + 305 " <bb>text</bb>\n" + 306 " </aa>\n" + 307 " </h>\n" + 308 "</author>\n"; 309 310 /* 311 * DataProvider: for testing the entities parameter 312 * Data columns: xml source, entities setting, expected result 313 */ 314 @DataProvider(name = "entities") 315 Object[][] getData() throws Exception { 316 return new Object[][]{ 317 {XML, Boolean.TRUE, RESULT_TRUE}, 318 {XML, Boolean.FALSE, RESULT_FALSE}, 319 }; 320 } 321 322 /** 323 * Tests serializing DOM Document with DOMConfiguration's "entities" parameter. 324 * 325 * @param source the XML source 326 * @param entities the entities parameter setting 327 * @param expected expected string result 328 * @throws Exception 329 * @bug 8114834 8206132 330 */ 331 @Test(dataProvider = "entities") 332 public void testEntityReference(String source, Boolean entities, String expected) 333 throws Exception { 334 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); 335 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); 336 337 DOMImplementation domImplementation = documentBuilder.getDOMImplementation(); 338 DOMImplementationLS domImplementationLS = (DOMImplementationLS) domImplementation; 339 340 LSParser domParser = domImplementationLS.createLSParser(MODE_SYNCHRONOUS, null); 341 domParser.getDomConfig().setParameter("entities", entities); 342 343 LSInput src = domImplementationLS.createLSInput(); 344 src.setStringData(source); 345 Document document = domParser.parse(src); 346 347 LSSerializer lsSerializer = domImplementationLS.createLSSerializer(); 348 lsSerializer.getDomConfig().setParameter("format-pretty-print", true); 349 System.out.println("test with default entities is " + 350 lsSerializer.getDomConfig().getParameter("entities")); 351 352 String result = lsSerializer.writeToString(document); 353 Assert.assertEquals(result, expected); 354 } 355 }