Index: libxml-commons-resolver1.1-java-1.2/src/org/apache/xml/resolver/NbCatalogManager.java =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ libxml-commons-resolver1.1-java-1.2/src/org/apache/xml/resolver/NbCatalogManager.java 2009-01-30 23:02:32.000000000 +0100 @@ -0,0 +1,840 @@ +// CatalogManager.java - Access CatalogManager.properties + +/* + * 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; + +import java.io.InputStream; + +import java.net.URL; +import java.net.MalformedURLException; + +import java.util.MissingResourceException; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.apache.xml.resolver.helpers.Debug; +import org.apache.xml.resolver.helpers.BootstrapResolver; +import org.apache.xml.resolver.Catalog; + +/** + * CatalogManager provides an interface to the catalog properties. + * + *

Properties can come from two places: from system properties or + * from a CatalogManager.properties file. This class provides a transparent + * interface to both, with system properties preferred over property file values.

+ * + *

The following table summarizes the properties:

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
System PropertyCatalogManager.properties
Property
Description
xml.catalog.ignoreMissing If true, a missing CatalogManager.properties file or missing properties + * within that file will not generate warning messages. See also the + * ignoreMissingProperties method.
xml.catalog.filescatalogsThe semicolon-delimited list of catalog files.
 relative-catalogsIf false, relative catalog URIs are made absolute with respect to the base URI of + * the CatalogManager.properties file. This setting only applies to catalog + * URIs obtained from the catalogs property in the + * CatalogManager.properties file
xml.catalog.verbosityverbosityIf non-zero, the Catalog classes will print informative and debugging messages. + * The higher the number, the more messages.
xml.catalog.preferpreferWhich identifier is preferred, "public" or "system"?
xml.catalog.staticCatalogstatic-catalogShould a single catalog be constructed for all parsing, or should a different + * catalog be created for each parser?
xml.catalog.allowPIallow-oasis-xml-catalog-piIf the source document contains "oasis-xml-catalog" processing instructions, + * should they be used?
xml.catalog.classNamecatalog-class-nameIf you're using the convenience classes + * org.apache.xml.resolver.tools.*), this setting + * allows you to specify an alternate class name to use for the underlying + * catalog.
+ * + * @see Catalog + * + * @author Norman Walsh + * Norman.Walsh@Sun.COM + * + * @version 1.0 + */ + +public class NbCatalogManager extends CatalogManager { + private static String pFiles = "xml.catalog.files"; + private static String pVerbosity = "xml.catalog.verbosity"; + private static String pPrefer = "xml.catalog.prefer"; + private static String pStatic = "xml.catalog.staticCatalog"; + private static String pAllowPI = "xml.catalog.allowPI"; + private static String pClassname = "xml.catalog.className"; + private static String pIgnoreMissing = "xml.catalog.ignoreMissing"; + + /** A static CatalogManager instance for sharing */ + private static NbCatalogManager staticManager = new NbCatalogManager(); + + /** The bootstrap resolver to use when loading XML Catalogs. */ + private BootstrapResolver bResolver = new BootstrapResolver(); + + /** Flag to ignore missing property files and/or properties */ + private boolean ignoreMissingProperties + = (System.getProperty(pIgnoreMissing) != null + || System.getProperty(pFiles) != null); + + /** Holds the resources after they are loaded from the file. */ + private ResourceBundle resources; + + /** The name of the CatalogManager properties file. */ + private String propertyFile = "CatalogManager.properties"; + + /** The location of the propertyFile */ + private URL propertyFileURI = null; + + /** Default catalog files list. */ + private String defaultCatalogFiles = "./xcatalog"; + + /** Current catalog files list. */ + private String catalogFiles = null; + + /** Did the catalogFiles come from the properties file? */ + private boolean fromPropertiesFile = false; + + /** Default verbosity level if there is no property setting for it. */ + private int defaultVerbosity = 1; + + /** Current verbosity level. */ + private Integer verbosity = null; + + /** Default preference setting. */ + private boolean defaultPreferPublic = true; + + /** Current preference setting. */ + private Boolean preferPublic = null; + + /** Default setting of the static catalog flag. */ + private boolean defaultUseStaticCatalog = true; + + /** Current setting of the static catalog flag. */ + private Boolean useStaticCatalog = null; + + /** The static catalog used by this manager. */ + private static Catalog staticCatalog = null; + + /** Default setting of the oasisXMLCatalogPI flag. */ + private boolean defaultOasisXMLCatalogPI = true; + + /** Current setting of the oasisXMLCatalogPI flag. */ + private Boolean oasisXMLCatalogPI = null; + + /** Default setting of the relativeCatalogs flag. */ + private boolean defaultRelativeCatalogs = true; + + /** Current setting of the relativeCatalogs flag. */ + private Boolean relativeCatalogs = null; + + /** Current catalog class name. */ + private String catalogClassName = null; + + /** The manager's debug object. Used for printing debugging messages. + * + *

This field is public so that objects that have access to this + * CatalogManager can use this debug object.

+ */ + public Debug debug = null; + + /** Constructor. */ + public NbCatalogManager() { + debug = new Debug(); + // Note that we don't setDebug() here; we do that lazily. Either the + // user will set it explicitly, or we'll do it automagically if they + // read from the propertyFile for some other reason. That way, there's + // no attempt to read from the file before the caller has had a chance + // to avoid it. + } + + /** + * Constructor that specifies an explicit property file. + * @param propertyFile path to poperty file (e.g. com/resources/CatalogManager). + * null means that no property file is consulted at all. + */ + public NbCatalogManager(String propertyFile) { + this.propertyFile = propertyFile; + + debug = new Debug(); + // Note that we don't setDebug() here; we do that lazily. Either the + // user will set it explicitly, or we'll do it automagically if they + // read from the propertyFile for some other reason. That way, there's + // no attempt to read from the file before the caller has had a chance + // to avoid it. + } + + /** Set the bootstrap resolver.*/ + public void setBootstrapResolver(BootstrapResolver resolver) { + bResolver = resolver; + } + + /** Get the bootstrap resolver.*/ + public BootstrapResolver getBootstrapResolver() { + return bResolver; + } + + /** + * Load the properties from the propertyFile and build the + * resources from it. + */ + private synchronized void readProperties() { + if (propertyFile == null) return; + try { + propertyFileURI = NbCatalogManager.class.getResource("/"+propertyFile); + InputStream in = + NbCatalogManager.class.getResourceAsStream("/"+propertyFile); + if (in==null) { + if (!ignoreMissingProperties) { + debug.message(2, "Cannot find "+propertyFile); + // there's no reason to give this warning more than once + ignoreMissingProperties = true; + } + return; + } + resources = new PropertyResourceBundle(in); + } catch (MissingResourceException mre) { + if (!ignoreMissingProperties) { + System.err.println("Cannot read "+propertyFile); + } + } catch (java.io.IOException e) { + if (!ignoreMissingProperties) { + System.err.println("Failure trying to read "+propertyFile); + } + } + + // This is a bit of a hack. After we've successfully read the properties, + // use them to set the default debug level, if the user hasn't already set + // the default debug level. + if (verbosity == null) { + try { + String verbStr = resources.getString("verbosity"); + int verb = Integer.parseInt(verbStr.trim()); + debug.setDebug(verb); + verbosity = new Integer(verb); + } catch (Exception e) { + // nop + } + } + } + + /** + * Allow access to the static CatalogManager + */ + public static CatalogManager getStaticManager() { + return staticManager; + } + + /** + * How are missing properties handled? + * + *

If true, missing or unreadable property files will + * not be reported. Otherwise, a message will be sent to System.err. + *

+ */ + public boolean getIgnoreMissingProperties() { + return ignoreMissingProperties; + } + + /** + * How should missing properties be handled? + * + *

If ignore is true, missing or unreadable property files will + * not be reported. Otherwise, a message will be sent to System.err. + *

+ */ + public void setIgnoreMissingProperties(boolean ignore) { + ignoreMissingProperties = ignore; + } + + /** + * How are missing properties handled? + * + *

If ignore is true, missing or unreadable property files will + * not be reported. Otherwise, a message will be sent to System.err. + *

+ * + * @deprecated No longer static; use get/set methods. + */ + public void ignoreMissingProperties(boolean ignore) { + setIgnoreMissingProperties(ignore); + } + + /** + * Obtain the verbosity setting from the properties. + * + * @return The verbosity level from the propertyFile or the + * defaultVerbosity. + */ + private int queryVerbosity () { + String defaultVerbStr = Integer.toString(defaultVerbosity); + + String verbStr = System.getProperty(pVerbosity); + + if (verbStr == null) { + if (resources==null) readProperties(); + if (resources != null) { + try { + verbStr = resources.getString("verbosity"); + } catch (MissingResourceException e) { + verbStr = defaultVerbStr; + } + } else { + verbStr = defaultVerbStr; + } + } + + int verb = defaultVerbosity; + + try { + verb = Integer.parseInt(verbStr.trim()); + } catch (Exception e) { + System.err.println("Cannot parse verbosity: \"" + verbStr + "\""); + } + + // This is a bit of a hack. After we've successfully got the verbosity, + // we have to use it to set the default debug level, + // if the user hasn't already set the default debug level. + if (verbosity == null) { + debug.setDebug(verb); + verbosity = new Integer(verb); + } + + return verb; + } + + /** + * What is the current verbosity? + */ + public int getVerbosity() { + if (verbosity == null) { + verbosity = new Integer(queryVerbosity()); + } + + return verbosity.intValue(); + } + + /** + * Set the current verbosity. + */ + public void setVerbosity (int verbosity) { + this.verbosity = new Integer(verbosity); + debug.setDebug(verbosity); + } + + /** + * What is the current verbosity? + * + * @deprecated No longer static; use get/set methods. + */ + public int verbosity () { + return getVerbosity(); + } + + /** + * Obtain the relativeCatalogs setting from the properties. + * + * @return The relativeCatalogs setting from the propertyFile or the + * defaultRelativeCatalogs. + */ + private boolean queryRelativeCatalogs () { + if (resources==null) readProperties(); + + if (resources==null) return defaultRelativeCatalogs; + + try { + String allow = resources.getString("relative-catalogs"); + return (allow.equalsIgnoreCase("true") + || allow.equalsIgnoreCase("yes") + || allow.equalsIgnoreCase("1")); + } catch (MissingResourceException e) { + return defaultRelativeCatalogs; + } + } + + /** + * Get the relativeCatalogs setting. + * + *

This property is used when the catalogFiles property is + * interrogated. If true, then relative catalog entry file names + * are returned. If false, relative catalog entry file names are + * made absolute with respect to the properties file before returning + * them.

+ * + *

This property only applies when the catalog files + * come from a properties file. If they come from a system property or + * the default list, they are never considered relative. (What would + * they be relative to?)

+ * + *

In the properties, a value of 'yes', 'true', or '1' is considered + * true, anything else is false.

+ * + * @return The relativeCatalogs setting from the propertyFile or the + * defaultRelativeCatalogs. + */ + public boolean getRelativeCatalogs () { + if (relativeCatalogs == null) { + relativeCatalogs = new Boolean(queryRelativeCatalogs()); + } + + return relativeCatalogs.booleanValue(); + } + + /** + * Set the relativeCatalogs setting. + * + * @see #getRelativeCatalogs() + */ + public void setRelativeCatalogs (boolean relative) { + relativeCatalogs = new Boolean(relative); + } + + /** + * Get the relativeCatalogs setting. + * + * @deprecated No longer static; use get/set methods. + */ + public boolean relativeCatalogs () { + return getRelativeCatalogs(); + } + + /** + * Obtain the list of catalog files from the properties. + * + * @return A semicolon delimited list of catlog file URIs + */ + private String queryCatalogFiles () { + String catalogList = System.getProperty(pFiles); + fromPropertiesFile = false; + + if (catalogList == null) { + if (resources == null) readProperties(); + if (resources != null) { + try { + catalogList = resources.getString("catalogs"); + fromPropertiesFile = true; + } catch (MissingResourceException e) { + System.err.println(propertyFile + ": catalogs not found."); + catalogList = null; + } + } + } + + if (catalogList == null) { + catalogList = defaultCatalogFiles; + } + + return catalogList; + } + + /** + * Return the current list of catalog files. + * + * @return A vector of the catalog file names or null if no catalogs + * are available in the properties. + */ + public Vector getCatalogFiles() { + if (catalogFiles == null) { + catalogFiles = queryCatalogFiles(); + } + + StringTokenizer files = new StringTokenizer(catalogFiles, ";"); + Vector catalogs = new Vector(); + while (files.hasMoreTokens()) { + String catalogFile = files.nextToken(); + URL absURI = null; + + if (fromPropertiesFile && !relativeCatalogs()) { + try { + absURI = new URL(propertyFileURI, catalogFile); + catalogFile = absURI.toString(); + } catch (MalformedURLException mue) { + absURI = null; + } + } + + catalogs.add(catalogFile); + } + + return catalogs; + } + + /** + * Set the list of catalog files. + */ + public void setCatalogFiles(String fileList) { + catalogFiles = fileList; + fromPropertiesFile = false; + } + + /** + * Return the current list of catalog files. + * + * @return A vector of the catalog file names or null if no catalogs + * are available in the properties. + * + * @deprecated No longer static; use get/set methods. + */ + public Vector catalogFiles() { + return getCatalogFiles(); + } + + /** + * Obtain the preferPublic setting from the properties. + * + *

In the properties, a value of 'public' is true, + * anything else is false.

+ * + * @return True if prefer is public or the + * defaultPreferSetting. + */ + private boolean queryPreferPublic () { + String prefer = System.getProperty(pPrefer); + + if (prefer == null) { + if (resources==null) readProperties(); + if (resources==null) return defaultPreferPublic; + try { + prefer = resources.getString("prefer"); + } catch (MissingResourceException e) { + return defaultPreferPublic; + } + } + + if (prefer == null) { + return defaultPreferPublic; + } + + return (prefer.equalsIgnoreCase("public")); + } + + /** + * Return the current prefer public setting. + * + * @return True if public identifiers are preferred. + */ + public boolean getPreferPublic () { + if (preferPublic == null) { + preferPublic = new Boolean(queryPreferPublic()); + } + return preferPublic.booleanValue(); + } + + /** + * Set the prefer public setting. + */ + public void setPreferPublic (boolean preferPublic) { + this.preferPublic = new Boolean(preferPublic); + } + + /** + * Return the current prefer public setting. + * + * @return True if public identifiers are preferred. + * + * @deprecated No longer static; use get/set methods. + */ + public boolean preferPublic () { + return getPreferPublic(); + } + + /** + * Obtain the static-catalog setting from the properties. + * + *

In the properties, a value of 'yes', 'true', or '1' is considered + * true, anything else is false.

+ * + * @return The static-catalog setting from the propertyFile or the + * defaultUseStaticCatalog. + */ + private boolean queryUseStaticCatalog () { + String staticCatalog = System.getProperty(pStatic); + + if (staticCatalog == null) { + if (resources==null) readProperties(); + if (resources==null) return defaultUseStaticCatalog; + try { + staticCatalog = resources.getString("static-catalog"); + } catch (MissingResourceException e) { + return defaultUseStaticCatalog; + } + } + + if (staticCatalog == null) { + return defaultUseStaticCatalog; + } + + return (staticCatalog.equalsIgnoreCase("true") + || staticCatalog.equalsIgnoreCase("yes") + || staticCatalog.equalsIgnoreCase("1")); + } + + /** + * Get the current use static catalog setting. + */ + public boolean getUseStaticCatalog() { + if (useStaticCatalog == null) { + useStaticCatalog = new Boolean(queryUseStaticCatalog()); + } + + return useStaticCatalog.booleanValue(); + } + + /** + * Set the use static catalog setting. + */ + public void setUseStaticCatalog(boolean useStatic) { + useStaticCatalog = new Boolean(useStatic); + } + + /** + * Get the current use static catalog setting. + * + * @deprecated No longer static; use get/set methods. + */ + public boolean staticCatalog() { + return getUseStaticCatalog(); + } + + /** + * Get a new catalog instance. + * + * This method always returns a new instance of the underlying catalog class. + */ + public Catalog getPrivateCatalog() { + Catalog catalog = staticCatalog; + + if (useStaticCatalog == null) { + useStaticCatalog = new Boolean(getUseStaticCatalog()); + } + + if (catalog == null || !useStaticCatalog.booleanValue()) { + + try { + String catalogClassName = getCatalogClassName(); + + if (catalogClassName == null) { + catalog = new Catalog(); + } else { + try { + catalog = (Catalog) Class.forName(catalogClassName).newInstance(); + } catch (ClassNotFoundException cnfe) { + debug.message(1,"Catalog class named '" + + catalogClassName + + "' could not be found. Using default."); + catalog = new Catalog(); + } catch (ClassCastException cnfe) { + debug.message(1,"Class named '" + + catalogClassName + + "' is not a Catalog. Using default."); + catalog = new Catalog(); + } + } + + catalog.setCatalogManager(this); + catalog.setupReaders(); + catalog.loadSystemCatalogs(); + } catch (Exception ex) { + ex.printStackTrace(); + } + + if (useStaticCatalog.booleanValue()) { + staticCatalog = catalog; + } + } + + return catalog; + } + + /** + * Get a catalog instance. + * + * If this manager uses static catalogs, the same static catalog will + * always be returned. Otherwise a new catalog will be returned. + */ + public Catalog getCatalog() { + Catalog catalog = staticCatalog; + + if (useStaticCatalog == null) { + useStaticCatalog = new Boolean(getUseStaticCatalog()); + } + + if (catalog == null || !useStaticCatalog.booleanValue()) { + catalog = getPrivateCatalog(); + if (useStaticCatalog.booleanValue()) { + staticCatalog = catalog; + } + } + + return catalog; + } + + /** + *

Obtain the oasisXMLCatalogPI setting from the properties.

+ * + *

In the properties, a value of 'yes', 'true', or '1' is considered + * true, anything else is false.

+ * + * @return The oasisXMLCatalogPI setting from the propertyFile or the + * defaultOasisXMLCatalogPI. + */ + public boolean queryAllowOasisXMLCatalogPI () { + String allow = System.getProperty(pAllowPI); + + if (allow == null) { + if (resources==null) readProperties(); + if (resources==null) return defaultOasisXMLCatalogPI; + try { + allow = resources.getString("allow-oasis-xml-catalog-pi"); + } catch (MissingResourceException e) { + return defaultOasisXMLCatalogPI; + } + } + + if (allow == null) { + return defaultOasisXMLCatalogPI; + } + + return (allow.equalsIgnoreCase("true") + || allow.equalsIgnoreCase("yes") + || allow.equalsIgnoreCase("1")); + } + + /** + * Get the current XML Catalog PI setting. + */ + public boolean getAllowOasisXMLCatalogPI () { + if (oasisXMLCatalogPI == null) { + oasisXMLCatalogPI = new Boolean(queryAllowOasisXMLCatalogPI()); + } + + return oasisXMLCatalogPI.booleanValue(); + } + + /** + * Set the XML Catalog PI setting + */ + public void setAllowOasisXMLCatalogPI(boolean allowPI) { + oasisXMLCatalogPI = new Boolean(allowPI); + } + + /** + * Get the current XML Catalog PI setting. + * + * @deprecated No longer static; use get/set methods. + */ + public boolean allowOasisXMLCatalogPI() { + return getAllowOasisXMLCatalogPI(); + } + + /** + * Obtain the Catalog class name setting from the properties. + * + */ + public String queryCatalogClassName () { + String className = System.getProperty(pClassname); + + if (className == null) { + if (resources==null) readProperties(); + if (resources==null) return null; + try { + return resources.getString("catalog-class-name"); + } catch (MissingResourceException e) { + return null; + } + } + + return className; + } + + /** + * Get the current Catalog class name. + */ + public String getCatalogClassName() { + if (catalogClassName == null) { + catalogClassName = queryCatalogClassName(); + } + + return catalogClassName; + } + + /** + * Set the Catalog class name. + */ + public void setCatalogClassName(String className) { + catalogClassName = className; + } + + /** + * Get the current Catalog class name. + * + * @deprecated No longer static; use get/set methods. + */ + public String catalogClassName() { + return getCatalogClassName(); + } +} Index: libxml-commons-resolver1.1-java-1.2/src/org/apache/xml/resolver/tools/NbCatalogResolver.java =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ libxml-commons-resolver1.1-java-1.2/src/org/apache/xml/resolver/tools/NbCatalogResolver.java 2009-01-30 23:02:49.000000000 +0100 @@ -0,0 +1,316 @@ +// 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.NbCatalogManager; +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 + * Norman.Walsh@Sun.COM + * + * @version 1.0 + */ +public class NbCatalogResolver 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 = NbCatalogManager.getStaticManager(); + + /** Constructor */ + public NbCatalogResolver() { + initializeCatalogs(false); + } + + /** Constructor */ + public NbCatalogResolver(boolean privateCatalog) { + initializeCatalogs(privateCatalog); + } + + /** Constructor */ + public NbCatalogResolver(NbCatalogManager 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) { + InputSource iSource = new InputSource(resolved); + iSource.setPublicId(publicId); + return iSource; + } + + 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; + } + } + } +}