1 /* 2 * Copyright (c) 2015, 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. 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 */ 25 package javax.xml.catalog; 26 27 import com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl; 28 import java.io.StringReader; 29 import java.net.URL; 30 import java.util.Iterator; 31 import javax.xml.parsers.ParserConfigurationException; 32 import javax.xml.parsers.SAXParserFactory; 33 import javax.xml.transform.Source; 34 import javax.xml.transform.sax.SAXSource; 35 import org.xml.sax.InputSource; 36 import org.xml.sax.SAXException; 37 import org.xml.sax.XMLReader; 38 39 /** 40 * A SAX EntityResolver/JAXP URIResolver that uses catalogs. 41 * <p> 42 * This class implements both a SAX EntityResolver and a JAXP URIResolver. 43 * 44 * 45 * @since 9 46 */ 47 final class CatalogUriResolverImpl implements CatalogUriResolver { 48 49 Catalog catalog; 50 CatalogResolverImpl entityResolver; 51 52 /** 53 * Construct an instance of the CatalogResolver from a Catalog. 54 * 55 * @param catalog A Catalog. 56 */ 57 public CatalogUriResolverImpl(Catalog catalog) { 58 this.catalog = catalog; 59 } 60 61 @Override 62 public Source resolve(String href, String base) { 63 href = Util.getNotNullOrEmpty(href); 64 base = Util.getNotNullOrEmpty(base); 65 66 if (href == null) return null; 67 68 String result = null; 69 CatalogImpl c = (CatalogImpl)catalog; 70 String uri = Normalizer.normalizeURI(href); 71 //check whether uri is an urn 72 if (uri != null && uri.startsWith(Util.URN)) { 73 String publicId = Normalizer.decodeURN(uri); 74 if (publicId != null) { 75 result = Util.resolve(c, publicId, null); 76 } 77 } 78 79 //if no match with a public id, continue search for an URI 80 if (result == null) { 81 //remove fragment if any. 82 int hashPos = uri.indexOf("#"); 83 if (hashPos >= 0) { 84 uri = uri.substring(0, hashPos); 85 } 86 87 //search the current catalog 88 result = resolve(c, uri); 89 } 90 91 //Report error or return the URI as is when no match is found 92 if (result == null) { 93 GroupEntry.ResolveType resolveType = c.getResolve(); 94 switch (resolveType) { 95 case IGNORE: 96 return new SAXSource(new InputSource(new StringReader(""))); 97 case STRICT: 98 CatalogMessages.reportError(CatalogMessages.ERR_NO_URI_MATCH, 99 new Object[]{href, base}); 100 } 101 try { 102 URL url = null; 103 104 if (base == null) { 105 url = new URL(uri); 106 result = url.toString(); 107 } else { 108 URL baseURL = new URL(base); 109 url = (href.length() == 0 ? baseURL : new URL(baseURL, uri)); 110 result = url.toString(); 111 } 112 } catch (java.net.MalformedURLException mue) { 113 CatalogMessages.reportError(CatalogMessages.ERR_CREATING_URI, 114 new Object[]{href, base}); 115 } 116 } 117 118 SAXSource source = new SAXSource(); 119 source.setInputSource(new InputSource(result)); 120 setEntityResolver(source); 121 return source; 122 } 123 124 /** 125 * Resolves the publicId or systemId to one specified in the catalog. 126 * @param catalog the catalog 127 * @param href an href attribute, which may be relative or absolute 128 * @return the resolved systemId if a match is found, null otherwise 129 */ 130 String resolve(CatalogImpl catalog, String href) { 131 String result = null; 132 133 //search the current catalog 134 catalog.reset(); 135 if (href != null) { 136 result = catalog.matchURI(href); 137 } 138 139 //mark the catalog as having been searched before trying alternatives 140 catalog.markAsSearched(); 141 142 //search alternative catalogs 143 if (result == null) { 144 Iterator<Catalog> iter = catalog.catalogs().iterator(); 145 while (iter.hasNext()) { 146 result = resolve((CatalogImpl)iter.next(), href); 147 if (result != null) { 148 break; 149 } 150 } 151 } 152 153 return result; 154 } 155 156 /** 157 * Establish an entityResolver for newly resolved URIs. 158 * <p> 159 * This is called from the URIResolver to set an EntityResolver on the SAX 160 * parser to be used for new XML documents that are encountered as a result 161 * of the document() function, xsl:import, or xsl:include. This is done 162 * because the XSLT processor calls out to the SAXParserFactory itself to 163 * create a new SAXParser to parse the new document. The new parser does not 164 * automatically inherit the EntityResolver of the original (although 165 * arguably it should). Quote from JAXP specification on Class 166 * SAXTransformerFactory: 167 * <p> 168 * {@code If an application wants to set the ErrorHandler or EntityResolver 169 * for an XMLReader used during a transformation, it should use a URIResolver 170 * to return the SAXSource which provides (with getXMLReader) a reference to 171 * the XMLReader} 172 * 173 */ 174 private void setEntityResolver(SAXSource source) { 175 XMLReader reader = source.getXMLReader(); 176 if (reader == null) { 177 SAXParserFactory spFactory = new SAXParserFactoryImpl(); 178 spFactory.setNamespaceAware(true); 179 try { 180 reader = spFactory.newSAXParser().getXMLReader(); 181 } catch (ParserConfigurationException | SAXException ex) { 182 CatalogMessages.reportRunTimeError(CatalogMessages.ERR_PARSER_CONF, ex); 183 } 184 } 185 if (entityResolver != null) { 186 entityResolver = new CatalogResolverImpl(catalog); 187 } 188 reader.setEntityResolver(entityResolver); 189 source.setXMLReader(reader); 190 } 191 }