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 
handleError(final DOMError error)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 {
getByteStream()85         public OutputStream getByteStream() {
86             return null;
87         }
88 
setByteStream(final OutputStream byteStream)89         public void setByteStream(final OutputStream byteStream) {
90         }
91 
getCharacterStream()92         public Writer getCharacterStream() {
93             return null;
94         }
95 
setCharacterStream(final Writer characterStream)96         public void setCharacterStream(final Writer characterStream) {
97         }
98 
getSystemId()99         public String getSystemId() {
100             return null;
101         }
102 
setSystemId(final String systemId)103         public void setSystemId(final String systemId) {
104         }
105 
getEncoding()106         public String getEncoding() {
107             return "UTF8";
108         }
109 
setEncoding(final String encoding)110         public void setEncoding(final String encoding) {
111         }
112     }
113 
114     /*
115      * @bug 8080906
116      */
117     @Test
testDefaultLSSerializer()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
testDOMErrorHandler()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
testXML11()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")
getData()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")
testEntityReference(String source, Boolean entities, String expected)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 }
356