org.apache.xml.resolver.tools.CatalogResolver Maven / Gradle / Ivy
Show all versions of com.liferay.saml.persistence.service
// CatalogResolver.java - A SAX EntityResolver/JAXP URI Resolver
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.xml.resolver.tools;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.MalformedURLException;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.InputSource;
import org.xml.sax.EntityResolver;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.Source;
import javax.xml.transform.URIResolver;
import javax.xml.transform.TransformerException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import org.apache.xml.resolver.Catalog;
import org.apache.xml.resolver.CatalogManager;
import org.apache.xml.resolver.helpers.FileURL;
/**
* A SAX EntityResolver/JAXP URIResolver that uses catalogs.
*
* This class implements both a SAX EntityResolver and a JAXP URIResolver.
*
*
* This resolver understands OASIS TR9401 catalogs, XCatalogs, and the
* current working draft of the OASIS Entity Resolution Technical
* Committee specification.
*
* @see Catalog
* @see org.xml.sax.EntityResolver
* @see javax.xml.transform.URIResolver
*
* @author Norman Walsh
* [email protected]
*
* @version 1.0
*/
public class CatalogResolver implements EntityResolver, URIResolver {
/** Make the parser Namespace aware? */
public boolean namespaceAware = true;
/** Make the parser validating? */
public boolean validating = false;
/** The underlying catalog */
private Catalog catalog = null;
/** The catalog manager */
private CatalogManager catalogManager = CatalogManager.getStaticManager();
/** Constructor */
public CatalogResolver() {
initializeCatalogs(false);
}
/** Constructor */
public CatalogResolver(boolean privateCatalog) {
initializeCatalogs(privateCatalog);
}
/** Constructor */
public CatalogResolver(CatalogManager manager) {
catalogManager = manager;
initializeCatalogs(!catalogManager.getUseStaticCatalog());
}
/** Initialize catalog */
private void initializeCatalogs(boolean privateCatalog) {
catalog = catalogManager.getCatalog();
}
/** Return the underlying catalog */
public Catalog getCatalog() {
return catalog;
}
/**
* Implements the guts of the resolveEntity
method
* for the SAX interface.
*
* Presented with an optional public identifier and a system
* identifier, this function attempts to locate a mapping in the
* catalogs.
*
* If such a mapping is found, it is returned. If no mapping is
* found, null is returned.
*
* @param publicId The public identifier for the entity in question.
* This may be null.
*
* @param systemId The system identifier for the entity in question.
* XML requires a system identifier on all external entities, so this
* value is always specified.
*
* @return The resolved identifier (a URI reference).
*/
public String getResolvedEntity (String publicId, String systemId) {
String resolved = null;
if (catalog == null) {
catalogManager.debug.message(1, "Catalog resolution attempted with null catalog; ignored");
return null;
}
if (systemId != null) {
try {
resolved = catalog.resolveSystem(systemId);
} catch (MalformedURLException me) {
catalogManager.debug.message(1, "Malformed URL exception trying to resolve",
publicId);
resolved = null;
} catch (IOException ie) {
catalogManager.debug.message(1, "I/O exception trying to resolve", publicId);
resolved = null;
}
}
if (resolved == null) {
if (publicId != null) {
try {
resolved = catalog.resolvePublic(publicId, systemId);
} catch (MalformedURLException me) {
catalogManager.debug.message(1, "Malformed URL exception trying to resolve",
publicId);
} catch (IOException ie) {
catalogManager.debug.message(1, "I/O exception trying to resolve", publicId);
}
}
if (resolved != null) {
catalogManager.debug.message(2, "Resolved public", publicId, resolved);
}
} else {
catalogManager.debug.message(2, "Resolved system", systemId, resolved);
}
return resolved;
}
/**
* Implements the resolveEntity
method
* for the SAX interface.
*
* Presented with an optional public identifier and a system
* identifier, this function attempts to locate a mapping in the
* catalogs.
*
* If such a mapping is found, the resolver attempts to open
* the mapped value as an InputSource and return it. Exceptions are
* ignored and null is returned if the mapped value cannot be opened
* as an input source.
*
* If no mapping is found (or an error occurs attempting to open
* the mapped value as an input source), null is returned and the system
* will use the specified system identifier as if no entityResolver
* was specified.
*
* @param publicId The public identifier for the entity in question.
* This may be null.
*
* @param systemId The system identifier for the entity in question.
* XML requires a system identifier on all external entities, so this
* value is always specified.
*
* @return An InputSource for the mapped identifier, or null.
*/
public InputSource resolveEntity (String publicId, String systemId) {
String resolved = getResolvedEntity(publicId, systemId);
if (resolved != null) {
try {
InputSource iSource = new InputSource(resolved);
iSource.setPublicId(publicId);
// Ideally this method would not attempt to open the
// InputStream, but there is a bug (in Xerces, at least)
// that causes the parser to mistakenly open the wrong
// system identifier if the returned InputSource does
// not have a byteStream.
//
// It could be argued that we still shouldn't do this here,
// but since the purpose of calling the entityResolver is
// almost certainly to open the input stream, it seems to
// do little harm.
//
URL url = new URL(resolved);
InputStream iStream = url.openStream();
iSource.setByteStream(iStream);
return iSource;
} catch (Exception e) {
catalogManager.debug.message(1,
"Failed to create InputSource ("
+ e.toString()
+ ")", resolved);
return null;
}
}
return null;
}
/** JAXP URIResolver API */
public Source resolve(String href, String base)
throws TransformerException {
String uri = href;
String fragment = null;
int hashPos = href.indexOf("#");
if (hashPos >= 0) {
uri = href.substring(0, hashPos);
fragment = href.substring(hashPos+1);
}
String result = null;
try {
result = catalog.resolveURI(href);
} catch (Exception e) {
// nop;
}
if (result == null) {
try {
URL url = null;
if (base==null) {
url = new URL(uri);
result = url.toString();
} else {
URL baseURL = new URL(base);
url = (href.length()==0 ? baseURL : new URL(baseURL, uri));
result = url.toString();
}
} catch (java.net.MalformedURLException mue) {
// try to make an absolute URI from the current base
String absBase = makeAbsolute(base);
if (!absBase.equals(base)) {
// don't bother if the absBase isn't different!
return resolve(href, absBase);
} else {
throw new TransformerException("Malformed URL "
+ href + "(base " + base + ")",
mue);
}
}
}
catalogManager.debug.message(2, "Resolved URI", href, result);
SAXSource source = new SAXSource();
source.setInputSource(new InputSource(result));
setEntityResolver(source);
return source;
}
/**
* Establish an entityResolver for newly resolved URIs.
*
* This is called from the URIResolver to set an EntityResolver
* on the SAX parser to be used for new XML documents that are
* encountered as a result of the document() function, xsl:import,
* or xsl:include. This is done because the XSLT processor calls
* out to the SAXParserFactory itself to create a new SAXParser to
* parse the new document. The new parser does not automatically
* inherit the EntityResolver of the original (although arguably
* it should). See below:
*
* "If an application wants to set the ErrorHandler or
* EntityResolver for an XMLReader used during a transformation,
* it should use a URIResolver to return the SAXSource which
* provides (with getXMLReader) a reference to the XMLReader"
*
* ...quoted from page 118 of the Java API for XML
* Processing 1.1 specification
*
*/
private void setEntityResolver(SAXSource source) throws TransformerException {
XMLReader reader = source.getXMLReader();
if (reader == null) {
SAXParserFactory spFactory = SAXParserFactory.newInstance();
spFactory.setNamespaceAware(true);
try {
reader = spFactory.newSAXParser().getXMLReader();
}
catch (ParserConfigurationException ex) {
throw new TransformerException(ex);
}
catch (SAXException ex) {
throw new TransformerException(ex);
}
}
reader.setEntityResolver(this);
source.setXMLReader(reader);
}
/** Attempt to construct an absolute URI */
private String makeAbsolute(String uri) {
if (uri == null) {
uri = "";
}
try {
URL url = new URL(uri);
return url.toString();
} catch (MalformedURLException mue) {
try {
URL fileURL = FileURL.makeURL(uri);
return fileURL.toString();
} catch (MalformedURLException mue2) {
// bail
return uri;
}
}
}
}