1 /*
   2  * Copyright (c) 2014, 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 package test.auctionportal;
  24 
  25 import static com.sun.org.apache.xerces.internal.impl.Constants.SP_ENTITY_EXPANSION_LIMIT;
  26 import static com.sun.org.apache.xerces.internal.impl.Constants.SP_MAX_OCCUR_LIMIT;
  27 import static com.sun.org.apache.xerces.internal.jaxp.JAXPConstants.JAXP_SCHEMA_LANGUAGE;
  28 import static com.sun.org.apache.xerces.internal.jaxp.JAXPConstants.JAXP_SCHEMA_SOURCE;
  29 import static org.testng.Assert.assertTrue;
  30 import java.io.File;
  31 import java.io.FileInputStream;
  32 import java.io.FileOutputStream;
  33 import java.io.FilePermission;
  34 import java.io.IOException;
  35 import java.io.InputStream;
  36 import java.io.UnsupportedEncodingException;
  37 import static javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING;
  38 import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI;
  39 import javax.xml.parsers.DocumentBuilder;
  40 import javax.xml.parsers.DocumentBuilderFactory;
  41 import javax.xml.parsers.ParserConfigurationException;
  42 import javax.xml.parsers.SAXParser;
  43 import javax.xml.parsers.SAXParserFactory;
  44 import javax.xml.transform.TransformerException;
  45 import javax.xml.transform.TransformerFactory;
  46 import javax.xml.transform.dom.DOMSource;
  47 import javax.xml.transform.stream.StreamResult;
  48 import jaxp.library.JAXPFileBaseTest;
  49 import static jaxp.library.JAXPTestUtilities.compareDocumentWithGold;
  50 import static org.testng.Assert.assertFalse;
  51 import org.testng.annotations.AfterGroups;
  52 import org.testng.annotations.BeforeGroups;
  53 import org.testng.annotations.Test;
  54 import org.w3c.dom.Document;
  55 import org.xml.sax.SAXException;
  56 import org.xml.sax.SAXParseException;
  57 import static test.auctionportal.HiBidConstants.CLASS_DIR;
  58 import static test.auctionportal.HiBidConstants.GOLDEN_DIR;
  59 import static test.auctionportal.HiBidConstants.XML_DIR;
  60 
  61 /**
  62  * This is a test class for the Auction portal HiBid.com.
  63  */
  64 public class AuctionItemRepository extends JAXPFileBaseTest {
  65     /**
  66      * XML file for parsing.
  67      */
  68     private final static String ENTITY_XML = XML_DIR + "entity.xml";
  69 
  70     /**
  71      * Feature name.
  72      */
  73     private final static String FEATURE_NAME = "http://xml.org/sax/features/namespace-prefixes";
  74 
  75     /**
  76      * Setting the EntityExpansion Limit to 128000 and checks if the XML
  77      * document that has more than two levels of entity expansion is parsed or
  78      * not. Previous system property was changed to jdk.xml.entityExpansionLimit
  79      * see http://docs.oracle.com/javase/tutorial/jaxp/limits/limits.html.
  80      * 
  81      * @throws ParserConfigurationException if a DocumentBuilder cannot be 
  82      *         created which satisfies the configuration requested.
  83      * @throws SAXException If any parse errors occur.
  84      * @throws IOException if the file exists but is a directory rather than
  85      *         a regular file, does not exist but cannot be created, or cannot 
  86      *         be opened for any other reason.
  87      */
  88     @Test
  89     public void testEntityExpansionSAXPos() throws ParserConfigurationException,
  90             SAXException, IOException { 
  91         SAXParserFactory factory = SAXParserFactory.newInstance();
  92         // Secure processing will limit XML processing to conform to
  93         // implementation limits.
  94         factory.setFeature(FEATURE_SECURE_PROCESSING, true);
  95         // Set entityExpansionLimit as 2 should expect fatalError
  96         setSystemProperty(SP_ENTITY_EXPANSION_LIMIT, String.valueOf(128000));
  97         SAXParser parser = factory.newSAXParser();
  98 
  99         MyErrorHandler fatalHandler = new MyErrorHandler();
 100         setPermissions(new FilePermission(ENTITY_XML, "read"));
 101         parser.parse(new File(ENTITY_XML), fatalHandler);
 102         assertFalse(fatalHandler.isAnyError());
 103     }
 104     /**
 105      * Setting the EntityExpansion Limit to 2 and checks if the XML
 106      * document that has more than two levels of entity expansion is parsed or
 107      * not. Previous system property was changed to jdk.xml.entityExpansionLimit
 108      * see http://docs.oracle.com/javase/tutorial/jaxp/limits/limits.html.
 109      * 
 110      * @throws ParserConfigurationException if a DocumentBuilder cannot be 
 111      *         created which satisfies the configuration requested.
 112      * @throws SAXException If any parse errors occur.
 113      * @throws IOException if the file exists but is a directory rather than
 114      *         a regular file, does not exist but cannot be created, or cannot 
 115      *         be opened for any other reason.
 116      */
 117     @Test(expectedExceptions = SAXParseException.class)
 118     public void testEntityExpansionSAXNeg() throws ParserConfigurationException, 
 119             SAXException, IOException {
 120         SAXParserFactory factory = SAXParserFactory.newInstance();
 121         // Secure processing will limit XML processing to conform to
 122         // implementation limits.
 123         factory.setFeature(FEATURE_SECURE_PROCESSING, true);
 124         // Set entityExpansionLimit as 2 should expect SAXParseException.
 125         setSystemProperty(SP_ENTITY_EXPANSION_LIMIT, String.valueOf(2)); 
 126 
 127         SAXParser parser = factory.newSAXParser();
 128         MyErrorHandler fatalHandler = new MyErrorHandler();
 129         setPermissions(new FilePermission(ENTITY_XML, "read"));
 130         parser.parse(new File(ENTITY_XML), fatalHandler);
 131     }
 132 
 133     /**
 134      * Testing set MaxOccursLimit to 10000 in the secure processing enabled for
 135      * SAXParserFactory.
 136      * 
 137      * @throws ParserConfigurationException if a DocumentBuilder cannot be 
 138      *         created which satisfies the configuration requested.
 139      * @throws SAXException If any parse errors occur.
 140      * @throws IOException if the file exists but is a directory rather than
 141      *         a regular file, does not exist but cannot be created, or cannot 
 142      *         be opened for any other reason.
 143      */
 144     @Test
 145     public void testMaxOccurLimitPos() throws ParserConfigurationException, 
 146             SAXException, IOException {
 147         String schema_file = XML_DIR + "toys.xsd";
 148         String xml_file = XML_DIR + "toys.xml";
 149         SAXParserFactory factory = SAXParserFactory.newInstance();
 150         factory.setValidating(true);
 151         factory.setFeature(FEATURE_SECURE_PROCESSING, true);
 152         setSystemProperty(SP_MAX_OCCUR_LIMIT, String.valueOf(10000));
 153         SAXParser parser = factory.newSAXParser();
 154         parser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA_NS_URI);
 155         setPermissions(new FilePermission(XML_DIR + "-", "read"));
 156         parser.setProperty(JAXP_SCHEMA_SOURCE, new File(schema_file));
 157         try (InputStream is = new FileInputStream(xml_file)) {
 158             MyErrorHandler eh = new MyErrorHandler();
 159             parser.parse(is, eh);
 160             assertFalse(eh.isAnyError());
 161         }
 162     }
 163 
 164     /**
 165      * Use a DocumentBuilder to create a DOM object and see if Secure Processing
 166      * feature affects the entity expansion.
 167      * 
 168      * @throws ParserConfigurationException if a DocumentBuilder cannot be 
 169      *         created which satisfies the configuration requested.
 170      * @throws SAXException If any parse errors occur.
 171      * @throws IOException if the file exists but is a directory rather than
 172      *         a regular file, does not exist but cannot be created, or cannot 
 173      *         be opened for any other reason.
 174      */
 175     @Test
 176     public void testEntityExpansionDOMPos() throws ParserConfigurationException,
 177             SAXException, IOException  {
 178         DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
 179         dfactory.setFeature(FEATURE_SECURE_PROCESSING, true);
 180         setSystemProperty(SP_ENTITY_EXPANSION_LIMIT, String.valueOf(10000));
 181         DocumentBuilder dBuilder = dfactory.newDocumentBuilder();
 182         MyErrorHandler eh = new MyErrorHandler();
 183         dBuilder.setErrorHandler(eh);
 184         setPermissions(new FilePermission(ENTITY_XML, "read"));
 185         dBuilder.parse(ENTITY_XML);
 186         assertFalse(eh.isAnyError());
 187     }
 188 
 189     /**
 190      * Use a DocumentBuilder to create a DOM object and see how does the Secure
 191      * Processing feature and entityExpansionLimit value affects output.
 192      * Negative test that when entityExpansionLimit is too small.
 193      * 
 194      * @throws ParserConfigurationException if a DocumentBuilder cannot be 
 195      *         created which satisfies the configuration requested.
 196      * @throws SAXException If any parse errors occur.
 197      * @throws IOException if the file exists but is a directory rather than
 198      *         a regular file, does not exist but cannot be created, or cannot 
 199      *         be opened for any other reason.
 200      */
 201     @Test(expectedExceptions = SAXParseException.class)
 202     public void testEntityExpansionDOMNeg() throws ParserConfigurationException,
 203             SAXException, IOException {
 204         DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
 205         dfactory.setFeature(FEATURE_SECURE_PROCESSING, true);
 206         setSystemProperty(SP_ENTITY_EXPANSION_LIMIT, String.valueOf(2));
 207         DocumentBuilder dBuilder = dfactory.newDocumentBuilder();
 208         MyErrorHandler eh = new MyErrorHandler();
 209         dBuilder.setErrorHandler(eh);
 210         setPermissions(new FilePermission(ENTITY_XML, "read"));
 211         dBuilder.parse(ENTITY_XML);
 212     }
 213 
 214     
 215     /**
 216      * Save system property for restoring.
 217      */
 218     @BeforeGroups (groups = {"readWriteLocalFiles"})
 219     public void setFilePermissions() {
 220         setPermissions(new FilePermission(XML_DIR + "/-", "read"),
 221                 new FilePermission(GOLDEN_DIR + "/-", "read"),
 222                 new FilePermission(CLASS_DIR + "/-", "read, write"));
 223     }
 224     
 225     /**
 226      * Restore the system property.
 227      */
 228     @AfterGroups (groups = {"readWriteLocalFiles"})
 229     public void restoreFilePermissions() {
 230         setPermissions();
 231     }
 232     /**
 233      * Test xi:include with a SAXParserFactory.
 234      * 
 235      * @throws UnsupportedEncodingException if given encoding is an invalid
 236      *         encoding name.
 237      * @throws ParserConfigurationException if a DocumentBuilder cannot be 
 238      *         created which satisfies the configuration requested.
 239      * @throws SAXException If any parse errors occur.
 240      * @throws IOException if the file exists but is a directory rather than
 241      *         a regular file, does not exist but cannot be created, or cannot 
 242      *         be opened for any other reason.
 243      */
 244     @Test(groups = {"readWriteLocalFiles"})
 245     public void testXIncludeSAXPos() throws UnsupportedEncodingException, 
 246             ParserConfigurationException, SAXException, IOException {
 247         String resultFile = CLASS_DIR + "doc_xinclude.out";
 248         String goldFile = GOLDEN_DIR + "doc_xincludeGold.xml";
 249         String xmlFile = XML_DIR + "doc_xinclude.xml";
 250         
 251         try(FileOutputStream fos = new FileOutputStream(resultFile)) {
 252             XInclHandler xh = new XInclHandler(fos, null);
 253             SAXParserFactory spf = SAXParserFactory.newInstance();
 254             spf.setNamespaceAware(true);
 255             spf.setXIncludeAware(true);
 256             spf.setFeature(FEATURE_NAME, true);
 257             spf.newSAXParser().parse(new File(xmlFile), xh);
 258         }
 259         assertTrue(compareDocumentWithGold(goldFile, resultFile));
 260     }
 261 
 262     /**
 263      * Test the simple case of including a document using xi:include using a
 264      * DocumentBuilder.
 265      * 
 266      * @throws ParserConfigurationException if a DocumentBuilder cannot be 
 267      *         created which satisfies the configuration requested.
 268      * @throws SAXException If any parse errors occur.
 269      * @throws IOException if the file exists but is a directory rather than
 270      *         a regular file, does not exist but cannot be created, or cannot 
 271      *         be opened for any other reason.
 272      * @throws TransformerException If an unrecoverable error occurs
 273      *         during the course of the transformation.
 274      */
 275     @Test(groups = {"readWriteLocalFiles"})
 276     public void testXIncludeDOMPos() throws ParserConfigurationException, 
 277             SAXException, IOException, TransformerException {
 278         String resultFile = CLASS_DIR + "doc_xincludeDOM.out";
 279         String goldFile = GOLDEN_DIR + "doc_xincludeGold.xml";
 280         String xmlFile = XML_DIR + "doc_xinclude.xml";
 281         try (FileOutputStream fos = new FileOutputStream(resultFile)) {
 282             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 283             dbf.setXIncludeAware(true);
 284             dbf.setNamespaceAware(true);
 285             Document doc = dbf.newDocumentBuilder().parse(new File(xmlFile));
 286             doc.setXmlStandalone(true);
 287             TransformerFactory.newInstance().newTransformer().
 288                     transform(new DOMSource(doc), new StreamResult(fos));
 289         }
 290         assertTrue(compareDocumentWithGold(goldFile, resultFile));
 291     }
 292 
 293     /**
 294      * Test the simple case of including a document using xi:include within a
 295      * xi:fallback using a DocumentBuilder.
 296      * 
 297      * @throws ParserConfigurationException if a DocumentBuilder cannot be 
 298      *         created which satisfies the configuration requested.
 299      * @throws SAXException If any parse errors occur.
 300      * @throws IOException if the file exists but is a directory rather than
 301      *         a regular file, does not exist but cannot be created, or cannot 
 302      *         be opened for any other reason.
 303      * @throws TransformerException If an unrecoverable error occurs
 304      *         during the course of the transformation.
 305      */
 306     @Test(groups = {"readWriteLocalFiles"})
 307     public void testXIncludeFallbackDOMPos() throws ParserConfigurationException, 
 308             SAXException, IOException, TransformerException {
 309         String resultFile = CLASS_DIR + "doc_fallbackDOM.out";
 310         String goldFile = GOLDEN_DIR + "doc_fallbackGold.xml";
 311         String xmlFile = XML_DIR + "doc_fallback.xml";
 312         try (FileOutputStream fos = new FileOutputStream(resultFile)) {
 313             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 314             dbf.setXIncludeAware(true);
 315             dbf.setNamespaceAware(true);
 316 
 317             Document doc = dbf.newDocumentBuilder().parse(new File(xmlFile));
 318             doc.setXmlStandalone(true);
 319             TransformerFactory.newInstance().newTransformer()
 320                     .transform(new DOMSource(doc), new StreamResult(fos));
 321         }
 322         assertTrue(compareDocumentWithGold(goldFile, resultFile));
 323     }
 324 
 325     /**
 326      * Test for xi:fallback where the fall back text is parsed as text. This
 327      * test uses a nested xi:include for the fallback test.
 328      * 
 329      * @throws ParserConfigurationException if a DocumentBuilder cannot be 
 330      *         created which satisfies the configuration requested.
 331      * @throws SAXException If any parse errors occur.
 332      * @throws IOException if the file exists but is a directory rather than
 333      *         a regular file, does not exist but cannot be created, or cannot 
 334      *         be opened for any other reason.
 335      * @throws TransformerException If an unrecoverable error occurs
 336      *         during the course of the transformation.
 337      */
 338     @Test(groups = {"readWriteLocalFiles"})
 339     public void testXIncludeFallbackTextPos() throws ParserConfigurationException, 
 340             SAXException, IOException, TransformerException {
 341         String resultFile = CLASS_DIR + "doc_fallback_text.out";
 342         String goldFile = GOLDEN_DIR + "doc_fallback_textGold.xml";
 343         String xmlFile = XML_DIR + "doc_fallback_text.xml";
 344         try (FileOutputStream fos = new FileOutputStream(resultFile)) {
 345             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 346             dbf.setXIncludeAware(true);
 347             dbf.setNamespaceAware(true);
 348 
 349             Document doc = dbf.newDocumentBuilder().parse(new File(xmlFile));
 350             doc.setXmlStandalone(true);
 351             TransformerFactory.newInstance().newTransformer()
 352                     .transform(new DOMSource(doc), new StreamResult(fos));
 353         }
 354         assertTrue(compareDocumentWithGold(goldFile, resultFile));
 355     }
 356 
 357     /**
 358      * Test the XPointer element() framework with XInclude.
 359      * 
 360      * @throws ParserConfigurationException if a DocumentBuilder cannot be 
 361      *         created which satisfies the configuration requested.
 362      * @throws SAXException If any parse errors occur.
 363      * @throws IOException if the file exists but is a directory rather than
 364      *         a regular file, does not exist but cannot be created, or cannot 
 365      *         be opened for any other reason.
 366      * @throws TransformerException If an unrecoverable error occurs
 367      *         during the course of the transformation.
 368      */
 369     @Test(groups = {"readWriteLocalFiles"})
 370     public void testXpointerElementPos() throws ParserConfigurationException, 
 371             TransformerException, SAXException, IOException {
 372         String resultFile = CLASS_DIR + "doc_xpointer_element.out";
 373         String goldFile = GOLDEN_DIR + "doc_xpointerGold.xml";
 374         String xmlFile = XML_DIR + "doc_xpointer_element.xml";
 375         try (FileOutputStream fos = new FileOutputStream(resultFile)) {
 376             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 377             dbf.setXIncludeAware(true);
 378             dbf.setNamespaceAware(true);
 379 
 380             DocumentBuilder db = dbf.newDocumentBuilder();
 381 
 382             TransformerFactory.newInstance().newTransformer()
 383                     .transform(new DOMSource(db.parse(new File(xmlFile))),
 384                             new StreamResult(fos));
 385         }
 386         assertTrue(compareDocumentWithGold(goldFile, resultFile));
 387     }
 388 
 389     /**
 390      * Test the XPointer framework with a SAX object.
 391      * 
 392      * @throws ParserConfigurationException if a DocumentBuilder cannot be 
 393      *         created which satisfies the configuration requested.
 394      * @throws SAXException If any parse errors occur.
 395      * @throws IOException if the file exists but is a directory rather than
 396      *         a regular file, does not exist but cannot be created, or cannot 
 397      *         be opened for any other reason.
 398      * @throws TransformerException If an unrecoverable error occurs
 399      *         during the course of the transformation.
 400      */
 401     @Test(groups = {"readWriteLocalFiles"})
 402     public void testXPointerPos() throws ParserConfigurationException, 
 403             TransformerException, SAXException, IOException {
 404         String resultFile = CLASS_DIR + "doc_xpointer.out";
 405         String goldFile = GOLDEN_DIR + "doc_xpointerGold.xml";
 406         String xmlFile = XML_DIR + "doc_xpointer.xml";
 407   
 408         try (FileOutputStream fos = new FileOutputStream(resultFile)) {
 409             SAXParserFactory spf = SAXParserFactory.newInstance();
 410             spf.setNamespaceAware(true);
 411             spf.setXIncludeAware(true);
 412             spf.setFeature(FEATURE_NAME, true);
 413             // parse the file
 414             spf.newSAXParser().parse(new File(xmlFile), new XInclHandler(fos, null));
 415         }
 416         assertTrue(compareDocumentWithGold(goldFile, resultFile));
 417     }
 418 
 419     /**
 420      * Test if xi:include may reference the doc containing the include if the
 421      * parse type is text.
 422      * 
 423      * @throws ParserConfigurationException if a DocumentBuilder cannot be 
 424      *         created which satisfies the configuration requested.
 425      * @throws SAXException If any parse errors occur.
 426      * @throws IOException if the file exists but is a directory rather than
 427      *         a regular file, does not exist but cannot be created, or cannot 
 428      *         be opened for any other reason.
 429      * @throws TransformerException If an unrecoverable error occurs
 430      *         during the course of the transformation.
 431      */
 432     @Test(groups = {"readWriteLocalFiles"})
 433     public void testXIncludeLoopPos() throws ParserConfigurationException, 
 434             TransformerException, SAXException, IOException {
 435         String resultFile = CLASS_DIR + "doc_xinc_loops.out";
 436         String goldFile = GOLDEN_DIR + "doc_xinc_loopGold.xml";
 437         String xmlFile = XML_DIR + "doc_xinc_loops.xml";
 438 
 439         try (FileOutputStream fos = new FileOutputStream(resultFile)) {
 440             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 441             dbf.setXIncludeAware(true);
 442             dbf.setNamespaceAware(true);
 443             DocumentBuilder db = dbf.newDocumentBuilder();
 444             Document doc = db.parse(new File(xmlFile));
 445             doc.normalizeDocument();
 446             doc.setXmlStandalone(true);
 447 
 448             TransformerFactory.newInstance().newTransformer()
 449                     .transform(new DOMSource(doc), new StreamResult(fos));
 450         }
 451         assertTrue(compareDocumentWithGold(goldFile, resultFile));
 452     }
 453 
 454     /**
 455      * Test if two non nested xi:include elements can include the same document
 456      * with an xi:include statement.
 457      * 
 458      * @throws ParserConfigurationException if a DocumentBuilder cannot be 
 459      *         created which satisfies the configuration requested.
 460      * @throws SAXException If any parse errors occur.
 461      * @throws IOException if the file exists but is a directory rather than
 462      *         a regular file, does not exist but cannot be created, or cannot 
 463      *         be opened for any other reason.
 464      * @throws TransformerException If an unrecoverable error occurs
 465      *         during the course of the transformation.
 466      */
 467     @Test(groups = {"readWriteLocalFiles"})
 468     public void testXIncludeNestedPos() throws ParserConfigurationException, 
 469             TransformerException, SAXException, IOException {
 470         String resultFile = CLASS_DIR + "schedule.out";
 471         String goldFile = GOLDEN_DIR + "scheduleGold.xml";
 472         String xmlFile = XML_DIR + "schedule.xml";
 473         
 474         try (FileOutputStream fos = new FileOutputStream(resultFile)) {
 475             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 476             dbf.setXIncludeAware(true);
 477             dbf.setNamespaceAware(true);
 478 
 479             Document doc = dbf.newDocumentBuilder().parse(new File(xmlFile));
 480             doc.setXmlStandalone(true);
 481             TransformerFactory.newInstance().newTransformer()
 482                     .transform(new DOMSource(doc), new StreamResult(fos));
 483         }
 484         assertTrue(compareDocumentWithGold(goldFile, resultFile));
 485     }
 486 }