1/* 2 * Copyright (c) 2015, 2017, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25package javax.xml.catalog; 26 27import java.io.StringReader; 28import javax.xml.catalog.BaseEntry.CatalogEntryType; 29import javax.xml.parsers.SAXParser; 30import javax.xml.transform.Source; 31import javax.xml.transform.TransformerException; 32import javax.xml.transform.URIResolver; 33import javax.xml.transform.sax.SAXSource; 34import org.xml.sax.Attributes; 35import org.xml.sax.EntityResolver; 36import org.xml.sax.InputSource; 37import org.xml.sax.SAXException; 38import org.xml.sax.helpers.DefaultHandler; 39 40/** 41 * CatalogReader handles SAX events while parsing through a catalog file to 42 * create a catalog object. 43 * 44 * @since 9 45 */ 46class CatalogReader extends DefaultHandler implements EntityResolver, URIResolver { 47 /** URI of the W3C XML Schema for OASIS XML Catalog files. */ 48 public static final String xmlCatalogXSD = "http://www.oasis-open.org/committees/entity/release/1.0/catalog.xsd"; 49 50 /** Public identifier for OASIS XML Catalog files. */ 51 public static final String xmlCatalogPubId = "-//OASIS//DTD XML Catalogs V1.0//EN"; 52 53 /** 54 * The namespace name defined by the OASIS Standard 55 */ 56 public static final String NAMESPACE_OASIS = "urn:oasis:names:tc:entity:xmlns:xml:catalog"; 57 58 //Indicate whether the root element has been found 59 boolean seenRoot; 60 61 //Indicate that the parser is in a group entry 62 boolean inGroup; 63 64 //The Catalog instance 65 CatalogImpl catalog; 66 67 //The parser for reading the catalog 68 SAXParser parser; 69 70 //The current catalog entry 71 CatalogEntry catalogEntry; 72 73 //The current group 74 GroupEntry group; 75 76 //The current entry 77 BaseEntry entry; 78 79 //remove this variable once 8136778 is committed 80 boolean ignoreTheCatalog = false; 81 82 /** 83 * Constructs an instance with a Catalog object and parser. 84 * 85 * @param catalog The Catalog object that represents a catalog 86 */ 87 @SuppressWarnings("unchecked") 88 public CatalogReader(Catalog catalog, SAXParser parser) { 89 this.catalog = (CatalogImpl) catalog; 90 this.parser = parser; 91 } 92 93 @Override 94 public void startElement(String namespaceURI, 95 String localName, 96 String qName, 97 Attributes atts) 98 throws SAXException { 99 100 //ignore the catalog if it's not compliant. See section 8, item 3 of the spec. 101 if (ignoreTheCatalog) return; 102 if (!NAMESPACE_OASIS.equals(namespaceURI)) { 103//wait till 8136778 is committed 104// parser.stop(); 105 ignoreTheCatalog = true; 106 return; 107 } 108 109 110 CatalogEntryType type = CatalogEntryType.getType(localName); 111 if (type == null) { 112 CatalogMessages.reportError(CatalogMessages.ERR_INVALID_ENTRY_TYPE, 113 new Object[]{localName}); 114 } 115 if (type != CatalogEntryType.CATALOGENTRY) { 116 if (!seenRoot) { 117 CatalogMessages.reportError(CatalogMessages.ERR_INVALID_CATALOG); 118 } 119 } 120 121 String base = atts.getValue("xml:base"); 122 if (base == null) { 123 if (inGroup) { 124 base = group.getBaseURI().toString(); 125 } else { 126 if (type == CatalogEntryType.CATALOGENTRY) { 127 base = catalog.getBaseURI().toString(); 128 } else { 129 base = catalogEntry.getBaseURI().toString(); 130 } 131 } 132 } else { 133 base = Normalizer.normalizeURI(base); 134 } 135 136 //parse the catalog and group entries 137 if (type == CatalogEntryType.CATALOGENTRY 138 || type == CatalogEntryType.GROUP) { 139 String prefer = atts.getValue("prefer"); 140 if (prefer == null) { 141 if (type == CatalogEntryType.CATALOGENTRY) { 142 //use the general setting 143 prefer = catalog.isPreferPublic() ? 144 CatalogFeatures.PREFER_PUBLIC : CatalogFeatures.PREFER_SYSTEM; 145 } else { 146 //Group inherit from the catalog entry 147 prefer = catalogEntry.isPreferPublic() ? 148 CatalogFeatures.PREFER_PUBLIC : CatalogFeatures.PREFER_SYSTEM; 149 } 150 } 151 152 if (type == CatalogEntryType.CATALOGENTRY) { 153 seenRoot = true; 154 if (catalog.isTop()) { 155 String defer = atts.getValue("defer"); 156 String resolve = atts.getValue("resolve"); 157 if (defer == null) { 158 defer = catalog.isDeferred() ? 159 CatalogFeatures.DEFER_TRUE : CatalogFeatures.DEFER_FALSE; 160 } 161 if (resolve == null) { 162 resolve = catalog.getResolve().literal; 163 } 164 //override property settings with those from the catalog file 165 catalog.setResolve(resolve); 166 catalog.setDeferred(defer); 167 catalogEntry = new CatalogEntry(base, prefer, defer, resolve); 168 } else { 169 catalogEntry = new CatalogEntry(base, prefer); 170 } 171 catalog.setPrefer(prefer); 172 return; 173 } else { 174 inGroup = true; 175 group = new GroupEntry(catalog, base, prefer); 176 catalog.addEntry(group); 177 return; 178 } 179 } 180 181 //parse entries other than the catalog and group entries 182 switch (type) { 183 case PUBLIC: 184 entry = new PublicEntry(base, atts.getValue("publicId"), atts.getValue("uri")); 185 break; 186 case SYSTEM: 187 entry = new SystemEntry(base, atts.getValue("systemId"), atts.getValue("uri")); 188 break; 189 case REWRITESYSTEM: 190 entry = new RewriteSystem(base, atts.getValue("systemIdStartString"), atts.getValue("rewritePrefix")); 191 break; 192 case SYSTEMSUFFIX: 193 entry = new SystemSuffix(base, atts.getValue("systemIdSuffix"), atts.getValue("uri")); 194 break; 195 case DELEGATEPUBLIC: 196 entry = new DelegatePublic(base, atts.getValue("publicIdStartString"), atts.getValue("catalog")); 197 break; 198 case DELEGATESYSTEM: 199 entry = new DelegateSystem(base, atts.getValue("systemIdStartString"), atts.getValue("catalog")); 200 break; 201 case URI: 202 entry = new UriEntry(base, atts.getValue("name"), atts.getValue("uri")); 203 break; 204 case REWRITEURI: 205 entry = new RewriteUri(base, atts.getValue("uriStartString"), atts.getValue("rewritePrefix")); 206 break; 207 case URISUFFIX: 208 entry = new UriSuffix(base, atts.getValue("uriSuffix"), atts.getValue("uri")); 209 break; 210 case DELEGATEURI: 211 entry = new DelegateUri(base, atts.getValue("uriStartString"), atts.getValue("catalog")); 212 break; 213 case NEXTCATALOG: 214 entry = new NextCatalog(base, atts.getValue("catalog")); 215 break; 216 } 217 218 if (type == CatalogEntryType.NEXTCATALOG) { 219 catalog.addNextCatalog((NextCatalog) entry); 220 } else if (inGroup) { 221 group.addEntry(entry); 222 } else { 223 catalog.addEntry(entry); 224 } 225 226 } 227 228 /** 229 * Handles endElement event 230 */ 231 @Override 232 public void endElement(String namespaceURI, String localName, String qName) 233 throws SAXException { 234 if (ignoreTheCatalog) return; 235 236 CatalogEntryType type = CatalogEntryType.getType(localName); 237 if (type == CatalogEntryType.GROUP) { 238 inGroup = false; 239 } 240 } 241 242 243 /** 244 * Skips external DTD since resolving external DTD is not required 245 * by the specification. 246 */ 247 @Override 248 public InputSource resolveEntity(String publicId, String systemId) { 249 return new InputSource(new StringReader("")); 250 } 251 252 /** 253 * Skips external references since resolution is not required 254 * by the specification. 255 */ 256 @Override 257 public Source resolve(String href, String base) 258 throws TransformerException { 259 return new SAXSource(new InputSource(new StringReader(""))); 260 } 261 262} 263