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