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 
  24 package stream.XMLStreamReaderTest;
  25 
  26 import java.io.File;
  27 import java.io.FileInputStream;
  28 import java.io.StringReader;
  29 import java.util.List;
  30 
  31 import javax.xml.stream.XMLEventReader;
  32 import javax.xml.stream.XMLInputFactory;
  33 import javax.xml.stream.XMLStreamConstants;
  34 import javax.xml.stream.events.Characters;
  35 import javax.xml.stream.events.DTD;
  36 import javax.xml.stream.events.EntityDeclaration;
  37 import javax.xml.stream.events.EntityReference;
  38 import javax.xml.stream.events.XMLEvent;
  39 
  40 import org.testng.Assert;
  41 import org.testng.annotations.Test;
  42 
  43 /*
  44  * @summary Test SUPPORT_DTD and IS_REPLACING_ENTITY_REFERENCES.
  45  */
  46 
  47 /**
  48 *
  49 * SUPPORT_DTD behavior:
  50 * Regardless of supportDTD, always report a DTD event () and throw an
  51 * exception if an entity reference is found when supportDTD is false
  52 *
  53 * The behavior is related to property IS_REPLACING_ENTITY_REFERENCES.
  54 *
  55 * SUPPORT_DTD      Replace Entity   DTD                    ENTITY_REFERENCE
  56 * true (default)   true (default)   yes, has entities      no, return Characters
  57 * true (default)   false            yes, has entities      yes, can print entity name
  58 * false            true (default)   yes, but no entity     Exception: Undeclared general entity
  59 * false            false            yes, but no entity     yes, can print entity name
  60 *
  61 * Two patches related:
  62 * sjsxp issue 9: XMLDocumentScannerImpl.java rev 1.6
  63 * If the supportDTD property is set to FALSE, external and internal subsets
  64 * are now ignored, rather than an error being reported. In particular, with
  65 * this property set to FALSE, no error is reported if an external subset cannot
  66 * be found. Note that the internal subset is still parsed (and errors could be
  67 * reported here) but no events are returned by the parser. This fixes SJSXP
  68 * issue 9 from Java.net.
  69 * Note: SAX and DOM report fatal errors:
  70 *       If either SAX or DOM is used, turning on http://apache.org/xml/features/disallow-doctype-decl [1] effectively disables DTD,
  71 *       according to the spec: A fatal error is thrown if the incoming document contains a DOCTYPE declaration.
  72 *       The current jaxp implementation actually throws a nullpointexception. A better error message could be used.
  73 *
  74 */
  75 public class SupportDTDTest {
  76     final boolean DEBUG = false;
  77     final String _file = "ExternalDTD.xml";
  78     final String XML = "<?xml version='1.0' ?>" + "<!DOCTYPE root [\n" + "<!ENTITY intEnt 'internal entity'>\n" + "<!ENTITY extParsedEnt SYSTEM 'url:dummy'>\n"
  79             + "<!NOTATION notation PUBLIC 'notation-public-id'>\n" + "<!NOTATION notation2 SYSTEM 'url:dummy'>\n"
  80             + "<!ENTITY extUnparsedEnt SYSTEM 'url:dummy2' NDATA notation>\n" + "]>" + "<root>&intEnt;</root>";
  81 
  82     final String XML1 = "<?xml version='1.0' encoding ='utf-8'?>" + "<!DOCTYPE document SYSTEM \"" + this.getClass().getResource("ExternalDTD.dtd").getFile()
  83             + "\">" + "<document>" + "<name>&mkm;</name>" + "</document>";
  84 
  85    // final String XML1 = "<?xml version='1.0' encoding ='utf-8'?>" + "<!DOCTYPE document SYSTEM \"/home/oracle/repo/xmlwork/dev/jdk/test/javax/xml/jaxp/unittest/javax/xml/stream/XMLStreamReaderTest/ExternalDTD.dtd\">" + "<document>"
  86    //         + "<name>&mkm;</name>" + "</document>";
  87 
  88     final int ENTITY_INTERNAL_ONLY = 1;
  89     final int ENTITY_EXTERNAL_ONLY = 2;
  90     final int ENTITY_BOTH = 3;
  91 
  92     boolean _DTDReturned = false;
  93     boolean _EntityEventReturned = false;
  94     boolean _hasEntityDelaration = false;
  95     boolean _exceptionThrown = false;
  96 
  97     /** Creates a new instance of StreamReader */
  98     public SupportDTDTest(String name) {
  99     }
 100 
 101     void reset() {
 102         _DTDReturned = false;
 103         _EntityEventReturned = false;
 104         _hasEntityDelaration = false;
 105         _exceptionThrown = false;
 106     }
 107 
 108     // tests 1-4 test internal entities only
 109     @Test
 110     public void test1() {
 111         supportDTD(true, true, ENTITY_INTERNAL_ONLY);
 112         Assert.assertEquals(true, _DTDReturned);
 113         Assert.assertEquals(true, _hasEntityDelaration);
 114         Assert.assertEquals(false, _EntityEventReturned);
 115     }
 116 
 117     @Test
 118     public void test2() {
 119         supportDTD(true, false, ENTITY_INTERNAL_ONLY);
 120         Assert.assertEquals(true, _DTDReturned);
 121         Assert.assertEquals(true, _hasEntityDelaration);
 122         Assert.assertEquals(true, _EntityEventReturned);
 123     }
 124 
 125     @Test
 126     public void test3() {
 127         supportDTD(false, true, ENTITY_INTERNAL_ONLY);
 128         Assert.assertEquals(true, _DTDReturned);
 129         Assert.assertEquals(false, _hasEntityDelaration);
 130         Assert.assertEquals(true, _exceptionThrown);
 131     }
 132 
 133     @Test
 134     public void test4() {
 135         supportDTD(false, false, ENTITY_INTERNAL_ONLY);
 136         Assert.assertEquals(true, _DTDReturned);
 137         Assert.assertEquals(false, _hasEntityDelaration);
 138         Assert.assertEquals(true, _EntityEventReturned);
 139     }
 140 
 141     // tests 5-8 test external entities only
 142     @Test
 143     public void test5() {
 144         supportDTD(true, true, ENTITY_EXTERNAL_ONLY);
 145         Assert.assertEquals(true, _DTDReturned);
 146         Assert.assertEquals(true, _hasEntityDelaration);
 147         Assert.assertEquals(false, _EntityEventReturned);
 148     }
 149 
 150     @Test
 151     public void test6() {
 152         supportDTD(true, false, ENTITY_EXTERNAL_ONLY);
 153         Assert.assertEquals(true, _DTDReturned);
 154         Assert.assertEquals(true, _hasEntityDelaration);
 155         Assert.assertEquals(true, _EntityEventReturned);
 156     }
 157 
 158     @Test
 159     public void test7() {
 160         supportDTD(false, true, ENTITY_EXTERNAL_ONLY);
 161         Assert.assertEquals(true, _DTDReturned);
 162         Assert.assertEquals(false, _hasEntityDelaration);
 163         Assert.assertEquals(true, _exceptionThrown);
 164     }
 165 
 166     @Test
 167     public void test8() {
 168         supportDTD(false, false, ENTITY_EXTERNAL_ONLY);
 169         Assert.assertEquals(true, _DTDReturned);
 170         Assert.assertEquals(false, _hasEntityDelaration);
 171         Assert.assertEquals(true, _EntityEventReturned);
 172     }
 173 
 174     // tests 9-12 test both internal and external entities
 175     @Test
 176     public void test9() {
 177         supportDTD(true, true, ENTITY_BOTH);
 178         Assert.assertEquals(true, _DTDReturned);
 179         Assert.assertEquals(true, _hasEntityDelaration);
 180         Assert.assertEquals(false, _EntityEventReturned);
 181     }
 182 
 183     @Test
 184     public void test10() {
 185         supportDTD(true, false, ENTITY_BOTH);
 186         Assert.assertEquals(true, _DTDReturned);
 187         Assert.assertEquals(true, _hasEntityDelaration);
 188         Assert.assertEquals(true, _EntityEventReturned);
 189     }
 190 
 191     @Test
 192     public void test11() {
 193         supportDTD(false, true, ENTITY_BOTH);
 194         Assert.assertEquals(true, _DTDReturned);
 195         Assert.assertEquals(false, _hasEntityDelaration);
 196         Assert.assertEquals(true, _exceptionThrown);
 197     }
 198 
 199     @Test
 200     public void test12() {
 201         supportDTD(false, false, ENTITY_BOTH);
 202         Assert.assertEquals(true, _DTDReturned);
 203         Assert.assertEquals(false, _hasEntityDelaration);
 204         Assert.assertEquals(true, _EntityEventReturned);
 205     }
 206 
 207     public void supportDTD(boolean supportDTD, boolean replaceEntity, int inputType) {
 208         reset();
 209         print("\n");
 210         print((supportDTD ? "SupportDTD=true" : "SupportDTD=false") + ", " + (replaceEntity ? "replaceEntity=true" : "replaceEntity=false"));
 211         try {
 212             XMLInputFactory xif = getFactory(supportDTD, replaceEntity);
 213             XMLEventReader r = getEventReader(xif, inputType);
 214             int eventType = 0;
 215             int count = 0;
 216             while (r.hasNext()) {
 217                 XMLEvent event = r.nextEvent();
 218                 eventType = event.getEventType();
 219                 print("Event " + ++count + ": " + eventType);
 220                 switch (eventType) {
 221                     case XMLStreamConstants.DTD:
 222                         DisplayEntities((DTD) event);
 223                         _DTDReturned = true;
 224                         break;
 225                     case XMLStreamConstants.ENTITY_REFERENCE:
 226                         print("Entity Name: " + ((EntityReference) event).getName());
 227                         _EntityEventReturned = true;
 228                         break;
 229                     case XMLStreamConstants.CHARACTERS:
 230                         print("Text: " + ((Characters) event).getData());
 231                 }
 232             }
 233 
 234         } catch (Exception e) {
 235             _exceptionThrown = true;
 236             if (DEBUG)
 237                 e.printStackTrace();
 238         }
 239     }
 240 
 241     XMLInputFactory getFactory(boolean supportDTD, boolean replaceEntity) {
 242         XMLInputFactory xif = XMLInputFactory.newInstance();
 243         xif.setProperty(XMLInputFactory.SUPPORT_DTD, (supportDTD) ? Boolean.TRUE : Boolean.FALSE);
 244         xif.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, (replaceEntity) ? Boolean.TRUE : Boolean.FALSE);
 245         // xif.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.TRUE);
 246         return xif;
 247     }
 248 
 249     private XMLEventReader getEventReader(XMLInputFactory inputFactory, int input) throws Exception {
 250         XMLEventReader er = null;
 251         if (input == ENTITY_INTERNAL_ONLY) {
 252             er = inputFactory.createXMLEventReader(new StringReader(XML));
 253         } else if (input == ENTITY_EXTERNAL_ONLY) {
 254             er = inputFactory.createXMLEventReader(new StringReader(XML1));
 255         } else {
 256             File file = new File(this.getClass().getResource(_file).getFile());
 257             FileInputStream inputStream = new FileInputStream(file);
 258             // XMLStreamReader r = xif.createXMLStreamReader(inputStream);
 259             er = inputFactory.createXMLEventReader(inputStream);
 260         }
 261         return er;
 262     }
 263 
 264     void DisplayEntities(DTD event) {
 265         List entities = event.getEntities();
 266         if (entities == null) {
 267             _hasEntityDelaration = false;
 268             print("No entity found.");
 269         } else {
 270             _hasEntityDelaration = true;
 271             for (int i = 0; i < entities.size(); i++) {
 272                 EntityDeclaration entity = (EntityDeclaration) entities.get(i);
 273                 print(entity.getName());
 274             }
 275         }
 276 
 277     }
 278 
 279     void print(String s) {
 280         if (DEBUG)
 281             System.out.println(s);
 282     }
 283 
 284 }