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>&lt;att&gt;</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>&lt;att&gt;</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>&lt;att&gt;</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 }