From 92f652862f18278808e4357cf03602f997f51488 Mon Sep 17 00:00:00 2001
From: ndw
Date: Wed, 30 Jan 2002 12:25:00 +0000
Subject: [PATCH] Initial checkin of Sun Resolver 1.1 sources
git-svn-id: https://svn.apache.org/repos/asf/xml/commons/trunk@225950 13f79535-47bb-0310-9956-ffa450edef68
---
java/src/manifest.resolver | 11 +
java/src/org/apache/xml/resolver/Catalog.java | 2071 +++++++++++++++++
.../org/apache/xml/resolver/CatalogEntry.java | 289 +++
.../apache/xml/resolver/CatalogException.java | 203 ++
.../apache/xml/resolver/CatalogManager.java | 463 ++++
java/src/org/apache/xml/resolver/LICENSE | 57 +
.../src/org/apache/xml/resolver/Resolver.java | 746 ++++++
.../apache/xml/resolver/apps/XParseError.java | 200 ++
.../org/apache/xml/resolver/apps/package.html | 12 +
.../apache/xml/resolver/apps/resolver.java | 338 +++
.../org/apache/xml/resolver/apps/xparse.java | 300 +++
.../org/apache/xml/resolver/apps/xread.java | 303 +++
.../apache/xml/resolver/helpers/Debug.java | 145 ++
.../xml/resolver/helpers/Namespaces.java | 151 ++
.../apache/xml/resolver/helpers/PublicId.java | 198 ++
.../apache/xml/resolver/helpers/package.html | 12 +
.../src/org/apache/xml/resolver/overview.html | 41 +
java/src/org/apache/xml/resolver/package.html | 34 +
.../xml/resolver/readers/CatalogReader.java | 118 +
.../resolver/readers/DOMCatalogParser.java | 90 +
.../resolver/readers/DOMCatalogReader.java | 288 +++
.../readers/ExtendedXMLCatalogReader.java | 235 ++
.../readers/OASISXMLCatalogReader.java | 565 +++++
.../resolver/readers/SAXCatalogParser.java | 82 +
.../resolver/readers/SAXCatalogReader.java | 515 ++++
.../resolver/readers/SAXParserHandler.java | 187 ++
.../resolver/readers/TR9401CatalogReader.java | 179 ++
.../resolver/readers/TextCatalogReader.java | 328 +++
.../xml/resolver/readers/XCatalogReader.java | 234 ++
.../apache/xml/resolver/readers/package.html | 12 +
.../xml/resolver/tools/CatalogResolver.java | 371 +++
.../xml/resolver/tools/ResolvingParser.java | 459 ++++
.../resolver/tools/ResolvingXMLFilter.java | 370 +++
.../resolver/tools/ResolvingXMLReader.java | 107 +
.../apache/xml/resolver/tools/package.html | 47 +
35 files changed, 9761 insertions(+)
create mode 100644 java/src/manifest.resolver
create mode 100644 java/src/org/apache/xml/resolver/Catalog.java
create mode 100644 java/src/org/apache/xml/resolver/CatalogEntry.java
create mode 100644 java/src/org/apache/xml/resolver/CatalogException.java
create mode 100644 java/src/org/apache/xml/resolver/CatalogManager.java
create mode 100644 java/src/org/apache/xml/resolver/LICENSE
create mode 100644 java/src/org/apache/xml/resolver/Resolver.java
create mode 100644 java/src/org/apache/xml/resolver/apps/XParseError.java
create mode 100644 java/src/org/apache/xml/resolver/apps/package.html
create mode 100644 java/src/org/apache/xml/resolver/apps/resolver.java
create mode 100644 java/src/org/apache/xml/resolver/apps/xparse.java
create mode 100644 java/src/org/apache/xml/resolver/apps/xread.java
create mode 100644 java/src/org/apache/xml/resolver/helpers/Debug.java
create mode 100644 java/src/org/apache/xml/resolver/helpers/Namespaces.java
create mode 100644 java/src/org/apache/xml/resolver/helpers/PublicId.java
create mode 100644 java/src/org/apache/xml/resolver/helpers/package.html
create mode 100644 java/src/org/apache/xml/resolver/overview.html
create mode 100644 java/src/org/apache/xml/resolver/package.html
create mode 100644 java/src/org/apache/xml/resolver/readers/CatalogReader.java
create mode 100644 java/src/org/apache/xml/resolver/readers/DOMCatalogParser.java
create mode 100644 java/src/org/apache/xml/resolver/readers/DOMCatalogReader.java
create mode 100644 java/src/org/apache/xml/resolver/readers/ExtendedXMLCatalogReader.java
create mode 100644 java/src/org/apache/xml/resolver/readers/OASISXMLCatalogReader.java
create mode 100644 java/src/org/apache/xml/resolver/readers/SAXCatalogParser.java
create mode 100644 java/src/org/apache/xml/resolver/readers/SAXCatalogReader.java
create mode 100644 java/src/org/apache/xml/resolver/readers/SAXParserHandler.java
create mode 100644 java/src/org/apache/xml/resolver/readers/TR9401CatalogReader.java
create mode 100644 java/src/org/apache/xml/resolver/readers/TextCatalogReader.java
create mode 100644 java/src/org/apache/xml/resolver/readers/XCatalogReader.java
create mode 100644 java/src/org/apache/xml/resolver/readers/package.html
create mode 100644 java/src/org/apache/xml/resolver/tools/CatalogResolver.java
create mode 100644 java/src/org/apache/xml/resolver/tools/ResolvingParser.java
create mode 100644 java/src/org/apache/xml/resolver/tools/ResolvingXMLFilter.java
create mode 100644 java/src/org/apache/xml/resolver/tools/ResolvingXMLReader.java
create mode 100644 java/src/org/apache/xml/resolver/tools/package.html
diff --git a/java/src/manifest.resolver b/java/src/manifest.resolver
new file mode 100644
index 0000000..e6c6b14
--- /dev/null
+++ b/java/src/manifest.resolver
@@ -0,0 +1,11 @@
+Manifest-Version: 1.0
+Created-By: 1.2.2 (Sun Microsystems Inc.)
+Main-Class: org.apache.xml.resolver.Catalog
+
+Name: org/apache/xml/resolver
+Comment: xml-commons Resolver code
+Implementation-Title: org.apache.xml.resolver.Catalog
+Implementation-Version: 1.0
+Implementation-Vendor: Apache Software Foundation
+Implementation-URL: http://xml.apache.org/commons/
+
diff --git a/java/src/org/apache/xml/resolver/Catalog.java b/java/src/org/apache/xml/resolver/Catalog.java
new file mode 100644
index 0000000..875643c
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/Catalog.java
@@ -0,0 +1,2071 @@
+// Catalog.java - Represents OASIS Open Catalog files.
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver;
+
+import java.lang.Integer;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.io.File;
+import java.io.DataInputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.net.URL;
+import java.net.MalformedURLException;
+import org.apache.xml.resolver.CatalogManager;
+import org.apache.xml.resolver.helpers.Debug;
+import org.apache.xml.resolver.helpers.PublicId;
+import org.apache.xml.resolver.readers.CatalogReader;
+import org.apache.xml.resolver.readers.SAXCatalogReader;
+import org.apache.xml.resolver.readers.TR9401CatalogReader;
+import org.apache.xml.resolver.readers.OASISXMLCatalogReader;
+import javax.xml.parsers.SAXParserFactory;
+
+/**
+ * Represents OASIS Open Catalog files.
+ *
+ * This class implements the semantics of OASIS Open Catalog files
+ * (defined by
+ * OASIS Technical
+ * Resolution 9401:1997 (Amendment 2 to TR 9401)).
+ *
+ * The primary purpose of the Catalog is to associate resources in the
+ * document with local system identifiers. Some entities
+ * (document types, XML entities, and notations) have names and all of them
+ * can have either public or system identifiers or both. (In XML, only a
+ * notation can have a public identifier without a system identifier, but
+ * the methods implemented in this class obey the Catalog semantics
+ * from the SGML
+ * days when system identifiers were optional.)
+ *
+ * The system identifiers returned by the resolution methods in this
+ * class are valid, i.e. usable by, and in fact constructed by, the
+ * java.net.URL class. Unfortunately, this class seems to behave in
+ * somewhat non-standard ways and the system identifiers returned may
+ * not be directly usable in a browser or filesystem context.
+ *
+ *
This class recognizes all of the Catalog entries defined in
+ * TR9401:1997:
+ *
+ *
+ * - BASE
+ * changes the base URI for resolving relative system identifiers. The
+ * initial base URI is the URI of the location of the catalog (which is,
+ * in turn, relative to the location of the current working directory
+ * at startup, as returned by the user.dir system property).
+ * - CATALOG
+ * processes other catalog files. An included catalog occurs logically
+ * at the end of the including catalog.
+ * - DELEGATE_PUBLIC
+ * specifies alternate catalogs for some public identifiers. The delegated
+ * catalogs are not loaded until they are needed, but they are cached
+ * once loaded.
+ * - DELEGATE_SYSTEM
+ * specifies alternate catalogs for some system identifiers. The delegated
+ * catalogs are not loaded until they are needed, but they are cached
+ * once loaded.
+ * - DELEGATE_URI
+ * specifies alternate catalogs for some URIs. The delegated
+ * catalogs are not loaded until they are needed, but they are cached
+ * once loaded.
+ * - REWRITE_SYSTEM
+ * specifies alternate prefix for a system identifier.
+ * - REWRITE_URI
+ * specifies alternate prefix for a URI.
+ * - DOCTYPE
+ * associates the names of root elements with URIs. (In other words, an XML
+ * processor might infer the doctype of an XML document that does not include
+ * a doctype declaration by looking for the DOCTYPE entry in the
+ * catalog which matches the name of the root element of the document.)
+ * - DOCUMENT
+ * provides a default document.
+ * - DTDDECL
+ * recognized and silently ignored. Not relevant for XML.
+ * - ENTITY
+ * associates entity names with URIs.
+ * - LINKTYPE
+ * recognized and silently ignored. Not relevant for XML.
+ * - NOTATION
+ * associates notation names with URIs.
+ * - OVERRIDE
+ * changes the override behavior. Initial behavior is set by the
+ * system property xml.catalog.override. The default initial
+ * behavior is 'YES', that is, entries in the catalog override
+ * system identifiers specified in the document.
+ * - PUBLIC
+ * maps a public identifier to a system identifier.
+ * - SGMLDECL
+ * recognized and silently ignored. Not relevant for XML.
+ * - SYSTEM
+ * maps a system identifier to another system identifier.
+ * - URI
+ * maps a URI to another URI.
+ *
+ *
+ * Note that BASE entries are treated as described by RFC2396. In
+ * particular, this has the counter-intuitive property that after a BASE
+ * entry identifing "http://example.com/a/b/c" as the base URI,
+ * the relative URI "foo" is resolved to the absolute URI
+ * "http://example.com/a/b/foo". You must provide the trailing slash if
+ * you do not want the final component of the path to be discarded as a
+ * filename would in a URI for a resource: "http://example.com/a/b/c/".
+ *
+ *
+ * Note that subordinate catalogs (all catalogs except the first,
+ * including CATALOG and DELEGATE* catalogs) are only loaded if and when
+ * they are required.
+ *
+ * This class relies on classes which implement the CatalogReader
+ * interface to actually load catalog files. This allows the catalog
+ * semantics to be implemented for TR9401 text-based catalogs, XML
+ * catalogs, or any number of other storage formats.
+ *
+ * Additional catalogs may also be loaded with the
+ * {@link #parseCatalog} method.
+ *
+ *
+ *
+ * Change Log:
+ *
+ * - 2.0
+ * Rewrite to use CatalogReaders.
+ * - 1.1
+ * Allow quoted components in xml.catalog.files
+ * so that URLs containing colons can be used on Unix.
+ * The string passed to xml.catalog.files can now have the form:
+ *
+ * unquoted-path-with-no-sep-chars:"double-quoted path with or without sep chars":'single-quoted path with or without sep chars'
+ *
+ * (Where ":" is the separater character in this example.)
+ * If an unquoted path contains an embedded double or single quote
+ * character, no special processig is performed on that character. No
+ * path can contain separater characters, double, and single quotes
+ * simultaneously.
+ * Fix bug in calculation of BASE entries: if
+ * a catalog contains multiple BASE entries, each is relative to the preceding
+ * base, not the default base URI of the catalog.
+ *
+ * - 1.0.1
+ * Fixed a bug in the calculation of the list of subordinate catalogs.
+ * This bug caused an infinite loop where parsing would alternately process
+ * two catalogs indefinitely.
+ *
+ *
+ *
+ * @see CatalogReader
+ * @see CatalogEntry
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ *
+ * Derived from public domain code originally published by Arbortext,
+ * Inc.
+ */
+public class Catalog {
+ /** The BASE Catalog Entry type */
+ public static final int BASE = CatalogEntry.addEntryType("BASE", 1);
+
+ /** The CATALOG Catalog Entry type */
+ public static final int CATALOG = CatalogEntry.addEntryType("CATALOG", 1);
+
+ /** The DOCUMENT Catalog Entry type */
+ public static final int DOCUMENT = CatalogEntry.addEntryType("DOCUMENT", 1);
+
+ /** The OVERRIDE Catalog Entry type */
+ public static final int OVERRIDE = CatalogEntry.addEntryType("OVERRIDE", 1);
+
+ /** The SGMLDECL Catalog Entry type */
+ public static final int SGMLDECL = CatalogEntry.addEntryType("SGMLDECL", 1);
+
+ /** The DELEGATE_PUBLIC Catalog Entry type */
+ public static final int DELEGATE_PUBLIC = CatalogEntry.addEntryType("DELEGATE_PUBLIC", 2);
+
+ /** The DELEGATE_SYSTEM Catalog Entry type */
+ public static final int DELEGATE_SYSTEM = CatalogEntry.addEntryType("DELEGATE_SYSTEM", 2);
+
+ /** The DELEGATE_URI Catalog Entry type */
+ public static final int DELEGATE_URI = CatalogEntry.addEntryType("DELEGATE_URI", 2);
+
+ /** The DOCTYPE Catalog Entry type */
+ public static final int DOCTYPE = CatalogEntry.addEntryType("DOCTYPE", 2);
+
+ /** The DTDDECL Catalog Entry type */
+ public static final int DTDDECL = CatalogEntry.addEntryType("DTDDECL", 2);
+
+ /** The ENTITY Catalog Entry type */
+ public static final int ENTITY = CatalogEntry.addEntryType("ENTITY", 2);
+
+ /** The LINKTYPE Catalog Entry type */
+ public static final int LINKTYPE = CatalogEntry.addEntryType("LINKTYPE", 2);
+
+ /** The NOTATION Catalog Entry type */
+ public static final int NOTATION = CatalogEntry.addEntryType("NOTATION", 2);
+
+ /** The PUBLIC Catalog Entry type */
+ public static final int PUBLIC = CatalogEntry.addEntryType("PUBLIC", 2);
+
+ /** The SYSTEM Catalog Entry type */
+ public static final int SYSTEM = CatalogEntry.addEntryType("SYSTEM", 2);
+
+ /** The URI Catalog Entry type */
+ public static final int URI = CatalogEntry.addEntryType("URI", 2);
+
+ /** The REWRITE_SYSTEM Catalog Entry type */
+ public static final int REWRITE_SYSTEM = CatalogEntry.addEntryType("REWRITE_SYSTEM", 2);
+
+ /** The REWRITE_URI Catalog Entry type */
+ public static final int REWRITE_URI = CatalogEntry.addEntryType("REWRITE_URI", 2);
+
+ /**
+ * The base URI for relative system identifiers in the catalog.
+ * This may be changed by BASE entries in the catalog.
+ */
+ protected URL base;
+
+ /** The base URI of the Catalog file currently being parsed. */
+ protected URL catalogCwd;
+
+ /** The catalog entries currently known to the system. */
+ protected Vector catalogEntries = new Vector();
+
+ /** The default initial override setting. */
+ protected boolean default_override = true;
+
+ /**
+ * A vector of catalog files to be loaded.
+ *
+ * This list is initially established by
+ * loadSystemCatalogs when
+ * it parses the system catalog list, but CATALOG entries may
+ * contribute to it during the course of parsing.
+ *
+ * @see #loadSystemCatalogs
+ * @see #localCatalogFiles
+ */
+ protected Vector catalogFiles = new Vector();
+
+ /**
+ * A vector of catalog files constructed during processing of
+ * CATALOG entries in the current catalog.
+ *
+ * This two-level system is actually necessary to correctly implement
+ * the semantics of the CATALOG entry. If one catalog file includes
+ * another with a CATALOG entry, the included catalog logically
+ * occurs at the end of the including catalog, and after any
+ * preceding CATALOG entries. In other words, the CATALOG entry
+ * cannot insert anything into the middle of a catalog file.
+ *
+ * When processing reaches the end of each catalog files, any
+ * elements on this vector are added to the front of the
+ * catalogFiles vector.
+ *
+ * @see #catalogFiles
+ */
+ protected Vector localCatalogFiles = new Vector();
+
+ /**
+ * A vector of Catalogs.
+ *
+ * The semantics of Catalog resolution are such that each
+ * catalog is effectively a list of Catalogs (in other words,
+ * a recursive list of Catalog instances).
+ *
+ * Catalogs that are processed as the result of CATALOG or
+ * DELEGATE* entries are subordinate to the catalog that contained
+ * them, but they may in turn have subordinate catalogs.
+ *
+ * Catalogs are only loaded when they are needed, so this vector
+ * initially contains a list of Catalog filenames (URLs). If, during
+ * processing, one of these catalogs has to be loaded, the resulting
+ * Catalog object is placed in the vector, effectively caching it
+ * for the next query.
+ */
+ protected Vector catalogs = new Vector();
+
+ /**
+ * A vector of DELEGATE* Catalog entries constructed during
+ * processing of the Catalog.
+ *
+ * This two-level system has two purposes; first, it allows
+ * us to sort the DELEGATE* entries by the length of the partial
+ * public identifier so that a linear search encounters them in
+ * the correct order and second, it puts them all at the end of
+ * the Catalog.
+ *
+ * When processing reaches the end of each catalog file, any
+ * elements on this vector are added to the end of the
+ * catalogEntries vector. This assures that matching
+ * PUBLIC keywords are encountered before DELEGATE* entries.
+ */
+ protected Vector localDelegate = new Vector();
+
+ /**
+ * A hash of CatalogReaders.
+ *
+ * This hash maps MIME types to elements in the readerArr
+ * vector. This allows the Catalog to quickly locate the reader
+ * for a particular MIME type.
+ */
+ protected Hashtable readerMap = new Hashtable();
+
+ /**
+ * A vector of CatalogReaders.
+ *
+ * This vector contains all of the readers in the order that they
+ * were added. In the event that a catalog is read from a file, where
+ * the MIME type is unknown, each reader is attempted in turn until
+ * one succeeds.
+ */
+ protected Vector readerArr = new Vector();
+
+ /**
+ * Setup readers.
+ */
+ public void setupReaders() {
+ SAXParserFactory spf = SAXParserFactory.newInstance();
+ spf.setNamespaceAware(true);
+ spf.setValidating(false);
+
+ SAXCatalogReader saxReader = new SAXCatalogReader(spf);
+
+ saxReader.setCatalogParser(null, "XMLCatalog",
+ "org.apache.xml.resolver.readers.XCatalogReader");
+
+ saxReader.setCatalogParser(OASISXMLCatalogReader.namespaceName,
+ "catalog",
+ "org.apache.xml.resolver.readers.OASISXMLCatalogReader");
+
+ addReader("application/xml", saxReader);
+
+ TR9401CatalogReader textReader = new TR9401CatalogReader();
+ addReader("text/plain", textReader);
+ }
+
+ /**
+ * Add a new CatalogReader to the Catalog.
+ *
+ * This method allows you to add a new CatalogReader to the
+ * catalog. The reader will be associated with the specified mimeType.
+ * You can only have one reader per mimeType.
+ *
+ * In the absence of a mimeType (e.g., when reading a catalog
+ * directly from a file on the local system), the readers are attempted
+ * in the order that you add them to the Catalog.
+ *
+ * Note that subordinate catalogs (created by CATALOG or
+ * DELEGATE* entries) get a copy of the set of readers present in
+ * the primary catalog when they are created. Readers added subsequently
+ * will not be available. For this reason, it is best to add all
+ * of the readers before the first call to parse a catalog.
+ *
+ * @param mimeType The MIME type associated with this reader.
+ * @param reader The CatalogReader to use.
+ */
+ public void addReader(String mimeType, CatalogReader reader) {
+ if (readerMap.contains(mimeType)) {
+ Integer pos = (Integer) readerMap.get(mimeType);
+ readerArr.set(pos.intValue(), reader);
+ } else {
+ readerArr.add(reader);
+ Integer pos = new Integer(readerArr.size()-1);
+ readerMap.put(mimeType, pos);
+ }
+ }
+
+ /**
+ * Copies the reader list from the current Catalog to a new Catalog
+ *
+ * This method is used internally when constructing a new catalog.
+ * It copies the current reader associations over to the new catalog.
+ *
+ *
+ * @param newCatalog The new Catalog.
+ */
+ protected void copyReaders(Catalog newCatalog) {
+ // Have to copy the readers in the right order...convert hash to arr
+ Vector mapArr = new Vector(readerMap.size());
+
+ // Pad the mapArr out to the right length
+ for (int count = 0; count < readerMap.size(); count++) {
+ mapArr.add(null);
+ }
+
+ Enumeration enum = readerMap.keys();
+ while (enum.hasMoreElements()) {
+ String mimeType = (String) enum.nextElement();
+ Integer pos = (Integer) readerMap.get(mimeType);
+ mapArr.set(pos.intValue(), mimeType);
+ }
+
+ for (int count = 0; count < mapArr.size(); count++) {
+ String mimeType = (String) mapArr.get(count);
+ Integer pos = (Integer) readerMap.get(mimeType);
+ newCatalog.addReader(mimeType,
+ (CatalogReader)
+ readerArr.get(pos.intValue()));
+ }
+ }
+
+ /**
+ * Create a new Catalog object.
+ *
+ * This method constructs a new instance of the running Catalog
+ * class (which might be a subtype of org.apache.xml.resolver.Catalog).
+ *
+ *
+ * N.B. All Catalog subtypes should call newCatalog() to construct
+ * a new Catalog. Do not simply use "new Subclass()" since that will
+ * confuse future subclasses.
+ */
+ protected Catalog newCatalog() {
+ String catalogClass = this.getClass().getName();
+
+ try {
+ Catalog c = (Catalog) (Class.forName(catalogClass).newInstance());
+ copyReaders(c);
+ return c;
+ } catch (ClassNotFoundException cnfe) {
+ Debug.message(1, "Class Not Found Exception: " + catalogClass);
+ } catch (IllegalAccessException iae) {
+ Debug.message(1, "Illegal Access Exception: " + catalogClass);
+ } catch (InstantiationException ie) {
+ Debug.message(1, "Instantiation Exception: " + catalogClass);
+ } catch (ClassCastException cce) {
+ Debug.message(1, "Class Cast Exception: " + catalogClass);
+ } catch (Exception e) {
+ Debug.message(1, "Other Exception: " + catalogClass);
+ }
+
+ Catalog c = new Catalog();
+ copyReaders(c);
+ return c;
+ }
+
+ /**
+ * Constructs an empty Catalog.
+ *
+ * The constructor interrogates the relevant system properties
+ * and initializes the catalog data structures.
+ */
+ public Catalog() {
+ default_override = CatalogManager.preferPublic();
+ }
+
+ /**
+ * Returns the current base URI.
+ */
+ public String getCurrentBase() {
+ return base.toString();
+ }
+
+ /**
+ * Returns the default override setting associated with this
+ * catalog.
+ *
+ * All catalog files loaded by this catalog will have the
+ * initial override setting specified by this default.
+ */
+ public String getDefaultOverride() {
+ if (default_override) {
+ return "yes";
+ } else {
+ return "no";
+ }
+ }
+
+ /**
+ * Load the system catalog files.
+ *
+ * The method adds all of the
+ * catalogs specified in the xml.catalog.files property
+ * to the Catalog list.
+ *
+ * @throws MalformedURLException One of the system catalogs is
+ * identified with a filename that is not a valid URL.
+ * @throws IOException One of the system catalogs cannot be read.
+ */
+ public void loadSystemCatalogs()
+ throws MalformedURLException, IOException {
+ Vector catalogs = CatalogManager.catalogFiles();
+ if (catalogs != null) {
+ for (int count = 0; count < catalogs.size(); count++) {
+ catalogFiles.addElement(catalogs.elementAt(count));
+ }
+ }
+
+ if (catalogFiles.size() > 0) {
+ // This is a little odd. The parseCatalog() method expects
+ // a filename, but it adds that name to the end of the
+ // catalogFiles vector, and then processes that vector.
+ // This allows the system to handle CATALOG entries
+ // correctly.
+ //
+ // In this init case, we take the last element off the
+ // catalogFiles vector and pass it to parseCatalog. This
+ // will "do the right thing" in the init case, and allow
+ // parseCatalog() to do the right thing in the non-init
+ // case. Honest.
+ //
+ String catfile = (String) catalogFiles.lastElement();
+ catalogFiles.removeElement(catfile);
+ parseCatalog(catfile);
+ }
+ }
+
+ /**
+ * Parse a catalog file, augmenting internal data structures
+ *
+ * @param fileName The filename of the catalog file to process
+ *
+ * @throws MalformedURLException The fileName cannot be turned into
+ * a valid URL.
+ * @throws IOException Error reading catalog file.
+ */
+ public synchronized void parseCatalog(String fileName)
+ throws MalformedURLException, IOException {
+
+ Debug.message(4, "Parse catalog: " + fileName);
+
+ // Put the file into the list of catalogs to process...
+ // In all cases except the case when initCatalog() is the
+ // caller, this will be the only catalog initially in the list...
+ catalogFiles.addElement(fileName);
+
+ // Now process all the pending catalogs...
+ parsePendingCatalogs();
+ }
+
+ /**
+ * Parse a catalog file, augmenting internal data structures
+ *
+ * Catalogs retrieved over the net may have an associated MIME type.
+ * The MIME type can be used to select an appropriate reader.
+ *
+ * @param mimeType The MIME type of the catalog file.
+ * @param is The InputStream from which the catalog should be read
+ *
+ * @throws CatalogException Failed to load catalog
+ * mimeType.
+ * @throws IOException Error reading catalog file.
+ */
+ public synchronized void parseCatalog(String mimeType, InputStream is)
+ throws IOException, CatalogException {
+
+ Debug.message(4, "Parse " + mimeType + " catalog on input stream");
+
+ CatalogReader reader = null;
+
+ if (readerMap.containsKey(mimeType)) {
+ int arrayPos = ((Integer) readerMap.get(mimeType)).intValue();
+ reader = (CatalogReader) readerArr.get(arrayPos);
+ }
+
+ if (reader == null) {
+ String msg = "No CatalogReader for MIME type: " + mimeType;
+ Debug.message(2, msg);
+ throw new CatalogException(CatalogException.UNPARSEABLE, msg);
+ }
+
+ reader.readCatalog(this, is);
+
+ // Now process all the pending catalogs...
+ parsePendingCatalogs();
+ }
+
+ /**
+ * Parse all of the pending catalogs.
+ *
+ * Catalogs may refer to other catalogs, this method parses
+ * all of the currently pending catalog files.
+ */
+ protected synchronized void parsePendingCatalogs()
+ throws MalformedURLException, IOException {
+
+ if (!localCatalogFiles.isEmpty()) {
+ // Move all the localCatalogFiles into the front of
+ // the catalogFiles queue
+ Vector newQueue = new Vector();
+ Enumeration q = localCatalogFiles.elements();
+ while (q.hasMoreElements()) {
+ newQueue.addElement(q.nextElement());
+ }
+
+ // Put the rest of the catalogs on the end of the new list
+ for (int curCat = 0; curCat < catalogFiles.size(); curCat++) {
+ String catfile = (String) catalogFiles.elementAt(curCat);
+ newQueue.addElement(catfile);
+ }
+
+ catalogFiles = newQueue;
+ localCatalogFiles.clear();
+ }
+
+ // Suppose there are no catalog files to process, but the
+ // single catalog already parsed included some delegate
+ // entries? Make sure they don't get lost.
+ if (catalogFiles.isEmpty() && !localDelegate.isEmpty()) {
+ Enumeration e = localDelegate.elements();
+ while (e.hasMoreElements()) {
+ catalogEntries.addElement(e.nextElement());
+ }
+ localDelegate.clear();
+ }
+
+ // Now process all the files on the catalogFiles vector. This
+ // vector can grow during processing if CATALOG entries are
+ // encountered in the catalog
+ while (!catalogFiles.isEmpty()) {
+ String catfile = (String) catalogFiles.elementAt(0);
+ try {
+ catalogFiles.remove(0);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // can't happen
+ }
+
+ if (catalogEntries.size() == 0 && catalogs.size() == 0) {
+ // We haven't parsed any catalogs yet, let this
+ // catalog be the first...
+ try {
+ parseCatalogFile(catfile);
+ } catch (CatalogException ce) {
+ System.out.println("FIXME: " + ce.toString());
+ }
+ } else {
+ // This is a subordinate catalog. We save its name,
+ // but don't bother to load it unless it's necessary.
+ catalogs.addElement(catfile);
+ }
+
+ if (!localCatalogFiles.isEmpty()) {
+ // Move all the localCatalogFiles into the front of
+ // the catalogFiles queue
+ Vector newQueue = new Vector();
+ Enumeration q = localCatalogFiles.elements();
+ while (q.hasMoreElements()) {
+ newQueue.addElement(q.nextElement());
+ }
+
+ // Put the rest of the catalogs on the end of the new list
+ for (int curCat = 0; curCat < catalogFiles.size(); curCat++) {
+ catfile = (String) catalogFiles.elementAt(curCat);
+ newQueue.addElement(catfile);
+ }
+
+ catalogFiles = newQueue;
+ localCatalogFiles.clear();
+ }
+
+ if (!localDelegate.isEmpty()) {
+ Enumeration e = localDelegate.elements();
+ while (e.hasMoreElements()) {
+ catalogEntries.addElement(e.nextElement());
+ }
+ localDelegate.clear();
+ }
+ }
+
+ // We've parsed them all, reinit the vector...
+ catalogFiles.clear();
+ }
+
+ /**
+ * Parse a single catalog file, augmenting internal data structures
+ *
+ * @param fileName The filename of the catalog file to process
+ *
+ * @throws MalformedURLException The fileName cannot be turned into
+ * a valid URL.
+ * @throws IOException Error reading catalog file.
+ */
+ protected synchronized void parseCatalogFile(String fileName)
+ throws MalformedURLException, IOException, CatalogException {
+
+ CatalogEntry entry;
+
+ // The base-base is the cwd. If the catalog file is specified
+ // with a relative path, this assures that it gets resolved
+ // properly...
+ try {
+ // tack on a basename because URLs point to files not dirs
+ String userdir = fixSlashes(System.getProperty("user.dir"));
+ catalogCwd = new URL("file:///" + userdir + "/basename");
+ } catch (MalformedURLException e) {
+ String userdir = fixSlashes(System.getProperty("user.dir"));
+ Debug.message(1, "Malformed URL on cwd", userdir);
+ catalogCwd = null;
+ }
+
+ // The initial base URI is the location of the catalog file
+ try {
+ base = new URL(catalogCwd, fixSlashes(fileName));
+ } catch (MalformedURLException e) {
+ try {
+ base = new URL("file:///" + fixSlashes(fileName));
+ } catch (MalformedURLException e2) {
+ Debug.message(1, "Malformed URL on catalog filename",
+ fixSlashes(fileName));
+ base = null;
+ }
+ }
+
+ Debug.message(2, "Loading catalog", fileName);
+ Debug.message(4, "Default BASE", base.toString());
+
+ fileName = base.toString();
+
+ DataInputStream inStream = null;
+ boolean parsed = false;
+ boolean notFound = false;
+
+ for (int count = 0; !parsed && count < readerArr.size(); count++) {
+ CatalogReader reader = (CatalogReader) readerArr.get(count);
+
+ try {
+ notFound = false;
+ inStream = new DataInputStream(base.openStream());
+ } catch (FileNotFoundException fnfe) {
+ // No catalog; give up!
+ notFound = true;
+ break;
+ }
+
+ try {
+ reader.readCatalog(this, inStream);
+ parsed = true;
+ } catch (CatalogException ce) {
+ if (ce.getExceptionType() == CatalogException.PARSE_FAILED) {
+ // give up!
+ break;
+ } else {
+ // try again!
+ }
+ }
+
+ try {
+ inStream.close();
+ } catch (IOException e) {
+ //nop
+ }
+ }
+
+ if (!parsed) {
+ if (notFound) {
+ Debug.message(3, "Catalog does not exist", fileName);
+ } else {
+ Debug.message(1, "Failed to parse catalog", fileName);
+ }
+ }
+ }
+
+ /**
+ * Cleanup and process a Catalog entry.
+ *
+ * This method processes each Catalog entry, changing mapped
+ * relative system identifiers into absolute ones (based on the current
+ * base URI), and maintaining other information about the current
+ * catalog.
+ *
+ * @param entry The CatalogEntry to process.
+ */
+ public void addEntry(CatalogEntry entry) {
+ int type = entry.getEntryType();
+
+ if (type == BASE) {
+ String value = entry.getEntryArg(0);
+ URL newbase = null;
+
+ Debug.message(5, "BASE CUR", base.toString());
+ Debug.message(4, "BASE STR", value);
+
+ try {
+ value = fixSlashes(value);
+ newbase = new URL(base, value);
+ } catch (MalformedURLException e) {
+ try {
+ newbase = new URL("file:///" + value);
+ } catch (MalformedURLException e2) {
+ Debug.message(1, "Malformed URL on base", value);
+ newbase = null;
+ }
+ }
+
+ if (newbase != null) {
+ base = newbase;
+ }
+
+ Debug.message(5, "BASE NEW", base.toString());
+ } else if (type == CATALOG) {
+ String fsi = makeAbsolute(entry.getEntryArg(0));
+
+ Debug.message(4, "CATALOG", fsi);
+
+ localCatalogFiles.addElement(fsi);
+ } else if (type == PUBLIC) {
+ String publicid = PublicId.normalize(entry.getEntryArg(0));
+ String systemid = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
+
+ entry.setEntryArg(0, publicid);
+ entry.setEntryArg(1, systemid);
+
+ Debug.message(4, "PUBLIC", publicid, systemid);
+
+ catalogEntries.addElement(entry);
+ } else if (type == SYSTEM) {
+ String systemid = normalizeURI(entry.getEntryArg(0));
+ String fsi = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
+
+ entry.setEntryArg(1, fsi);
+
+ Debug.message(4, "SYSTEM", systemid, fsi);
+
+ catalogEntries.addElement(entry);
+ } else if (type == URI) {
+ String uri = normalizeURI(entry.getEntryArg(0));
+ String altURI = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
+
+ entry.setEntryArg(1, altURI);
+
+ Debug.message(4, "URI", uri, altURI);
+
+ catalogEntries.addElement(entry);
+ } else if (type == DOCUMENT) {
+ String fsi = makeAbsolute(normalizeURI(entry.getEntryArg(0)));
+ entry.setEntryArg(0, fsi);
+
+ Debug.message(4, "DOCUMENT", fsi);
+
+ catalogEntries.addElement(entry);
+ } else if (type == OVERRIDE) {
+ Debug.message(4, "OVERRIDE", entry.getEntryArg(0));
+
+ catalogEntries.addElement(entry);
+ } else if (type == SGMLDECL) {
+ // meaningless in XML
+ String fsi = makeAbsolute(normalizeURI(entry.getEntryArg(0)));
+ entry.setEntryArg(0, fsi);
+
+ Debug.message(4, "SGMLDECL", fsi);
+
+ catalogEntries.addElement(entry);
+ } else if (type == DELEGATE_PUBLIC) {
+ String ppi = PublicId.normalize(entry.getEntryArg(0));
+ String fsi = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
+
+ entry.setEntryArg(0, ppi);
+ entry.setEntryArg(1, fsi);
+
+ Debug.message(4, "DELEGATE_PUBLIC", ppi, fsi);
+
+ addDelegate(entry);
+ } else if (type == DELEGATE_SYSTEM) {
+ String psi = normalizeURI(entry.getEntryArg(0));
+ String fsi = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
+
+ entry.setEntryArg(0, psi);
+ entry.setEntryArg(1, fsi);
+
+ Debug.message(4, "DELEGATE_SYSTEM", psi, fsi);
+
+ addDelegate(entry);
+ } else if (type == DELEGATE_URI) {
+ String pui = normalizeURI(entry.getEntryArg(0));
+ String fsi = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
+
+ entry.setEntryArg(0, pui);
+ entry.setEntryArg(1, fsi);
+
+ Debug.message(4, "DELEGATE_URI", pui, fsi);
+
+ addDelegate(entry);
+ } else if (type == REWRITE_SYSTEM) {
+ String psi = normalizeURI(entry.getEntryArg(0));
+ String rpx = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
+
+ entry.setEntryArg(0, psi);
+ entry.setEntryArg(1, rpx);
+
+ Debug.message(4, "REWRITE_SYSTEM", psi, rpx);
+
+ catalogEntries.addElement(entry);
+ } else if (type == REWRITE_URI) {
+ String pui = normalizeURI(entry.getEntryArg(0));
+ String upx = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
+
+ entry.setEntryArg(0, pui);
+ entry.setEntryArg(1, upx);
+
+ Debug.message(4, "REWRITE_URI", pui, upx);
+
+ catalogEntries.addElement(entry);
+ } else if (type == DOCTYPE) {
+ String fsi = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
+ entry.setEntryArg(1, fsi);
+
+ Debug.message(4, "DOCTYPE", entry.getEntryArg(0), fsi);
+
+ catalogEntries.addElement(entry);
+ } else if (type == DTDDECL) {
+ // meaningless in XML
+ String fpi = PublicId.normalize(entry.getEntryArg(0));
+ entry.setEntryArg(0, fpi);
+ String fsi = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
+ entry.setEntryArg(1, fsi);
+
+ Debug.message(4, "DTDDECL", fpi, fsi);
+
+ catalogEntries.addElement(entry);
+ } else if (type == ENTITY) {
+ String fsi = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
+ entry.setEntryArg(1, fsi);
+
+ Debug.message(4, "ENTITY", entry.getEntryArg(0), fsi);
+
+ catalogEntries.addElement(entry);
+ } else if (type == LINKTYPE) {
+ // meaningless in XML
+ String fsi = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
+ entry.setEntryArg(1, fsi);
+
+ Debug.message(4, "LINKTYPE", entry.getEntryArg(0), fsi);
+
+ catalogEntries.addElement(entry);
+ } else if (type == NOTATION) {
+ String fsi = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
+ entry.setEntryArg(1, fsi);
+
+ Debug.message(4, "NOTATION", entry.getEntryArg(0), fsi);
+
+ catalogEntries.addElement(entry);
+ } else {
+ catalogEntries.addElement(entry);
+ }
+ }
+
+ /**
+ * Handle unknown CatalogEntry types.
+ *
+ * This method exists to allow subclasses to deal with unknown
+ * entry types.
+ */
+ public void unknownEntry(Vector strings) {
+ if (strings != null && strings.size() > 0) {
+ String keyword = (String) strings.elementAt(0);
+ Debug.message(2, "Unrecognized token parsing catalog", keyword);
+ }
+ }
+
+ /**
+ * Parse all subordinate catalogs.
+ *
+ * This method recursively parses all of the subordinate catalogs.
+ * If this method does not throw an exception, you can be confident that
+ * no subsequent call to any resolve*() method will either, with two
+ * possible exceptions:
+ *
+ *
+ * Delegated catalogs are re-parsed each time they are needed
+ * (because a variable list of them may be needed in each case,
+ * depending on the length of the matching partial public identifier).
+ * But they are parsed by this method, so as long as they don't
+ * change or disappear while the program is running, they shouldn't
+ * generate errors later if they don't generate errors now.
+ * If you add new catalogs with parseCatalog, they
+ * won't be loaded until they are needed or until you call
+ * parseAllCatalogs again.
+ *
+ *
+ * On the other hand, if you don't call this method, you may
+ * successfully parse documents without having to load all possible
+ * catalogs.
+ *
+ * @throws MalformedURLException The filename (URL) for a
+ * subordinate or delegated catalog is not a valid URL.
+ * @throws IOException Error reading some subordinate or delegated
+ * catalog file.
+ */
+ public void parseAllCatalogs()
+ throws MalformedURLException, IOException {
+
+ // Parse all the subordinate catalogs
+ for (int catPos = 0; catPos < catalogs.size(); catPos++) {
+ Catalog c = null;
+
+ try {
+ c = (Catalog) catalogs.elementAt(catPos);
+ } catch (ClassCastException e) {
+ String catfile = (String) catalogs.elementAt(catPos);
+ c = newCatalog();
+
+ c.parseCatalog(catfile);
+ catalogs.setElementAt(c, catPos);
+ c.parseAllCatalogs();
+ }
+ }
+
+ // Parse all the DELEGATE catalogs
+ Enumeration enum = catalogEntries.elements();
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+ if (e.getEntryType() == DELEGATE_PUBLIC
+ || e.getEntryType() == DELEGATE_SYSTEM
+ || e.getEntryType() == DELEGATE_URI) {
+ Catalog dcat = newCatalog();
+ dcat.parseCatalog(e.getEntryArg(1));
+ }
+ }
+ }
+
+
+ /**
+ * Return the applicable DOCTYPE system identifier.
+ *
+ * @param entityName The name of the entity (element) for which
+ * a doctype is required.
+ * @param publicId The nominal public identifier for the doctype
+ * (as provided in the source document).
+ * @param systemId The nominal system identifier for the doctype
+ * (as provided in the source document).
+ *
+ * @return The system identifier to use for the doctype.
+ *
+ * @throws MalformedURLException The formal system identifier of a
+ * subordinate catalog cannot be turned into a valid URL.
+ * @throws IOException Error reading subordinate catalog file.
+ */
+ public String resolveDoctype(String entityName,
+ String publicId,
+ String systemId)
+ throws MalformedURLException, IOException {
+ String resolved = null;
+
+ Debug.message(3, "resolveDoctype("
+ +entityName+","+publicId+","+systemId+")");
+
+ systemId = normalizeURI(systemId);
+
+ if (publicId != null && publicId.startsWith("urn:publicid:")) {
+ publicId = PublicId.decodeURN(publicId);
+ }
+
+ if (systemId != null && systemId.startsWith("urn:publicid:")) {
+ systemId = PublicId.decodeURN(systemId);
+ if (publicId != null && !publicId.equals(systemId)) {
+ Debug.message(1, "urn:publicid: system identifier differs from public identifier; using public identifier");
+ systemId = null;
+ } else {
+ publicId = systemId;
+ systemId = null;
+ }
+ }
+
+ if (systemId != null) {
+ // If there's a SYSTEM entry in this catalog, use it
+ resolved = resolveLocalSystem(systemId);
+ if (resolved != null) {
+ return resolved;
+ }
+ }
+
+ if (publicId != null) {
+ // If there's a PUBLIC entry in this catalog, use it
+ resolved = resolveLocalPublic(DOCTYPE,
+ entityName,
+ publicId,
+ systemId);
+ if (resolved != null) {
+ return resolved;
+ }
+ }
+
+ // If there's a DOCTYPE entry in this catalog, use it
+ boolean over = default_override;
+ Enumeration enum = catalogEntries.elements();
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+ if (e.getEntryType() == OVERRIDE) {
+ over = e.getEntryArg(0).equalsIgnoreCase("YES");
+ continue;
+ }
+
+ if (e.getEntryType() == DOCTYPE
+ && e.getEntryArg(0).equals(entityName)) {
+ if (over || systemId == null) {
+ return e.getEntryArg(1);
+ }
+ }
+ }
+
+ // Otherwise, look in the subordinate catalogs
+ return resolveSubordinateCatalogs(DOCTYPE,
+ entityName,
+ publicId,
+ systemId);
+ }
+
+ /**
+ * Return the applicable DOCUMENT entry.
+ *
+ * @return The system identifier to use for the doctype.
+ *
+ * @throws MalformedURLException The formal system identifier of a
+ * subordinate catalog cannot be turned into a valid URL.
+ * @throws IOException Error reading subordinate catalog file.
+ */
+ public String resolveDocument()
+ throws MalformedURLException, IOException {
+ // If there's a DOCUMENT entry, return it
+
+ Debug.message(3, "resolveDocument");
+
+ Enumeration enum = catalogEntries.elements();
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+ if (e.getEntryType() == DOCUMENT) {
+ return e.getEntryArg(1); //FIXME check this
+ }
+ }
+
+ return resolveSubordinateCatalogs(DOCUMENT,
+ null, null, null);
+ }
+
+ /**
+ * Return the applicable ENTITY system identifier.
+ *
+ * @param entityName The name of the entity for which
+ * a system identifier is required.
+ * @param publicId The nominal public identifier for the entity
+ * (as provided in the source document).
+ * @param systemId The nominal system identifier for the entity
+ * (as provided in the source document).
+ *
+ * @return The system identifier to use for the entity.
+ *
+ * @throws MalformedURLException The formal system identifier of a
+ * subordinate catalog cannot be turned into a valid URL.
+ * @throws IOException Error reading subordinate catalog file.
+ */
+ public String resolveEntity(String entityName,
+ String publicId,
+ String systemId)
+ throws MalformedURLException, IOException {
+ String resolved = null;
+
+ Debug.message(3, "resolveEntity("
+ +entityName+","+publicId+","+systemId+")");
+
+ systemId = normalizeURI(systemId);
+
+ if (publicId != null && publicId.startsWith("urn:publicid:")) {
+ publicId = PublicId.decodeURN(publicId);
+ }
+
+ if (systemId != null && systemId.startsWith("urn:publicid:")) {
+ systemId = PublicId.decodeURN(systemId);
+ if (publicId != null && !publicId.equals(systemId)) {
+ Debug.message(1, "urn:publicid: system identifier differs from public identifier; using public identifier");
+ systemId = null;
+ } else {
+ publicId = systemId;
+ systemId = null;
+ }
+ }
+
+ if (systemId != null) {
+ // If there's a SYSTEM entry in this catalog, use it
+ resolved = resolveLocalSystem(systemId);
+ if (resolved != null) {
+ return resolved;
+ }
+ }
+
+ if (publicId != null) {
+ // If there's a PUBLIC entry in this catalog, use it
+ resolved = resolveLocalPublic(ENTITY,
+ entityName,
+ publicId,
+ systemId);
+ if (resolved != null) {
+ return resolved;
+ }
+ }
+
+ // If there's a ENTITY entry in this catalog, use it
+ boolean over = default_override;
+ Enumeration enum = catalogEntries.elements();
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+ if (e.getEntryType() == OVERRIDE) {
+ over = e.getEntryArg(0).equalsIgnoreCase("YES");
+ continue;
+ }
+
+ if (e.getEntryType() == ENTITY
+ && e.getEntryArg(0).equals(entityName)) {
+ if (over || systemId == null) {
+ return e.getEntryArg(1);
+ }
+ }
+ }
+
+ // Otherwise, look in the subordinate catalogs
+ return resolveSubordinateCatalogs(ENTITY,
+ entityName,
+ publicId,
+ systemId);
+ }
+
+ /**
+ * Return the applicable NOTATION system identifier.
+ *
+ * @param notationName The name of the notation for which
+ * a doctype is required.
+ * @param publicId The nominal public identifier for the notation
+ * (as provided in the source document).
+ * @param systemId The nominal system identifier for the notation
+ * (as provided in the source document).
+ *
+ * @return The system identifier to use for the notation.
+ *
+ * @throws MalformedURLException The formal system identifier of a
+ * subordinate catalog cannot be turned into a valid URL.
+ * @throws IOException Error reading subordinate catalog file.
+ */
+ public String resolveNotation(String notationName,
+ String publicId,
+ String systemId)
+ throws MalformedURLException, IOException {
+ String resolved = null;
+
+ Debug.message(3, "resolveNotation("
+ +notationName+","+publicId+","+systemId+")");
+
+ systemId = normalizeURI(systemId);
+
+ if (publicId != null && publicId.startsWith("urn:publicid:")) {
+ publicId = PublicId.decodeURN(publicId);
+ }
+
+ if (systemId != null && systemId.startsWith("urn:publicid:")) {
+ systemId = PublicId.decodeURN(systemId);
+ if (publicId != null && !publicId.equals(systemId)) {
+ Debug.message(1, "urn:publicid: system identifier differs from public identifier; using public identifier");
+ systemId = null;
+ } else {
+ publicId = systemId;
+ systemId = null;
+ }
+ }
+
+ if (systemId != null) {
+ // If there's a SYSTEM entry in this catalog, use it
+ resolved = resolveLocalSystem(systemId);
+ if (resolved != null) {
+ return resolved;
+ }
+ }
+
+ if (publicId != null) {
+ // If there's a PUBLIC entry in this catalog, use it
+ resolved = resolveLocalPublic(NOTATION,
+ notationName,
+ publicId,
+ systemId);
+ if (resolved != null) {
+ return resolved;
+ }
+ }
+
+ // If there's a NOTATION entry in this catalog, use it
+ boolean over = default_override;
+ Enumeration enum = catalogEntries.elements();
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+ if (e.getEntryType() == OVERRIDE) {
+ over = e.getEntryArg(0).equalsIgnoreCase("YES");
+ continue;
+ }
+
+ if (e.getEntryType() == NOTATION
+ && e.getEntryArg(0).equals(notationName)) {
+ if (over || systemId == null) {
+ return e.getEntryArg(1);
+ }
+ }
+ }
+
+ // Otherwise, look in the subordinate catalogs
+ return resolveSubordinateCatalogs(NOTATION,
+ notationName,
+ publicId,
+ systemId);
+ }
+
+ /**
+ * Return the applicable PUBLIC or SYSTEM identifier.
+ *
+ * This method searches the Catalog and returns the system
+ * identifier specified for the given system or
+ * public identifiers. If
+ * no appropriate PUBLIC or SYSTEM entry is found in the Catalog,
+ * null is returned.
+ *
+ * @param publicId The public identifier to locate in the catalog.
+ * Public identifiers are normalized before comparison.
+ * @param systemId The nominal system identifier for the entity
+ * in question (as provided in the source document).
+ *
+ * @throws MalformedURLException The formal system identifier of a
+ * subordinate catalog cannot be turned into a valid URL.
+ * @throws IOException Error reading subordinate catalog file.
+ *
+ * @return The system identifier to use.
+ * Note that the nominal system identifier is not returned if a
+ * match is not found in the catalog, instead null is returned
+ * to indicate that no match was found.
+ */
+ public String resolvePublic(String publicId, String systemId)
+ throws MalformedURLException, IOException {
+
+ Debug.message(3, "resolvePublic("+publicId+","+systemId+")");
+
+ systemId = normalizeURI(systemId);
+
+ if (publicId != null && publicId.startsWith("urn:publicid:")) {
+ publicId = PublicId.decodeURN(publicId);
+ }
+
+ if (systemId != null && systemId.startsWith("urn:publicid:")) {
+ systemId = PublicId.decodeURN(systemId);
+ if (publicId != null && !publicId.equals(systemId)) {
+ Debug.message(1, "urn:publicid: system identifier differs from public identifier; using public identifier");
+ systemId = null;
+ } else {
+ publicId = systemId;
+ systemId = null;
+ }
+ }
+
+ // If there's a SYSTEM entry in this catalog, use it
+ if (systemId != null) {
+ String resolved = resolveLocalSystem(systemId);
+ if (resolved != null) {
+ return resolved;
+ }
+ }
+
+ // If there's a PUBLIC entry in this catalog, use it
+ String resolved = resolveLocalPublic(PUBLIC,
+ null,
+ publicId,
+ systemId);
+ if (resolved != null) {
+ return resolved;
+ }
+
+ // Otherwise, look in the subordinate catalogs
+ return resolveSubordinateCatalogs(PUBLIC,
+ null,
+ publicId,
+ systemId);
+ }
+
+ /**
+ * Return the applicable PUBLIC or SYSTEM identifier
+ *
+ * This method searches the Catalog and returns the system
+ * identifier specified for the given system or public identifiers.
+ * If no appropriate PUBLIC or SYSTEM entry is found in the Catalog,
+ * delegated Catalogs are interrogated.
+ *
+ * There are four possible cases:
+ *
+ *
+ * - If the system identifier provided matches a SYSTEM entry
+ * in the current catalog, the SYSTEM entry is returned.
+ *
- If the system identifier is not null, the PUBLIC entries
+ * that were encountered when OVERRIDE YES was in effect are
+ * interrogated and the first matching entry is returned.
+ * - If the system identifier is null, then all of the PUBLIC
+ * entries are interrogated and the first matching entry
+ * is returned. This may not be the same as the preceding case, if
+ * some PUBLIC entries are encountered when OVERRIDE NO is in effect. In
+ * XML, the only place where a public identifier may occur without
+ * a system identifier is in a notation declaration.
+ * - Finally, if the public identifier matches one of the partial
+ * public identifiers specified in a DELEGATE* entry in
+ * the Catalog, the delegated catalog is interrogated. The first
+ * time that the delegated catalog is required, it will be
+ * retrieved and parsed. It is subsequently cached.
+ *
+ *
+ *
+ * @param entityType The CatalogEntry type for which this query is
+ * being conducted. This is necessary in order to do the approprate
+ * query on a delegated catalog.
+ * @param entityName The name of the entity being searched for, if
+ * appropriate.
+ * @param publicId The public identifier of the entity in question.
+ * @param systemId The nominal system identifier for the entity
+ * in question (as provided in the source document).
+ *
+ * @throws MalformedURLException The formal system identifier of a
+ * delegated catalog cannot be turned into a valid URL.
+ * @throws IOException Error reading delegated catalog file.
+ *
+ * @return The system identifier to use.
+ * Note that the nominal system identifier is not returned if a
+ * match is not found in the catalog, instead null is returned
+ * to indicate that no match was found.
+ */
+ protected synchronized String resolveLocalPublic(int entityType,
+ String entityName,
+ String publicId,
+ String systemId)
+ throws MalformedURLException, IOException {
+
+ // Always normalize the public identifier before attempting a match
+ publicId = PublicId.normalize(publicId);
+
+ // If there's a SYSTEM entry in this catalog, use it
+ if (systemId != null) {
+ String resolved = resolveLocalSystem(systemId);
+ if (resolved != null) {
+ return resolved;
+ }
+ }
+
+ // If there's a PUBLIC entry in this catalog, use it
+ boolean over = default_override;
+ Enumeration enum = catalogEntries.elements();
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+ if (e.getEntryType() == OVERRIDE) {
+ over = e.getEntryArg(0).equalsIgnoreCase("YES");
+ continue;
+ }
+
+ if (e.getEntryType() == PUBLIC
+ && e.getEntryArg(0).equals(publicId)) {
+ if (over || systemId == null) {
+ return e.getEntryArg(1);
+ }
+ }
+ }
+
+ // If there's a DELEGATE_PUBLIC entry in this catalog, use it
+ over = default_override;
+ enum = catalogEntries.elements();
+ Vector delCats = new Vector();
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+ if (e.getEntryType() == OVERRIDE) {
+ over = e.getEntryArg(0).equalsIgnoreCase("YES");
+ continue;
+ }
+
+ if (e.getEntryType() == DELEGATE_PUBLIC
+ && (over || systemId == null)) {
+ String p = (String) e.getEntryArg(0);
+ if (p.length() <= publicId.length()
+ && p.equals(publicId.substring(0, p.length()))) {
+ // delegate this match to the other catalog
+
+ delCats.addElement(e.getEntryArg(1));
+ }
+ }
+ }
+
+ if (delCats.size() > 0) {
+ Enumeration enumCats = delCats.elements();
+
+ if (Debug.getDebug() > 1) {
+ Debug.message(2, "Switching to delegated catalog(s):");
+ while (enumCats.hasMoreElements()) {
+ String delegatedCatalog = (String) enumCats.nextElement();
+ Debug.message(2, "\t" + delegatedCatalog);
+ }
+ }
+
+ Catalog dcat = newCatalog();
+
+ enumCats = delCats.elements();
+ while (enumCats.hasMoreElements()) {
+ String delegatedCatalog = (String) enumCats.nextElement();
+ dcat.parseCatalog(delegatedCatalog);
+ }
+
+ return dcat.resolvePublic(publicId, null);
+ }
+
+ // Nada!
+ return null;
+ }
+
+ /**
+ * Return the applicable SYSTEM system identifier
+ *
+ * If a SYSTEM entry exists in the Catalog
+ * for the system ID specified, return the mapped value.
+ *
+ * On Windows-based operating systems, the comparison between
+ * the system identifier provided and the SYSTEM entries in the
+ * Catalog is case-insensitive.
+ *
+ * @param systemId The system ID to locate in the catalog.
+ *
+ * @return The resolved system identifier.
+ *
+ * @throws MalformedURLException The formal system identifier of a
+ * subordinate catalog cannot be turned into a valid URL.
+ * @throws IOException Error reading subordinate catalog file.
+ */
+ public String resolveSystem(String systemId)
+ throws MalformedURLException, IOException {
+
+ Debug.message(3, "resolveSystem("+systemId+")");
+
+ systemId = normalizeURI(systemId);
+
+ if (systemId != null && systemId.startsWith("urn:publicid:")) {
+ systemId = PublicId.decodeURN(systemId);
+ return resolvePublic(systemId, null);
+ }
+
+ // If there's a SYSTEM entry in this catalog, use it
+ if (systemId != null) {
+ String resolved = resolveLocalSystem(systemId);
+ if (resolved != null) {
+ return resolved;
+ }
+ }
+
+ // Otherwise, look in the subordinate catalogs
+ return resolveSubordinateCatalogs(SYSTEM,
+ null,
+ null,
+ systemId);
+ }
+
+ /**
+ * Return the applicable SYSTEM system identifier in this
+ * catalog.
+ *
+ * If a SYSTEM entry exists in the catalog file
+ * for the system ID specified, return the mapped value.
+ *
+ * @param systemId The system ID to locate in the catalog
+ *
+ * @return The mapped system identifier or null
+ */
+ protected String resolveLocalSystem(String systemId)
+ throws MalformedURLException, IOException {
+
+ String osname = System.getProperty("os.name");
+ boolean windows = (osname.indexOf("Windows") >= 0);
+ Enumeration enum = catalogEntries.elements();
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+ if (e.getEntryType() == SYSTEM
+ && (e.getEntryArg(0).equals(systemId)
+ || (windows
+ && e.getEntryArg(0).equalsIgnoreCase(systemId)))) {
+ return e.getEntryArg(1);
+ }
+ }
+
+ // If there's a REWRITE_SYSTEM entry in this catalog, use it
+ enum = catalogEntries.elements();
+ String startString = null;
+ String prefix = null;
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+
+ if (e.getEntryType() == REWRITE_SYSTEM) {
+ String p = (String) e.getEntryArg(0);
+ if (p.length() <= systemId.length()
+ && p.equals(systemId.substring(0, p.length()))) {
+ // Is this the longest prefix?
+ if (startString == null
+ || p.length() > startString.length()) {
+ startString = p;
+ prefix = e.getEntryArg(1);
+ }
+ }
+ }
+
+ if (prefix != null) {
+ // return the systemId with the new prefix
+ return prefix + systemId.substring(startString.length());
+ }
+ }
+
+ // If there's a DELEGATE_SYSTEM entry in this catalog, use it
+ enum = catalogEntries.elements();
+ Vector delCats = new Vector();
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+
+ if (e.getEntryType() == DELEGATE_SYSTEM) {
+ String p = (String) e.getEntryArg(0);
+ if (p.length() <= systemId.length()
+ && p.equals(systemId.substring(0, p.length()))) {
+ // delegate this match to the other catalog
+
+ delCats.addElement(e.getEntryArg(1));
+ }
+ }
+ }
+
+ if (delCats.size() > 0) {
+ Enumeration enumCats = delCats.elements();
+
+ if (Debug.getDebug() > 1) {
+ Debug.message(2, "Switching to delegated catalog(s):");
+ while (enumCats.hasMoreElements()) {
+ String delegatedCatalog = (String) enumCats.nextElement();
+ Debug.message(2, "\t" + delegatedCatalog);
+ }
+ }
+
+ Catalog dcat = newCatalog();
+
+ enumCats = delCats.elements();
+ while (enumCats.hasMoreElements()) {
+ String delegatedCatalog = (String) enumCats.nextElement();
+ dcat.parseCatalog(delegatedCatalog);
+ }
+
+ return dcat.resolveSystem(systemId);
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the applicable URI
+ *
+ * If a URI entry exists in the Catalog
+ * for the URI specified, return the mapped value.
+ *
+ * URI comparison is case sensitive.
+ *
+ * @param uri The URI to locate in the catalog.
+ *
+ * @return The resolved URI.
+ *
+ * @throws MalformedURLException The system identifier of a
+ * subordinate catalog cannot be turned into a valid URL.
+ * @throws IOException Error reading subordinate catalog file.
+ */
+ public String resolveURI(String uri)
+ throws MalformedURLException, IOException {
+
+ Debug.message(3, "resolveURI("+uri+")");
+
+ uri = normalizeURI(uri);
+
+ if (uri != null && uri.startsWith("urn:publicid:")) {
+ uri = PublicId.decodeURN(uri);
+ return resolvePublic(uri, null);
+ }
+
+ // If there's a URI entry in this catalog, use it
+ if (uri != null) {
+ String resolved = resolveLocalURI(uri);
+ if (resolved != null) {
+ return resolved;
+ }
+ }
+
+ // Otherwise, look in the subordinate catalogs
+ return resolveSubordinateCatalogs(URI,
+ null,
+ null,
+ uri);
+ }
+
+ /**
+ * Return the applicable URI in this
+ * catalog.
+ *
+ * If a URI entry exists in the catalog file
+ * for the URI specified, return the mapped value.
+ *
+ * @param uri The URI to locate in the catalog
+ *
+ * @return The mapped URI or null
+ */
+ protected String resolveLocalURI(String uri)
+ throws MalformedURLException, IOException {
+ Enumeration enum = catalogEntries.elements();
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+ if (e.getEntryType() == URI
+ && (e.getEntryArg(0).equals(uri))) {
+ return e.getEntryArg(1);
+ }
+ }
+
+ // If there's a REWRITE_URI entry in this catalog, use it
+ enum = catalogEntries.elements();
+ String startString = null;
+ String prefix = null;
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+
+ if (e.getEntryType() == REWRITE_URI) {
+ String p = (String) e.getEntryArg(0);
+ if (p.length() <= uri.length()
+ && p.equals(uri.substring(0, p.length()))) {
+ // Is this the longest prefix?
+ if (startString == null
+ || p.length() > startString.length()) {
+ startString = p;
+ prefix = e.getEntryArg(1);
+ }
+ }
+ }
+
+ if (prefix != null) {
+ // return the systemId with the new prefix
+ return prefix + uri.substring(startString.length());
+ }
+ }
+
+ // If there's a DELEGATE_URI entry in this catalog, use it
+ enum = catalogEntries.elements();
+ Vector delCats = new Vector();
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+
+ if (e.getEntryType() == DELEGATE_URI) {
+ String p = (String) e.getEntryArg(0);
+ if (p.length() <= uri.length()
+ && p.equals(uri.substring(0, p.length()))) {
+ // delegate this match to the other catalog
+
+ delCats.addElement(e.getEntryArg(1));
+ }
+ }
+ }
+
+ if (delCats.size() > 0) {
+ Enumeration enumCats = delCats.elements();
+
+ if (Debug.getDebug() > 1) {
+ Debug.message(2, "Switching to delegated catalog(s):");
+ while (enumCats.hasMoreElements()) {
+ String delegatedCatalog = (String) enumCats.nextElement();
+ Debug.message(2, "\t" + delegatedCatalog);
+ }
+ }
+
+ Catalog dcat = newCatalog();
+
+ enumCats = delCats.elements();
+ while (enumCats.hasMoreElements()) {
+ String delegatedCatalog = (String) enumCats.nextElement();
+ dcat.parseCatalog(delegatedCatalog);
+ }
+
+ return dcat.resolveURI(uri);
+ }
+
+ return null;
+ }
+
+ /**
+ * Search the subordinate catalogs, in order, looking for a
+ * match.
+ *
+ * This method searches the Catalog and returns the system
+ * identifier specified for the given entity type with the given
+ * name, public, and system identifiers. In some contexts, these
+ * may be null.
+ *
+ * @param entityType The CatalogEntry type for which this query is
+ * being conducted. This is necessary in order to do the approprate
+ * query on a subordinate catalog.
+ * @param entityName The name of the entity being searched for, if
+ * appropriate.
+ * @param publicId The public identifier of the entity in question
+ * (as provided in the source document).
+ * @param systemId The nominal system identifier for the entity
+ * in question (as provided in the source document). This parameter is
+ * overloaded for the URI entry type.
+ *
+ * @throws MalformedURLException The formal system identifier of a
+ * delegated catalog cannot be turned into a valid URL.
+ * @throws IOException Error reading delegated catalog file.
+ *
+ * @return The system identifier to use.
+ * Note that the nominal system identifier is not returned if a
+ * match is not found in the catalog, instead null is returned
+ * to indicate that no match was found.
+ */
+ protected synchronized String resolveSubordinateCatalogs(int entityType,
+ String entityName,
+ String publicId,
+ String systemId)
+ throws MalformedURLException, IOException {
+
+ for (int catPos = 0; catPos < catalogs.size(); catPos++) {
+ Catalog c = null;
+
+ try {
+ c = (Catalog) catalogs.elementAt(catPos);
+ } catch (ClassCastException e) {
+ String catfile = (String) catalogs.elementAt(catPos);
+ c = newCatalog();
+
+ try {
+ c.parseCatalog(catfile);
+ } catch (MalformedURLException mue) {
+ Debug.message(1, "Malformed Catalog URL", catfile);
+ } catch (FileNotFoundException fnfe) {
+ Debug.message(1, "Failed to load catalog, file not found",
+ catfile);
+ } catch (IOException ioe) {
+ Debug.message(1, "Failed to load catalog, I/O error", catfile);
+ }
+
+ catalogs.setElementAt(c, catPos);
+ }
+
+ String resolved = null;
+
+ // Ok, now what are we supposed to call here?
+ if (entityType == DOCTYPE) {
+ resolved = c.resolveDoctype(entityName,
+ publicId,
+ systemId);
+ } else if (entityType == DOCUMENT) {
+ resolved = c.resolveDocument();
+ } else if (entityType == ENTITY) {
+ resolved = c.resolveEntity(entityName,
+ publicId,
+ systemId);
+ } else if (entityType == NOTATION) {
+ resolved = c.resolveNotation(entityName,
+ publicId,
+ systemId);
+ } else if (entityType == PUBLIC) {
+ resolved = c.resolvePublic(publicId, systemId);
+ } else if (entityType == SYSTEM) {
+ resolved = c.resolveSystem(systemId);
+ } else if (entityType == URI) {
+ resolved = c.resolveURI(systemId);
+ }
+
+ if (resolved != null) {
+ return resolved;
+ }
+ }
+
+ return null;
+ }
+
+ // -----------------------------------------------------------------
+
+ /**
+ * Replace backslashes with forward slashes. (URLs always use
+ * forward slashes.)
+ *
+ * @param sysid The input system identifier.
+ * @return The same system identifier with backslashes turned into
+ * forward slashes.
+ */
+ protected String fixSlashes (String sysid) {
+ return sysid.replace('\\', '/');
+ }
+
+ /**
+ * Construct an absolute URI from a relative one, using the current
+ * base URI.
+ *
+ * @param sysid The (possibly relative) system identifier
+ * @return The system identifier made absolute with respect to the
+ * current {@link #base}.
+ */
+ protected String makeAbsolute(String sysid) {
+ URL local = null;
+
+ sysid = fixSlashes(sysid);
+
+ try {
+ local = new URL(base, sysid);
+ } catch (MalformedURLException e) {
+ Debug.message(1, "Malformed URL on system identifier", sysid);
+ }
+
+ if (local != null) {
+ return local.toString();
+ } else {
+ return sysid;
+ }
+ }
+
+ /**
+ * Perform character normalization on a URI reference.
+ *
+ * @param uriref The URI reference
+ * @return The normalized URI reference.
+ */
+ protected String normalizeURI(String uriref) {
+ String newRef = "";
+ byte[] bytes;
+
+ if (uriref == null) {
+ return null;
+ }
+
+ try {
+ bytes = uriref.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException uee) {
+ // this can't happen
+ Debug.message(1, "UTF-8 is an unsupported encoding!?");
+ return uriref;
+ }
+
+ for (int count = 0; count < bytes.length; count++) {
+ int ch = bytes[count] & 0xFF;
+
+ if ((ch <= 0x20) // ctrl
+ || (ch > 0x7F) // high ascii
+ || (ch == 0x22) // "
+ || (ch == 0x3C) // <
+ || (ch == 0x3E) // >
+ || (ch == 0x5C) // \
+ || (ch == 0x5E) // ^
+ || (ch == 0x60) // `
+ || (ch == 0x7B) // {
+ || (ch == 0x7C) // |
+ || (ch == 0x7D) // }
+ || (ch == 0x7F)) {
+ newRef += encodedByte(ch);
+ } else {
+ newRef += (char) bytes[count];
+ }
+ }
+
+ return newRef;
+ }
+
+ /**
+ * Perform %-encoding on a single byte.
+ *
+ * @param b The 8-bit integer that represents th byte. (Bytes are signed
+ but encoding needs to look at the bytes unsigned.)
+ * @return The %-encoded string for the byte in question.
+ */
+ protected String encodedByte (int b) {
+ String hex = Integer.toHexString(b).toUpperCase();
+ if (hex.length() < 2) {
+ return "%0" + hex;
+ } else {
+ return "%" + hex;
+ }
+ }
+
+ // -----------------------------------------------------------------
+
+ /**
+ * Add to the current list of delegated catalogs.
+ *
+ * This method always constructs the {@link #localDelegate}
+ * vector so that it is ordered by length of partial
+ * public identifier.
+ *
+ * @param entry The DELEGATE catalog entry
+ */
+ protected void addDelegate(CatalogEntry entry) {
+ int pos = 0;
+ String partial = entry.getEntryArg(0);
+
+ Enumeration local = localDelegate.elements();
+ while (local.hasMoreElements()) {
+ CatalogEntry dpe = (CatalogEntry) local.nextElement();
+ String dp = dpe.getEntryArg(0);
+ if (dp.equals(partial)) {
+ // we already have this prefix
+ return;
+ }
+ if (dp.length() > partial.length()) {
+ pos++;
+ }
+ if (dp.length() < partial.length()) {
+ break;
+ }
+ }
+
+ // now insert partial into the vector at [pos]
+ if (localDelegate.size() == 0) {
+ localDelegate.addElement(entry);
+ } else {
+ localDelegate.insertElementAt(entry, pos);
+ }
+ }
+}
+
diff --git a/java/src/org/apache/xml/resolver/CatalogEntry.java b/java/src/org/apache/xml/resolver/CatalogEntry.java
new file mode 100644
index 0000000..a7340ab
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/CatalogEntry.java
@@ -0,0 +1,289 @@
+// CatalogEntry.java - Represents Catalog entries
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver;
+
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ * Represents a Catalog entry.
+ *
+ * Instances of this class represent individual entries
+ * in a Catalog.
+ *
+ * Each catalog entry has a unique name and is associated with
+ * an arbitrary number of arguments (all strings). For example, the
+ * TR9401 catalog entry "PUBLIC" has two arguments, a public identifier
+ * and a system identifier. Each entry has a unique numeric type,
+ * assigned automatically when the entry type is created.
+ *
+ * The number and type of catalog entries is maintained
+ * statically. Catalog classes, or their subclasses, can add
+ * new entry types, but all Catalog objects share the same global pool
+ * of types.
+ *
+ * Initially there are no valid entries.
+ *
+ * @see Catalog
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class CatalogEntry {
+ /** The nextEntry is the ordinal number of the next entry type. */
+ protected static int nextEntry = 0;
+
+ /**
+ * The entryTypes vector maps catalog entry names
+ * (e.g., 'BASE' or 'SYSTEM') to their type (1, 2, etc.).
+ * Names are case sensitive.
+ */
+ protected static Hashtable entryTypes = new Hashtable();
+
+ /** The entryTypes vector maps catalog entry types to the
+ number of arguments they're required to have. */
+ protected static Vector entryArgs = new Vector();
+
+ /**
+ * Adds a new catalog entry type.
+ *
+ * @param name The name of the catalog entry type. This must be
+ * unique among all types and is case-sensitive. (Adding a duplicate
+ * name effectively replaces the old type with the new type.)
+ * @param numArgs The number of arguments that this entry type
+ * is required to have. There is no provision for variable numbers
+ * of arguments.
+ * @return The type for the new entry.
+ */
+ public static int addEntryType(String name, int numArgs) {
+ entryTypes.put(name, new Integer(nextEntry));
+ entryArgs.add(nextEntry, new Integer(numArgs));
+ nextEntry++;
+
+ return nextEntry-1;
+ }
+
+ /**
+ * Lookup an entry type
+ *
+ * @param name The name of the catalog entry type.
+ * @return The type of the catalog entry with the specified name.
+ * @throws InvalidCatalogEntryTypeException if no entry has the
+ * specified name.
+ */
+ public static int getEntryType(String name)
+ throws CatalogException {
+ if (!entryTypes.containsKey(name)) {
+ throw new CatalogException(CatalogException.INVALID_ENTRY_TYPE);
+ }
+
+ Integer iType = (Integer) entryTypes.get(name);
+
+ if (iType == null) {
+ throw new CatalogException(CatalogException.INVALID_ENTRY_TYPE);
+ }
+
+ return iType.intValue();
+ }
+
+ /**
+ * Find out how many arguments an entry is required to have.
+ *
+ * @param name The name of the catalog entry type.
+ * @return The number of arguments that entry type is required to have.
+ * @throws InvalidCatalogEntryTypeException if no entry has the
+ * specified name.
+ */
+ public static int getEntryArgCount(String name)
+ throws CatalogException {
+ return getEntryArgCount(getEntryType(name));
+ }
+
+ /**
+ * Find out how many arguments an entry is required to have.
+ *
+ * @param type A valid catalog entry type.
+ * @return The number of arguments that entry type is required to have.
+ * @throws InvalidCatalogEntryTypeException if the type is invalid.
+ */
+ public static int getEntryArgCount(int type)
+ throws CatalogException {
+ try {
+ Integer iArgs = (Integer) entryArgs.get(type);
+ return iArgs.intValue();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new CatalogException(CatalogException.INVALID_ENTRY_TYPE);
+ }
+ }
+
+ /** The entry type of this entry */
+ protected int entryType = 0;
+
+ /** The arguments associated with this entry */
+ protected Vector args = null;
+
+ /**
+ * Null constructor; something for subclasses to call.
+ */
+ public CatalogEntry() {}
+
+ /**
+ * Construct a catalog entry of the specified type.
+ *
+ * @param name The name of the entry type
+ * @param args A String Vector of arguments
+ * @throws InvalidCatalogEntryTypeException if no such entry type
+ * exists.
+ * @throws InvalidCatalogEntryException if the wrong number of arguments
+ * is passed.
+ */
+ public CatalogEntry(String name, Vector args)
+ throws CatalogException {
+ Integer iType = (Integer) entryTypes.get(name);
+
+ if (iType == null) {
+ throw new CatalogException(CatalogException.INVALID_ENTRY_TYPE);
+ }
+
+ int type = iType.intValue();
+
+ try {
+ Integer iArgs = (Integer) entryArgs.get(type);
+ if (iArgs.intValue() != args.size()) {
+ throw new CatalogException(CatalogException.INVALID_ENTRY);
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new CatalogException(CatalogException.INVALID_ENTRY_TYPE);
+ }
+
+ entryType = type;
+ this.args = args;
+ }
+
+ /**
+ * Construct a catalog entry of the specified type.
+ *
+ * @param name The name of the entry type
+ * @param args A String Vector of arguments
+ * @throws InvalidCatalogEntryTypeException if no such entry type
+ * exists.
+ * @throws InvalidCatalogEntryException if the wrong number of arguments
+ * is passed.
+ */
+ public CatalogEntry(int type, Vector args)
+ throws CatalogException {
+ try {
+ Integer iArgs = (Integer) entryArgs.get(type);
+ if (iArgs.intValue() != args.size()) {
+ throw new CatalogException(CatalogException.INVALID_ENTRY);
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new CatalogException(CatalogException.INVALID_ENTRY_TYPE);
+ }
+
+ entryType = type;
+ this.args = args;
+ }
+
+ /**
+ * Get the entry type.
+ *
+ * @return The entry type of the CatalogEntry
+ */
+ public int getEntryType() {
+ return entryType;
+ }
+
+ /**
+ * Get an entry argument.
+ *
+ * @param argNum The argument number (arguments are numbered from 0).
+ * @return The specified argument or null if an invalid argNum is
+ * provided.
+ */
+ public String getEntryArg(int argNum) {
+ try {
+ String arg = (String) args.get(argNum);
+ return arg;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Set an entry argument.
+ *
+ * Catalogs sometimes need to adjust the catlog entry parameters,
+ * for example to make a relative URI absolute with respect to the
+ * current base URI. But in general, this function should only be
+ * called shortly after object creation to do some sort of cleanup.
+ * Catalog entries should not mutate over time.
+ *
+ * @param argNum The argument number (arguments are numbered from 0).
+ * @throws ArrayIndexOutOfBoundsException if an invalid argument
+ * number is provided.
+ */
+ public void setEntryArg(int argNum, String newspec)
+ throws ArrayIndexOutOfBoundsException {
+ args.set(argNum, newspec);
+ }
+}
diff --git a/java/src/org/apache/xml/resolver/CatalogException.java b/java/src/org/apache/xml/resolver/CatalogException.java
new file mode 100644
index 0000000..27170e6
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/CatalogException.java
@@ -0,0 +1,203 @@
+// CatalogException.java - Catalog exception
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver;
+
+/**
+ * Signal Catalog exception.
+ *
+ * This exception is thrown if an error occurs loading a
+ * catalog file.
+ *
+ * @see Catalog
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class CatalogException extends Exception {
+ /** A wrapper around another exception */
+ public static final int WRAPPER = 1;
+ /** An invalid entry */
+ public static final int INVALID_ENTRY = 2;
+ /** An invalid entry type */
+ public static final int INVALID_ENTRY_TYPE = 3;
+ /** Could not instantiate an XML parser */
+ public static final int NO_XML_PARSER = 4;
+ /** Unknown XML format */
+ public static final int UNKNOWN_FORMAT = 5;
+ /** Unparseable XML catalog (not XML)*/
+ public static final int UNPARSEABLE = 6;
+ /** XML but parse failed */
+ public static final int PARSE_FAILED = 7;
+
+ /**
+ * The embedded exception if tunnelling, or null.
+ */
+ private Exception exception = null;
+ private int exceptionType = 0;
+
+ /**
+ * Create a new CatalogException.
+ *
+ * @param type The exception type
+ * @param message The error or warning message.
+ */
+ public CatalogException (int type, String message) {
+ super(message);
+ this.exceptionType = type;
+ this.exception = null;
+ }
+
+ /**
+ * Create a new CatalogException.
+ *
+ * @param type The exception type
+ */
+ public CatalogException (int type) {
+ super("Catalog Exception " + type);
+ this.exceptionType = type;
+ this.exception = null;
+ }
+
+ /**
+ * Create a new CatalogException wrapping an existing exception.
+ *
+ * The existing exception will be embedded in the new
+ * one, and its message will become the default message for
+ * the CatalogException.
+ *
+ * @param e The exception to be wrapped in a CatalogException.
+ */
+ public CatalogException (Exception e) {
+ super();
+ this.exceptionType = WRAPPER;
+ this.exception = e;
+ }
+
+ /**
+ * Create a new CatalogException from an existing exception.
+ *
+ * The existing exception will be embedded in the new
+ * one, but the new exception will have its own message.
+ *
+ * @param message The detail message.
+ * @param e The exception to be wrapped in a CatalogException.
+ */
+ public CatalogException (String message, Exception e) {
+ super(message);
+ this.exceptionType = WRAPPER;
+ this.exception = e;
+ }
+
+ /**
+ * Return a detail message for this exception.
+ *
+ * If there is an embedded exception, and if the CatalogException
+ * has no detail message of its own, this method will return
+ * the detail message from the embedded exception.
+ *
+ * @return The error or warning message.
+ */
+ public String getMessage ()
+ {
+ String message = super.getMessage();
+
+ if (message == null && exception != null) {
+ return exception.getMessage();
+ } else {
+ return message;
+ }
+ }
+
+ /**
+ * Return the embedded exception, if any.
+ *
+ * @return The embedded exception, or null if there is none.
+ */
+ public Exception getException ()
+ {
+ return exception;
+ }
+
+ /**
+ * Return the exception type
+ *
+ * @return The exception type
+ */
+ public int getExceptionType ()
+ {
+ return exceptionType;
+ }
+
+ /**
+ * Override toString to pick up any embedded exception.
+ *
+ * @return A string representation of this exception.
+ */
+ public String toString ()
+ {
+ if (exception != null) {
+ return exception.toString();
+ } else {
+ return super.toString();
+ }
+ }
+}
diff --git a/java/src/org/apache/xml/resolver/CatalogManager.java b/java/src/org/apache/xml/resolver/CatalogManager.java
new file mode 100644
index 0000000..67063ce
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/CatalogManager.java
@@ -0,0 +1,463 @@
+// CatalogManager.java - Access CatalogManager.properties
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver;
+
+import java.lang.ClassNotFoundException;
+import java.lang.IllegalAccessException;
+import java.lang.InstantiationException;
+import java.lang.SecurityException;
+import java.lang.ClassCastException;
+import java.net.URL;
+import java.net.MalformedURLException;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * 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 Property |
+ * CatalogManager.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.files |
+ * catalogs |
+ * The semicolon-delimited list of catalog files. |
+ *
+ *
+ *
+ * | |
+ * relative-catalogs |
+ * If 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.verbosity |
+ * verbosity |
+ * If non-zero, the Catalog classes will print informative and debugging messages.
+ * The higher the number, the more messages. |
+ *
+ *
+ *
+ * | xml.catalog.prefer |
+ * prefer |
+ * Which identifier is preferred, "public" or "system"? |
+ *
+ *
+ *
+ * | xml.catalog.staticCatalog |
+ * static-catalog |
+ * Should a single catalog be constructed for all parsing, or should a different
+ * catalog be created for each parser? |
+ *
+ *
+ *
+ * | xml.catalog.allowPI |
+ * allow-oasis-xml-catalog-pi |
+ * If the source document contains "oasis-xml-catalog" processing instructions,
+ * should they be used? |
+ *
+ *
+ *
+ * | xml.catalog.className |
+ * catalog-class-name |
+ * If 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 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";
+
+ /** Flag to ignore missing property files and/or properties */
+ private static boolean ignoreMissingProperties
+ = (System.getProperty(pIgnoreMissing) != null
+ || System.getProperty(pFiles) != null);
+
+ /** Holds the resources after they are loaded from the file. */
+ private static ResourceBundle resources;
+
+ /** The name of the CatalogManager properties file. */
+ private static String propertyFile = "CatalogManager.properties";
+
+ /** The location of the propertyFile */
+ private static URL propertyFileURI = null;
+
+ /** Default catalog files list. */
+ private static String defaultCatalogFiles = "./xcatalog";
+
+ /** Default verbosity level if there is no property setting for it. */
+ private static int defaultVerbosity = 1;
+
+ /** Default preference setting. */
+ private static boolean defaultPreferPublic = true;
+
+ /** Default setting of the static catalog flag. */
+ private static boolean defaultStaticCatalog = true;
+
+ /** Default setting of the oasisXMLCatalogPI flag. */
+ private static boolean defaultOasisXMLCatalogPI = true;
+
+ /** Default setting of the relativeCatalogs flag. */
+ private static boolean defaultRelativeCatalogs = true;
+
+ /**
+ * Load the properties from the propertyFile and build the
+ * resources from it.
+ */
+ private synchronized static void readProperties() {
+ try {
+ propertyFileURI = CatalogManager.class.getResource("/"+propertyFile);
+ InputStream in =
+ CatalogManager.class.getResourceAsStream("/"+propertyFile);
+ if (in==null) {
+ if (!ignoreMissingProperties) {
+ System.err.println("Cannot find "+propertyFile);
+ }
+ 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);
+ }
+ }
+ }
+
+ /**
+ * Tell the CatalogManager how to handle missing properties
+ *
+ * If ignore is true, missing or unreadable property files will
+ * not be reported. Otherwise, a message will be sent to System.err.
+ *
+ */
+ public static void ignoreMissingProperties(boolean ignore) {
+ ignoreMissingProperties = ignore;
+ }
+
+ /**
+ * Obtain the verbosity setting from the properties.
+ *
+ * @returns The verbosity level from the propertyFile or the
+ * defaultVerbosity.
+ */
+ public static int verbosity () {
+ String verbStr = System.getProperty(pVerbosity);
+
+ if (verbStr == null) {
+ if (resources==null) readProperties();
+ if (resources==null) return defaultVerbosity;
+ try {
+ verbStr = resources.getString("verbosity");
+ } catch (MissingResourceException e) {
+ return defaultVerbosity;
+ }
+ }
+
+ try {
+ int verb = Integer.parseInt(verbStr.trim());
+ return verb;
+ } catch (Exception e) {
+ System.err.println("Cannot parse verbosity: \"" + verbStr + "\"");
+ return defaultVerbosity;
+ }
+ }
+
+ /**
+ * Obtain the relativeCatalogs setting from the properties.
+ *
+ * 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.
+ *
+ * @returns The relativeCatalogs setting from the propertyFile or the
+ * defaultRelativeCatalogs.
+ */
+ public static boolean relativeCatalogs () {
+ 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;
+ }
+ }
+
+ /**
+ * Obtain the list of catalog files from the properties.
+ *
+ * Note that the list of catalog files is always a semicolon
+ * delimited list, even on Unix systems where a colon delimited list
+ * might be considered more natural.
+ *
+ * @returns A vector of the catalog file names or null if no catalogs
+ * are available in the properties.
+ */
+ public static Vector catalogFiles () {
+ String catalogList = System.getProperty(pFiles);
+ boolean 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;
+ }
+
+ StringTokenizer files = new StringTokenizer(catalogList, ";");
+ 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;
+ }
+
+ /**
+ * Obtain the preferPublic setting from the properties.
+ *
+ * In the properties, a value of 'public' is true,
+ * anything else is false.
+ *
+ * @returns True if prefer is public or the
+ * defaultPreferSetting.
+ */
+ public static boolean preferPublic () {
+ 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"));
+ }
+
+ /**
+ * 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.
+ *
+ * @returns The static-catalog setting from the propertyFile or the
+ * defaultStaticCatalog.
+ */
+ public static boolean staticCatalog () {
+ String staticCatalog = System.getProperty(pStatic);
+
+ if (staticCatalog == null) {
+ if (resources==null) readProperties();
+ if (resources==null) return defaultStaticCatalog;
+ try {
+ staticCatalog = resources.getString("static-catalog");
+ } catch (MissingResourceException e) {
+ return defaultStaticCatalog;
+ }
+ }
+
+ if (staticCatalog == null) {
+ return defaultStaticCatalog;
+ }
+
+ return (staticCatalog.equalsIgnoreCase("true")
+ || staticCatalog.equalsIgnoreCase("yes")
+ || staticCatalog.equalsIgnoreCase("1"));
+ }
+
+ /**
+ * Obtain the oasisXMLCatalogPI setting from the properties.
+ *
+ * In the properties, a value of 'yes', 'true', or '1' is considered
+ * true, anything else is false.
+ *
+ * @returns The oasisXMLCatalogPI setting from the propertyFile or the
+ * defaultOasisXMLCatalogPI.
+ */
+ public static boolean allowOasisXMLCatalogPI () {
+ 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"));
+ }
+
+ /**
+ * Obtain the Catalog class name setting from the properties.
+ *
+ */
+ public static String catalogClassName () {
+ 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;
+ }
+}
diff --git a/java/src/org/apache/xml/resolver/LICENSE b/java/src/org/apache/xml/resolver/LICENSE
new file mode 100644
index 0000000..558c10d
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/LICENSE
@@ -0,0 +1,57 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
diff --git a/java/src/org/apache/xml/resolver/Resolver.java b/java/src/org/apache/xml/resolver/Resolver.java
new file mode 100644
index 0000000..d9445f7
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/Resolver.java
@@ -0,0 +1,746 @@
+// Resolver.java - Represents an extension of OASIS Open Catalog files.
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver;
+
+import java.lang.Integer;
+import java.io.IOException;
+import java.io.File;
+import java.io.InputStream;
+import java.io.DataInputStream;
+import java.io.PrintWriter;
+import java.io.FileWriter;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.FileNotFoundException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import org.apache.xml.resolver.readers.CatalogReader;
+import org.apache.xml.resolver.readers.SAXCatalogReader;
+import org.apache.xml.resolver.readers.OASISXMLCatalogReader;
+import org.apache.xml.resolver.readers.ExtendedXMLCatalogReader;
+import org.apache.xml.resolver.readers.TR9401CatalogReader;
+import org.apache.xml.resolver.readers.TextCatalogReader;
+import org.apache.xml.resolver.helpers.Debug;
+import org.xml.sax.SAXException;
+import org.xml.sax.EntityResolver;
+import javax.xml.parsers.SAXParserFactory;
+
+/**
+ * An extension to OASIS Open Catalog files, this class supports
+ * suffix-based matching and an external RFC2483 resolver.
+ *
+ * @see Catalog
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class Resolver extends Catalog {
+ /**
+ * The URISUFFIX Catalog Entry type.
+ *
+ * URI suffix entries match URIs that end in a specified suffix.
+ */
+ public static final int URISUFFIX = CatalogEntry.addEntryType("URISUFFIX", 2);
+
+ /**
+ * The SYSTEMSUFFIX Catalog Entry type.
+ *
+ * System suffix entries match system identifiers that end in a
+ * specified suffix.
+ */
+ public static final int SYSTEMSUFFIX = CatalogEntry.addEntryType("SYSTEMSUFFIX", 2);
+
+ /**
+ * The RESOLVER Catalog Entry type.
+ *
+ * A hook for providing support for web-based backup resolvers.
+ */
+ public static final int RESOLVER = CatalogEntry.addEntryType("RESOLVER", 1);
+
+ /**
+ * The SYSTEMREVERSE Catalog Entry type.
+ *
+ * This is a bit of a hack. There's no actual SYSTEMREVERSE entry,
+ * but this entry type is used to indicate that a reverse lookup is
+ * being performed. (This allows the Resolver to implement
+ * RFC2483 I2N and I2NS.)
+ */
+ public static final int SYSTEMREVERSE
+ = CatalogEntry.addEntryType("SYSTEMREVERSE", 1);
+
+ /**
+ *
Setup readers.
+ */
+ public void setupReaders() {
+ SAXParserFactory spf = SAXParserFactory.newInstance();
+ spf.setNamespaceAware(true);
+ spf.setValidating(false);
+
+ SAXCatalogReader saxReader = new SAXCatalogReader(spf);
+
+ saxReader.setCatalogParser(null, "XMLCatalog",
+ "org.apache.xml.resolver.readers.XCatalogReader");
+
+ saxReader.setCatalogParser(OASISXMLCatalogReader.namespaceName,
+ "catalog",
+ "org.apache.xml.resolver.readers.ExtendedXMLCatalogReader");
+
+ addReader("application/xml", saxReader);
+
+ TR9401CatalogReader textReader = new TR9401CatalogReader();
+ addReader("text/plain", textReader);
+ }
+
+ /**
+ * Cleanup and process a Catalog entry.
+ *
+ * This method processes each Catalog entry, changing mapped
+ * relative system identifiers into absolute ones (based on the current
+ * base URI), and maintaining other information about the current
+ * catalog.
+ *
+ * @param entry The CatalogEntry to process.
+ */
+ public void addEntry(CatalogEntry entry) {
+ int type = entry.getEntryType();
+
+ if (type == URISUFFIX) {
+ String suffix = normalizeURI(entry.getEntryArg(0));
+ String fsi = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
+
+ entry.setEntryArg(1, fsi);
+
+ Debug.message(4, "URISUFFIX", suffix, fsi);
+ } else if (type == SYSTEMSUFFIX) {
+ String suffix = normalizeURI(entry.getEntryArg(0));
+ String fsi = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
+
+ entry.setEntryArg(1, fsi);
+
+ Debug.message(4, "SYSTEMSUFFIX", suffix, fsi);
+ }
+
+ super.addEntry(entry);
+ }
+
+ /**
+ * Return the applicable URI
+ *
+ * If a URI entry exists in the Catalog
+ * for the URI specified, return the mapped value.
+ *
+ * In the Resolver (as opposed to the Catalog) class, if the
+ * URI isn't found by the usual algorithm, URISUFFIX entries are
+ * considered.
+ *
+ * URI comparison is case sensitive.
+ *
+ * @param uri The URI to locate in the catalog.
+ *
+ * @return The resolved URI.
+ *
+ * @throws MalformedURLException The system identifier of a
+ * subordinate catalog cannot be turned into a valid URL.
+ * @throws IOException Error reading subordinate catalog file.
+ */
+ public String resolveURI(String uri)
+ throws MalformedURLException, IOException {
+
+ String resolved = super.resolveURI(uri);
+ if (resolved != null) {
+ return resolved;
+ }
+
+ Enumeration enum = catalogEntries.elements();
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+ if (e.getEntryType() == RESOLVER) {
+ resolved = resolveExternalSystem(uri, e.getEntryArg(0));
+ if (resolved != null) {
+ return resolved;
+ }
+ } else if (e.getEntryType() == URISUFFIX) {
+ String suffix = e.getEntryArg(0);
+ String result = e.getEntryArg(1);
+
+ if (suffix.length() <= uri.length()
+ && uri.substring(uri.length()-suffix.length()).equals(suffix)) {
+ return result;
+ }
+ }
+ }
+
+ // Otherwise, look in the subordinate catalogs
+ return resolveSubordinateCatalogs(Catalog.URI,
+ null,
+ null,
+ uri);
+ }
+
+ /**
+ * Return the applicable SYSTEM system identifier, resorting
+ * to external RESOLVERs if necessary.
+ *
+ * If a SYSTEM entry exists in the Catalog
+ * for the system ID specified, return the mapped value.
+ *
+ * In the Resolver (as opposed to the Catalog) class, if the
+ * URI isn't found by the usual algorithm, SYSTEMSUFFIX entries are
+ * considered.
+ *
+ * On Windows-based operating systems, the comparison between
+ * the system identifier provided and the SYSTEM entries in the
+ * Catalog is case-insensitive.
+ *
+ * @param systemId The system ID to locate in the catalog.
+ *
+ * @return The system identifier to use for systemId.
+ *
+ * @throws MalformedURLException The formal system identifier of a
+ * subordinate catalog cannot be turned into a valid URL.
+ * @throws IOException Error reading subordinate catalog file.
+ */
+ public String resolveSystem(String systemId)
+ throws MalformedURLException, IOException {
+
+ String resolved = super.resolveSystem(systemId);
+ if (resolved != null) {
+ return resolved;
+ }
+
+ Enumeration enum = catalogEntries.elements();
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+ if (e.getEntryType() == RESOLVER) {
+ resolved = resolveExternalSystem(systemId, e.getEntryArg(0));
+ if (resolved != null) {
+ return resolved;
+ }
+ } else if (e.getEntryType() == SYSTEMSUFFIX) {
+ String suffix = e.getEntryArg(0);
+ String result = e.getEntryArg(1);
+
+ if (suffix.length() <= systemId.length()
+ && systemId.substring(systemId.length()-suffix.length()).equals(suffix)) {
+ return result;
+ }
+ }
+ }
+
+ return resolveSubordinateCatalogs(Catalog.SYSTEM,
+ null,
+ null,
+ systemId);
+ }
+
+ /**
+ * Return the applicable PUBLIC or SYSTEM identifier, resorting
+ * to external resolvers if necessary.
+ *
+ * This method searches the Catalog and returns the system
+ * identifier specified for the given system or
+ * public identifiers. If
+ * no appropriate PUBLIC or SYSTEM entry is found in the Catalog,
+ * null is returned.
+ *
+ * Note that a system or public identifier in the current catalog
+ * (or subordinate catalogs) will be used in preference to an
+ * external resolver. Further, if a systemId is present, the external
+ * resolver(s) will be queried for that before the publicId.
+ *
+ * @param publicId The public identifier to locate in the catalog.
+ * Public identifiers are normalized before comparison.
+ * @param systemId The nominal system identifier for the entity
+ * in question (as provided in the source document).
+ *
+ * @throws MalformedURLException The formal system identifier of a
+ * subordinate catalog cannot be turned into a valid URL.
+ * @throws IOException Error reading subordinate catalog file.
+ *
+ * @return The system identifier to use.
+ * Note that the nominal system identifier is not returned if a
+ * match is not found in the catalog, instead null is returned
+ * to indicate that no match was found.
+ */
+ public String resolvePublic(String publicId, String systemId)
+ throws MalformedURLException, IOException {
+
+ String resolved = super.resolvePublic(publicId, systemId);
+ if (resolved != null) {
+ return resolved;
+ }
+
+ Enumeration enum = catalogEntries.elements();
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+ if (e.getEntryType() == RESOLVER) {
+ if (systemId != null) {
+ resolved = resolveExternalSystem(systemId,
+ e.getEntryArg(0));
+ if (resolved != null) {
+ return resolved;
+ }
+ }
+ resolved = resolveExternalPublic(publicId, e.getEntryArg(0));
+ if (resolved != null) {
+ return resolved;
+ }
+ }
+ }
+
+ return resolveSubordinateCatalogs(Catalog.PUBLIC,
+ null,
+ publicId,
+ systemId);
+ }
+
+ /**
+ * Query an external RFC2483 resolver for a system identifier.
+ *
+ * @param systemId The system ID to locate.
+ * @param resolver The name of the resolver to use.
+ *
+ * @return The system identifier to use for the systemId.
+ */
+ protected String resolveExternalSystem(String systemId, String resolver)
+ throws MalformedURLException, IOException {
+ Resolver r = queryResolver(resolver, "i2l", systemId, null);
+ if (r != null) {
+ return r.resolveSystem(systemId);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Query an external RFC2483 resolver for a public identifier.
+ *
+ * @param publicId The system ID to locate.
+ * @param resolver The name of the resolver to use.
+ *
+ * @return The system identifier to use for the systemId.
+ */
+ protected String resolveExternalPublic(String publicId, String resolver)
+ throws MalformedURLException, IOException {
+ Resolver r = queryResolver(resolver, "fpi2l", publicId, null);
+ if (r != null) {
+ return r.resolvePublic(publicId, null);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Query an external RFC2483 resolver.
+ *
+ * @param resolver The URL of the RFC2483 resolver.
+ * @param command The command to send the resolver.
+ * @param arg1 The first argument to the resolver.
+ * @param arg2 The second argument to the resolver, usually null.
+ *
+ * @return The Resolver constructed.
+ */
+ protected Resolver queryResolver(String resolver,
+ String command,
+ String arg1,
+ String arg2) {
+ InputStream iStream = null;
+ String RFC2483 = resolver + "?command=" + command
+ + "&format=tr9401&uri=" + arg1
+ + "&uri2=" + arg2;
+ String line = null;
+
+ try {
+ URL url = new URL(RFC2483);
+
+ URLConnection urlCon = url.openConnection();
+
+ urlCon.setUseCaches(false);
+
+ Resolver r = (Resolver) newCatalog();
+
+ String cType = urlCon.getContentType();
+
+ // I don't care about the character set or subtype
+ if (cType.indexOf(";") > 0) {
+ cType = cType.substring(0, cType.indexOf(";"));
+ }
+
+ r.parseCatalog(cType, urlCon.getInputStream());
+
+ return r;
+ } catch (CatalogException cex) {
+ if (cex.getExceptionType() == CatalogException.UNPARSEABLE) {
+ Debug.message(1, "Unparseable catalog: " + RFC2483);
+ } else if (cex.getExceptionType()
+ == CatalogException.UNKNOWN_FORMAT) {
+ Debug.message(1, "Unknown catalog format: " + RFC2483);
+ }
+ return null;
+ } catch (MalformedURLException mue) {
+ Debug.message(1, "Malformed resolver URL: " + RFC2483);
+ return null;
+ } catch (IOException ie) {
+ Debug.message(1, "I/O Exception opening resolver: " + RFC2483);
+ return null;
+ }
+ }
+
+ /**
+ * Append two vectors, returning the result.
+ *
+ * @param vec The first vector
+ * @param appvec The vector to be appended
+ * @return The vector vec, with appvec's elements appended to it
+ */
+ private Vector appendVector(Vector vec, Vector appvec) {
+ if (appvec != null) {
+ for (int count = 0; count < appvec.size(); count++) {
+ vec.addElement(appvec.elementAt(count));
+ }
+ }
+ return vec;
+ }
+
+ /**
+ * Find the URNs for a given system identifier in all catalogs.
+ *
+ * @param systemId The system ID to locate.
+ *
+ * @return A vector of URNs that map to the systemId.
+ */
+ public Vector resolveAllSystemReverse(String systemId)
+ throws MalformedURLException, IOException {
+ Vector resolved = new Vector();
+
+ // If there's a SYSTEM entry in this catalog, use it
+ if (systemId != null) {
+ Vector localResolved = resolveLocalSystemReverse(systemId);
+ resolved = appendVector(resolved, localResolved);
+ }
+
+ // Otherwise, look in the subordinate catalogs
+ Vector subResolved = resolveAllSubordinateCatalogs(SYSTEMREVERSE,
+ null,
+ null,
+ systemId);
+
+ return appendVector(resolved, subResolved);
+ }
+
+ /**
+ * Find the URN for a given system identifier.
+ *
+ * @param systemId The system ID to locate.
+ *
+ * @return A (single) URN that maps to the systemId.
+ */
+ public String resolveSystemReverse(String systemId)
+ throws MalformedURLException, IOException {
+ Vector resolved = resolveAllSystemReverse(systemId);
+ if (resolved != null && resolved.size() > 0) {
+ return (String) resolved.elementAt(0);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Return the applicable SYSTEM system identifiers
+ *
+ * If one or more SYSTEM entries exists in the Catalog
+ * for the system ID specified, return the mapped values.
+ *
+ * The caller is responsible for doing any necessary
+ * normalization of the system identifier before calling
+ * this method. For example, a relative system identifier in
+ * a document might be converted to an absolute system identifier
+ * before attempting to resolve it.
+ *
+ * Note that this function will force all subordinate catalogs
+ * to be loaded.
+ *
+ * On Windows-based operating systems, the comparison between
+ * the system identifier provided and the SYSTEM entries in the
+ * Catalog is case-insensitive.
+ *
+ * @param systemId The system ID to locate in the catalog.
+ *
+ * @return The system identifier to use for the notation.
+ *
+ * @throws MalformedURLException The formal system identifier of a
+ * subordinate catalog cannot be turned into a valid URL.
+ * @throws IOException Error reading subordinate catalog file.
+ */
+ public Vector resolveAllSystem(String systemId)
+ throws MalformedURLException, IOException {
+ Vector resolutions = new Vector();
+
+ // If there are SYSTEM entries in this catalog, start with them
+ if (systemId != null) {
+ Vector localResolutions = resolveAllLocalSystem(systemId);
+ resolutions = appendVector(resolutions, localResolutions);
+ }
+
+ // Then look in the subordinate catalogs
+ Vector subResolutions = resolveAllSubordinateCatalogs(SYSTEM,
+ null,
+ null,
+ systemId);
+ resolutions = appendVector(resolutions, subResolutions);
+
+ if (resolutions.size() > 0) {
+ return resolutions;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Return all applicable SYSTEM system identifiers in this
+ * catalog.
+ *
+ * If one or more SYSTEM entries exists in the catalog file
+ * for the system ID specified, return the mapped values.
+ *
+ * @param systemId The system ID to locate in the catalog
+ *
+ * @return A vector of the mapped system identifiers or null
+ */
+ private Vector resolveAllLocalSystem(String systemId) {
+ Vector map = new Vector();
+ String osname = System.getProperty("os.name");
+ boolean windows = (osname.indexOf("Windows") >= 0);
+ Enumeration enum = catalogEntries.elements();
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+ if (e.getEntryType() == SYSTEM
+ && (e.getEntryArg(0).equals(systemId)
+ || (windows
+ && e.getEntryArg(0).equalsIgnoreCase(systemId)))) {
+ map.addElement(e.getEntryArg(1));
+ }
+ }
+ if (map.size() == 0) {
+ return null;
+ } else {
+ return map;
+ }
+ }
+
+ /**
+ * Find the URNs for a given system identifier in the current catalog.
+ *
+ * @param systemId The system ID to locate.
+ *
+ * @return A vector of URNs that map to the systemId.
+ */
+ private Vector resolveLocalSystemReverse(String systemId) {
+ Vector map = new Vector();
+ String osname = System.getProperty("os.name");
+ boolean windows = (osname.indexOf("Windows") >= 0);
+ Enumeration enum = catalogEntries.elements();
+ while (enum.hasMoreElements()) {
+ CatalogEntry e = (CatalogEntry) enum.nextElement();
+ if (e.getEntryType() == SYSTEM
+ && (e.getEntryArg(1).equals(systemId)
+ || (windows
+ && e.getEntryArg(1).equalsIgnoreCase(systemId)))) {
+ map.addElement(e.getEntryArg(0));
+ }
+ }
+ if (map.size() == 0) {
+ return null;
+ } else {
+ return map;
+ }
+ }
+
+ /**
+ * Search the subordinate catalogs, in order, looking for all
+ * match.
+ *
+ * This method searches the Catalog and returns all of the system
+ * identifiers specified for the given entity type with the given
+ * name, public, and system identifiers. In some contexts, these
+ * may be null.
+ *
+ * @param entityType The CatalogEntry type for which this query is
+ * being conducted. This is necessary in order to do the approprate
+ * query on a subordinate catalog.
+ * @param entityName The name of the entity being searched for, if
+ * appropriate.
+ * @param publicId The public identifier of the entity in question
+ * (as provided in the source document).
+ * @param systemId The nominal system identifier for the entity
+ * in question (as provided in the source document).
+ *
+ * @throws MalformedURLException The formal system identifier of a
+ * delegated catalog cannot be turned into a valid URL.
+ * @throws IOException Error reading delegated catalog file.
+ *
+ * @return The system identifier to use.
+ * Note that the nominal system identifier is not returned if a
+ * match is not found in the catalog, instead null is returned
+ * to indicate that no match was found.
+ */
+ private synchronized Vector resolveAllSubordinateCatalogs(int entityType,
+ String entityName,
+ String publicId,
+ String systemId)
+ throws MalformedURLException, IOException {
+
+ Vector resolutions = new Vector();
+
+ for (int catPos = 0; catPos < catalogs.size(); catPos++) {
+ Resolver c = null;
+
+ try {
+ c = (Resolver) catalogs.elementAt(catPos);
+ } catch (ClassCastException e) {
+ String catfile = (String) catalogs.elementAt(catPos);
+ c = (Resolver) newCatalog();
+
+ try {
+ c.parseCatalog(catfile);
+ } catch (MalformedURLException mue) {
+ Debug.message(1, "Malformed Catalog URL", catfile);
+ } catch (FileNotFoundException fnfe) {
+ Debug.message(1, "Failed to load catalog, file not found",
+ catfile);
+ } catch (IOException ioe) {
+ Debug.message(1, "Failed to load catalog, I/O error", catfile);
+ }
+
+ catalogs.setElementAt(c, catPos);
+ }
+
+ String resolved = null;
+
+ // Ok, now what are we supposed to call here?
+ if (entityType == DOCTYPE) {
+ resolved = c.resolveDoctype(entityName,
+ publicId,
+ systemId);
+ if (resolved != null) {
+ // Only find one DOCTYPE resolution
+ resolutions.addElement(resolved);
+ return resolutions;
+ }
+ } else if (entityType == DOCUMENT) {
+ resolved = c.resolveDocument();
+ if (resolved != null) {
+ // Only find one DOCUMENT resolution
+ resolutions.addElement(resolved);
+ return resolutions;
+ }
+ } else if (entityType == ENTITY) {
+ resolved = c.resolveEntity(entityName,
+ publicId,
+ systemId);
+ if (resolved != null) {
+ // Only find one ENTITY resolution
+ resolutions.addElement(resolved);
+ return resolutions;
+ }
+ } else if (entityType == NOTATION) {
+ resolved = c.resolveNotation(entityName,
+ publicId,
+ systemId);
+ if (resolved != null) {
+ // Only find one NOTATION resolution
+ resolutions.addElement(resolved);
+ return resolutions;
+ }
+ } else if (entityType == PUBLIC) {
+ resolved = c.resolvePublic(publicId, systemId);
+ if (resolved != null) {
+ // Only find one PUBLIC resolution
+ resolutions.addElement(resolved);
+ return resolutions;
+ }
+ } else if (entityType == SYSTEM) {
+ Vector localResolutions = c.resolveAllSystem(systemId);
+ resolutions = appendVector(resolutions, localResolutions);
+ break;
+ } else if (entityType == SYSTEMREVERSE) {
+ Vector localResolutions = c.resolveAllSystemReverse(systemId);
+ resolutions = appendVector(resolutions, localResolutions);
+ }
+ }
+
+ if (resolutions != null) {
+ return resolutions;
+ } else {
+ return null;
+ }
+ }
+}
+
+
+
+
diff --git a/java/src/org/apache/xml/resolver/apps/XParseError.java b/java/src/org/apache/xml/resolver/apps/XParseError.java
new file mode 100644
index 0000000..7a18839
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/apps/XParseError.java
@@ -0,0 +1,200 @@
+// XParseError.java - An error handler for xparse
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.apps;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.MalformedURLException;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+
+/**
+ * An ErrorHandler for xparse.
+ *
+ * This class is just the error handler for xparse.
+ *
+ * @see xparse
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class XParseError implements ErrorHandler {
+ /** Show errors? */
+ private boolean showErrors = true;
+
+ /** Show warnings? */
+ private boolean showWarnings = false;
+
+ /** How many messages should be presented? */
+ private int maxMessages = 10;
+
+ /** The number of fatal errors seen so far. */
+ private int fatalCount = 0;
+
+ /** The number of errors seen so far. */
+ private int errorCount = 0;
+
+ /** The number of warnings seen so far. */
+ private int warningCount = 0;
+
+ /** The base URI of the running application. */
+ private String baseURI = "";
+
+ /** Constructor */
+ public XParseError(boolean errors, boolean warnings) {
+ showErrors = errors;
+ showWarnings = warnings;
+
+ String dir = System.getProperty("user.dir");
+ String file = "";
+
+ if (dir.endsWith("/")) {
+ file = "file:" + dir + "file";
+ } else {
+ file = "file:" + dir + "/" + file;
+ }
+
+ try {
+ URL url = new URL(file);
+ baseURI = url.toString();
+ } catch (MalformedURLException mue) {
+ // nop;
+ }
+ }
+
+ /** Return the error count */
+ public int getErrorCount() {
+ return errorCount;
+ }
+
+ /** Return the fatal error count */
+ public int getFatalCount() {
+ return fatalCount;
+ }
+
+ /** Return the warning count */
+ public int getWarningCount() {
+ return warningCount;
+ }
+
+ /** Return the number of messages to display */
+ public int getMaxMessages() {
+ return maxMessages;
+ }
+
+ /** Set the number of messages to display */
+ public void setMaxMessages(int max) {
+ maxMessages = max;
+ }
+
+ /** SAX2 API */
+ public void error(SAXParseException exception) {
+ if (showErrors) {
+ if (errorCount+warningCount < maxMessages) {
+ message("Error", exception);
+ }
+ errorCount++;
+ }
+ }
+
+ /** SAX2 API */
+ public void fatalError(SAXParseException exception) {
+ if (showErrors) {
+ if (errorCount+warningCount < maxMessages) {
+ message("Fatal error", exception);
+ }
+ errorCount++;
+ fatalCount++;
+ }
+ }
+
+ /** SAX2 API */
+ public void warning(SAXParseException exception) {
+ if (showWarnings) {
+ if ((errorCount+warningCount < maxMessages)) {
+ message("Warning", exception);
+ }
+ warningCount++;
+ }
+ }
+
+ /** Display a message to the user */
+ private void message(String type, SAXParseException exception) {
+ String filename = exception.getSystemId();
+ if (filename.startsWith(baseURI)) {
+ filename = filename.substring(baseURI.length());
+ }
+
+ System.out.print(type
+ + ":"
+ + filename
+ + ":"
+ + exception.getLineNumber());
+
+ if (exception.getColumnNumber() > 0) {
+ System.out.print(":" + exception.getColumnNumber());
+ }
+
+ System.out.println(":" + exception.getMessage());
+ }
+}
diff --git a/java/src/org/apache/xml/resolver/apps/package.html b/java/src/org/apache/xml/resolver/apps/package.html
new file mode 100644
index 0000000..a04bf36
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/apps/package.html
@@ -0,0 +1,12 @@
+
+
+Apache XML Commons Resolver Applications package
+
+
+Apache XML Commons Resolver Applications package
+
+This package provides a few simple command-line tools for exploring
+the facilities of the resolver.
+
+
+
diff --git a/java/src/org/apache/xml/resolver/apps/resolver.java b/java/src/org/apache/xml/resolver/apps/resolver.java
new file mode 100644
index 0000000..73e86d7
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/apps/resolver.java
@@ -0,0 +1,338 @@
+// resolver.java - A simple command-line test tool for the resolver
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.apps;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+import java.net.MalformedURLException;
+import java.util.Vector;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+
+import javax.xml.parsers.*;
+import javax.xml.transform.*;
+import javax.xml.transform.sax.SAXSource;
+
+import org.apache.xml.resolver.Catalog;
+import org.apache.xml.resolver.tools.CatalogResolver;
+import org.apache.xml.resolver.helpers.Debug;
+import org.apache.xml.resolver.tools.CatalogResolver;
+
+/**
+ * A simple command-line resolver.
+ *
+ * This class implements a simple command-line resolver. It takes
+ * some parameters and passes them through the resolver, printing the
+ * result.
+ *
+ *
+ * Usage: resolver [options] keyword
+ *
+ * Where options are:
+ *
+ *
+ * -c catalogfile
+ * - Load a particular catalog file.
+ * -n name
+ * - Sets the name.
+ * -p publicId
+ * - Sets the public identifier.
+ * -s systemId
+ * - Sets the system identifier.
+ * -a
+ * - Absolute system URI.
+ * -u uri
+ * - Sets the URI.
+ * -d integer
+ * - Set the debug level.
+ *
+ *
+ * And keyword is one of: doctype, document, entity, notation, public,
+ * system, or uri.
+ *
+ * The process ends with error-level 1, if there errors.
+ *
+ * @see org.apache.xml.resolver.tools.ResolvingParser
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0 */
+public class resolver {
+ /** The main entry point */
+ public static void main (String[] args)
+ throws FileNotFoundException, IOException {
+
+ int debug = 0;
+ Vector catalogFiles = new Vector();
+ int resType = 0;
+ String resTypeStr = null;
+ String name = null;
+ String publicId = null;
+ String systemId = null;
+ String uri = null;
+ boolean absoluteSystem = false;
+
+ for (int i=0; i= 0) {
+ Debug.setDebug(debug);
+ }
+ } catch (Exception e) {
+ // nop
+ }
+ continue;
+ }
+
+ resTypeStr = args[i];
+ }
+
+ if (resTypeStr == null) {
+ usage();
+ }
+
+ if (resTypeStr.equalsIgnoreCase("doctype")) {
+ resType = Catalog.DOCTYPE;
+ if (publicId == null && systemId == null) {
+ System.out.println("DOCTYPE requires public or system identifier.");
+ usage();
+ }
+ } else if (resTypeStr.equalsIgnoreCase("document")) {
+ resType = Catalog.DOCUMENT;
+ } else if (resTypeStr.equalsIgnoreCase("entity")) {
+ resType = Catalog.ENTITY;
+ if (publicId == null && systemId == null && name == null) {
+ System.out.println("ENTITY requires name or public or system identifier.");
+ usage();
+ }
+ } else if (resTypeStr.equalsIgnoreCase("notation")) {
+ resType = Catalog.NOTATION;
+ if (publicId == null && systemId == null && name == null) {
+ System.out.println("NOTATION requires name or public or system identifier.");
+ usage();
+ }
+ } else if (resTypeStr.equalsIgnoreCase("public")) {
+ resType = Catalog.PUBLIC;
+ if (publicId == null) {
+ System.out.println("PUBLIC requires public identifier.");
+ usage();
+ }
+ } else if (resTypeStr.equalsIgnoreCase("system")) {
+ resType = Catalog.SYSTEM;
+ if (systemId == null) {
+ System.out.println("SYSTEM requires system identifier.");
+ usage();
+ }
+ } else if (resTypeStr.equalsIgnoreCase("uri")) {
+ resType = Catalog.URI;
+ if (uri == null) {
+ System.out.println("URI requires a uri.");
+ usage();
+ }
+ } else {
+ System.out.println(resTypeStr + " is not a recognized keyword.");
+ usage();
+ }
+
+ if (absoluteSystem) {
+ URL base = null;
+ URL sysid = null;
+
+ // Calculate the appropriate BASE URI
+ try {
+ // tack on a basename because URLs point to files not dirs
+ String userdir = System.getProperty("user.dir");
+ userdir.replace('\\', '/');
+ base = new URL("file:///" + userdir + "/basename");
+ } catch (MalformedURLException e) {
+ String userdir = System.getProperty("user.dir");
+ userdir.replace('\\', '/');
+ Debug.message(1, "Malformed URL on cwd", userdir);
+ base = null;
+ }
+
+ try {
+ sysid = new URL(base, systemId);
+ systemId = sysid.toString();
+ } catch (MalformedURLException e) {
+ try {
+ sysid = new URL("file:///" + systemId);
+ } catch (MalformedURLException e2) {
+ Debug.message(1, "Malformed URL on system id", systemId);
+ }
+ }
+ }
+
+ CatalogResolver catalogResolver = new CatalogResolver();
+ Catalog resolver = catalogResolver.getCatalog();
+
+ for (int count = 0; count < catalogFiles.size(); count++) {
+ String file = (String) catalogFiles.elementAt(count);
+ resolver.parseCatalog(file);
+ }
+ String result = null;
+
+ if (resType == Catalog.DOCTYPE) {
+ System.out.println("Resolve DOCTYPE (name, publicid, systemid):");
+ if (name != null) { System.out.println(" name: " + name); }
+ if (publicId != null) { System.out.println(" public id: " + publicId); }
+ if (systemId != null) { System.out.println(" system id: " + systemId); }
+ if (uri != null) { System.out.println(" uri: " + uri); }
+ result = resolver.resolveDoctype(name, publicId, systemId);
+ } else if (resType == Catalog.DOCUMENT) {
+ System.out.println("Resolve DOCUMENT ():");
+ result = resolver.resolveDocument();
+ } else if (resType == Catalog.ENTITY) {
+ System.out.println("Resolve ENTITY (name, publicid, systemid):");
+ if (name != null) { System.out.println(" name: " + name); }
+ if (publicId != null) { System.out.println(" public id: " + publicId); }
+ if (systemId != null) { System.out.println(" system id: " + systemId); }
+ result = resolver.resolveEntity(name, publicId, systemId);
+ } else if (resType == Catalog.NOTATION) {
+ System.out.println("Resolve NOTATION (name, publicid, systemid):");
+ if (name != null) { System.out.println(" name: " + name); }
+ if (publicId != null) { System.out.println(" public id: " + publicId); }
+ if (systemId != null) { System.out.println(" system id: " + systemId); }
+ result = resolver.resolveNotation(name, publicId, systemId);
+ } else if (resType == Catalog.PUBLIC) {
+ System.out.println("Resolve PUBLIC (publicid, systemid):");
+ if (publicId != null) { System.out.println(" public id: " + publicId); }
+ if (systemId != null) { System.out.println(" system id: " + systemId); }
+ result = resolver.resolvePublic(publicId, systemId);
+ } else if (resType == Catalog.SYSTEM) {
+ System.out.println("Resolve SYSTEM (systemid):");
+ if (systemId != null) { System.out.println(" system id: " + systemId); }
+ result = resolver.resolveSystem(systemId);
+ } else if (resType == Catalog.URI) {
+ System.out.println("Resolve URI (uri):");
+ if (uri != null) { System.out.println(" uri: " + uri); }
+ result = resolver.resolveURI(uri);
+ } else {
+ System.out.println("resType is wrong!? This can't happen!");
+ usage();
+ }
+
+ System.out.println("Result: " + result);
+ }
+
+ public static void usage() {
+ System.out.println("Usage: resolver [options] keyword");
+ System.out.println("");
+ System.out.println("Where:");
+ System.out.println("");
+ System.out.println("-c catalogfile Loads a particular catalog file.");
+ System.out.println("-n name Sets the name.");
+ System.out.println("-p publicId Sets the public identifier.");
+ System.out.println("-s systemId Sets the system identifier.");
+ System.out.println("-a Makes the system URI absolute before resolution");
+ System.out.println("-u uri Sets the URI.");
+ System.out.println("-d integer Set the debug level.");
+ System.out.println("keyword Identifies the type of resolution to perform:");
+ System.out.println(" doctype, document, entity, notation, public, system,");
+ System.out.println(" or uri.");
+
+ System.exit(1);
+ }
+}
+
+
diff --git a/java/src/org/apache/xml/resolver/apps/xparse.java b/java/src/org/apache/xml/resolver/apps/xparse.java
new file mode 100644
index 0000000..d1a09b2
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/apps/xparse.java
@@ -0,0 +1,300 @@
+// xparse.java - A simple command-line XML parser
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.apps;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Vector;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+
+import javax.xml.parsers.*;
+
+import org.apache.xml.resolver.tools.ResolvingParser;
+import org.apache.xml.resolver.Catalog;
+import org.apache.xml.resolver.helpers.Debug;
+
+/**
+ * A simple command-line XML parsing application.
+ *
+ * This class implements a simple command-line XML Parser. It's
+ * just a little wrapper around the JAXP Parser with support for
+ * catalogs.
+ *
+ *
+ * Usage: xparse [options] document.xml
+ *
+ * Where:
+ *
+ *
+ * -c catalogfile
+ * - Load a particular catalog file.
+ * -w
+ * - Perform a well-formed parse, not a validating parse.
+ * -v (the default)
+ * - Perform a validating parse.
+ * -n
+ * - Perform a namespace-ignorant parse.
+ * -N (the default)
+ * - Perform a namespace-aware parse.
+ * -d integer
+ * - Set the debug level. Warnings are shown if the debug level
+ * is > 2.
+ * -E integer
+ * - Set the maximum number of errors to display.
+ *
+ *
+ * The process ends with error-level 1, if there errors.
+ *
+ * @deprecated This interface has been replaced by the
+ * {@link org.apache.xml.resolver.tools.ResolvingXMLReader} for SAX2.
+ *
+ * @see org.apache.xml.resolver.tools.ResolvingParser
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class xparse
+{
+ /** The main entry point */
+ public static void main (String[] args)
+ throws FileNotFoundException, IOException {
+
+ String xmlfile = null;
+ int debug = 0;
+ int maxErrs = 10;
+ boolean nsAware = true;
+ boolean validating = true;
+ boolean showWarnings = (debug > 2);
+ boolean showErrors = true;
+ Vector catalogFiles = new Vector();
+
+ for (int i=0; i= 0) {
+ Debug.setDebug(debug);
+ showWarnings = (debug > 2);
+ }
+ } catch (Exception e) {
+ // nop
+ }
+ continue;
+ }
+
+ if (args[i].equals("-E")) {
+ ++i;
+ String errstr = args[i];
+ try {
+ int errs = Integer.parseInt(errstr);
+ if (errs >= 0) {
+ maxErrs = errs;
+ }
+ } catch (Exception e) {
+ // nop
+ }
+ continue;
+ }
+
+ xmlfile = args[i];
+ }
+
+ if (xmlfile == null) {
+ System.out.println("Usage: org.apache.xml.resolver.apps.xparse [opts] xmlfile");
+ System.exit(1);
+ }
+
+ ResolvingParser.validating = validating;
+ ResolvingParser.namespaceAware = nsAware;
+ ResolvingParser reader = new ResolvingParser();
+ Catalog catalog = reader.getCatalog();
+
+ for (int count = 0; count < catalogFiles.size(); count++) {
+ String file = (String) catalogFiles.elementAt(count);
+ catalog.parseCatalog(file);
+ }
+
+ XParseError xpe = new XParseError(showErrors, showWarnings);
+ xpe.setMaxMessages(maxErrs);
+ reader.setErrorHandler(xpe);
+
+ String parseType = validating ? "validating" : "well-formed";
+ String nsType = nsAware ? "namespace-aware" : "namespace-ignorant";
+ if (maxErrs > 0) {
+ System.out.println("Attempting "
+ + parseType
+ + ", "
+ + nsType
+ + " parse");
+ }
+
+ Date startTime = new Date();
+
+ try {
+ reader.parse(xmlfile);
+ } catch (SAXException sx) {
+ System.out.println("SAX Exception: " + sx);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ Date endTime = new Date();
+
+ long millisec = endTime.getTime() - startTime.getTime();
+ long secs = 0;
+ long mins = 0;
+ long hours = 0;
+
+ if (millisec > 1000) {
+ secs = millisec / 1000;
+ millisec = millisec % 1000;
+ }
+
+ if (secs > 60) {
+ mins = secs / 60;
+ secs = secs % 60;
+ }
+
+ if (mins > 60) {
+ hours = mins / 60;
+ mins = mins % 60;
+ }
+
+ if (maxErrs > 0) {
+ System.out.print("Parse ");
+ if (xpe.getFatalCount() > 0) {
+ System.out.print("failed ");
+ } else {
+ System.out.print("succeeded ");
+ System.out.print("(");
+ if (hours > 0) {
+ System.out.print(hours + ":");
+ }
+ if (hours > 0 || mins > 0) {
+ System.out.print(mins + ":");
+ }
+ System.out.print(secs + "." + millisec);
+ System.out.print(") ");
+ }
+ System.out.print("with ");
+
+ int errCount = xpe.getErrorCount();
+ int warnCount = xpe.getWarningCount();
+
+ if (errCount > 0) {
+ System.out.print(errCount + " error");
+ System.out.print(errCount > 1 ? "s" : "");
+ System.out.print(" and ");
+ } else {
+ System.out.print("no errors and ");
+ }
+
+ if (warnCount > 0) {
+ System.out.print(warnCount + " warning");
+ System.out.print(warnCount > 1 ? "s" : "");
+ System.out.print(".");
+ } else {
+ System.out.print("no warnings.");
+ }
+
+ System.out.println("");
+ }
+
+ if (xpe.getErrorCount() > 0) {
+ System.exit(1);
+ }
+ }
+}
+
+
diff --git a/java/src/org/apache/xml/resolver/apps/xread.java b/java/src/org/apache/xml/resolver/apps/xread.java
new file mode 100644
index 0000000..4434601
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/apps/xread.java
@@ -0,0 +1,303 @@
+// xread.java - A simple command-line XML parser
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.apps;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Vector;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+
+import javax.xml.parsers.*;
+
+import org.apache.xml.resolver.tools.ResolvingXMLReader;
+import org.apache.xml.resolver.Catalog;
+import org.apache.xml.resolver.helpers.Debug;
+
+/**
+ * A simple command-line XML parsing application.
+ *
+ * This class implements a simple command-line XML Parser. It's
+ * just a little wrapper around the JAXP XMLReader with support for
+ * catalogs.
+ *
+ *
+ * Usage: xread [options] document.xml
+ *
+ * Where:
+ *
+ *
+ * -c catalogfile
+ * - Load a particular catalog file.
+ * -w
+ * - Perform a well-formed parse, not a validating parse.
+ * -v (the default)
+ * - Perform a validating parse.
+ * -n
+ * - Perform a namespace-ignorant parse.
+ * -N (the default)
+ * - Perform a namespace-aware parse.
+ * -d integer
+ * - Set the debug level. Warnings are shown if the debug level
+ * is > 2.
+ * -E integer
+ * - Set the maximum number of errors to display.
+ *
+ *
+ * The process ends with error-level 1, if there errors.
+ *
+ * @see org.apache.xml.resolver.tools.ResolvingXMLReader
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class xread
+{
+ /** The main entry point */
+ public static void main (String[] args)
+ throws FileNotFoundException, IOException {
+
+ String xmlfile = null;
+ int debug = 0;
+ int maxErrs = 10;
+ boolean nsAware = true;
+ boolean validating = true;
+ boolean showWarnings = (debug > 2);
+ boolean showErrors = true;
+ Vector catalogFiles = new Vector();
+
+ for (int i=0; i= 0) {
+ Debug.setDebug(debug);
+ showWarnings = (debug > 2);
+ }
+ } catch (Exception e) {
+ // nop
+ }
+ continue;
+ }
+
+ if (args[i].equals("-E")) {
+ ++i;
+ String errstr = args[i];
+ try {
+ int errs = Integer.parseInt(errstr);
+ if (errs >= 0) {
+ maxErrs = errs;
+ }
+ } catch (Exception e) {
+ // nop
+ }
+ continue;
+ }
+
+ xmlfile = args[i];
+ }
+
+ if (xmlfile == null) {
+ System.out.println("Usage: org.apache.xml.resolver.apps.xread [opts] xmlfile");
+ System.exit(1);
+ }
+
+ ResolvingXMLReader reader = new ResolvingXMLReader();
+
+ try {
+ reader.setFeature("http://xml.org/sax/features/namespaces", nsAware);
+ reader.setFeature("http://xml.org/sax/features/validation", validating);
+ } catch (SAXException e) {
+ // nop;
+ }
+
+ Catalog catalog = reader.getCatalog();
+
+ for (int count = 0; count < catalogFiles.size(); count++) {
+ String file = (String) catalogFiles.elementAt(count);
+ catalog.parseCatalog(file);
+ }
+
+ XParseError xpe = new XParseError(showErrors, showWarnings);
+ xpe.setMaxMessages(maxErrs);
+ reader.setErrorHandler(xpe);
+
+ String parseType = validating ? "validating" : "well-formed";
+ String nsType = nsAware ? "namespace-aware" : "namespace-ignorant";
+ if (maxErrs > 0) {
+ System.out.println("Attempting "
+ + parseType
+ + ", "
+ + nsType
+ + " parse");
+ }
+
+ Date startTime = new Date();
+
+ try {
+ reader.parse(xmlfile);
+ } catch (SAXException sx) {
+ System.out.println("SAX Exception: " + sx);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ Date endTime = new Date();
+
+ long millisec = endTime.getTime() - startTime.getTime();
+ long secs = 0;
+ long mins = 0;
+ long hours = 0;
+
+ if (millisec > 1000) {
+ secs = millisec / 1000;
+ millisec = millisec % 1000;
+ }
+
+ if (secs > 60) {
+ mins = secs / 60;
+ secs = secs % 60;
+ }
+
+ if (mins > 60) {
+ hours = mins / 60;
+ mins = mins % 60;
+ }
+
+ if (maxErrs > 0) {
+ System.out.print("Parse ");
+ if (xpe.getFatalCount() > 0) {
+ System.out.print("failed ");
+ } else {
+ System.out.print("succeeded ");
+ System.out.print("(");
+ if (hours > 0) {
+ System.out.print(hours + ":");
+ }
+ if (hours > 0 || mins > 0) {
+ System.out.print(mins + ":");
+ }
+ System.out.print(secs + "." + millisec);
+ System.out.print(") ");
+ }
+ System.out.print("with ");
+
+ int errCount = xpe.getErrorCount();
+ int warnCount = xpe.getWarningCount();
+
+ if (errCount > 0) {
+ System.out.print(errCount + " error");
+ System.out.print(errCount > 1 ? "s" : "");
+ System.out.print(" and ");
+ } else {
+ System.out.print("no errors and ");
+ }
+
+ if (warnCount > 0) {
+ System.out.print(warnCount + " warning");
+ System.out.print(warnCount > 1 ? "s" : "");
+ System.out.print(".");
+ } else {
+ System.out.print("no warnings.");
+ }
+
+ System.out.println("");
+ }
+
+ if (xpe.getErrorCount() > 0) {
+ System.exit(1);
+ }
+ }
+}
+
+
diff --git a/java/src/org/apache/xml/resolver/helpers/Debug.java b/java/src/org/apache/xml/resolver/helpers/Debug.java
new file mode 100644
index 0000000..d9fb536
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/helpers/Debug.java
@@ -0,0 +1,145 @@
+// Debug.java - Print debug messages
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.helpers;
+
+import org.apache.xml.resolver.CatalogManager;
+
+/**
+ * Static debugging/messaging class for Catalogs.
+ *
+ * This class defines a set of static methods that can be called
+ * to produce debugging messages. Messages have an associated "debug
+ * level" and messages below the current setting are not displayed.
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class Debug {
+ /** The internal debug level. */
+ protected static int debug = CatalogManager.verbosity();
+
+ /** Set the debug level for future messages. */
+ public static void setDebug(int newDebug) {
+ debug = newDebug;
+ }
+
+ /** Get the current debug level. */
+ public static int getDebug() {
+ return debug;
+ }
+
+ /**
+ * Print debug message (if the debug level is high enough).
+ *
+ * Prints "the message"
+ *
+ * @param level The debug level of this message. This message
+ * will only be
+ * displayed if the current debug level is at least equal to this
+ * value.
+ * @param message The text of the message.
+ */
+ public static void message(int level, String message) {
+ if (debug >= level) {
+ System.out.println(message);
+ }
+ }
+
+ /**
+ * Print debug message (if the debug level is high enough).
+ *
+ * Prints "the message: spec"
+ *
+ * @param level The debug level of this message. This message
+ * will only be
+ * displayed if the current debug level is at least equal to this
+ * value.
+ * @param message The text of the message.
+ * @param spec An argument to the message.
+ */
+ public static void message(int level, String message, String spec) {
+ if (debug >= level) {
+ System.out.println(message + ": " + spec);
+ }
+ }
+
+ /**
+ * Print debug message (if the debug level is high enough).
+ *
+ * Prints "the message: spec1" and "spec2" indented on the next line.
+ *
+ * @param level The debug level of this message. This message
+ * will only be
+ * displayed if the current debug level is at least equal to this
+ * value.
+ * @param message The text of the message.
+ * @param spec1 An argument to the message.
+ * @param spec2 Another argument to the message.
+ */
+ public static void message(int level, String message,
+ String spec1, String spec2) {
+ if (debug >= level) {
+ System.out.println(message + ": " + spec1);
+ System.out.println("\t" + spec2);
+ }
+ }
+}
diff --git a/java/src/org/apache/xml/resolver/helpers/Namespaces.java b/java/src/org/apache/xml/resolver/helpers/Namespaces.java
new file mode 100644
index 0000000..ffd2fba
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/helpers/Namespaces.java
@@ -0,0 +1,151 @@
+// Namespaces.java - Analyze namespace nodes in a DOM tree
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.helpers;
+
+import org.w3c.dom.*;
+
+/**
+ * Static Namespace query methods.
+ *
+ * This class defines a set of static methods that can be called
+ * to analyze the namespace properties of DOM nodes.
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class Namespaces {
+ /**
+ * Returns the "prefix" part of a QName or the empty string (not
+ * null) if the name has no prefix.
+ *
+ * @param element The QName of an element.
+ * @return The prefix part of the element name.
+ */
+ public static String getPrefix(Element element) {
+ String name = element.getTagName();
+ String prefix = "";
+
+ if (name.indexOf(':') > 0) {
+ prefix = name.substring(0, name.indexOf(':'));
+ }
+
+ return prefix;
+ }
+
+ /**
+ * Returns the "localname" part of a QName, which is the whole
+ * name if it has no prefix.
+ *
+ * @param element The QName of an element.
+ * @return The local part of a QName.
+ */
+ public static String getLocalName(Element element) {
+ String name = element.getTagName();
+
+ if (name.indexOf(':') > 0) {
+ name = name.substring(name.indexOf(':')+1);
+ }
+
+ return name;
+ }
+
+ /**
+ * Returns the namespace URI for the specified prefix at the
+ * specified context node.
+ *
+ * @param node The context node.
+ * @param prefix The prefix.
+ * @return The namespace URI associated with the prefix, or
+ * null if no namespace declaration exists for the prefix.
+ */
+ public static String getNamespaceURI(Node node, String prefix) {
+ if (node == null || node.getNodeType() != Node.ELEMENT_NODE) {
+ return null;
+ }
+
+ if (prefix.equals("")) {
+ if (((Element) node).hasAttribute("xmlns")) {
+ return ((Element) node).getAttribute("xmlns");
+ }
+ } else {
+ String nsattr = "xmlns:" + prefix;
+ if (((Element) node).hasAttribute(nsattr)) {
+ return ((Element) node).getAttribute(nsattr);
+ }
+ }
+
+ return getNamespaceURI(node.getParentNode(), prefix);
+ }
+
+ /**
+ * Returns the namespace URI for the namespace to which the
+ * element belongs.
+ *
+ * @param element The element.
+ * @return The namespace URI associated with the namespace of the
+ * element, or null if no namespace declaration exists for it.
+ */
+ public static String getNamespaceURI(Element element) {
+ String prefix = getPrefix(element);
+ return getNamespaceURI(element, prefix);
+ }
+}
diff --git a/java/src/org/apache/xml/resolver/helpers/PublicId.java b/java/src/org/apache/xml/resolver/helpers/PublicId.java
new file mode 100644
index 0000000..b964d90
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/helpers/PublicId.java
@@ -0,0 +1,198 @@
+// PublicId.java - Information about public identifiers
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.helpers;
+
+/**
+ * Static methods for dealing with public identifiers.
+ *
+ * This class defines a set of static methods that can be called
+ * to handle public identifiers.
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public abstract class PublicId {
+ protected PublicId() { }
+
+ /**
+ * Normalize a public identifier.
+ *
+ * Public identifiers must be normalized according to the following
+ * rules before comparisons between them can be made:
+ *
+ *
+ * - Whitespace characters are normalized to spaces (e.g., line feeds,
+ * tabs, etc. become spaces).
+ * - Leading and trailing whitespace is removed.
+ * - Multiple internal whitespaces are normalized to a single
+ * space.
+ *
+ *
+ * This method is declared static so that other classes
+ * can use it directly.
+ *
+ * @param publicId The unnormalized public identifier.
+ *
+ * @return The normalized identifier.
+ */
+ public static String normalize(String publicId) {
+ String normal = publicId.replace('\t', ' ');
+ normal = normal.replace('\r', ' ');
+ normal = normal.replace('\n', ' ');
+ normal = normal.trim();
+
+ int pos;
+
+ while ((pos = normal.indexOf(" ")) >= 0) {
+ normal = normal.substring(0, pos) + normal.substring(pos+1);
+ }
+
+ return normal;
+ }
+
+ /**
+ * Encode a public identifier as a "publicid" URN.
+ *
+ * This method is declared static so that other classes
+ * can use it directly.
+ *
+ * @param publicId The unnormalized public identifier.
+ *
+ * @return The normalized identifier.
+ */
+ public static String encodeURN(String publicId) {
+ String urn = PublicId.normalize(publicId);
+
+ urn = PublicId.stringReplace(urn, "%", "%25");
+ urn = PublicId.stringReplace(urn, ";", "%3B");
+ urn = PublicId.stringReplace(urn, "'", "%27");
+ urn = PublicId.stringReplace(urn, "?", "%3F");
+ urn = PublicId.stringReplace(urn, "#", "%23");
+ urn = PublicId.stringReplace(urn, "+", "%2B");
+ urn = PublicId.stringReplace(urn, " ", "+");
+ urn = PublicId.stringReplace(urn, "::", ";");
+ urn = PublicId.stringReplace(urn, ":", "%3A");
+ urn = PublicId.stringReplace(urn, "//", ":");
+ urn = PublicId.stringReplace(urn, "/", "%2F");
+
+ return "urn:publicid:" + urn;
+ }
+
+ /**
+ * Decode a "publicid" URN into a public identifier.
+ *
+ * This method is declared static so that other classes
+ * can use it directly.
+ *
+ * @param publicId The unnormalized public identifier.
+ *
+ * @return The normalized identifier.
+ */
+ public static String decodeURN(String urn) {
+ String publicId = "";
+
+ if (urn.startsWith("urn:publicid:")) {
+ publicId = urn.substring(13);
+ } else {
+ return urn;
+ }
+
+ publicId = PublicId.stringReplace(publicId, "%2F", "/");
+ publicId = PublicId.stringReplace(publicId, ":", "//");
+ publicId = PublicId.stringReplace(publicId, "%3A", ":");
+ publicId = PublicId.stringReplace(publicId, ";", "::");
+ publicId = PublicId.stringReplace(publicId, "+", " ");
+ publicId = PublicId.stringReplace(publicId, "%2B", "+");
+ publicId = PublicId.stringReplace(publicId, "%23", "#");
+ publicId = PublicId.stringReplace(publicId, "%3F", "?");
+ publicId = PublicId.stringReplace(publicId, "%27", "'");
+ publicId = PublicId.stringReplace(publicId, "%3B", ";");
+ publicId = PublicId.stringReplace(publicId, "%25", "%");
+
+ return publicId;
+ }
+
+ /**
+ * Replace one string with another.
+ *
+ */
+ private static String stringReplace(String str,
+ String oldStr,
+ String newStr) {
+
+ String result = "";
+ int pos = str.indexOf(oldStr);
+
+ // System.out.println(str + ": " + oldStr + " => " + newStr);
+
+ while (pos >= 0) {
+ // System.out.println(str + " (" + pos + ")");
+ result += str.substring(0, pos);
+ result += newStr;
+ str = str.substring(pos+1);
+
+ pos = str.indexOf(oldStr);
+ }
+
+ return result + str;
+ }
+}
diff --git a/java/src/org/apache/xml/resolver/helpers/package.html b/java/src/org/apache/xml/resolver/helpers/package.html
new file mode 100644
index 0000000..a0ad685
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/helpers/package.html
@@ -0,0 +1,12 @@
+
+
+Apache XML Commons Resolver Helpers package
+
+
+Apache XML Commons Resolver Helpers package
+
+This package provides a collection of static helper functions used
+across a number of different classes.
+
+
+
diff --git a/java/src/org/apache/xml/resolver/overview.html b/java/src/org/apache/xml/resolver/overview.html
new file mode 100644
index 0000000..0f5d2c6
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/overview.html
@@ -0,0 +1,41 @@
+
+
+Apache XML Common Resolver
+
+
+The Apache XML Commons Resolver classes implement Catalog-based entity and
+URI resolution.
+
+Overview
+
+The resolver class implements the full semantics of OASIS
+Technical
+Resolution 9401:1997 (Amendment 2 to TR 9401) catalogs and
+the 06 Aug 2001 Committee Specification of OASIS
+XML
+Catalogs.
+
+It also
+includes a framework of classes designed to read catalog files in
+a number of formats:
+
+
+
+- The plain-text flavor described by TR9401.
+
- The XCatalog
+XML format defined by John Cowan
+
- The XML Catalog format defined by the OASIS
+Entity Resolution
+Technical Committee.
+
+
+Quick Start
+
+The tools
+classes provide "out-of-the-box" SAX1 Parser, SAX2 XMLReader,
+and JAXP URIResolvers. If you're just interested in hooking a
+parser or URI resolver into your application, this is the place to start.
+
+
+
+
diff --git a/java/src/org/apache/xml/resolver/package.html b/java/src/org/apache/xml/resolver/package.html
new file mode 100644
index 0000000..9e80df3
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/package.html
@@ -0,0 +1,34 @@
+
+
+Apache XML Commons Resolver package
+
+
+Apache XML Commons Resolver package
+
+The classes in this package implement the full semantics of
+OASIS Technical
+Resolution 9401:1997 (Amendment 2 to TR 9401) catalogs. Also included
+are a framework of classes designed to read catalog files in
+a number of formats.
+
+
+The principal classes in this package are:
+
+
+- Catalog, implements the
+semantics of OASIS Catalogs.
+
- Resolver, demonstrates how the semantics
+of OASIS Catalogs can be extended with these classes.
+
- CatalogManager, interfaces with the
+Catalog properties file (that controls the default values of certain
+properties).
+
- TR9401CatalogReader, reads
+plain text TR9401 catalog files
+
- OASISXMLCatalogReader, reads
+OASIS XML Catalogs (as defined in the 2001-08-01 committee draft)
+
- XCatalogReader, reads John Cowan's
+XCatalog files
+
+
+
+
diff --git a/java/src/org/apache/xml/resolver/readers/CatalogReader.java b/java/src/org/apache/xml/resolver/readers/CatalogReader.java
new file mode 100644
index 0000000..63d85ea
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/readers/CatalogReader.java
@@ -0,0 +1,118 @@
+// CatalogReader.java - An interface for reading catalog files
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.readers;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import org.apache.xml.resolver.CatalogException;
+
+import java.io.InputStream;
+import org.apache.xml.resolver.Catalog;
+
+/**
+ * The CatalogReader interface.
+ *
+ * The Catalog class requires that classes implement this interface
+ * in order to be used to read catalogs. Examples of CatalogReaders
+ * include the TextCatalogReader, the SAXCatalogReader, and the
+ * DOMCatalogReader.
+ *
+ * @see Catalog
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public interface CatalogReader {
+ /**
+ * Read a catalog from a file
+ *
+ * This class reads a catalog from a URL.
+ *
+ * @param catalog The catalog for which this reader is called.
+ * @param fileUrl The URL of a document to be read.
+ * @throws MalformedURLException if the specified URL cannot be
+ * turned into a URL object.
+ * @throws IOException if the URL cannot be read.
+ * @throws UnknownCatalogFormatException if the catalog format is
+ * not recognized.
+ * @throws UnparseableCatalogException if the catalog cannot be parsed.
+ * (For example, if it is supposed to be XML and isn't well-formed.)
+ */
+ public void readCatalog(Catalog catalog, String fileUrl)
+ throws MalformedURLException, IOException, CatalogException;
+
+ /**
+ * Read a catalog from an input stream
+ *
+ * This class reads a catalog from an input stream.
+ *
+ * @param catalog The catalog for which this reader is called.
+ * @param is The input stream that is to be read.
+ * @throws IOException if the URL cannot be read.
+ * @throws UnknownCatalogFormatException if the catalog format is
+ * not recognized.
+ * @throws UnparseableCatalogException if the catalog cannot be parsed.
+ * (For example, if it is supposed to be XML and isn't well-formed.)
+ */
+ public void readCatalog(Catalog catalog, InputStream is)
+ throws IOException, CatalogException;
+}
diff --git a/java/src/org/apache/xml/resolver/readers/DOMCatalogParser.java b/java/src/org/apache/xml/resolver/readers/DOMCatalogParser.java
new file mode 100644
index 0000000..3095eea
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/readers/DOMCatalogParser.java
@@ -0,0 +1,90 @@
+// DOMCatalogParser.java - An interface for reading catalog files
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.readers;
+
+import org.apache.xml.resolver.Catalog;
+import org.w3c.dom.Node;
+
+/**
+ * The DOMCatalogParser interface.
+ *
+ * This interface must be implemented in order for a class to
+ * participate as a parser for the DOMCatalogReader.
+ *
+ * @see Catalog
+ * @see DOMCatalogReader
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public interface DOMCatalogParser {
+ /**
+ *
Parse a DOM node as a catalog entry
+ *
+ * This method is expected to analyze the specified node and
+ * construct appropriate catalog entry(ies) from it.
+ *
+ * @param catalog The catalog for which this node is being considered.
+ * @param node The DOM Node from the catalog.
+ */
+ public void parseCatalogEntry(Catalog catalog, Node node);
+}
diff --git a/java/src/org/apache/xml/resolver/readers/DOMCatalogReader.java b/java/src/org/apache/xml/resolver/readers/DOMCatalogReader.java
new file mode 100644
index 0000000..9a67bd2
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/readers/DOMCatalogReader.java
@@ -0,0 +1,288 @@
+// DOMCatalogReader.java - Read XML Catalog files
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.readers;
+
+import java.lang.Integer;
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.MalformedURLException;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.xml.resolver.Catalog;
+import org.apache.xml.resolver.CatalogEntry;
+import org.apache.xml.resolver.CatalogException;
+import org.apache.xml.resolver.readers.CatalogReader;
+import org.apache.xml.resolver.helpers.Debug;
+import org.apache.xml.resolver.helpers.PublicId;
+import org.apache.xml.resolver.helpers.Namespaces;
+
+import org.xml.sax.SAXException;
+import org.w3c.dom.*;
+
+/**
+ * A DOM-based CatalogReader
+ *
+ * This class is used to read XML Catalogs using the DOM. This reader
+ * has an advantage over the SAX-based reader that it can analyze the
+ * DOM tree rather than simply a series of SAX events. It has the disadvantage
+ * that it requires all of the code necessary to build and walk a DOM
+ * tree.
+ *
+ * Since the choice of CatalogReaders (in the InputStream case) can only
+ * be made on the basis of MIME type, the following problem occurs: only
+ * one CatalogReader can exist for all XML mime types. In order to get
+ * around this problem, the DOMCatalogReader relies on a set of external
+ * CatalogParsers to actually build the catalog.
+ *
+ * The selection of CatalogParsers is made on the basis of the QName
+ * of the root element of the document.
+ *
+ * This class requires the Java API for XML Parsing.
+ *
+ * @see Catalog
+ * @see CatalogReader
+ * @see SAXCatalogReader
+ * @see TextCatalogReader
+ * @see DOMCatalogParser
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class DOMCatalogReader implements CatalogReader {
+ /**
+ * Mapping table from QNames to CatalogParser classes.
+ *
+ * Each key in this hash table has the form "elementname"
+ * or "{namespaceuri}elementname". The former is used if the
+ * namespace URI is null.
+ */
+ protected Hashtable namespaceMap = new Hashtable();
+
+ /**
+ * Add a new parser to the reader.
+ *
+ * This method associates the specified parserClass with the
+ * namespaceURI/rootElement names specified.
+ *
+ * @param namespaceURI The namespace URI. Not the prefix.
+ * @param rootElement The name of the root element.
+ * @param parserClass The name of the parserClass to instantiate
+ * for this kind of catalog.
+ */
+ public void setCatalogParser(String namespaceURI,
+ String rootElement,
+ String parserClass) {
+ if (namespaceURI == null) {
+ namespaceMap.put(rootElement, parserClass);
+ } else {
+ namespaceMap.put("{"+namespaceURI+"}"+rootElement, parserClass);
+ }
+ }
+
+ /**
+ * Get the name of the parser class for a given catalog type.
+ *
+ * This method returns the parserClass associated with the
+ * namespaceURI/rootElement names specified.
+ *
+ * @param namespaceURI The namespace URI. Not the prefix.
+ * @param rootElement The name of the root element.
+ * @return The parser class.
+ */
+ public String getCatalogParser(String namespaceURI,
+ String rootElement) {
+ if (namespaceURI == null) {
+ return (String) namespaceMap.get(rootElement);
+ } else {
+ return (String) namespaceMap.get("{"+namespaceURI+"}"+rootElement);
+ }
+ }
+
+ /**
+ * Null constructor; something for subclasses to call.
+ */
+ public DOMCatalogReader() { }
+
+ /**
+ * Read a catalog from an input stream
+ *
+ * This class reads a catalog from an input stream:
+ *
+ *
+ * - Based on the QName of the root element, it determines which
+ * parser to instantiate for this catalog.
+ * - It constructs a DOM Document from the catalog and
+ * - For each child of the root node, it calls the parser's
+ * parseCatalogEntry method. This method is expected to make
+ * appropriate calls back into the catalog to add entries for the
+ * entries in the catalog. It is free to do this in whatever manner
+ * is appropriate (perhaps using just the node passed in, perhaps
+ * wandering arbitrarily throughout the tree).
+ *
+ *
+ * @param catalog The catalog for which this reader is called.
+ * @param is The input stream that is to be read.
+ * @throws IOException if the URL cannot be read.
+ * @throws UnknownCatalogFormatException if the catalog format is
+ * not recognized.
+ * @throws UnparseableCatalogException if the catalog cannot be parsed.
+ * (For example, if it is supposed to be XML and isn't well-formed or
+ * if the parser class cannot be instantiated.)
+ */
+ public void readCatalog(Catalog catalog, InputStream is)
+ throws IOException, CatalogException {
+
+ DocumentBuilderFactory factory = null;
+ DocumentBuilder builder = null;
+
+ factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(false);
+ factory.setValidating(false);
+ try {
+ builder = factory.newDocumentBuilder();
+ } catch (ParserConfigurationException pce) {
+ throw new CatalogException(CatalogException.UNPARSEABLE);
+ }
+
+ Document doc = null;
+
+ try {
+ doc = builder.parse(is);
+ } catch (SAXException se) {
+ throw new CatalogException(CatalogException.UNKNOWN_FORMAT);
+ }
+
+ Element root = doc.getDocumentElement();
+
+ String namespaceURI = Namespaces.getNamespaceURI(root);
+ String localName = Namespaces.getLocalName(root);
+
+ String domParserClass = getCatalogParser(namespaceURI,
+ localName);
+
+ if (domParserClass == null) {
+ if (namespaceURI == null) {
+ Debug.message(1, "No Catalog parser for " + localName);
+ } else {
+ Debug.message(1, "No Catalog parser for "
+ + "{" + namespaceURI + "}"
+ + localName);
+ }
+ return;
+ }
+
+ DOMCatalogParser domParser = null;
+
+ try {
+ domParser = (DOMCatalogParser) Class.forName(domParserClass).newInstance();
+ } catch (ClassNotFoundException cnfe) {
+ Debug.message(1, "Cannot load XML Catalog Parser class", domParserClass);
+ throw new CatalogException(CatalogException.UNPARSEABLE);
+ } catch (InstantiationException ie) {
+ Debug.message(1, "Cannot instantiate XML Catalog Parser class", domParserClass);
+ throw new CatalogException(CatalogException.UNPARSEABLE);
+ } catch (IllegalAccessException iae) {
+ Debug.message(1, "Cannot access XML Catalog Parser class", domParserClass);
+ throw new CatalogException(CatalogException.UNPARSEABLE);
+ } catch (ClassCastException cce ) {
+ Debug.message(1, "Cannot cast XML Catalog Parser class", domParserClass);
+ throw new CatalogException(CatalogException.UNPARSEABLE);
+ }
+
+ Node node = root.getFirstChild();
+ while (node != null) {
+ domParser.parseCatalogEntry(catalog, node);
+ node = node.getNextSibling();
+ }
+ }
+
+ /**
+ * Read the catalog behind the specified URL.
+ *
+ * @see #readCatalog(Catalog, InputStream)
+ *
+ * @param catalog The catalog for which we are reading.
+ * @param fileUrl The URL of the document that should be read.
+ *
+ * @throws MalformedURLException if the specified URL cannot be
+ * turned into a URL object.
+ * @throws IOException if the URL cannot be read.
+ * @throws UnknownCatalogFormatException if the catalog format is
+ * not recognized.
+ * @throws UnparseableCatalogException if the catalog cannot be parsed.
+ * (For example, if it is supposed to be XML and isn't well-formed.)
+ */
+ public void readCatalog(Catalog catalog, String fileUrl)
+ throws MalformedURLException, IOException, CatalogException {
+ URL url = new URL(fileUrl);
+ URLConnection urlCon = url.openConnection();
+ readCatalog(catalog, urlCon.getInputStream());
+ }
+}
diff --git a/java/src/org/apache/xml/resolver/readers/ExtendedXMLCatalogReader.java b/java/src/org/apache/xml/resolver/readers/ExtendedXMLCatalogReader.java
new file mode 100644
index 0000000..86e0d28
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/readers/ExtendedXMLCatalogReader.java
@@ -0,0 +1,235 @@
+// ExtendedXMLCatalogReader.java - Read XML Catalog files
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.readers;
+
+import java.lang.Integer;
+import java.util.Stack;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.MalformedURLException;
+import org.apache.xml.resolver.Catalog;
+import org.apache.xml.resolver.Resolver;
+import org.apache.xml.resolver.CatalogEntry;
+import org.apache.xml.resolver.CatalogException;
+import org.apache.xml.resolver.readers.CatalogReader;
+import org.apache.xml.resolver.helpers.PublicId;
+import org.apache.xml.resolver.helpers.Debug;
+
+import org.xml.sax.*;
+import org.w3c.dom.*;
+
+/**
+ * Parse Extended OASIS Entity Resolution Technical Committee
+ * XML Catalog files.
+ *
+ * @see Catalog
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class ExtendedXMLCatalogReader extends OASISXMLCatalogReader {
+ /** The namespace name of extended catalog elements */
+ public static final String extendedNamespaceName = "http://nwalsh.com/xcatalog/1.0";
+
+ /**
+ * The SAX startElement method recognizes elements
+ * from the plain catalog format and instantiates CatalogEntry
+ * objects for them.
+ *
+ * @param namespaceURI The namespace name of the element.
+ * @param localName The local name of the element.
+ * @param qName The QName of the element.
+ * @param atts The list of attributes on the element.
+ *
+ * @see CatalogEntry
+ */
+ public void startElement (String namespaceURI,
+ String localName,
+ String qName,
+ Attributes atts)
+ throws SAXException {
+
+ // Check before calling the super because super will report our
+ // namespace as an extension namespace, but that doesn't count
+ // for this element.
+ boolean inExtension = inExtensionNamespace();
+
+ super.startElement(namespaceURI, localName, qName, atts);
+
+ int entryType = -1;
+ Vector entryArgs = new Vector();
+
+ if (namespaceURI != null && extendedNamespaceName.equals(namespaceURI)
+ && !inExtension) {
+ // This is an Extended XML Catalog entry
+
+ if (atts.getValue("xml:base") != null) {
+ String baseURI = atts.getValue("xml:base");
+ entryType = Catalog.BASE;
+ entryArgs.add(baseURI);
+ baseURIStack.push(baseURI);
+
+ Debug.message(4, "xml:base", baseURI);
+
+ try {
+ CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
+ catalog.addEntry(ce);
+ } catch (CatalogException cex) {
+ if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
+ Debug.message(1, "Invalid catalog entry type", localName);
+ } else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
+ Debug.message(1, "Invalid catalog entry (base)", localName);
+ }
+ }
+
+ entryType = -1;
+ entryArgs = new Vector();
+ } else {
+ baseURIStack.push(baseURIStack.peek());
+ }
+
+ if (localName.equals("uriSuffix")) {
+ if (checkAttributes(atts, "suffix", "uri")) {
+ entryType = Resolver.URISUFFIX;
+ entryArgs.add(atts.getValue("suffix"));
+ entryArgs.add(atts.getValue("uri"));
+
+ Debug.message(4, "uriSuffix",
+ atts.getValue("suffix"),
+ atts.getValue("uri"));
+ }
+ } else if (localName.equals("systemSuffix")) {
+ if (checkAttributes(atts, "suffix", "uri")) {
+ entryType = Resolver.SYSTEMSUFFIX;
+ entryArgs.add(atts.getValue("suffix"));
+ entryArgs.add(atts.getValue("uri"));
+
+ Debug.message(4, "systemSuffix",
+ atts.getValue("suffix"),
+ atts.getValue("uri"));
+ }
+ } else {
+ // This is equivalent to an invalid catalog entry type
+ Debug.message(1, "Invalid catalog entry type", localName);
+ }
+
+ if (entryType >= 0) {
+ try {
+ CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
+ catalog.addEntry(ce);
+ } catch (CatalogException cex) {
+ if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
+ Debug.message(1, "Invalid catalog entry type", localName);
+ } else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
+ Debug.message(1, "Invalid catalog entry", localName);
+ }
+ }
+ }
+ }
+ }
+
+ /** The SAX endElement method does nothing.
*/
+ public void endElement (String namespaceURI,
+ String localName,
+ String qName)
+ throws SAXException {
+
+ super.endElement(namespaceURI, localName, qName);
+
+ // Check after popping the stack so we don't erroneously think we
+ // are our own extension namespace...
+ boolean inExtension = inExtensionNamespace();
+
+ int entryType = -1;
+ Vector entryArgs = new Vector();
+
+ if (namespaceURI != null
+ && (extendedNamespaceName.equals(namespaceURI))
+ && !inExtension) {
+
+ String popURI = (String) baseURIStack.pop();
+ String baseURI = (String) baseURIStack.peek();
+
+ if (!baseURI.equals(popURI)) {
+ entryType = catalog.BASE;
+ entryArgs.add(baseURI);
+
+ Debug.message(4, "(reset) xml:base", baseURI);
+
+ try {
+ CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
+ catalog.addEntry(ce);
+ } catch (CatalogException cex) {
+ if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
+ Debug.message(1, "Invalid catalog entry type", localName);
+ } else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
+ Debug.message(1, "Invalid catalog entry (rbase)", localName);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/java/src/org/apache/xml/resolver/readers/OASISXMLCatalogReader.java b/java/src/org/apache/xml/resolver/readers/OASISXMLCatalogReader.java
new file mode 100644
index 0000000..5314c4d
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/readers/OASISXMLCatalogReader.java
@@ -0,0 +1,565 @@
+// OASISXMLCatalogReader.java - Read XML Catalog files
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.readers;
+
+import java.lang.Integer;
+import java.util.Stack;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.MalformedURLException;
+import org.apache.xml.resolver.Catalog;
+import org.apache.xml.resolver.CatalogEntry;
+import org.apache.xml.resolver.CatalogException;
+import org.apache.xml.resolver.readers.CatalogReader;
+import org.apache.xml.resolver.helpers.PublicId;
+import org.apache.xml.resolver.helpers.Debug;
+
+import org.xml.sax.*;
+import org.w3c.dom.*;
+
+/**
+ * Parse OASIS Entity Resolution Technical Committee
+ * XML Catalog files.
+ *
+ * @see Catalog
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class OASISXMLCatalogReader extends SAXCatalogReader implements SAXCatalogParser {
+ /** The catalog object needs to be stored by the object so that
+ * SAX callbacks can use it.
+ */
+ protected Catalog catalog = null;
+
+ /** The namespace name of OASIS ERTC catalogs */
+ public static final String namespaceName = "urn:oasis:names:tc:entity:xmlns:xml:catalog";
+
+ /** The namespace name of OASIS ERTC TR9401 catalog extension */
+ public static final String tr9401NamespaceName = "urn:oasis:names:tc:entity:xmlns:tr9401:catalog";
+
+ protected Stack baseURIStack = new Stack();
+ protected Stack overrideStack = new Stack();
+ protected Stack namespaceStack = new Stack();
+
+ /** Set the current catalog. */
+ public void setCatalog (Catalog catalog) {
+ this.catalog = catalog;
+ }
+
+ /** Get the current catalog. */
+ public Catalog getCatalog () {
+ return catalog;
+ }
+
+ /**
+ * Are we in an extension namespace?
+ *
+ * @returns true if the current stack of open namespaces includes
+ * an extension namespace.
+ */
+ protected boolean inExtensionNamespace() {
+ boolean inExtension = false;
+
+ Enumeration elements = namespaceStack.elements();
+ while (!inExtension && elements.hasMoreElements()) {
+ String ns = (String) elements.nextElement();
+ if (ns == null) {
+ inExtension = true;
+ } else {
+ inExtension = (!ns.equals(tr9401NamespaceName)
+ && !ns.equals(namespaceName));
+ }
+ }
+
+ return inExtension;
+ }
+
+ // ----------------------------------------------------------------------
+ // Implement the SAX ContentHandler interface
+
+ /** The SAX setDocumentLocator method does nothing.
*/
+ public void setDocumentLocator (Locator locator) {
+ return;
+ }
+
+ /** The SAX startDocument method does nothing.
*/
+ public void startDocument ()
+ throws SAXException {
+ baseURIStack.push(catalog.getCurrentBase());
+ overrideStack.push(catalog.getDefaultOverride());
+ return;
+ }
+
+ /** The SAX endDocument method does nothing.
*/
+ public void endDocument ()
+ throws SAXException {
+ return;
+ }
+
+ /**
+ * The SAX startElement method recognizes elements
+ * from the plain catalog format and instantiates CatalogEntry
+ * objects for them.
+ *
+ * @param namespaceURI The namespace name of the element.
+ * @param localName The local name of the element.
+ * @param qName The QName of the element.
+ * @param atts The list of attributes on the element.
+ *
+ * @see CatalogEntry
+ */
+ public void startElement (String namespaceURI,
+ String localName,
+ String qName,
+ Attributes atts)
+ throws SAXException {
+
+ int entryType = -1;
+ Vector entryArgs = new Vector();
+
+ namespaceStack.push(namespaceURI);
+
+ boolean inExtension = inExtensionNamespace();
+
+ if (namespaceURI != null && namespaceName.equals(namespaceURI)
+ && !inExtension) {
+ // This is an XML Catalog entry
+
+ if (atts.getValue("xml:base") != null) {
+ String baseURI = atts.getValue("xml:base");
+ entryType = Catalog.BASE;
+ entryArgs.add(baseURI);
+ baseURIStack.push(baseURI);
+
+ Debug.message(4, "xml:base", baseURI);
+
+ try {
+ CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
+ catalog.addEntry(ce);
+ } catch (CatalogException cex) {
+ if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
+ Debug.message(1, "Invalid catalog entry type", localName);
+ } else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
+ Debug.message(1, "Invalid catalog entry (base)", localName);
+ }
+ }
+
+ entryType = -1;
+ entryArgs = new Vector();
+
+ } else {
+ baseURIStack.push(baseURIStack.peek());
+ }
+
+ if ((localName.equals("catalog") || localName.equals("group"))
+ && atts.getValue("prefer") != null) {
+ String override = atts.getValue("prefer");
+
+ if (override.equals("public")) {
+ override = "yes";
+ } else if (override.equals("system")) {
+ override = "no";
+ } else {
+ Debug.message(1,
+ "Invalid prefer: must be 'system' or 'public'",
+ localName);
+ override = catalog.getDefaultOverride();
+ }
+
+ entryType = Catalog.OVERRIDE;
+ entryArgs.add(override);
+ overrideStack.push(override);
+
+ Debug.message(4, "override", override);
+
+ try {
+ CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
+ catalog.addEntry(ce);
+ } catch (CatalogException cex) {
+ if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
+ Debug.message(1, "Invalid catalog entry type", localName);
+ } else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
+ Debug.message(1, "Invalid catalog entry (override)", localName);
+ }
+ }
+
+ entryType = -1;
+ entryArgs = new Vector();
+
+ } else {
+ overrideStack.push(overrideStack.peek());
+ }
+
+ if (localName.equals("delegatePublic")) {
+ if (checkAttributes(atts, "publicIdStartString", "catalog")) {
+ entryType = Catalog.DELEGATE_PUBLIC;
+ entryArgs.add(atts.getValue("publicIdStartString"));
+ entryArgs.add(atts.getValue("catalog"));
+
+ Debug.message(4, "delegatePublic",
+ PublicId.normalize(atts.getValue("publicIdStartString")),
+ atts.getValue("catalog"));
+ }
+ } else if (localName.equals("delegateSystem")) {
+ if (checkAttributes(atts, "systemIdStartString", "catalog")) {
+ entryType = Catalog.DELEGATE_SYSTEM;
+ entryArgs.add(atts.getValue("systemIdStartString"));
+ entryArgs.add(atts.getValue("catalog"));
+
+ Debug.message(4, "delegateSystem",
+ atts.getValue("systemIdStartString"),
+ atts.getValue("catalog"));
+ }
+ } else if (localName.equals("delegateURI")) {
+ if (checkAttributes(atts, "uriStartString", "catalog")) {
+ entryType = Catalog.DELEGATE_URI;
+ entryArgs.add(atts.getValue("uriStartString"));
+ entryArgs.add(atts.getValue("catalog"));
+
+ Debug.message(4, "delegateURI",
+ atts.getValue("uriStartString"),
+ atts.getValue("catalog"));
+ }
+ } else if (localName.equals("rewriteSystem")) {
+ if (checkAttributes(atts, "systemIdStartString", "rewritePrefix")) {
+ entryType = Catalog.REWRITE_SYSTEM;
+ entryArgs.add(atts.getValue("systemIdStartString"));
+ entryArgs.add(atts.getValue("rewritePrefix"));
+
+ Debug.message(4, "rewriteSystem",
+ atts.getValue("systemIdStartString"),
+ atts.getValue("rewritePrefix"));
+ }
+ } else if (localName.equals("rewriteURI")) {
+ if (checkAttributes(atts, "uriStartString", "rewritePrefix")) {
+ entryType = Catalog.REWRITE_URI;
+ entryArgs.add(atts.getValue("uriStartString"));
+ entryArgs.add(atts.getValue("rewritePrefix"));
+
+ Debug.message(4, "rewriteURI",
+ atts.getValue("uriStartString"),
+ atts.getValue("rewritePrefix"));
+ }
+ } else if (localName.equals("nextCatalog")) {
+ if (checkAttributes(atts, "catalog")) {
+ entryType = Catalog.CATALOG;
+ entryArgs.add(atts.getValue("catalog"));
+
+ Debug.message(4, "nextCatalog", atts.getValue("catalog"));
+ }
+ } else if (localName.equals("public")) {
+ if (checkAttributes(atts, "publicId", "uri")) {
+ entryType = Catalog.PUBLIC;
+ entryArgs.add(atts.getValue("publicId"));
+ entryArgs.add(atts.getValue("uri"));
+
+ Debug.message(4, "public",
+ PublicId.normalize(atts.getValue("publicId")),
+ atts.getValue("uri"));
+ }
+ } else if (localName.equals("system")) {
+ if (checkAttributes(atts, "systemId", "uri")) {
+ entryType = Catalog.SYSTEM;
+ entryArgs.add(atts.getValue("systemId"));
+ entryArgs.add(atts.getValue("uri"));
+
+ Debug.message(4, "system",
+ atts.getValue("systemId"),
+ atts.getValue("uri"));
+ }
+ } else if (localName.equals("uri")) {
+ if (checkAttributes(atts, "name", "uri")) {
+ entryType = Catalog.URI;
+ entryArgs.add(atts.getValue("name"));
+ entryArgs.add(atts.getValue("uri"));
+
+ Debug.message(4, "uri",
+ atts.getValue("name"),
+ atts.getValue("uri"));
+ }
+ } else if (localName.equals("catalog")) {
+ // nop, start of catalog
+ } else if (localName.equals("group")) {
+ // nop, a group
+ } else {
+ // This is equivalent to an invalid catalog entry type
+ Debug.message(1, "Invalid catalog entry type", localName);
+ }
+
+ if (entryType >= 0) {
+ try {
+ CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
+ catalog.addEntry(ce);
+ } catch (CatalogException cex) {
+ if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
+ Debug.message(1, "Invalid catalog entry type", localName);
+ } else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
+ Debug.message(1, "Invalid catalog entry", localName);
+ }
+ }
+ }
+ }
+
+ if (namespaceURI != null && tr9401NamespaceName.equals(namespaceURI)
+ && !inExtension) {
+ // This is a TR9401 Catalog entry
+
+ if (atts.getValue("xml:base") != null) {
+ String baseURI = atts.getValue("xml:base");
+ entryType = Catalog.BASE;
+ entryArgs.add(baseURI);
+ baseURIStack.push(baseURI);
+
+ Debug.message(4, "xml:base", baseURI);
+
+ try {
+ CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
+ catalog.addEntry(ce);
+ } catch (CatalogException cex) {
+ if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
+ Debug.message(1, "Invalid catalog entry type", localName);
+ } else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
+ Debug.message(1, "Invalid catalog entry (base)", localName);
+ }
+ }
+
+ entryType = -1;
+ entryArgs = new Vector();
+
+ } else {
+ baseURIStack.push(baseURIStack.peek());
+ }
+
+ if (localName.equals("doctype")) {
+ entryType = catalog.DOCTYPE;
+ entryArgs.add(atts.getValue("name"));
+ entryArgs.add(atts.getValue("uri"));
+ } else if (localName.equals("document")) {
+ entryType = catalog.DOCUMENT;
+ entryArgs.add(atts.getValue("uri"));
+ } else if (localName.equals("dtddecl")) {
+ entryType = catalog.DTDDECL;
+ entryArgs.add(atts.getValue("publicId"));
+ entryArgs.add(atts.getValue("uri"));
+ } else if (localName.equals("entity")) {
+ entryType = Catalog.ENTITY;
+ entryArgs.add(atts.getValue("name"));
+ entryArgs.add(atts.getValue("uri"));
+ } else if (localName.equals("linktype")) {
+ entryType = Catalog.LINKTYPE;
+ entryArgs.add(atts.getValue("name"));
+ entryArgs.add(atts.getValue("uri"));
+ } else if (localName.equals("notation")) {
+ entryType = Catalog.NOTATION;
+ entryArgs.add(atts.getValue("name"));
+ entryArgs.add(atts.getValue("uri"));
+ } else if (localName.equals("sgmldecl")) {
+ entryType = Catalog.SGMLDECL;
+ entryArgs.add(atts.getValue("uri"));
+ } else {
+ // This is equivalent to an invalid catalog entry type
+ Debug.message(1, "Invalid catalog entry type", localName);
+ }
+
+ if (entryType >= 0) {
+ try {
+ CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
+ catalog.addEntry(ce);
+ } catch (CatalogException cex) {
+ if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
+ Debug.message(1, "Invalid catalog entry type", localName);
+ } else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
+ Debug.message(1, "Invalid catalog entry", localName);
+ }
+ }
+ }
+ }
+ }
+
+ public boolean checkAttributes (Attributes atts, String attName) {
+ if (atts.getValue(attName) == null) {
+ Debug.message(1, "Error: required attribute " + attName + " missing.");
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ public boolean checkAttributes (Attributes atts,
+ String attName1,
+ String attName2) {
+ return checkAttributes(atts, attName1)
+ && checkAttributes(atts, attName2);
+ }
+
+ /** The SAX endElement method does nothing.
*/
+ public void endElement (String namespaceURI,
+ String localName,
+ String qName)
+ throws SAXException {
+
+ int entryType = -1;
+ Vector entryArgs = new Vector();
+
+ boolean inExtension = inExtensionNamespace();
+
+ if (namespaceURI != null
+ && !inExtension
+ && (namespaceName.equals(namespaceURI)
+ || tr9401NamespaceName.equals(namespaceURI))) {
+
+ String popURI = (String) baseURIStack.pop();
+ String baseURI = (String) baseURIStack.peek();
+
+ if (!baseURI.equals(popURI)) {
+ entryType = catalog.BASE;
+ entryArgs.add(baseURI);
+
+ Debug.message(4, "(reset) xml:base", baseURI);
+
+ try {
+ CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
+ catalog.addEntry(ce);
+ } catch (CatalogException cex) {
+ if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
+ Debug.message(1, "Invalid catalog entry type", localName);
+ } else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
+ Debug.message(1, "Invalid catalog entry (rbase)", localName);
+ }
+ }
+ }
+ }
+
+ if (namespaceURI != null && namespaceName.equals(namespaceURI)
+ && !inExtension) {
+ if (localName.equals("catalog") || localName.equals("group")) {
+ String popOverride = (String) overrideStack.pop();
+ String override = (String) overrideStack.peek();
+
+ if (!override.equals(popOverride)) {
+ entryType = catalog.OVERRIDE;
+ entryArgs.add(override);
+ overrideStack.push(override);
+
+ Debug.message(4, "(reset) override", override);
+
+ try {
+ CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
+ catalog.addEntry(ce);
+ } catch (CatalogException cex) {
+ if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
+ Debug.message(1, "Invalid catalog entry type", localName);
+ } else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
+ Debug.message(1, "Invalid catalog entry (roverride)", localName);
+ }
+ }
+ }
+ }
+ }
+
+ namespaceStack.pop();
+
+ return;
+ }
+
+ /** The SAX characters method does nothing.
*/
+ public void characters (char ch[], int start, int length)
+ throws SAXException {
+ return;
+ }
+
+ /** The SAX ignorableWhitespace method does nothing.
*/
+ public void ignorableWhitespace (char ch[], int start, int length)
+ throws SAXException {
+ return;
+ }
+
+ /** The SAX processingInstruction method does nothing.
*/
+ public void processingInstruction (String target, String data)
+ throws SAXException {
+ return;
+ }
+
+ /** The SAX skippedEntity method does nothing.
*/
+ public void skippedEntity (String name)
+ throws SAXException {
+ return;
+ }
+
+ /** The SAX startPrefixMapping method does nothing.
*/
+ public void startPrefixMapping(String prefix, String uri)
+ throws SAXException {
+ return;
+ }
+
+ /** The SAX endPrefixMapping method does nothing.
*/
+ public void endPrefixMapping(String prefix)
+ throws SAXException {
+ return;
+ }
+
+}
diff --git a/java/src/org/apache/xml/resolver/readers/SAXCatalogParser.java b/java/src/org/apache/xml/resolver/readers/SAXCatalogParser.java
new file mode 100644
index 0000000..abec686
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/readers/SAXCatalogParser.java
@@ -0,0 +1,82 @@
+// SAXCatalogParser.java - An interface for reading catalog files
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.readers;
+
+import org.apache.xml.resolver.Catalog;
+import org.xml.sax.*;
+
+/**
+ * The SAXCatalogParser interface.
+ *
+ * This interface must be implemented in order for a class to
+ * participate as a parser for the SAXCatalogReader.
+ *
+ * @see Catalog
+ * @see SAXCatalogReader
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public interface SAXCatalogParser extends ContentHandler, DocumentHandler {
+ /** Set the Catalog for which parsing is being performed. */
+ public void setCatalog(Catalog catalog);
+}
diff --git a/java/src/org/apache/xml/resolver/readers/SAXCatalogReader.java b/java/src/org/apache/xml/resolver/readers/SAXCatalogReader.java
new file mode 100644
index 0000000..ff2a471
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/readers/SAXCatalogReader.java
@@ -0,0 +1,515 @@
+// SAXCatalogReader.java - Read XML Catalog files
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.readers;
+
+import java.lang.Integer;
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import org.apache.xml.resolver.Catalog;
+import org.apache.xml.resolver.CatalogEntry;
+import org.apache.xml.resolver.CatalogException;
+import org.apache.xml.resolver.readers.CatalogReader;
+import org.apache.xml.resolver.helpers.Debug;
+import org.apache.xml.resolver.helpers.PublicId;
+import org.apache.xml.resolver.helpers.Namespaces;
+
+import org.xml.sax.*;
+
+import javax.xml.parsers.*;
+
+/**
+ *
A SAX-based CatalogReader
+ *
+ * This class is used to read XML Catalogs using the SAX. This reader
+ * has an advantage over the DOM-based reader in that it functions on
+ * the stream of SAX events. It has the disadvantage
+ * that it cannot look around in the tree.
+ *
+ * Since the choice of CatalogReaders (in the InputStream case) can only
+ * be made on the basis of MIME type, the following problem occurs: only
+ * one CatalogReader can exist for all XML mime types. In order to get
+ * around this problem, the SAXCatalogReader relies on a set of external
+ * CatalogParsers to actually build the catalog.
+ *
+ * The selection of CatalogParsers is made on the basis of the QName
+ * of the root element of the document.
+ *
+ * @see Catalog
+ * @see CatalogReader
+ * @see SAXCatalogReader
+ * @see TextCatalogReader
+ * @see DOMCatalogParser
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class SAXCatalogReader implements CatalogReader, ContentHandler, DocumentHandler {
+ /** The SAX Parser Factory */
+ protected SAXParserFactory parserFactory = null;
+
+ /** The SAX Parser Class */
+ protected String parserClass = null;
+
+ /**
+ * Mapping table from QNames to CatalogParser classes.
+ *
+ * Each key in this hash table has the form "elementname"
+ * or "{namespaceuri}elementname". The former is used if the
+ * namespace URI is null.
+ */
+ protected Hashtable namespaceMap = new Hashtable();
+
+ /** The parser in use for the current catalog. */
+ private SAXCatalogParser saxParser = null;
+
+ /** Set if something goes horribly wrong. It allows the class to
+ * ignore the rest of the events that are received.
+ */
+ private boolean abandonHope = false;
+
+ /** The Catalog that we're working for. */
+ private Catalog catalog;
+
+ /** Set the XML SAX Parser Factory.
+ */
+ public void setParserFactory(SAXParserFactory parserFactory) {
+ this.parserFactory = parserFactory;
+ }
+
+ /** Set the XML SAX Parser Class
+ */
+ public void setParserClass(String parserClass) {
+ this.parserClass = parserClass;
+ }
+
+ /** Get the parser factory currently in use. */
+ public SAXParserFactory getParserFactory() {
+ return parserFactory;
+ }
+
+ /** Get the parser class currently in use. */
+ public String getParserClass() {
+ return parserClass;
+ }
+
+ /** Set the SAXCatalogParser class for the given namespace/root
+ * element type.
+ */
+ public void setCatalogParser(String namespaceURI,
+ String rootElement,
+ String parserClass) {
+ if (namespaceURI == null) {
+ namespaceMap.put(rootElement, parserClass);
+ } else {
+ namespaceMap.put("{"+namespaceURI+"}"+rootElement, parserClass);
+ }
+ }
+
+ /** Get the SAXCatalogParser class for the given namespace/root
+ * element type.
+ */
+ public String getCatalogParser(String namespaceURI,
+ String rootElement) {
+ if (namespaceURI == null) {
+ return (String) namespaceMap.get(rootElement);
+ } else {
+ return (String) namespaceMap.get("{"+namespaceURI+"}"+rootElement);
+ }
+ }
+
+ /** The constructor */
+ public SAXCatalogReader() {
+ parserFactory = null;
+ parserClass = null;
+ }
+
+ /** The constructor */
+ public SAXCatalogReader(SAXParserFactory parserFactory) {
+ this.parserFactory = parserFactory;
+ }
+
+ /** The constructor */
+ public SAXCatalogReader(String parserClass) {
+ this.parserClass = parserClass;
+ }
+
+ /**
+ * Parse an XML Catalog file.
+ *
+ * @param catalog The catalog to which this catalog file belongs
+ * @param fileUrl The URL or filename of the catalog file to process
+ *
+ * @throws MalformedURLException Improper fileUrl
+ * @throws IOException Error reading catalog file
+ */
+ public void readCatalog(Catalog catalog, String fileUrl)
+ throws MalformedURLException, IOException,
+ CatalogException {
+
+ URL url = null;
+
+ try {
+ url = new URL(fileUrl);
+ } catch (MalformedURLException e) {
+ url = new URL("file:///" + fileUrl);
+ }
+
+ try {
+ URLConnection urlCon = url.openConnection();
+ readCatalog(catalog, urlCon.getInputStream());
+ } catch (FileNotFoundException e) {
+ Debug.message(1, "Failed to load catalog, file not found",
+ url.toString());
+ }
+ }
+
+ /**
+ * Parse an XML Catalog stream.
+ *
+ * @param catalog The catalog to which this catalog file belongs
+ * @param is The input stream from which the catalog will be read
+ *
+ * @throws MalformedURLException Improper fileUrl
+ * @throws IOException Error reading catalog file
+ * @throws CatalogException A Catalog exception
+ */
+ public void readCatalog(Catalog catalog, InputStream is)
+ throws IOException, CatalogException {
+
+ // Create an instance of the parser
+ if (parserFactory == null && parserClass == null) {
+ Debug.message(1, "Cannot read SAX catalog without a parser");
+ throw new CatalogException(CatalogException.UNPARSEABLE);
+ }
+
+ this.catalog = catalog;
+
+ try {
+ if (parserFactory != null) {
+ SAXParser parser = parserFactory.newSAXParser();
+ SAXParserHandler spHandler = new SAXParserHandler();
+ spHandler.setContentHandler(this);
+ parser.parse(new InputSource(is), spHandler);
+ } else {
+ Parser parser = (Parser) Class.forName(parserClass).newInstance();
+ parser.setDocumentHandler(this);
+ parser.parse(new InputSource(is));
+ }
+ } catch (ClassNotFoundException cnfe) {
+ throw new CatalogException(CatalogException.UNPARSEABLE);
+ } catch (IllegalAccessException iae) {
+ throw new CatalogException(CatalogException.UNPARSEABLE);
+ } catch (InstantiationException ie) {
+ throw new CatalogException(CatalogException.UNPARSEABLE);
+ } catch (ParserConfigurationException pce) {
+ throw new CatalogException(CatalogException.UNKNOWN_FORMAT);
+ } catch (SAXException se) {
+ Exception e = se.getException();
+ // FIXME: there must be a better way
+ UnknownHostException uhe = new UnknownHostException();
+ FileNotFoundException fnfe = new FileNotFoundException();
+ if (e != null) {
+ if (e.getClass() == uhe.getClass()) {
+ throw new CatalogException(CatalogException.PARSE_FAILED,
+ e.toString());
+ } else if (e.getClass() == fnfe.getClass()) {
+ throw new CatalogException(CatalogException.PARSE_FAILED,
+ e.toString());
+ }
+ }
+ throw new CatalogException(se);
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ // Implement the SAX ContentHandler interface
+
+ /** The SAX setDocumentLocator method. Does nothing.
*/
+ public void setDocumentLocator (Locator locator) {
+ if (saxParser != null) {
+ saxParser.setDocumentLocator(locator);
+ }
+ }
+
+ /** The SAX startDocument method. Does nothing.
*/
+ public void startDocument () throws SAXException {
+ saxParser = null;
+ abandonHope = false;
+ return;
+ }
+
+ /** The SAX endDocument method. Does nothing.
*/
+ public void endDocument ()throws SAXException {
+ if (saxParser != null) {
+ saxParser.endDocument();
+ }
+ }
+
+ /**
+ * The SAX startElement method.
+ *
+ * The catalog parser is selected based on the namespace of the
+ * first element encountered in the catalog.
+ */
+ public void startElement (String name,
+ AttributeList atts)
+ throws SAXException {
+
+ if (abandonHope) {
+ return;
+ }
+
+ if (saxParser == null) {
+ String prefix = "";
+ if (name.indexOf(':') > 0) {
+ prefix = name.substring(0, name.indexOf(':'));
+ }
+
+ String localName = name;
+ if (localName.indexOf(':') > 0) {
+ localName = localName.substring(localName.indexOf(':')+1);
+ }
+
+ String namespaceURI = null;
+ if (prefix.equals("")) {
+ namespaceURI = atts.getValue("xmlns");
+ } else {
+ namespaceURI = atts.getValue("xmlns:" + prefix);
+ }
+
+ String saxParserClass = getCatalogParser(namespaceURI,
+ localName);
+
+ if (saxParserClass == null) {
+ abandonHope = true;
+ if (namespaceURI == null) {
+ Debug.message(2, "No Catalog parser for " + name);
+ } else {
+ Debug.message(2, "No Catalog parser for "
+ + "{" + namespaceURI + "}"
+ + name);
+ }
+ return;
+ }
+
+ try {
+ saxParser = (SAXCatalogParser)
+ Class.forName(saxParserClass).newInstance();
+
+ saxParser.setCatalog(catalog);
+ saxParser.startDocument();
+ saxParser.startElement(name, atts);
+ } catch (ClassNotFoundException cnfe) {
+ saxParser = null;
+ abandonHope = true;
+ Debug.message(2, cnfe.toString());
+ } catch (InstantiationException ie) {
+ saxParser = null;
+ abandonHope = true;
+ Debug.message(2, ie.toString());
+ } catch (IllegalAccessException iae) {
+ saxParser = null;
+ abandonHope = true;
+ Debug.message(2, iae.toString());
+ } catch (ClassCastException cce ) {
+ saxParser = null;
+ abandonHope = true;
+ Debug.message(2, cce.toString());
+ }
+ } else {
+ saxParser.startElement(name, atts);
+ }
+ }
+
+ /**
+ * The SAX2 startElement method.
+ *
+ * The catalog parser is selected based on the namespace of the
+ * first element encountered in the catalog.
+ */
+ public void startElement (String namespaceURI,
+ String localName,
+ String qName,
+ Attributes atts)
+ throws SAXException {
+
+ if (abandonHope) {
+ return;
+ }
+
+ if (saxParser == null) {
+ String saxParserClass = getCatalogParser(namespaceURI,
+ localName);
+
+ if (saxParserClass == null) {
+ abandonHope = true;
+ if (namespaceURI == null) {
+ Debug.message(2, "No Catalog parser for " + localName);
+ } else {
+ Debug.message(2, "No Catalog parser for "
+ + "{" + namespaceURI + "}"
+ + localName);
+ }
+ return;
+ }
+
+ try {
+ saxParser = (SAXCatalogParser)
+ Class.forName(saxParserClass).newInstance();
+
+ saxParser.setCatalog(catalog);
+ saxParser.startDocument();
+ saxParser.startElement(namespaceURI, localName, qName, atts);
+ } catch (ClassNotFoundException cnfe) {
+ saxParser = null;
+ abandonHope = true;
+ Debug.message(2, cnfe.toString());
+ } catch (InstantiationException ie) {
+ saxParser = null;
+ abandonHope = true;
+ Debug.message(2, ie.toString());
+ } catch (IllegalAccessException iae) {
+ saxParser = null;
+ abandonHope = true;
+ Debug.message(2, iae.toString());
+ } catch (ClassCastException cce ) {
+ saxParser = null;
+ abandonHope = true;
+ Debug.message(2, cce.toString());
+ }
+ } else {
+ saxParser.startElement(namespaceURI, localName, qName, atts);
+ }
+ }
+
+ /** The SAX endElement method. Does nothing.
*/
+ public void endElement (String name) throws SAXException {
+ if (saxParser != null) {
+ saxParser.endElement(name);
+ }
+ }
+
+ /** The SAX2 endElement method. Does nothing.
*/
+ public void endElement (String namespaceURI,
+ String localName,
+ String qName) throws SAXException {
+ if (saxParser != null) {
+ saxParser.endElement(namespaceURI, localName, qName);
+ }
+ }
+
+ /** The SAX characters method. Does nothing.
*/
+ public void characters (char ch[], int start, int length)
+ throws SAXException {
+ if (saxParser != null) {
+ saxParser.characters(ch, start, length);
+ }
+ }
+
+ /** The SAX ignorableWhitespace method. Does nothing.
*/
+ public void ignorableWhitespace (char ch[], int start, int length)
+ throws SAXException {
+ if (saxParser != null) {
+ saxParser.ignorableWhitespace(ch, start, length);
+ }
+ }
+
+ /** The SAX processingInstruction method. Does nothing.
*/
+ public void processingInstruction (String target, String data)
+ throws SAXException {
+ if (saxParser != null) {
+ saxParser.processingInstruction(target, data);
+ }
+ }
+
+ /** The SAX startPrefixMapping method. Does nothing.
*/
+ public void startPrefixMapping (String prefix, String uri)
+ throws SAXException {
+ if (saxParser != null) {
+ saxParser.startPrefixMapping (prefix, uri);
+ }
+ }
+
+ /** The SAX endPrefixMapping method. Does nothing.
*/
+ public void endPrefixMapping (String prefix)
+ throws SAXException {
+ if (saxParser != null) {
+ saxParser.endPrefixMapping (prefix);
+ }
+ }
+
+ /** The SAX skippedentity method. Does nothing.
*/
+ public void skippedEntity (String name)
+ throws SAXException {
+ if (saxParser != null) {
+ saxParser.skippedEntity(name);
+ }
+ }
+}
diff --git a/java/src/org/apache/xml/resolver/readers/SAXParserHandler.java b/java/src/org/apache/xml/resolver/readers/SAXParserHandler.java
new file mode 100644
index 0000000..8e6dbcf
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/readers/SAXParserHandler.java
@@ -0,0 +1,187 @@
+// SAXParserHandler.java - An entity-resolving DefaultHandler
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.readers;
+
+import java.io.IOException;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+
+/**
+ * An entity-resolving DefaultHandler
+ *
+ * This class provides a SAXParser DefaultHandler that performs
+ * entity resolution.
+ *
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ * @version 1.0
+ */
+public class SAXParserHandler extends DefaultHandler {
+ private EntityResolver er = null;
+ private ContentHandler ch = null;
+
+ public SAXParserHandler() {
+ super();
+ }
+
+ public void setEntityResolver(EntityResolver er) {
+ this.er = er;
+ }
+
+ public void setContentHandler(ContentHandler ch) {
+ this.ch = ch;
+ }
+
+ // Entity Resolver
+ public InputSource resolveEntity(String publicId, String systemId)
+ throws SAXException {
+
+ if (er != null) {
+ try {
+ return er.resolveEntity(publicId, systemId);
+ } catch (IOException e) {
+ System.out.println("resolveEntity threw IOException!");
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ // Content Handler
+ public void characters(char[] ch, int start, int length)
+ throws SAXException {
+ if (this.ch != null) {
+ this.ch.characters(ch, start, length);
+ }
+ }
+
+ public void endDocument()
+ throws SAXException {
+ if (ch != null) {
+ ch.endDocument();
+ }
+ }
+
+ public void endElement(String namespaceURI, String localName, String qName)
+ throws SAXException {
+ if (ch != null) {
+ ch.endElement(namespaceURI, localName, qName);
+ }
+ }
+
+ public void endPrefixMapping(String prefix)
+ throws SAXException {
+ if (ch != null) {
+ ch.endPrefixMapping(prefix);
+ }
+ }
+
+ public void ignorableWhitespace(char[] ch, int start, int length)
+ throws SAXException {
+ if (this.ch != null) {
+ this.ch.ignorableWhitespace(ch, start, length);
+ }
+ }
+
+ public void processingInstruction(String target, String data)
+ throws SAXException {
+ if (ch != null) {
+ ch.processingInstruction(target, data);
+ }
+ }
+
+ public void setDocumentLocator(Locator locator) {
+ if (ch != null) {
+ ch.setDocumentLocator(locator);
+ }
+ }
+
+ public void skippedEntity(String name)
+ throws SAXException {
+ if (ch != null) {
+ ch.skippedEntity(name);
+ }
+ }
+
+ public void startDocument()
+ throws SAXException {
+ if (ch != null) {
+ ch.startDocument();
+ }
+ }
+
+ public void startElement(String namespaceURI, String localName,
+ String qName, Attributes atts)
+ throws SAXException {
+ if (ch != null) {
+ ch.startElement(namespaceURI, localName, qName, atts);
+ }
+ }
+
+ public void startPrefixMapping(String prefix, String uri)
+ throws SAXException {
+ if (ch != null) {
+ ch.startPrefixMapping(prefix, uri);
+ }
+ }
+}
diff --git a/java/src/org/apache/xml/resolver/readers/TR9401CatalogReader.java b/java/src/org/apache/xml/resolver/readers/TR9401CatalogReader.java
new file mode 100644
index 0000000..67ad4ee
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/readers/TR9401CatalogReader.java
@@ -0,0 +1,179 @@
+// TR9401CatalogReader.java - Read OASIS Catalog files
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.readers;
+
+import java.lang.Integer;
+import java.io.DataInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.MalformedURLException;
+import java.util.Vector;
+import java.util.Stack;
+import org.apache.xml.resolver.Catalog;
+import org.apache.xml.resolver.CatalogEntry;
+import org.apache.xml.resolver.CatalogException;
+import org.apache.xml.resolver.readers.CatalogReader;
+import org.apache.xml.resolver.helpers.Debug;
+import org.apache.xml.resolver.helpers.PublicId;
+
+/**
+ * Parses OASIS Open Catalog files.
+ *
+ * This class reads OASIS Open Catalog files, returning a stream
+ * of tokens.
+ *
+ * This code interrogates the following non-standard system properties:
+ *
+ *
+ * - xml.catalog.debug
+ * Sets the debug level. A value of 0 is assumed if the
+ * property is not set or is not a number.
+ *
+ *
+ * @see Catalog
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class TR9401CatalogReader extends TextCatalogReader {
+
+ /**
+ * Start parsing an OASIS TR9401 Open Catalog file. The file is
+ * actually read and parsed
+ * as needed by nextEntry.
+ *
+ * In a TR9401 Catalog the 'DELEGATE' entry delegates public
+ * identifiers. There is no delegate entry for system identifiers
+ * or URIs.
+ *
+ * @param fileUrl The URL or filename of the catalog file to process
+ *
+ * @throws MalformedURLException Improper fileUrl
+ * @throws IOException Error reading catalog file
+ */
+ public void readCatalog(Catalog catalog, InputStream is)
+ throws MalformedURLException, IOException {
+
+ catfile = is;
+
+ if (catfile == null) {
+ return;
+ }
+
+ Vector unknownEntry = null;
+
+ while (true) {
+ String token = nextToken();
+
+ if (token == null) {
+ if (unknownEntry != null) {
+ catalog.unknownEntry(unknownEntry);
+ unknownEntry = null;
+ }
+ catfile.close();
+ catfile = null;
+ return;
+ }
+
+ String entryToken = null;
+ if (caseSensitive) {
+ entryToken = token;
+ } else {
+ entryToken = token.toUpperCase();
+ }
+
+ if (entryToken.equals("DELEGATE")) {
+ entryToken = "DELEGATE_PUBLIC";
+ }
+
+ try {
+ int type = CatalogEntry.getEntryType(entryToken);
+ int numArgs = CatalogEntry.getEntryArgCount(type);
+ Vector args = new Vector();
+
+ if (unknownEntry != null) {
+ catalog.unknownEntry(unknownEntry);
+ unknownEntry = null;
+ }
+
+ for (int count = 0; count < numArgs; count++) {
+ args.addElement(nextToken());
+ }
+
+ catalog.addEntry(new CatalogEntry(entryToken, args));
+ } catch (CatalogException cex) {
+ if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
+ if (unknownEntry == null) {
+ unknownEntry = new Vector();
+ }
+ unknownEntry.addElement(token);
+ } else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
+ Debug.message(1, "Invalid catalog entry", token);
+ unknownEntry = null;
+ }
+ }
+ }
+ }
+}
diff --git a/java/src/org/apache/xml/resolver/readers/TextCatalogReader.java b/java/src/org/apache/xml/resolver/readers/TextCatalogReader.java
new file mode 100644
index 0000000..8f69f82
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/readers/TextCatalogReader.java
@@ -0,0 +1,328 @@
+// TextCatalogReader.java - Read text/plain Catalog files
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.readers;
+
+import java.lang.Integer;
+import java.io.DataInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.MalformedURLException;
+import java.util.Vector;
+import java.util.Stack;
+import org.apache.xml.resolver.Catalog;
+import org.apache.xml.resolver.CatalogEntry;
+import org.apache.xml.resolver.CatalogException;
+import org.apache.xml.resolver.readers.CatalogReader;
+import org.apache.xml.resolver.helpers.Debug;
+import org.apache.xml.resolver.helpers.PublicId;
+
+/**
+ * Parses plain text Catalog files.
+ *
+ * This class reads plain text Open Catalog files.
+ *
+ * @see Catalog
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class TextCatalogReader implements CatalogReader {
+ /** The input stream used to read the catalog */
+ protected InputStream catfile = null;
+
+ /**
+ * Character lookahead stack. Reading a catalog sometimes requires
+ * up to two characters of lookahead.
+ */
+ protected int[] stack = new int[3];
+
+ /**
+ * Token stack. Recognizing an unexpected catalog entry requires
+ * the ability to "push back" a token.
+ */
+ protected Stack tokenStack = new Stack();
+
+ /** The current position on the lookahead stack */
+ protected int top = -1;
+
+ /** Are keywords in the catalog case sensitive? */
+ protected boolean caseSensitive = false;
+
+ /**
+ * Construct a CatalogReader object.
+ */
+ public TextCatalogReader() { }
+
+ public void setCaseSensitive(boolean isCaseSensitive) {
+ caseSensitive = isCaseSensitive;
+ }
+
+ public boolean getCaseSensitive() {
+ return caseSensitive;
+ }
+
+ /**
+ * Start parsing a text catalog file. The file is
+ * actually read and parsed
+ * as needed by nextEntry.
+ *
+ * @param fileUrl The URL or filename of the catalog file to process
+ *
+ * @throws MalformedURLException Improper fileUrl
+ * @throws IOException Error reading catalog file
+ */
+ public void readCatalog(Catalog catalog, String fileUrl)
+ throws MalformedURLException, IOException {
+ URL catURL = null;
+
+ try {
+ catURL = new URL(fileUrl);
+ } catch (MalformedURLException e) {
+ catURL = new URL("file:///" + fileUrl);
+ }
+
+ URLConnection urlCon = catURL.openConnection();
+ try {
+ readCatalog(catalog, urlCon.getInputStream());
+ } catch (FileNotFoundException e) {
+ Debug.message(1, "Failed to load catalog, file not found",
+ catURL.toString());
+ }
+ }
+
+ public void readCatalog(Catalog catalog, InputStream is)
+ throws MalformedURLException, IOException {
+
+ catfile = is;
+
+ if (catfile == null) {
+ return;
+ }
+
+ Vector unknownEntry = null;
+
+ while (true) {
+ String token = nextToken();
+
+ if (token == null) {
+ if (unknownEntry != null) {
+ catalog.unknownEntry(unknownEntry);
+ unknownEntry = null;
+ }
+ catfile.close();
+ catfile = null;
+ return;
+ }
+
+ String entryToken = null;
+ if (caseSensitive) {
+ entryToken = token;
+ } else {
+ entryToken = token.toUpperCase();
+ }
+
+ try {
+ int type = CatalogEntry.getEntryType(entryToken);
+ int numArgs = CatalogEntry.getEntryArgCount(type);
+ Vector args = new Vector();
+
+ if (unknownEntry != null) {
+ catalog.unknownEntry(unknownEntry);
+ unknownEntry = null;
+ }
+
+ for (int count = 0; count < numArgs; count++) {
+ args.addElement(nextToken());
+ }
+
+ catalog.addEntry(new CatalogEntry(entryToken, args));
+ } catch (CatalogException cex) {
+ if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
+ if (unknownEntry == null) {
+ unknownEntry = new Vector();
+ }
+ unknownEntry.addElement(token);
+ } else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
+ Debug.message(1, "Invalid catalog entry", token);
+ unknownEntry = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * The destructor.
+ *
+ * Makes sure the catalog file is closed.
+ */
+ protected void finalize() {
+ if (catfile != null) {
+ try {
+ catfile.close();
+ } catch (IOException e) {
+ // whatever...
+ }
+ }
+ catfile = null;
+ }
+
+ // -----------------------------------------------------------------
+
+ /**
+ * Return the next token in the catalog file.
+ *
+ * @return The Catalog file token from the input stream.
+ * @throws IOException If an error occurs reading from the stream.
+ */
+ protected String nextToken() throws IOException {
+ String token = "";
+ int ch, nextch;
+
+ if (!tokenStack.empty()) {
+ return (String) tokenStack.pop();
+ }
+
+ // Skip over leading whitespace and comments
+ while (true) {
+ // skip leading whitespace
+ ch = catfile.read();
+ while (ch <= ' ') { // all ctrls are whitespace
+ ch = catfile.read();
+ if (ch < 0) {
+ return null;
+ }
+ }
+
+ // now 'ch' is the current char from the file
+ nextch = catfile.read();
+ if (nextch < 0) {
+ return null;
+ }
+
+ if (ch == '-' && nextch == '-') {
+ // we've found a comment, skip it...
+ ch = ' ';
+ nextch = nextChar();
+ while (ch != '-' || nextch != '-') {
+ ch = nextch;
+ nextch = nextChar();
+ }
+
+ // Ok, we've found the end of the comment,
+ // loop back to the top and start again...
+ } else {
+ stack[++top] = nextch;
+ stack[++top] = ch;
+ break;
+ }
+ }
+
+ ch = nextChar();
+ if (ch == '"' || ch == '\'') {
+ int quote = ch;
+ while ((ch = nextChar()) != quote) {
+ char[] chararr = new char[1];
+ chararr[0] = (char) ch;
+ String s = new String(chararr);
+ token = token.concat(s);
+ }
+ return token;
+ } else {
+ // return the next whitespace or comment delimited
+ // string
+ while (ch > ' ') {
+ nextch = nextChar();
+ if (ch == '-' && nextch == '-') {
+ stack[++top] = ch;
+ stack[++top] = nextch;
+ return token;
+ } else {
+ char[] chararr = new char[1];
+ chararr[0] = (char) ch;
+ String s = new String(chararr);
+ token = token.concat(s);
+ ch = nextch;
+ }
+ }
+ return token;
+ }
+ }
+
+ /**
+ * Return the next logical character from the input stream.
+ *
+ * @return The next (logical) character from the input stream. The
+ * character may be buffered from a previous lookahead.
+ *
+ * @throws IOException If an error occurs reading from the stream.
+ */
+ protected int nextChar() throws IOException {
+ if (top < 0) {
+ return catfile.read();
+ } else {
+ return stack[top--];
+ }
+ }
+}
diff --git a/java/src/org/apache/xml/resolver/readers/XCatalogReader.java b/java/src/org/apache/xml/resolver/readers/XCatalogReader.java
new file mode 100644
index 0000000..e396b37
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/readers/XCatalogReader.java
@@ -0,0 +1,234 @@
+// XCatalogReader.java - Read XML Catalog files
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.readers;
+
+import java.lang.Integer;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.MalformedURLException;
+import org.apache.xml.resolver.Catalog;
+import org.apache.xml.resolver.CatalogEntry;
+import org.apache.xml.resolver.CatalogException;
+import org.apache.xml.resolver.readers.CatalogReader;
+import org.apache.xml.resolver.helpers.PublicId;
+import org.apache.xml.resolver.helpers.Debug;
+
+import org.xml.sax.*;
+
+import javax.xml.parsers.*;
+
+/**
+ * Parse "xcatalog" XML Catalog files, this is the XML Catalog format
+ * developed by John Cowan and supported by Apache.
+ *
+ * @see Catalog
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class XCatalogReader extends SAXCatalogReader implements SAXCatalogParser {
+ /** The catalog object needs to be stored by the object so that
+ * SAX callbacks can use it.
+ */
+ protected Catalog catalog = null;
+
+ /** Set the current catalog. */
+ public void setCatalog (Catalog catalog) {
+ this.catalog = catalog;
+ }
+
+ /** Get the current catalog. */
+ public Catalog getCatalog () {
+ return catalog;
+ }
+
+ /** The constructor */
+ public XCatalogReader(SAXParserFactory parserFactory) {
+ super(parserFactory);
+ }
+
+ // ----------------------------------------------------------------------
+ // Implement the SAX DocumentHandler interface
+
+ /** The SAX setDocumentLocator method does nothing.
*/
+ public void setDocumentLocator (Locator locator) {
+ return;
+ }
+
+ /** The SAX startDocument method does nothing.
*/
+ public void startDocument ()
+ throws SAXException {
+ return;
+ }
+
+ /** The SAX endDocument method does nothing.
*/
+ public void endDocument ()
+ throws SAXException {
+ return;
+ }
+
+ /**
+ * The SAX startElement method recognizes elements
+ * from the plain catalog format and instantiates CatalogEntry
+ * objects for them.
+ *
+ * @param namespaceURI The namespace name of the element.
+ * @param localName The local name of the element.
+ * @param qName The QName of the element.
+ * @param atts The list of attributes on the element.
+ *
+ * @see CatalogEntry
+ */
+ public void startElement (String namespaceURI,
+ String localName,
+ String qName,
+ Attributes atts)
+ throws SAXException {
+
+ int entryType = -1;
+ Vector entryArgs = new Vector();
+
+ if (localName.equals("Base")) {
+ entryType = catalog.BASE;
+ entryArgs.add(atts.getValue("HRef"));
+
+ Debug.message(4, "Base", atts.getValue("HRef"));
+ } else if (localName.equals("Delegate")) {
+ entryType = catalog.DELEGATE_PUBLIC;
+ entryArgs.add(atts.getValue("PublicId"));
+ entryArgs.add(atts.getValue("HRef"));
+
+ Debug.message(4, "Delegate",
+ PublicId.normalize(atts.getValue("PublicId")),
+ atts.getValue("HRef"));
+ } else if (localName.equals("Extend")) {
+ entryType = catalog.CATALOG;
+ entryArgs.add(atts.getValue("HRef"));
+
+ Debug.message(4, "Extend", atts.getValue("HRef"));
+ } else if (localName.equals("Map")) {
+ entryType = catalog.PUBLIC;
+ entryArgs.add(atts.getValue("PublicId"));
+ entryArgs.add(atts.getValue("HRef"));
+
+ Debug.message(4, "Map",
+ PublicId.normalize(atts.getValue("PublicId")),
+ atts.getValue("HRef"));
+ } else if (localName.equals("Remap")) {
+ entryType = catalog.SYSTEM;
+ entryArgs.add(atts.getValue("SystemId"));
+ entryArgs.add(atts.getValue("HRef"));
+
+ Debug.message(4, "Remap",
+ atts.getValue("SystemId"),
+ atts.getValue("HRef"));
+ } else if (localName.equals("XMLCatalog")) {
+ // nop, start of catalog
+ } else {
+ // This is equivalent to an invalid catalog entry type
+ Debug.message(1, "Invalid catalog entry type", localName);
+ }
+
+ if (entryType >= 0) {
+ try {
+ CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
+ catalog.addEntry(ce);
+ } catch (CatalogException cex) {
+ if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
+ Debug.message(1, "Invalid catalog entry type", localName);
+ } else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
+ Debug.message(1, "Invalid catalog entry", localName);
+ }
+ }
+ }
+ }
+
+ /** The SAX endElement method does nothing.
*/
+ public void endElement (String namespaceURI,
+ String localName,
+ String qName)
+ throws SAXException {
+ return;
+ }
+
+ /** The SAX characters method does nothing.
*/
+ public void characters (char ch[], int start, int length)
+ throws SAXException {
+ return;
+ }
+
+ /** The SAX ignorableWhitespace method does nothing.
*/
+ public void ignorableWhitespace (char ch[], int start, int length)
+ throws SAXException {
+ return;
+ }
+
+ /** The SAX processingInstruction method does nothing.
*/
+ public void processingInstruction (String target, String data)
+ throws SAXException {
+ return;
+ }
+}
diff --git a/java/src/org/apache/xml/resolver/readers/package.html b/java/src/org/apache/xml/resolver/readers/package.html
new file mode 100644
index 0000000..e79bf6d
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/readers/package.html
@@ -0,0 +1,12 @@
+
+
+Apache XML Commons Resolver Readers package
+
+
+Apache XML Commons Resolver Readers package
+
+This package provides the set of classes that read catalog files
+and extract catalog entries from them.
+
+
+
diff --git a/java/src/org/apache/xml/resolver/tools/CatalogResolver.java b/java/src/org/apache/xml/resolver/tools/CatalogResolver.java
new file mode 100644
index 0000000..5934f43
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/tools/CatalogResolver.java
@@ -0,0 +1,371 @@
+// CatalogResolver.java - A SAX EntityResolver/JAXP URI Resolver
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.tools;
+
+import java.lang.ClassNotFoundException;
+import java.lang.ClassCastException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.MalformedURLException;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+
+import javax.xml.parsers.*;
+import javax.xml.transform.*;
+import javax.xml.transform.sax.SAXSource;
+
+import org.apache.xml.resolver.Catalog;
+import org.apache.xml.resolver.CatalogManager;
+import org.apache.xml.resolver.helpers.Debug;
+
+/**
+ * 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 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 static Catalog staticCatalog = null;
+ private Catalog catalog = null;
+
+ /** Constructor */
+ public CatalogResolver() {
+ initializeCatalogs(false);
+ }
+
+ /** Constructor */
+ public CatalogResolver(boolean privateCatalog) {
+ initializeCatalogs(privateCatalog);
+ }
+
+ /** Initialize catalog */
+ private void initializeCatalogs(boolean privateCatalog) {
+ catalog = staticCatalog;
+
+ if (privateCatalog || catalog == null) {
+ try {
+ String catalogClassName = CatalogManager.catalogClassName();
+ 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.setupReaders();
+
+ if (!privateCatalog) {
+ catalog.loadSystemCatalogs();
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ if (!privateCatalog && catalog != null && CatalogManager.staticCatalog()) {
+ staticCatalog = catalog;
+ }
+ }
+
+ /** 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) {
+ Debug.message(1, "Catalog resolution attempted with null catalog; ignored");
+ return null;
+ }
+
+ if (systemId != null) {
+ try {
+ resolved = catalog.resolveSystem(systemId);
+ } catch (MalformedURLException me) {
+ Debug.message(1, "Malformed URL exception trying to resolve",
+ publicId);
+ resolved = null;
+ } catch (IOException ie) {
+ 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) {
+ Debug.message(1, "Malformed URL exception trying to resolve",
+ publicId);
+ } catch (IOException ie) {
+ Debug.message(1, "I/O exception trying to resolve", publicId);
+ }
+ }
+
+ if (resolved != null) {
+ Debug.message(2, "Resolved public", publicId, resolved);
+ }
+ } else {
+ 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) {
+ Debug.message(1, "Failed to create InputSource", 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);
+ }
+ }
+ }
+
+ // if (!href.equals(result)) {
+ Debug.message(2, "Resolved URI", href, result);
+ // }
+
+ SAXSource source = new SAXSource();
+ source.setInputSource(new InputSource(result));
+ return source;
+ }
+
+ /** 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) {
+ String dir = System.getProperty("user.dir");
+ String file = "";
+
+ if (dir.endsWith("/")) {
+ file = "file://" + dir + uri;
+ } else {
+ file = "file://" + dir + "/" + uri;
+ }
+
+ try {
+ URL fileURL = new URL(file);
+ return fileURL.toString();
+ } catch (MalformedURLException mue2) {
+ // bail
+ return uri;
+ }
+ }
+ }
+}
diff --git a/java/src/org/apache/xml/resolver/tools/ResolvingParser.java b/java/src/org/apache/xml/resolver/tools/ResolvingParser.java
new file mode 100644
index 0000000..64661b0
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/tools/ResolvingParser.java
@@ -0,0 +1,459 @@
+// ResolvingParser.java - An interface for reading catalog files
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.tools;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.MalformedURLException;
+import java.util.Locale;
+
+import org.xml.sax.*;
+
+import javax.xml.parsers.*;
+
+import org.apache.xml.resolver.Catalog;
+import org.apache.xml.resolver.CatalogManager;
+import org.apache.xml.resolver.helpers.Debug;
+
+/**
+ * A SAX Parser that performs catalog-based entity resolution.
+ *
+ * This class implements a SAX Parser that performs entity resolution
+ * using the CatalogResolver. The actual, underlying parser is obtained
+ * from a SAXParserFactory.
+ *
+ *
+ * @deprecated This interface has been replaced by the
+ * {@link org.apache.xml.resolver.tools.ResolvingXMLReader} for SAX2.
+ * @see CatalogResolver
+ * @see org.xml.sax.Parser
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class ResolvingParser
+ implements Parser, DTDHandler, DocumentHandler, EntityResolver {
+ /** Make the parser Namespace aware? */
+ public static boolean namespaceAware = true;
+
+ /** Make the parser validating? */
+ public static boolean validating = false;
+
+ /** Suppress explanatory message?
+ *
+ * @see #parse(InputSource)
+ */
+ public static boolean suppressExplanation = false;
+
+ /** The underlying parser */
+ private SAXParser saxParser = null;
+
+ /** The underlying reader */
+ private Parser parser = null;
+
+ /** The underlying DocumentHandler */
+ private DocumentHandler documentHandler = null;
+
+ /** The underlying DTDHandler */
+ private DTDHandler dtdHandler = null;
+
+ /** The underlying catalog resolver */
+ private CatalogResolver catalogResolver = new CatalogResolver();
+
+ /** A separate resolver for oasis-xml-pi catalogs */
+ private CatalogResolver piCatalogResolver = null;
+
+ /** Are we in the prolog? Is an oasis-xml-catalog PI valid now? */
+ private boolean allowXMLCatalogPI = false;
+
+ /** Has an oasis-xml-catalog PI been seen? */
+ private boolean oasisXMLCatalogPI = false;
+
+ /** The base URI of the input document, if known. */
+ private URL baseURL = null;
+
+ /** Constructor */
+ public ResolvingParser() {
+ SAXParserFactory spf = SAXParserFactory.newInstance();
+ spf.setNamespaceAware(namespaceAware);
+ spf.setValidating(validating);
+
+ try {
+ saxParser = spf.newSAXParser();
+ parser = saxParser.getParser();
+ documentHandler = null;
+ dtdHandler = null;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ /** Return the Catalog being used */
+ public Catalog getCatalog() {
+ return catalogResolver.getCatalog();
+ }
+
+ /**
+ * SAX Parser API
+ *
+ * Note that the JAXP 1.1ea2 parser crashes with an InternalError if
+ * it encounters a system identifier that appears to be a relative URI
+ * that begins with a slash. For example, the declaration:
+ *
+ *
+ * <!DOCTYPE book SYSTEM "/path/to/dtd/on/my/system/docbookx.dtd">
+ *
+ *
+ * would cause such an error. As a convenience, this method catches
+ * that error and prints an explanation. (Unfortunately, it's not possible
+ * to identify the particular system identifier that causes the problem.)
+ *
+ *
+ * The underlying error is forwarded after printing the explanatory
+ * message. The message is only every printed once and if
+ * suppressExplanation is set to false before
+ * parsing, it will never be printed.
+ */
+ public void parse(InputSource input)
+ throws IOException,
+ SAXException {
+ setupParse(input.getSystemId());
+ try {
+ parser.parse(input);
+ } catch (InternalError ie) {
+ explain(input.getSystemId());
+ throw ie;
+ }
+ }
+
+ /** SAX Parser API
+ *
+ * @see #parse(InputSource)
+ */
+ public void parse(String systemId)
+ throws IOException,
+ SAXException {
+ setupParse(systemId);
+ try {
+ parser.parse(systemId);
+ } catch (InternalError ie) {
+ explain(systemId);
+ throw ie;
+ }
+ }
+
+ /** SAX Parser API */
+ public void setDocumentHandler(DocumentHandler handler) {
+ documentHandler = handler;
+ }
+
+ /** SAX Parser API */
+ public void setDTDHandler(DTDHandler handler) {
+ dtdHandler = handler;
+ }
+
+ /**
+ * SAX Parser API
+ *
+ * The purpose of this class is to implement an entity resolver.
+ * Attempting to set a different one is pointless (and ignored).
+ */
+ public void setEntityResolver(EntityResolver resolver) {
+ // nop
+ }
+
+ /** SAX Parser API */
+ public void setErrorHandler(ErrorHandler handler) {
+ parser.setErrorHandler(handler);
+ }
+
+ /** SAX Parser API */
+ public void setLocale(Locale locale) throws SAXException {
+ parser.setLocale(locale);
+ }
+
+ /** SAX DocumentHandler API */
+ public void characters(char[] ch, int start, int length)
+ throws SAXException {
+ if (documentHandler != null) {
+ documentHandler.characters(ch,start,length);
+ }
+ }
+
+ /** SAX DocumentHandler API */
+ public void endDocument() throws SAXException {
+ if (documentHandler != null) {
+ documentHandler.endDocument();
+ }
+ }
+
+ /** SAX DocumentHandler API */
+ public void endElement(String name) throws SAXException {
+ if (documentHandler != null) {
+ documentHandler.endElement(name);
+ }
+ }
+
+ /** SAX DocumentHandler API */
+ public void ignorableWhitespace(char[] ch, int start, int length)
+ throws SAXException {
+ if (documentHandler != null) {
+ documentHandler.ignorableWhitespace(ch,start,length);
+ }
+ }
+
+ /** SAX DocumentHandler API */
+ public void processingInstruction(String target, String pidata)
+ throws SAXException {
+
+ if (target.equals("oasis-xml-catalog")) {
+ URL catalog = null;
+ String data = pidata;
+
+ int pos = data.indexOf("catalog=");
+ if (pos >= 0) {
+ data = data.substring(pos+8);
+ if (data.length() > 1) {
+ String quote = data.substring(0,1);
+ data = data.substring(1);
+ pos = data.indexOf(quote);
+ if (pos >= 0) {
+ data = data.substring(0, pos);
+ try {
+ if (baseURL != null) {
+ catalog = new URL(baseURL, data);
+ } else {
+ catalog = new URL(data);
+ }
+ } catch (MalformedURLException mue) {
+ // nevermind
+ }
+ }
+ }
+ }
+
+ if (allowXMLCatalogPI) {
+ if (CatalogManager.allowOasisXMLCatalogPI()) {
+ Debug.message(4,"oasis-xml-catalog PI", pidata);
+
+ if (catalog != null) {
+ try {
+ Debug.message(4,"oasis-xml-catalog", catalog.toString());
+ oasisXMLCatalogPI = true;
+
+ if (piCatalogResolver == null) {
+ piCatalogResolver = new CatalogResolver(true);
+ }
+
+ piCatalogResolver.getCatalog().parseCatalog(catalog.toString());
+ } catch (Exception e) {
+ Debug.message(3, "Exception parsing oasis-xml-catalog: "
+ + catalog.toString());
+ }
+ } else {
+ Debug.message(3, "PI oasis-xml-catalog unparseable: " + pidata);
+ }
+ } else {
+ Debug.message(4,"PI oasis-xml-catalog ignored: " + pidata);
+ }
+ } else {
+ Debug.message(3, "PI oasis-xml-catalog occurred in an invalid place: "
+ + pidata);
+ }
+ } else {
+ if (documentHandler != null) {
+ documentHandler.processingInstruction(target, pidata);
+ }
+ }
+ }
+
+ /** SAX DocumentHandler API */
+ public void setDocumentLocator(Locator locator) {
+ if (documentHandler != null) {
+ documentHandler.setDocumentLocator(locator);
+ }
+ }
+
+ /** SAX DocumentHandler API */
+ public void startDocument() throws SAXException {
+ if (documentHandler != null) {
+ documentHandler.startDocument();
+ }
+ }
+
+ /** SAX DocumentHandler API */
+ public void startElement(String name, AttributeList atts)
+ throws SAXException {
+ allowXMLCatalogPI = false;
+ if (documentHandler != null) {
+ documentHandler.startElement(name,atts);
+ }
+ }
+
+ /** SAX DTDHandler API */
+ public void notationDecl (String name, String publicId, String systemId)
+ throws SAXException {
+ allowXMLCatalogPI = false;
+ if (dtdHandler != null) {
+ dtdHandler.notationDecl(name,publicId,systemId);
+ }
+ }
+
+ /** SAX DTDHandler API */
+ public void unparsedEntityDecl (String name,
+ String publicId,
+ String systemId,
+ String notationName)
+ throws SAXException {
+ allowXMLCatalogPI = false;
+ if (dtdHandler != null) {
+ dtdHandler.unparsedEntityDecl (name, publicId, systemId, notationName);
+ }
+ }
+
+ /**
+ * Implements the resolveEntity method
+ * for the SAX interface, using an underlying CatalogResolver
+ * to do the real work.
+ */
+ public InputSource resolveEntity (String publicId, String systemId) {
+ allowXMLCatalogPI = false;
+ String resolved = catalogResolver.getResolvedEntity(publicId, systemId);
+
+ if (resolved == null && piCatalogResolver != null) {
+ resolved = piCatalogResolver.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) {
+ Debug.message(1, "Failed to create InputSource", resolved);
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /** Setup for parsing */
+ private void setupParse(String systemId) {
+ allowXMLCatalogPI = true;
+ parser.setEntityResolver(this);
+ parser.setDocumentHandler(this);
+ parser.setDTDHandler(this);
+
+ String userdir = System.getProperty("user.dir");
+ URL cwd = null;
+
+ userdir.replace('\\', '/');
+ try {
+ cwd = new URL("file:///" + userdir + "/basename");
+ } catch (MalformedURLException mue) {
+ cwd = null;
+ }
+
+ try {
+ baseURL = new URL(systemId);
+ } catch (MalformedURLException mue) {
+ if (cwd != null) {
+ try {
+ baseURL = new URL(cwd, systemId);
+ } catch (MalformedURLException mue2) {
+ // give up
+ baseURL = null;
+ }
+ } else {
+ // give up
+ baseURL = null;
+ }
+ }
+ }
+
+ /** Provide one possible explanation for an InternalError */
+ private void explain(String systemId) {
+ if (!suppressExplanation) {
+ System.out.println("Parser probably encountered bad URI in " + systemId);
+ System.out.println("For example, replace '/some/uri' with 'file:/some/uri'.");
+ }
+ }
+}
+
diff --git a/java/src/org/apache/xml/resolver/tools/ResolvingXMLFilter.java b/java/src/org/apache/xml/resolver/tools/ResolvingXMLFilter.java
new file mode 100644
index 0000000..e908e2d
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/tools/ResolvingXMLFilter.java
@@ -0,0 +1,370 @@
+// ResolvingXMLFilter.java - An XMLFilter that performs catalog resolution
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.tools;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.XMLFilterImpl;
+
+import javax.xml.parsers.*;
+
+import org.apache.xml.resolver.Catalog;
+import org.apache.xml.resolver.CatalogManager;
+import org.apache.xml.resolver.helpers.Debug;
+
+/**
+ * A SAX XMLFilter that performs catalog-based entity resolution.
+ *
+ * This class implements a SAX XMLFilter that performs entity resolution
+ * using the CatalogResolver. The actual, underlying parser is obtained
+ * from a SAXParserFactory.
+ *
+ *
+ * @see CatalogResolver
+ * @see org.xml.sax.XMLFilter
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class ResolvingXMLFilter extends XMLFilterImpl {
+ /** Suppress explanatory message?
+ *
+ * @see #parse(InputSource)
+ */
+ public static boolean suppressExplanation = false;
+
+ /** The underlying catalog resolver */
+ private CatalogResolver catalogResolver = new CatalogResolver();
+
+ /** A separate resolver for oasis-xml-pi catalogs */
+ private CatalogResolver piCatalogResolver = null;
+
+ /** Are we in the prolog? Is an oasis-xml-catalog PI valid now? */
+ private boolean allowXMLCatalogPI = false;
+
+ /** Has an oasis-xml-catalog PI been seen? */
+ private boolean oasisXMLCatalogPI = false;
+
+ /** The base URI of the input document, if known. */
+ private URL baseURL = null;
+
+ /** Construct an empty XML Filter with no parent */
+ public ResolvingXMLFilter() {
+ super();
+ }
+
+ /** Construct an XML filter with the specified parent */
+ public ResolvingXMLFilter(XMLReader parent) {
+ super(parent);
+ }
+
+ /**
+ * Provide accessto the underlying Catalog
+ */
+ public Catalog getCatalog() {
+ return catalogResolver.getCatalog();
+ }
+
+ /**
+ * SAX XMLReader API
+ *
+ * Note that the JAXP 1.1ea2 parser crashes with an InternalError if
+ * it encounters a system identifier that appears to be a relative URI
+ * that begins with a slash. For example, the declaration:
+ *
+ *
+ * <!DOCTYPE book SYSTEM "/path/to/dtd/on/my/system/docbookx.dtd">
+ *
+ *
+ * would cause such an error. As a convenience, this method catches
+ * that error and prints an explanation. (Unfortunately, it's not possible
+ * to identify the particular system identifier that causes the problem.)
+ *
+ *
+ * The underlying error is forwarded after printing the explanatory
+ * message. The message is only every printed once and if
+ * suppressExplanation is set to false before
+ * parsing, it will never be printed.
+ */
+ public void parse(InputSource input)
+ throws IOException, SAXException {
+ allowXMLCatalogPI = true;
+
+ setupBaseURI(input.getSystemId());
+
+ try {
+ super.parse(input);
+ } catch (InternalError ie) {
+ explain(input.getSystemId());
+ throw ie;
+ }
+ }
+
+ /** SAX XMLReader API
+ *
+ * @see #parse(InputSource)
+ */
+ public void parse(String systemId)
+ throws IOException, SAXException {
+ allowXMLCatalogPI = true;
+
+ setupBaseURI(systemId);
+
+ try {
+ super.parse(systemId);
+ } catch (InternalError ie) {
+ explain(systemId);
+ throw ie;
+ }
+ }
+
+ /**
+ * Implements the resolveEntity method
+ * for the SAX interface, using an underlying CatalogResolver
+ * to do the real work.
+ */
+ public InputSource resolveEntity (String publicId, String systemId) {
+ allowXMLCatalogPI = false;
+ String resolved = catalogResolver.getResolvedEntity(publicId, systemId);
+
+ if (resolved == null && piCatalogResolver != null) {
+ resolved = piCatalogResolver.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) {
+ Debug.message(1, "Failed to create InputSource", resolved);
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /** SAX DTDHandler API
+ *
+ * Captured here only to detect the end of the prolog so that
+ * we can ignore subsequent oasis-xml-catalog PIs. Otherwise
+ * the events are just passed through.
+ */
+ public void notationDecl (String name, String publicId, String systemId)
+ throws SAXException {
+ allowXMLCatalogPI = false;
+ super.notationDecl(name,publicId,systemId);
+ }
+
+ /** SAX DTDHandler API
+ *
+ * Captured here only to detect the end of the prolog so that
+ * we can ignore subsequent oasis-xml-catalog PIs. Otherwise
+ * the events are just passed through.
+ */
+ public void unparsedEntityDecl (String name,
+ String publicId,
+ String systemId,
+ String notationName)
+ throws SAXException {
+ allowXMLCatalogPI = false;
+ super.unparsedEntityDecl (name, publicId, systemId, notationName);
+ }
+
+ /** SAX ContentHandler API
+ *
+ * Captured here only to detect the end of the prolog so that
+ * we can ignore subsequent oasis-xml-catalog PIs. Otherwise
+ * the events are just passed through.
+ */
+ public void startElement (String uri, String localName, String qName,
+ Attributes atts)
+ throws SAXException {
+ allowXMLCatalogPI = false;
+ super.startElement(uri,localName,qName,atts);
+ }
+
+ /** SAX ContentHandler API
+ *
+ * Detect and use the oasis-xml-catalog PI if it occurs.
+ */
+ public void processingInstruction(String target, String pidata)
+ throws SAXException {
+ if (target.equals("oasis-xml-catalog")) {
+ URL catalog = null;
+ String data = pidata;
+
+ int pos = data.indexOf("catalog=");
+ if (pos >= 0) {
+ data = data.substring(pos+8);
+ if (data.length() > 1) {
+ String quote = data.substring(0,1);
+ data = data.substring(1);
+ pos = data.indexOf(quote);
+ if (pos >= 0) {
+ data = data.substring(0, pos);
+ try {
+ if (baseURL != null) {
+ catalog = new URL(baseURL, data);
+ } else {
+ catalog = new URL(data);
+ }
+ } catch (MalformedURLException mue) {
+ // nevermind
+ }
+ }
+ }
+ }
+
+ if (allowXMLCatalogPI) {
+ if (CatalogManager.allowOasisXMLCatalogPI()) {
+ Debug.message(4,"oasis-xml-catalog PI", pidata);
+
+ if (catalog != null) {
+ try {
+ Debug.message(4,"oasis-xml-catalog", catalog.toString());
+ oasisXMLCatalogPI = true;
+
+ if (piCatalogResolver == null) {
+ piCatalogResolver = new CatalogResolver(true);
+ }
+
+ piCatalogResolver.getCatalog().parseCatalog(catalog.toString());
+ } catch (Exception e) {
+ Debug.message(3, "Exception parsing oasis-xml-catalog: "
+ + catalog.toString());
+ }
+ } else {
+ Debug.message(3, "PI oasis-xml-catalog unparseable: " + pidata);
+ }
+ } else {
+ Debug.message(4,"PI oasis-xml-catalog ignored: " + pidata);
+ }
+ } else {
+ Debug.message(3, "PI oasis-xml-catalog occurred in an invalid place: "
+ + pidata);
+ }
+ } else {
+ super.processingInstruction(target, pidata);
+ }
+ }
+
+ /** Save the base URI of the document being parsed. */
+ private void setupBaseURI(String systemId) {
+ String userdir = System.getProperty("user.dir");
+ URL cwd = null;
+
+ userdir.replace('\\', '/');
+ try {
+ cwd = new URL("file:///" + userdir + "/basename");
+ } catch (MalformedURLException mue) {
+ cwd = null;
+ }
+
+ try {
+ baseURL = new URL(systemId);
+ } catch (MalformedURLException mue) {
+ if (cwd != null) {
+ try {
+ baseURL = new URL(cwd, systemId);
+ } catch (MalformedURLException mue2) {
+ // give up
+ baseURL = null;
+ }
+ } else {
+ // give up
+ baseURL = null;
+ }
+ }
+ }
+
+ /** Provide one possible explanation for an InternalError */
+ private void explain(String systemId) {
+ if (!suppressExplanation) {
+ System.out.println("XMLReader probably encountered bad URI in " + systemId);
+ System.out.println("For example, replace '/some/uri' with 'file:/some/uri'.");
+ }
+ suppressExplanation = true;
+ }
+}
+
diff --git a/java/src/org/apache/xml/resolver/tools/ResolvingXMLReader.java b/java/src/org/apache/xml/resolver/tools/ResolvingXMLReader.java
new file mode 100644
index 0000000..b613bd3
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/tools/ResolvingXMLReader.java
@@ -0,0 +1,107 @@
+// ResolvingXMLReader.java - An XMLReader that performs catalog resolution
+
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, International
+ * Business Machines Corporation., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.xml.resolver.tools;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.XMLFilterImpl;
+
+import javax.xml.parsers.*;
+
+import org.apache.xml.resolver.*;
+
+/**
+ * A SAX XMLReader that performs catalog-based entity resolution.
+ *
+ * This class implements a SAX XMLReader that performs entity resolution
+ * using the CatalogResolver. The actual, underlying parser is obtained
+ * from a SAXParserFactory.
+ *
+ *
+ * @see CatalogResolver
+ * @see org.xml.sax.XMLReader
+ *
+ * @author Norman Walsh
+ * Norman.Walsh@Sun.COM
+ *
+ * @version 1.0
+ */
+public class ResolvingXMLReader extends ResolvingXMLFilter {
+ /**
+ * Construct a new reader from the JAXP factory
+ *
+ * In order to do its job, a ResolvingXMLReader must in fact be
+ * a filter. So the only difference between this code and the filter
+ * code is that a zero-argument constructor builds a new reader.
+ */
+ public ResolvingXMLReader() {
+ super();
+ SAXParserFactory spf = SAXParserFactory.newInstance();
+ try {
+ SAXParser parser = spf.newSAXParser();
+ setParent(parser.getXMLReader());
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+}
+
diff --git a/java/src/org/apache/xml/resolver/tools/package.html b/java/src/org/apache/xml/resolver/tools/package.html
new file mode 100644
index 0000000..82eb95e
--- /dev/null
+++ b/java/src/org/apache/xml/resolver/tools/package.html
@@ -0,0 +1,47 @@
+
+
+Apache XML Commons Resolver Tools package
+
+
+Apache XML Commons Resolver Tools package
+
+This package implements several tool classes for catalog-based
+entity resolution:
+
+
+org.apache.xml.resolver.tools.CatalogResolver
+- This class provides a SAX EntityResolver and a JAXP URIResolver.
+
+
+org.apache.xml.resolver.tools.ResolvingXMLReader
+- This class provides a SAX2 XMLReader with catalog support.
+The parser uses a CatalogResolver to provide entity resolution.
+
+
+org.apache.xml.resolver.tools.ResolvingParser
+- This class provides a SAX1 Parser with catalog support.
+The parser uses a CatalogResolver to provide entity resolution.
+
+
+
+Typically, these classes can be used in other applications. For example,
+running the Saxon
+XSLT processor with the arguments:
+
+
+ -x org.apache.xml.resolver.tools.ResolvingXMLReader
+ -y org.apache.xml.resolver.tools.ResolvingXMLReader
+ -r org.apache.xml.resolver.tools.CatalogResolver
+
+
+will provide catalog-based entity resolution for all of the entities
+and stylesheets that you use. (The CatalogResolver can only be used
+with Saxon 6.1 or later.)
+
+Requirements
+
+In order to use these classes, you must have the JAXP 1.1 jar files
+in your CLASSPATH.
+
+
+