0N/A/*
196N/A * reserved comment block
0N/A * DO NOT REMOVE OR ALTER!
0N/A */
0N/A/*
0N/A * Copyright 2004,2005 The Apache Software Foundation.
0N/A *
0N/A * Licensed under the Apache License, Version 2.0 (the "License");
0N/A * you may not use this file except in compliance with the License.
0N/A * You may obtain a copy of the License at
0N/A *
0N/A * http://www.apache.org/licenses/LICENSE-2.0
0N/A *
0N/A * Unless required by applicable law or agreed to in writing, software
0N/A * distributed under the License is distributed on an "AS IS" BASIS,
0N/A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0N/A * See the License for the specific language governing permissions and
0N/A * limitations under the License.
0N/A */
0N/A
0N/Apackage com.sun.org.apache.xerces.internal.util;
0N/A
0N/Aimport java.io.IOException;
0N/A
0N/Aimport org.xml.sax.InputSource;
0N/Aimport org.xml.sax.SAXException;
0N/Aimport org.xml.sax.ext.EntityResolver2;
0N/A
0N/Aimport org.w3c.dom.ls.LSInput;
0N/Aimport org.w3c.dom.ls.LSResourceResolver;
0N/A
0N/Aimport javax.xml.parsers.SAXParserFactory;
113N/A
304N/Aimport com.sun.org.apache.xerces.internal.dom.DOMInputImpl;
0N/Aimport com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl;
0N/A
0N/Aimport com.sun.org.apache.xerces.internal.xni.XNIException;
0N/Aimport com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
0N/A
0N/Aimport com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
0N/Aimport com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
0N/A
0N/Aimport com.sun.org.apache.xml.internal.resolver.Catalog;
0N/Aimport com.sun.org.apache.xml.internal.resolver.CatalogManager;
0N/Aimport com.sun.org.apache.xml.internal.resolver.readers.OASISXMLCatalogReader;
0N/Aimport com.sun.org.apache.xml.internal.resolver.readers.SAXCatalogReader;
0N/A
0N/A/**
0N/A * <p>The catalog resolver handles the resolution of external
0N/A * identifiers and URI references through XML catalogs. This
0N/A * component supports XML catalogs defined by the
0N/A * <a href="http://www.oasis-open.org/committees/entity/spec.html">
0N/A * OASIS XML Catalogs Specification</a>. It encapsulates the
0N/A * <a href="http://xml.apache.org/commons/">XML Commons</a> resolver.
0N/A * An instance of this class may be registered on the parser
0N/A * as a SAX entity resolver, as a DOM LSResourceResolver or
0N/A * as an XNI entity resolver by setting the property
0N/A * (http://apache.org/xml/properties/internal/entity-resolver).</p>
0N/A *
0N/A * <p>It is intended that this class may be used standalone to perform
0N/A * catalog resolution outside of a parsing context. It may be shared
0N/A * between several parsers and the application.</p>
0N/A *
0N/A * @author Michael Glavassevich, IBM
0N/A *
0N/A */
0N/Apublic class XMLCatalogResolver
0N/A implements XMLEntityResolver, EntityResolver2, LSResourceResolver {
0N/A
0N/A /** Internal catalog manager for Apache catalogs. **/
0N/A private CatalogManager fResolverCatalogManager = null;
0N/A
0N/A /** Internal catalog structure. **/
0N/A private Catalog fCatalog = null;
0N/A
0N/A /** An array of catalog URIs. **/
0N/A private String [] fCatalogsList = null;
0N/A
0N/A /**
0N/A * Indicates whether the list of catalogs has
0N/A * changed since it was processed.
0N/A */
0N/A private boolean fCatalogsChanged = true;
0N/A
0N/A /** Application specified prefer public setting. **/
0N/A private boolean fPreferPublic = true;
0N/A
0N/A /**
0N/A * Indicates whether the application desires that
0N/A * the parser or some other component performing catalog
0N/A * resolution should use the literal system identifier
0N/A * instead of the expanded system identifier.
0N/A */
0N/A private boolean fUseLiteralSystemId = true;
0N/A
0N/A /**
0N/A * <p>Constructs a catalog resolver with a default configuration.</p>
0N/A */
0N/A public XMLCatalogResolver () {
0N/A this(null, true);
0N/A }
0N/A
0N/A /**
0N/A * <p>Constructs a catalog resolver with the given
0N/A * list of entry files.</p>
0N/A *
0N/A * @param catalogs an ordered array list of absolute URIs
0N/A */
0N/A public XMLCatalogResolver (String [] catalogs) {
0N/A this(catalogs, true);
0N/A }
0N/A
0N/A /**
0N/A * <p>Constructs a catalog resolver with the given
0N/A * list of entry files and the preference for whether
0N/A * system or public matches are preferred.</p>
0N/A *
0N/A * @param catalogs an ordered array list of absolute URIs
0N/A * @param preferPublic the prefer public setting
0N/A */
0N/A public XMLCatalogResolver (String [] catalogs, boolean preferPublic) {
0N/A init(catalogs, preferPublic);
0N/A }
0N/A
0N/A /**
0N/A * <p>Returns the initial list of catalog entry files.</p>
0N/A *
0N/A * @return the initial list of catalog entry files
0N/A */
0N/A public final synchronized String [] getCatalogList () {
0N/A return (fCatalogsList != null)
0N/A ? (String[]) fCatalogsList.clone() : null;
0N/A }
0N/A
0N/A /**
0N/A * <p>Sets the initial list of catalog entry files.
0N/A * If there were any catalog mappings cached from
0N/A * the previous list they will be replaced by catalog
0N/A * mappings from the new list the next time the catalog
0N/A * is queried.</p>
0N/A *
0N/A * @param catalogs an ordered array list of absolute URIs
0N/A */
0N/A public final synchronized void setCatalogList (String [] catalogs) {
0N/A fCatalogsChanged = true;
0N/A fCatalogsList = (catalogs != null)
0N/A ? (String[]) catalogs.clone() : null;
0N/A }
0N/A
0N/A /**
0N/A * <p>Forces the cache of catalog mappings to be cleared.</p>
0N/A */
0N/A public final synchronized void clear () {
0N/A fCatalog = null;
0N/A }
0N/A
0N/A /**
0N/A * <p>Returns the preference for whether system or public
0N/A * matches are preferred. This is used in the absence
0N/A * of any occurence of the <code>prefer</code> attribute
0N/A * on the <code>catalog</code> entry of a catalog. If this
0N/A * property has not yet been explicitly set its value is
0N/A * <code>true</code>.</p>
0N/A *
0N/A * @return the prefer public setting
0N/A */
0N/A public final boolean getPreferPublic () {
0N/A return fPreferPublic;
0N/A }
0N/A
0N/A /**
0N/A * <p>Sets the preference for whether system or public
0N/A * matches are preferred. This is used in the absence
0N/A * of any occurence of the <code>prefer</code> attribute
0N/A * on the <code>catalog</code> entry of a catalog.</p>
0N/A *
0N/A * @param preferPublic the prefer public setting
0N/A */
0N/A public final void setPreferPublic (boolean preferPublic) {
0N/A fPreferPublic = preferPublic;
0N/A fResolverCatalogManager.setPreferPublic(preferPublic);
0N/A }
0N/A
0N/A /**
0N/A * <p>Returns the preference for whether the literal system
0N/A * identifier should be used when resolving system
0N/A * identifiers when both it and the expanded system
0N/A * identifier are available. If this property has not yet
0N/A * been explicitly set its value is <code>true</code>.</p>
0N/A *
0N/A * @return the preference for using literal system identifers
0N/A * for catalog resolution
0N/A *
0N/A * @see #setUseLiteralSystemId
0N/A */
0N/A public final boolean getUseLiteralSystemId () {
0N/A return fUseLiteralSystemId;
0N/A }
0N/A
0N/A /**
0N/A * <p>Sets the preference for whether the literal system
0N/A * identifier should be used when resolving system
0N/A * identifiers when both it and the expanded system
0N/A * identifier are available.</p>
0N/A *
0N/A * <p>The literal system identifier is the URI as it was
0N/A * provided before absolutization. It may be embedded within
0N/A * an entity. It may be provided externally or it may be the
0N/A * result of redirection. For example, redirection may
0N/A * have come from the protocol level through HTTP or from
0N/A * an application's entity resolver.</p>
0N/A *
0N/A * <p>The expanded system identifier is an absolute URI
304N/A * which is the result of resolving the literal system
0N/A * identifier against a base URI.</p>
0N/A *
0N/A * @param useLiteralSystemId the preference for using
304N/A * literal system identifers for catalog resolution
304N/A */
0N/A public final void setUseLiteralSystemId (boolean useLiteralSystemId) {
0N/A fUseLiteralSystemId = useLiteralSystemId;
304N/A }
304N/A
304N/A /**
304N/A * <p>Resolves an external entity. If the entity cannot be
0N/A * resolved, this method should return <code>null</code>. This
0N/A * method returns an input source if an entry was found in the
304N/A * catalog for the given external identifier. It should be
304N/A * overrided if other behaviour is required.</p>
304N/A *
304N/A * @param publicId the public identifier, or <code>null</code> if none was supplied
304N/A * @param systemId the system identifier
0N/A *
0N/A * @throws SAXException any SAX exception, possibly wrapping another exception
0N/A * @throws IOException thrown if some i/o error occurs
0N/A */
0N/A public InputSource resolveEntity(String publicId, String systemId)
304N/A throws SAXException, IOException {
304N/A
0N/A String resolvedId = null;
0N/A if (publicId != null && systemId != null) {
0N/A resolvedId = resolvePublic(publicId, systemId);
0N/A }
0N/A else if (systemId != null) {
0N/A resolvedId = resolveSystem(systemId);
0N/A }
304N/A
0N/A if (resolvedId != null) {
0N/A InputSource source = new InputSource(resolvedId);
0N/A source.setPublicId(publicId);
0N/A return source;
0N/A }
0N/A return null;
0N/A }
0N/A
304N/A /**
113N/A * <p>Resolves an external entity. If the entity cannot be
0N/A * resolved, this method should return <code>null</code>. This
0N/A * method returns an input source if an entry was found in the
0N/A * catalog for the given external identifier. It should be
0N/A * overrided if other behaviour is required.</p>
0N/A *
304N/A * @param name the identifier of the external entity
0N/A * @param publicId the public identifier, or <code>null</code> if none was supplied
0N/A * @param baseURI the URI with respect to which relative systemIDs are interpreted.
0N/A * @param systemId the system identifier
0N/A *
0N/A * @throws SAXException any SAX exception, possibly wrapping another exception
0N/A * @throws IOException thrown if some i/o error occurs
0N/A */
0N/A public InputSource resolveEntity(String name, String publicId,
0N/A String baseURI, String systemId) throws SAXException, IOException {
0N/A
0N/A String resolvedId = null;
0N/A
0N/A if (!getUseLiteralSystemId() && baseURI != null) {
0N/A // Attempt to resolve the system identifier against the base URI.
304N/A try {
304N/A URI uri = new URI(new URI(baseURI), systemId);
0N/A systemId = uri.toString();
0N/A }
304N/A // Ignore the exception. Fallback to the literal system identifier.
304N/A catch (URI.MalformedURIException ex) {}
304N/A }
0N/A
304N/A if (publicId != null && systemId != null) {
304N/A resolvedId = resolvePublic(publicId, systemId);
304N/A }
304N/A else if (systemId != null) {
0N/A resolvedId = resolveSystem(systemId);
0N/A }
0N/A
0N/A if (resolvedId != null) {
304N/A InputSource source = new InputSource(resolvedId);
304N/A source.setPublicId(publicId);
304N/A return source;
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A /**
0N/A * <p>Locates an external subset for documents which do not explicitly
0N/A * provide one. This method always returns <code>null</code>. It
0N/A * should be overrided if other behaviour is required.</p>
304N/A *
0N/A * @param name the identifier of the document root element
0N/A * @param baseURI the document's base URI
0N/A *
0N/A * @throws SAXException any SAX exception, possibly wrapping another exception
0N/A * @throws IOException thrown if some i/o error occurs
0N/A */
0N/A public InputSource getExternalSubset(String name, String baseURI)
0N/A throws SAXException, IOException {
0N/A return null;
0N/A }
0N/A
0N/A /**
0N/A * <p>Resolves a resource using the catalog. This method interprets that
0N/A * the namespace URI corresponds to uri entries in the catalog.
0N/A * Where both a namespace and an external identifier exist, the namespace
0N/A * takes precedence.</p>
0N/A *
304N/A * @param type the type of the resource being resolved
0N/A * @param namespaceURI the namespace of the resource being resolved,
0N/A * or <code>null</code> if none was supplied
0N/A * @param publicId the public identifier of the resource being resolved,
0N/A * or <code>null</code> if none was supplied
0N/A * @param systemId the system identifier of the resource being resolved,
304N/A * or <code>null</code> if none was supplied
0N/A * @param baseURI the absolute base URI of the resource being parsed,
0N/A * or <code>null</code> if there is no base URI
304N/A */
0N/A public LSInput resolveResource(String type, String namespaceURI,
0N/A String publicId, String systemId, String baseURI) {
0N/A
0N/A String resolvedId = null;
0N/A
0N/A try {
0N/A // The namespace is useful for resolving namespace aware
0N/A // grammars such as XML schema. Let it take precedence over
0N/A // the external identifier if one exists.
304N/A if (namespaceURI != null) {
304N/A resolvedId = resolveURI(namespaceURI);
304N/A }
304N/A
304N/A if (!getUseLiteralSystemId() && baseURI != null) {
0N/A // Attempt to resolve the system identifier against the base URI.
0N/A try {
304N/A URI uri = new URI(new URI(baseURI), systemId);
304N/A systemId = uri.toString();
0N/A }
0N/A // Ignore the exception. Fallback to the literal system identifier.
0N/A catch (URI.MalformedURIException ex) {}
0N/A }
0N/A
304N/A // Resolve against an external identifier if one exists. This
0N/A // is useful for resolving DTD external subsets and other
0N/A // external entities. For XML schemas if there was no namespace
304N/A // mapping we might be able to resolve a system identifier
0N/A // specified as a location hint.
0N/A if (resolvedId == null) {
0N/A if (publicId != null && systemId != null) {
0N/A resolvedId = resolvePublic(publicId, systemId);
0N/A }
0N/A else if (systemId != null) {
0N/A resolvedId = resolveSystem(systemId);
0N/A }
0N/A }
0N/A }
0N/A // Ignore IOException. It cannot be thrown from this method.
0N/A catch (IOException ex) {}
0N/A
0N/A if (resolvedId != null) {
0N/A return new DOMInputImpl(publicId, resolvedId, baseURI);
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * <p>Resolves an external entity. If the entity cannot be
0N/A * resolved, this method should return <code>null</code>. This
0N/A * method only calls <code>resolveIdentifier</code> and returns
0N/A * an input source if an entry was found in the catalog. It
0N/A * should be overrided if other behaviour is required.</p>
0N/A *
0N/A * @param resourceIdentifier location of the XML resource to resolve
0N/A *
0N/A * @throws XNIException thrown on general error
0N/A * @throws IOException thrown if some i/o error occurs
0N/A */
0N/A public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier)
0N/A throws XNIException, IOException {
0N/A
0N/A String resolvedId = resolveIdentifier(resourceIdentifier);
0N/A if (resolvedId != null) {
0N/A return new XMLInputSource(resourceIdentifier.getPublicId(),
0N/A resolvedId,
0N/A resourceIdentifier.getBaseSystemId());
0N/A }
0N/A return null;
304N/A }
0N/A
0N/A /**
304N/A * <p>Resolves an identifier using the catalog. This method interprets that
0N/A * the namespace of the identifier corresponds to uri entries in the catalog.
0N/A * Where both a namespace and an external identifier exist, the namespace
0N/A * takes precedence.</p>
0N/A *
0N/A * @param resourceIdentifier the identifier to resolve
0N/A *
0N/A * @throws XNIException thrown on general error
0N/A * @throws IOException thrown if some i/o error occurs
0N/A */
0N/A public String resolveIdentifier(XMLResourceIdentifier resourceIdentifier)
304N/A throws IOException, XNIException {
0N/A
304N/A String resolvedId = null;
0N/A
0N/A // The namespace is useful for resolving namespace aware
0N/A // grammars such as XML schema. Let it take precedence over
0N/A // the external identifier if one exists.
0N/A String namespace = resourceIdentifier.getNamespace();
0N/A if (namespace != null) {
0N/A resolvedId = resolveURI(namespace);
0N/A }
0N/A
0N/A // Resolve against an external identifier if one exists. This
0N/A // is useful for resolving DTD external subsets and other
0N/A // external entities. For XML schemas if there was no namespace
0N/A // mapping we might be able to resolve a system identifier
0N/A // specified as a location hint.
0N/A if (resolvedId == null) {
0N/A String publicId = resourceIdentifier.getPublicId();
0N/A String systemId = getUseLiteralSystemId()
0N/A ? resourceIdentifier.getLiteralSystemId()
0N/A : resourceIdentifier.getExpandedSystemId();
0N/A if (publicId != null && systemId != null) {
0N/A resolvedId = resolvePublic(publicId, systemId);
0N/A }
0N/A else if (systemId != null) {
0N/A resolvedId = resolveSystem(systemId);
0N/A }
0N/A }
0N/A return resolvedId;
0N/A }
0N/A
0N/A /**
0N/A * <p>Returns the URI mapping in the catalog for the given
0N/A * external identifier or <code>null</code> if no mapping
0N/A * exists. If the system identifier is an URN in the
0N/A * <code>publicid</code> namespace it is converted into
0N/A * a public identifier by URN "unwrapping" as specified
0N/A * in the XML Catalogs specification.</p>
0N/A *
0N/A * @param systemId the system identifier to locate in the catalog
304N/A *
0N/A * @return the mapped URI or <code>null</code> if no mapping
0N/A * was found in the catalog
0N/A *
0N/A * @throws IOException if an i/o error occurred while reading
0N/A * the catalog
0N/A */
0N/A public final synchronized String resolveSystem (String systemId)
304N/A throws IOException {
0N/A
0N/A if (fCatalogsChanged) {
0N/A parseCatalogs();
0N/A fCatalogsChanged = false;
304N/A }
0N/A return (fCatalog != null)
0N/A ? fCatalog.resolveSystem(systemId) : null;
304N/A }
304N/A
512N/A /**
0N/A * <p>Returns the URI mapping in the catalog for the given
0N/A * external identifier or <code>null</code> if no mapping
0N/A * exists. Public identifiers are normalized before
0N/A * comparison.</p>
0N/A *
304N/A * @param publicId the public identifier to locate in the catalog
0N/A * @param systemId the system identifier to locate in the catalog
0N/A *
0N/A * @return the mapped URI or <code>null</code> if no mapping
0N/A * was found in the catalog
0N/A *
0N/A * @throws IOException if an i/o error occurred while reading
0N/A * the catalog
0N/A */
0N/A public final synchronized String resolvePublic (String publicId, String systemId)
0N/A throws IOException {
0N/A
0N/A if (fCatalogsChanged) {
0N/A parseCatalogs();
0N/A fCatalogsChanged = false;
0N/A }
0N/A return (fCatalog != null)
0N/A ? fCatalog.resolvePublic(publicId, systemId) : null;
0N/A }
0N/A
0N/A /**
0N/A * <p>Returns the URI mapping in the catalog for the given URI
0N/A * reference or <code>null</code> if no mapping exists.
0N/A * URI comparison is case sensitive. If the URI reference
0N/A * is an URN in the <code>publicid</code> namespace
0N/A * it is converted into a public identifier by URN "unwrapping"
0N/A * as specified in the XML Catalogs specification and then
0N/A * resolution is performed following the semantics of
0N/A * external identifier resolution.</p>
0N/A *
0N/A * @param uri the URI to locate in the catalog
0N/A *
0N/A * @return the mapped URI or <code>null</code> if no mapping
0N/A * was found in the catalog
0N/A *
0N/A * @throws IOException if an i/o error occurred while reading
0N/A * the catalog
0N/A */
0N/A public final synchronized String resolveURI (String uri)
0N/A throws IOException {
0N/A
0N/A if (fCatalogsChanged) {
0N/A parseCatalogs();
0N/A fCatalogsChanged = false;
0N/A }
0N/A return (fCatalog != null)
0N/A ? fCatalog.resolveURI(uri) : null;
0N/A }
304N/A
304N/A /**
0N/A * Initialization. Create a CatalogManager and set all
0N/A * the properties upfront. This prevents JVM wide system properties
0N/A * or a property file somewhere in the environment from affecting
0N/A * the behaviour of this catalog resolver.
0N/A */
0N/A private void init (String [] catalogs, boolean preferPublic) {
0N/A fCatalogsList = (catalogs != null) ? (String[]) catalogs.clone() : null;
0N/A fPreferPublic = preferPublic;
0N/A fResolverCatalogManager = new CatalogManager();
0N/A fResolverCatalogManager.setAllowOasisXMLCatalogPI(false);
0N/A fResolverCatalogManager.setCatalogClassName("com.sun.org.apache.xml.internal.resolver.Catalog");
0N/A fResolverCatalogManager.setCatalogFiles("");
0N/A fResolverCatalogManager.setIgnoreMissingProperties(true);
0N/A fResolverCatalogManager.setPreferPublic(fPreferPublic);
0N/A fResolverCatalogManager.setRelativeCatalogs(false);
0N/A fResolverCatalogManager.setUseStaticCatalog(false);
0N/A fResolverCatalogManager.setVerbosity(0);
0N/A }
0N/A
0N/A /**
0N/A * Instruct the <code>Catalog</code> to parse each of the
0N/A * catalogs in the list. Only the first catalog will actually be
0N/A * parsed immediately. The others will be queued and read if
0N/A * they are needed later.
0N/A */
0N/A private void parseCatalogs () throws IOException {
0N/A if (fCatalogsList != null) {
0N/A fCatalog = new Catalog(fResolverCatalogManager);
0N/A attachReaderToCatalog(fCatalog);
0N/A for (int i = 0; i < fCatalogsList.length; ++i) {
0N/A String catalog = fCatalogsList[i];
0N/A if (catalog != null && catalog.length() > 0) {
0N/A fCatalog.parseCatalog(catalog);
0N/A }
0N/A }
0N/A }
0N/A else {
0N/A fCatalog = null;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Attaches the reader to the catalog.
0N/A */
0N/A private void attachReaderToCatalog (Catalog catalog) {
0N/A
0N/A SAXParserFactory spf = new SAXParserFactoryImpl();
0N/A spf.setNamespaceAware(true);
0N/A spf.setValidating(false);
0N/A
0N/A SAXCatalogReader saxReader = new SAXCatalogReader(spf);
0N/A saxReader.setCatalogParser(OASISXMLCatalogReader.namespaceName, "catalog",
0N/A "com.sun.org.apache.xml.internal.resolver.readers.OASISXMLCatalogReader");
0N/A catalog.addReader("application/xml", saxReader);
0N/A }
0N/A}
0N/A