1 /*
   2  * Copyright (c) 2014, 2016, 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 transform;
  25 
  26 import java.io.BufferedReader;
  27 import java.io.ByteArrayInputStream;
  28 import java.io.File;
  29 import java.io.FileReader;
  30 import java.io.IOException;
  31 import java.io.InputStream;
  32 import java.io.StringReader;
  33 import java.io.StringWriter;
  34 
  35 import javax.xml.transform.Transformer;
  36 import javax.xml.transform.TransformerException;
  37 import javax.xml.transform.TransformerFactory;
  38 import javax.xml.transform.dom.DOMResult;
  39 import javax.xml.transform.sax.SAXSource;
  40 import javax.xml.transform.stream.StreamResult;
  41 import javax.xml.transform.stream.StreamSource;
  42 
  43 import jaxp.library.JAXPTestUtilities;
  44 
  45 import org.testng.Assert;
  46 import org.testng.AssertJUnit;
  47 import org.testng.annotations.Listeners;
  48 import org.testng.annotations.Test;
  49 import org.w3c.dom.Document;
  50 import org.w3c.dom.Node;
  51 import org.w3c.dom.NodeList;
  52 import org.xml.sax.ContentHandler;
  53 import org.xml.sax.DTDHandler;
  54 import org.xml.sax.EntityResolver;
  55 import org.xml.sax.ErrorHandler;
  56 import org.xml.sax.InputSource;
  57 import org.xml.sax.SAXException;
  58 import org.xml.sax.SAXNotRecognizedException;
  59 import org.xml.sax.SAXNotSupportedException;
  60 import org.xml.sax.XMLReader;
  61 import org.xml.sax.helpers.AttributesImpl;
  62 
  63 import com.sun.org.apache.xml.internal.serialize.OutputFormat;
  64 import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
  65 
  66 /*
  67  * @summary Transformer Tests
  68  * @bug 6272879 6305029 6505031 8150704
  69  */
  70 @Listeners({jaxp.library.FilePolicy.class})
  71 public class TransformerTest {
  72     private Transformer createTransformer() throws TransformerException {
  73         return TransformerFactory.newInstance().newTransformer();
  74     }
  75 
  76     private Transformer createTransformerFromInputstream(InputStream xslStream) throws TransformerException {
  77         return TransformerFactory.newInstance().newTransformer(new StreamSource(xslStream));
  78     }
  79 
  80     private Transformer createTransformerFromResource(String xslResource) throws TransformerException {
  81         return TransformerFactory.newInstance().newTransformer(new StreamSource(getClass().getResource(xslResource).toString()));
  82     }
  83 
  84     private Document transformInputStreamToDocument(Transformer transformer, InputStream sourceStream) throws TransformerException {
  85         DOMResult response = new DOMResult();
  86         transformer.transform(new StreamSource(sourceStream), response);
  87         return (Document)response.getNode();
  88     }
  89 
  90     private StringWriter transformResourceToStringWriter(Transformer transformer, String xmlResource) throws TransformerException {
  91         StringWriter sw = new StringWriter();
  92         transformer.transform(new StreamSource(getClass().getResource(xmlResource).toString()), new StreamResult(sw));
  93         return sw;
  94     }
  95 
  96     /**
  97      * Reads the contents of the given file into a string.
  98      * WARNING: this method adds a final line feed even if the last line of the file doesn't contain one.
  99      *
 100      * @param f
 101      * The file to read
 102      * @return The content of the file as a string, with line terminators as \"n"
 103      * for all platforms
 104      * @throws IOException
 105      * If there was an error reading
 106      */
 107     private String getFileContentAsString(File f) throws IOException {
 108         try (BufferedReader reader = new BufferedReader(new FileReader(f))) {
 109             String line;
 110             StringBuilder sb = new StringBuilder();
 111             while ((line = reader.readLine()) != null) {
 112                 sb.append(line).append("\n");
 113             }
 114             return sb.toString();
 115         }
 116     }
 117 
 118     private class XMLReaderFor6305029 implements XMLReader {
 119         private static final String NAMESPACES = "http://xml.org/sax/features/namespaces";
 120         private static final String NAMESPACE_PREFIXES = "http://xml.org/sax/features/namespace-prefixes";
 121         private boolean namespaces = true;
 122         private boolean namespacePrefixes = false;
 123         private EntityResolver resolver;
 124         private DTDHandler dtdHandler;
 125         private ContentHandler contentHandler;
 126         private ErrorHandler errorHandler;
 127 
 128         public boolean getFeature(final String name) throws SAXNotRecognizedException, SAXNotSupportedException {
 129             if (name.equals(NAMESPACES)) {
 130                 return namespaces;
 131             } else if (name.equals(NAMESPACE_PREFIXES)) {
 132                 return namespacePrefixes;
 133             } else {
 134                 throw new SAXNotRecognizedException();
 135             }
 136         }
 137 
 138         public void setFeature(final String name, final boolean value) throws SAXNotRecognizedException, SAXNotSupportedException {
 139             if (name.equals(NAMESPACES)) {
 140                 namespaces = value;
 141             } else if (name.equals(NAMESPACE_PREFIXES)) {
 142                 namespacePrefixes = value;
 143             } else {
 144                 throw new SAXNotRecognizedException();
 145             }
 146         }
 147 
 148         public Object getProperty(final String name) throws SAXNotRecognizedException, SAXNotSupportedException {
 149             return null;
 150         }
 151 
 152         public void setProperty(final String name, final Object value) throws SAXNotRecognizedException, SAXNotSupportedException {
 153         }
 154 
 155         public void setEntityResolver(final EntityResolver theResolver) {
 156             this.resolver = theResolver;
 157         }
 158 
 159         public EntityResolver getEntityResolver() {
 160             return resolver;
 161         }
 162 
 163         public void setDTDHandler(final DTDHandler theHandler) {
 164             dtdHandler = theHandler;
 165         }
 166 
 167         public DTDHandler getDTDHandler() {
 168             return dtdHandler;
 169         }
 170 
 171         public void setContentHandler(final ContentHandler handler) {
 172             contentHandler = handler;
 173         }
 174 
 175         public ContentHandler getContentHandler() {
 176             return contentHandler;
 177         }
 178 
 179         public void setErrorHandler(final ErrorHandler handler) {
 180             errorHandler = handler;
 181         }
 182 
 183         public ErrorHandler getErrorHandler() {
 184             return errorHandler;
 185         }
 186 
 187         public void parse(final InputSource input) throws IOException, SAXException {
 188             parse();
 189         }
 190 
 191         public void parse(final String systemId) throws IOException, SAXException {
 192             parse();
 193         }
 194 
 195         private void parse() throws SAXException {
 196             contentHandler.startDocument();
 197             contentHandler.startPrefixMapping("prefix", "namespaceUri");
 198 
 199             AttributesImpl atts = new AttributesImpl();
 200             if (namespacePrefixes) {
 201                 atts.addAttribute("", "xmlns:prefix", "xmlns:prefix", "CDATA", "namespaceUri");
 202             }
 203 
 204             contentHandler.startElement("namespaceUri", "localName", namespacePrefixes ? "prefix:localName" : "", atts);
 205             contentHandler.endElement("namespaceUri", "localName", namespacePrefixes ? "prefix:localName" : "");
 206             contentHandler.endPrefixMapping("prefix");
 207             contentHandler.endDocument();
 208         }
 209     }
 210 
 211     /*
 212      * @bug 6272879
 213      * @summary Test for JDK-6272879
 214      */
 215     @Test
 216     public final void testBug6272879() throws IOException, TransformerException {
 217         final String LINE_SEPARATOR = System.getProperty("line.separator");
 218 
 219         final String xsl =
 220                 "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + LINE_SEPARATOR +
 221                 "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">" + LINE_SEPARATOR +
 222                 "<xsl:output method=\"xml\" indent=\"no\" encoding=\"ISO-8859-1\"/>" + LINE_SEPARATOR +
 223                 "<xsl:template match=\"/\">" + LINE_SEPARATOR +
 224                 "<xsl:element name=\"TransformateurXML\">" + LINE_SEPARATOR +
 225                 "  <xsl:for-each select=\"XMLUtils/test\">" + LINE_SEPARATOR +
 226                 "  <xsl:element name=\"test2\">" + LINE_SEPARATOR +
 227                 "    <xsl:element name=\"valeur2\">" + LINE_SEPARATOR +
 228                 "      <xsl:attribute name=\"attribut2\">" + LINE_SEPARATOR +
 229                 "        <xsl:value-of select=\"valeur/@attribut\"/>" + LINE_SEPARATOR +
 230                 "      </xsl:attribute>" + LINE_SEPARATOR +
 231                 "      <xsl:value-of select=\"valeur\"/>" + LINE_SEPARATOR +
 232                 "    </xsl:element>" + LINE_SEPARATOR +
 233                 "  </xsl:element>" + LINE_SEPARATOR +
 234                 "  </xsl:for-each>" + LINE_SEPARATOR +
 235                 "</xsl:element>" + LINE_SEPARATOR +
 236                 "</xsl:template>" + LINE_SEPARATOR +
 237                 "</xsl:stylesheet>";
 238 
 239         final String sourceXml =
 240                 "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + LINE_SEPARATOR +
 241                 // "<!DOCTYPE XMLUtils [" + LINE_SEPARATOR +
 242                 // "<!ELEMENT XMLUtils (test*)>" + LINE_SEPARATOR +
 243                 // "<!ELEMENT test (valeur*)>" + LINE_SEPARATOR +
 244                 // "<!ELEMENT valeur (#PCDATA)>" + LINE_SEPARATOR +
 245                 // "<!ATTLIST valeur attribut CDATA #REQUIRED>]>" +
 246                 // LINE_SEPARATOR +
 247                 "<XMLUtils>" + LINE_SEPARATOR +
 248                 "  <test>" + LINE_SEPARATOR +
 249                 "    <valeur attribut=\"Attribut 1\">Valeur 1</valeur>" + LINE_SEPARATOR +
 250                 "  </test>" + LINE_SEPARATOR +
 251                 "  <test>" + LINE_SEPARATOR +
 252                 "    <valeur attribut=\"Attribut 2\">Valeur 2</valeur>" + LINE_SEPARATOR +
 253                 "  </test>" + LINE_SEPARATOR +
 254                 "</XMLUtils>";
 255 
 256         Document document;
 257         Node node;
 258 
 259         System.out.println("Stylesheet:");
 260         System.out.println("==================================");
 261         System.out.println(xsl);
 262         System.out.println();
 263 
 264         System.out.println("Source file before transformation:");
 265         System.out.println("==================================");
 266         System.out.println(sourceXml);
 267         System.out.println();
 268 
 269         System.out.println("Source file after transformation:");
 270         System.out.println("=================================");
 271         document = transformInputStreamToDocument(createTransformerFromInputstream(new ByteArrayInputStream(xsl.getBytes())),
 272             new ByteArrayInputStream(sourceXml.getBytes()));
 273         OutputFormat format = new OutputFormat();
 274         format.setIndenting(true);
 275         new XMLSerializer(System.out, format).serialize(document);
 276         System.out.println();
 277 
 278         System.out.println("Node content for element valeur2:");
 279         System.out.println("=================================");
 280         NodeList nodes = document.getElementsByTagName("valeur2");
 281         nodes = document.getElementsByTagName("valeur2");
 282         for (int i = 0; i < nodes.getLength(); i++) {
 283             node = nodes.item(i);
 284             System.out.println("  Node value: " + node.getFirstChild().getNodeValue());
 285             System.out.println("  Node attribute: " + node.getAttributes().item(0).getNodeValue());
 286 
 287             AssertJUnit.assertEquals("Node value mismatch", "Valeur " + (i + 1), node.getFirstChild().getNodeValue());
 288             AssertJUnit.assertEquals("Node attribute mismatch", "Attribut " + (i + 1), node.getAttributes().item(0).getNodeValue());
 289         }
 290     }
 291 
 292     /*
 293      * @bug 6305029
 294      * @summary Test for JDK-6305029
 295      */
 296     @Test
 297     public final void testBug6305029() throws TransformerException {
 298         final String XML_DOCUMENT = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<prefix:localName xmlns:prefix=\"namespaceUri\"/>";
 299 
 300         // test SAXSource
 301         SAXSource saxSource = new SAXSource(new XMLReaderFor6305029(), new InputSource());
 302         StringWriter resultWriter = new StringWriter();
 303         createTransformer().transform(saxSource, new StreamResult(resultWriter));
 304         AssertJUnit.assertEquals("Identity transform of SAXSource", XML_DOCUMENT, resultWriter.toString());
 305 
 306         // test StreamSource
 307         StreamSource streamSource = new StreamSource(new StringReader(XML_DOCUMENT));
 308         resultWriter = new StringWriter();
 309         createTransformer().transform(streamSource, new StreamResult(resultWriter));
 310         AssertJUnit.assertEquals("Identity transform of StreamSource", XML_DOCUMENT, resultWriter.toString());
 311     }
 312 
 313     /*
 314      * @bug 6505031
 315      * @summary Test transformer parses keys and their values coming from different xml documents.
 316      */
 317     @Test
 318     public final void testBug6505031() throws TransformerException {
 319         Transformer transformer = createTransformerFromResource("transform.xsl");
 320         transformer.setParameter("config", getClass().getResource("config.xml").toString());
 321         transformer.setParameter("mapsFile", getClass().getResource("maps.xml").toString());
 322         String s = transformResourceToStringWriter(transformer, "template.xml").toString();
 323         Assert.assertTrue(s.contains("map1key1value") && s.contains("map2key1value"));
 324     }
 325 
 326     /*
 327      * @bug 8150704
 328      * @summary Test that XSL transformation with lots of temporary result trees will not run out of DTM IDs.
 329      */
 330     @Test
 331     public final void testBug8150704() throws TransformerException, IOException {
 332         System.out.println("Testing transformation of Bug8150704-1.xml...");
 333         Transformer transformer = createTransformerFromResource("Bug8150704-1.xsl");
 334         StringWriter result = transformResourceToStringWriter(transformer, "Bug8150704-1.xml");
 335         String resultstring = result.toString().replaceAll("\\r\\n", "\n").replaceAll("\\r", "\n");
 336         String reference = getFileContentAsString(new File(getClass().getResource("Bug8150704-1.ref").getPath()));
 337         Assert.assertEquals(resultstring, reference, "Output of transformation of Bug8150704-1.xml does not match reference");
 338         System.out.println("Passed.");
 339 
 340         System.out.println("Testing transformation of Bug8150704-2.xml...");
 341         transformer = createTransformerFromResource("Bug8150704-2.xsl");
 342         result = transformResourceToStringWriter(transformer, "Bug8150704-2.xml");
 343         resultstring = result.toString().replaceAll("\\r\\n", "\n").replaceAll("\\r", "\n");
 344         reference = getFileContentAsString(new File(getClass().getResource("Bug8150704-2.ref").getPath()));
 345         Assert.assertEquals(resultstring, reference, "Output of transformation of Bug8150704-2.xml does not match reference");
 346         System.out.println("Passed.");
 347     }
 348 }