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 java.io.StringReader; 28 import java.util.Iterator; 29 import org.xml.sax.InputSource; 30 31 /** 32 * A SAX EntityResolver/JAXP URIResolver that uses catalogs. 33 * 34 * <p> 35 * This class implements both a SAX EntityResolver and a JAXP URIResolver. 36 * 37 * 38 * @since 9 39 */ 40 final class CatalogResolverImpl implements CatalogResolver { 41 Catalog catalog; 42 43 /** 44 * Construct an instance of the CatalogResolver from a Catalog. 45 * 46 * @param catalog A Catalog. 47 */ 48 public CatalogResolverImpl(Catalog catalog) { 49 this.catalog = catalog; 50 } 51 52 @Override 53 public InputSource resolveEntity(String publicId, String systemId) { 54 CatalogMessages.reportNPEOnNull("systemId", systemId); 55 //Normalize publicId and systemId 56 systemId = Normalizer.normalizeURI(Util.getNotNullOrEmpty(systemId)); 57 publicId = Normalizer.normalizePublicId(Normalizer.decodeURN(Util.getNotNullOrEmpty(publicId))); 58 59 //check whether systemId is an urn 60 if (systemId != null && systemId.startsWith(Util.URN)) { 61 systemId = Normalizer.decodeURN(systemId); 62 if (publicId != null && !publicId.equals(systemId)) { 63 systemId = null; 64 } else { 65 publicId = systemId; 66 systemId = null; 67 } 68 } 69 70 CatalogImpl c = (CatalogImpl)catalog; 71 String resolvedSystemId = Util.resolve(c, publicId, systemId); 72 73 if (resolvedSystemId != null) { 74 return new InputSource(resolvedSystemId); 75 } 76 77 GroupEntry.ResolveType resolveType = ((CatalogImpl) catalog).getResolve(); 78 switch (resolveType) { 79 case IGNORE: 80 return new InputSource(new StringReader("")); 81 case STRICT: 82 CatalogMessages.reportError(CatalogMessages.ERR_NO_MATCH, 83 new Object[]{publicId, systemId}); 84 } 85 86 //no action, allow the parser to continue 87 return null; 88 } 89 90 } | 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.IOException; 29 import java.io.InputStream; 30 import java.io.Reader; 31 import java.io.StringReader; 32 import java.net.URL; 33 import javax.xml.parsers.ParserConfigurationException; 34 import javax.xml.parsers.SAXParserFactory; 35 import javax.xml.transform.Source; 36 import javax.xml.transform.sax.SAXSource; 37 import org.w3c.dom.ls.LSInput; 38 import org.xml.sax.InputSource; 39 import org.xml.sax.SAXException; 40 import org.xml.sax.XMLReader; 41 42 /** 43 * Implements CatalogResolver. 44 * 45 * <p> 46 * This class implements a SAX EntityResolver, StAX XMLResolver, 47 * Schema Validation LSResourceResolver and Transform URIResolver. 48 * 49 * 50 * @since 9 51 */ 52 final class CatalogResolverImpl implements CatalogResolver { 53 Catalog catalog; 54 55 /** 56 * Construct an instance of the CatalogResolver from a Catalog. 57 * 58 * @param catalog A Catalog. 59 */ 60 public CatalogResolverImpl(Catalog catalog) { 61 this.catalog = catalog; 62 } 63 64 /* 65 Implements the EntityResolver interface 66 */ 67 @Override 68 public InputSource resolveEntity(String publicId, String systemId) { 69 //8150187: NPE expected if the system identifier is null for CatalogResolver 70 CatalogMessages.reportNPEOnNull("systemId", systemId); 71 72 //Normalize publicId and systemId 73 systemId = Normalizer.normalizeURI(Util.getNotNullOrEmpty(systemId)); 74 publicId = Normalizer.normalizePublicId(Normalizer.decodeURN(Util.getNotNullOrEmpty(publicId))); 75 76 //check whether systemId is an urn 77 if (systemId != null && systemId.startsWith(Util.URN)) { 78 systemId = Normalizer.decodeURN(systemId); 79 if (publicId != null && !publicId.equals(systemId)) { 80 systemId = null; 81 } else { 82 publicId = systemId; 83 systemId = null; 84 } 85 } 86 87 CatalogImpl c = (CatalogImpl)catalog; 88 String resolvedSystemId = Util.resolve(c, publicId, systemId); 89 90 if (resolvedSystemId != null) { 91 return new InputSource(resolvedSystemId); 92 } 93 94 GroupEntry.ResolveType resolveType = ((CatalogImpl) catalog).getResolve(); 95 switch (resolveType) { 96 case IGNORE: 97 return new InputSource(new StringReader("")); 98 case STRICT: 99 CatalogMessages.reportError(CatalogMessages.ERR_NO_MATCH, 100 new Object[]{publicId, systemId}); 101 } 102 103 //no action, allow the parser to continue 104 return null; 105 } 106 107 /* 108 Implements the URIResolver interface 109 */ 110 CatalogResolverImpl entityResolver; 111 112 @Override 113 public Source resolve(String href, String base) { 114 CatalogMessages.reportNPEOnNull("href", href); 115 116 href = Util.getNotNullOrEmpty(href); 117 base = Util.getNotNullOrEmpty(base); 118 119 String result = null; 120 CatalogImpl c = (CatalogImpl)catalog; 121 String uri = Normalizer.normalizeURI(href); 122 //check whether uri is an urn 123 if (uri != null && uri.startsWith(Util.URN)) { 124 String publicId = Normalizer.decodeURN(uri); 125 if (publicId != null) { 126 result = Util.resolve(c, publicId, null); 127 } 128 } 129 130 //if no match with a public id, continue search for an URI 131 if (result == null) { 132 //remove fragment if any. 133 int hashPos = uri.indexOf("#"); 134 if (hashPos >= 0) { 135 uri = uri.substring(0, hashPos); 136 } 137 138 //search the current catalog 139 result = Util.resolve(c, null, uri); 140 } 141 142 //Report error or return the URI as is when no match is found 143 if (result == null) { 144 GroupEntry.ResolveType resolveType = c.getResolve(); 145 switch (resolveType) { 146 case IGNORE: 147 return new SAXSource(new InputSource(new StringReader(""))); 148 case STRICT: 149 CatalogMessages.reportError(CatalogMessages.ERR_NO_URI_MATCH, 150 new Object[]{href, base}); 151 } 152 try { 153 URL url = null; 154 155 if (base == null) { 156 url = new URL(uri); 157 result = url.toString(); 158 } else { 159 URL baseURL = new URL(base); 160 url = (href.length() == 0 ? baseURL : new URL(baseURL, uri)); 161 result = url.toString(); 162 } 163 } catch (java.net.MalformedURLException mue) { 164 CatalogMessages.reportError(CatalogMessages.ERR_CREATING_URI, 165 new Object[]{href, base}); 166 } 167 } 168 169 SAXSource source = new SAXSource(); 170 source.setInputSource(new InputSource(result)); 171 setEntityResolver(source); 172 return source; 173 } 174 175 /** 176 * Establish an entityResolver for newly resolved URIs. 177 * <p> 178 * This is called from the URIResolver to set an EntityResolver on the SAX 179 * parser to be used for new XML documents that are encountered as a result 180 * of the document() function, xsl:import, or xsl:include. This is done 181 * because the XSLT processor calls out to the SAXParserFactory itself to 182 * create a new SAXParser to parse the new document. The new parser does not 183 * automatically inherit the EntityResolver of the original (although 184 * arguably it should). Quote from JAXP specification on Class 185 * SAXTransformerFactory: 186 * <p> 187 * {@code If an application wants to set the ErrorHandler or EntityResolver 188 * for an XMLReader used during a transformation, it should use a URIResolver 189 * to return the SAXSource which provides (with getXMLReader) a reference to 190 * the XMLReader} 191 * 192 */ 193 private void setEntityResolver(SAXSource source) { 194 XMLReader reader = source.getXMLReader(); 195 if (reader == null) { 196 SAXParserFactory spFactory = new SAXParserFactoryImpl(); 197 spFactory.setNamespaceAware(true); 198 try { 199 reader = spFactory.newSAXParser().getXMLReader(); 200 } catch (ParserConfigurationException | SAXException ex) { 201 CatalogMessages.reportRunTimeError(CatalogMessages.ERR_PARSER_CONF, ex); 202 } 203 } 204 if (entityResolver != null) { 205 entityResolver = new CatalogResolverImpl(catalog); 206 } 207 reader.setEntityResolver(entityResolver); 208 source.setXMLReader(reader); 209 } 210 211 @Override 212 public InputStream resolveEntity(String publicId, String systemId, String baseUri, String namespace) { 213 InputSource is = resolveEntity(publicId, systemId); 214 215 if (is != null && !is.isEmpty()) { 216 217 try { 218 return new URL(is.getSystemId()).openStream(); 219 } catch (IOException ex) { 220 //considered as no mapping. 221 } 222 223 } 224 225 GroupEntry.ResolveType resolveType = ((CatalogImpl) catalog).getResolve(); 226 switch (resolveType) { 227 case IGNORE: 228 return null; 229 case STRICT: 230 CatalogMessages.reportError(CatalogMessages.ERR_NO_MATCH, 231 new Object[]{publicId, systemId}); 232 } 233 234 //no action, allow the parser to continue 235 return null; 236 } 237 238 @Override 239 public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) { 240 InputSource is = resolveEntity(publicId, systemId); 241 242 if (is != null && !is.isEmpty()) { 243 return new LSInputImpl(is.getSystemId()); 244 } 245 246 GroupEntry.ResolveType resolveType = ((CatalogImpl) catalog).getResolve(); 247 switch (resolveType) { 248 case IGNORE: 249 return null; 250 case STRICT: 251 CatalogMessages.reportError(CatalogMessages.ERR_NO_MATCH, 252 new Object[]{publicId, systemId}); 253 } 254 255 //no action, allow the parser to continue 256 return null; 257 } 258 259 /** 260 * Implements LSInput. All that we need is the systemId since the Catalog 261 * has already resolved it. 262 */ 263 class LSInputImpl implements LSInput { 264 265 private String systemId; 266 267 public LSInputImpl(String systemId) { 268 this.systemId = systemId; 269 } 270 271 @Override 272 public Reader getCharacterStream() { 273 return null; 274 } 275 276 @Override 277 public void setCharacterStream(Reader characterStream) { 278 } 279 280 @Override 281 public InputStream getByteStream() { 282 return null; 283 } 284 285 @Override 286 public void setByteStream(InputStream byteStream) { 287 } 288 289 @Override 290 public String getStringData() { 291 return null; 292 } 293 294 @Override 295 public void setStringData(String stringData) { 296 } 297 298 @Override 299 public String getSystemId() { 300 return systemId; 301 } 302 303 @Override 304 public void setSystemId(String systemId) { 305 this.systemId = systemId; 306 } 307 308 @Override 309 public String getPublicId() { 310 return null; 311 } 312 313 @Override 314 public void setPublicId(String publicId) { 315 } 316 317 @Override 318 public String getBaseURI() { 319 return null; 320 } 321 322 @Override 323 public void setBaseURI(String baseURI) { 324 } 325 326 @Override 327 public String getEncoding() { 328 return null; 329 } 330 331 @Override 332 public void setEncoding(String encoding) { 333 } 334 335 @Override 336 public boolean getCertifiedText() { 337 return false; 338 } 339 340 @Override 341 public void setCertifiedText(boolean certifiedText) { 342 } 343 } 344 345 } |