diff --git a/WHATSNEW b/WHATSNEW index fc5c90ed2..c797b3fbb 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -67,6 +67,10 @@ Other changes: define ids or paths and use Ant's location magic for filename resolutions in the XML file. +* will now support external catalogs according to the + OASIS "Open Catalog" standard - if resolver.jar from Apache's + xml-commons is in your CLASSPATH. + Changes from Ant 1.5.1Beta1 to 1.5.1 ==================================== diff --git a/build.xml b/build.xml index 03cb8710b..9963fdf3a 100644 --- a/build.xml +++ b/build.xml @@ -51,6 +51,7 @@ + @@ -195,6 +196,9 @@ + + + @@ -341,6 +345,9 @@ + @@ -570,6 +577,7 @@ + @@ -739,6 +747,7 @@ + @@ -792,6 +801,12 @@ + + + + diff --git a/docs/manual/CoreTypes/xmlcatalog.html b/docs/manual/CoreTypes/xmlcatalog.html index ef41cdc8f..75292d91a 100644 --- a/docs/manual/CoreTypes/xmlcatalog.html +++ b/docs/manual/CoreTypes/xmlcatalog.html @@ -19,6 +19,10 @@ documents to efficiently allow a local substitution for a resource available on the web.

+

Note: This task uses, but does not depend on external +libraries not included in the Ant distribution. See Library Dependencies for more +information.

This data type provides a catalog of resource locations based on the @@ -59,17 +63,34 @@ task uses XMLCatalogs for both entity and URI resolution.

XMLCatalogs are specified as either a reference to another XMLCatalog, defined previously in a build file, or as a list of dtd or -entity locations. A separate classpath for entity resolution +entity locations. In addition, external catalog files +may be specified in catalogfiles filesets, but they will +be ignored unless the resolver library from xml-commons is available +in the system classpath. A separate classpath for entity resolution may be specified inline via nested classpath elements; otherwise the system classpath is used for this as well.

XMLCatalogs can also be nested inside other XMLCatalogs. For example, a "superset" XMLCatalog could be made by including several nested XMLCatalogs that referred to other, previously defined XMLCatalogs.

+

Resource locations can be specified either in-line or in +external catalog file(s), or both. In order to use an external +catalog file, the xml-commons resolver library ("resolver.jar") +must be in your path. External catalog files may be either +plain text format or +XML format. If the xml-commons resolver library is not found in the +classpath, external catalog files, specified in catalogfiles +filesets, will be ignored and a warning will be logged. In this case, however, +processing of inline entries will proceed normally.

Currently, only <dtd> and <entity> elements may be specified inline; these roughly correspond to OASIS catalog entry types PUBLIC and -URI respectively.

+URI respectively. By contrast, external catalog files +may use any of the entry types defined in the + ++OASIS specification.

Entity/DTD/URI Resolution Algorithm

When an entity, DTD, or URI is looked up by the XML processor, the @@ -101,6 +122,18 @@ will not resolve an entity whose location is blat.dtd. +

3a. Apache xml-commons resolver lookup

+ +

What happens next depends on whether the resolver library from +xml-commons is available on the classpath. If so, we defer all +further attempts at resolving to it. The resolver library supports +extremely sophisticated functionality like URL rewriting and so on, +which can be accessed by making the appropriate entries in external +catalog files (XMLCatalog does not yet provide inline support for all +of the entries defined in the OASIS +standard).

+

3. URL-space lookup

Finally, we attempt to make a URL out of the location. @@ -171,6 +204,22 @@ basedir.

The classpath to use for entity resolution. The nested <classpath> is a path-like structure.

+

catalogfiles

+

+The nested catalogfiles element specifies a FileSet. All files included in +this fileset are assumed to be OASIS catalog files, in either + +plain text format or +XML format. Multiple catalogfiles filesets may be +specified. Of course, if you use wildcards in your fileset, you will +want to use some sort of naming convention to ensure that you don't +accidentally match non-catalog files. If the resolver library from +xml-commons is not available in the classpath, all +catalogfiles will be ignored and a warning will be +logged. +

Examples

Set up an XMLCatalog with a single dtd referenced locally in a user's home @@ -197,7 +246,8 @@ filesystem (relative to the Ant project basedir) or in the classpath:

Set up an XMLCatalog with a combination of DTDs and entities as -well as a nested XMLCatalog:

+well as a nested XMLCatalog and external catalog files in both +formats:

     <xmlcatalog id="allcatalogs">
@@ -207,7 +257,13 @@ well as a nested XMLCatalog:

<entity publicId="LargeLogo" location="com/arielpartners/images/ariel-logo-large.gif"/> - <xmlcatalog refid="commonDTDs"/> + <xmlcatalog refid="commonDTDs"/> + <catalogfiles + dir="/anetwork/drive" + includes="**/catalog"/> + <catalogfiles + dir="/my/catalogs" + includes="**/catalog.xml"/> </xmlcatalog>

To reference the above XMLCatalog in an xslt task:

diff --git a/docs/manual/install.html b/docs/manual/install.html index aae41cce8..3c19beb88 100644 --- a/docs/manual/install.html +++ b/docs/manual/install.html @@ -381,6 +381,12 @@ Installing Ant / Optional Tasks section above.

http://www.clarkware.com/software/JDepend.html + + resolver.jar + xmlcatalog datatype only if support for external catalog files is desired + http://xml.apache.org/dist/commons +

diff --git a/src/etc/testcases/taskdefs/optional/xmlvalidate.xml b/src/etc/testcases/taskdefs/optional/xmlvalidate.xml index 35bc9ce9e..ff71f9125 100644 --- a/src/etc/testcases/taskdefs/optional/xmlvalidate.xml +++ b/src/etc/testcases/taskdefs/optional/xmlvalidate.xml @@ -38,8 +38,18 @@
+ + + + + + + + + + - diff --git a/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java b/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java index d01037bc0..9271c0c5d 100644 --- a/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java +++ b/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java @@ -67,6 +67,7 @@ import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.types.XMLCatalog; import org.apache.tools.ant.util.FileUtils; +import javax.xml.transform.URIResolver; /** * Processes a set of XML documents via XSLT. This is diff --git a/src/main/org/apache/tools/ant/types/DTDLocation.java b/src/main/org/apache/tools/ant/types/DTDLocation.java index ac44378dc..977fa3c51 100644 --- a/src/main/org/apache/tools/ant/types/DTDLocation.java +++ b/src/main/org/apache/tools/ant/types/DTDLocation.java @@ -54,44 +54,25 @@ package org.apache.tools.ant.types; /** - * Helper class to handle the DTD and Entity nested elements. + *

Helper class to handle the DTD nested element. Instances of + * this class correspond to the PUBLIC catalog entry type + * of the + * OASIS "Open Catalog" standard.

* + *

Possible Future Enhancement: Bring the Ant element name into + * conformance with the OASIS standard.

+ * + * @see org.apache.xml.resolver.Catalog * @author Conor MacNeill * @author dIon Gillard + * @author Craeg Strong + * @version $Id$ */ -public class DTDLocation { - /** publicId of the dtd/entity */ - private String publicId = null; - /** location of the dtd/entity - a file/resource/URL */ - private String location = null; - - /** - * @param publicId uniquely identifies the resource - */ - public void setPublicId(String publicId) { - this.publicId = publicId; - } +public class DTDLocation extends ResourceLocation { - /** - * @param location the location of the resource associated with the - * publicId - */ - public void setLocation(String location) { - this.location = location; + public DTDLocation() { + super("PUBLIC"); } - /** - * @return the publicId - */ - public String getPublicId() { - return publicId; - } - - /** - * @return the location of the resource identified by the publicId - */ - public String getLocation() { - return location; - } } - diff --git a/src/main/org/apache/tools/ant/types/EntityLocation.java b/src/main/org/apache/tools/ant/types/EntityLocation.java new file mode 100644 index 000000000..c5351f989 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/EntityLocation.java @@ -0,0 +1,77 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 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 acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", 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 names without prior written + * permission of the Apache Group. + * + * 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. For more + * information on the Apache Software Foundation, please see + * . + */ +package org.apache.tools.ant.types; + +/** + * Helper class to handle the Entity nested element. Instances of + * this class correspond to the URI catalog entry type of + * the + * OASIS "Open Catalog" standard.

+ * + *

Possible Future Enhancement: Bring the Ant element name into + * conformance with the OASIS standard.

+ * + * @see org.apache.xml.resolver.Catalog + * @author Conor MacNeill + * @author dIon Gillard + * @author Craeg Strong + */ +public class EntityLocation extends ResourceLocation { + + public EntityLocation() { + super("URI"); + } + +} diff --git a/src/main/org/apache/tools/ant/types/ResourceLocation.java b/src/main/org/apache/tools/ant/types/ResourceLocation.java new file mode 100644 index 000000000..c23eeaf39 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/ResourceLocation.java @@ -0,0 +1,165 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 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 acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", 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 names without prior written + * permission of the Apache Group. + * + * 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. For more + * information on the Apache Software Foundation, please see + * . + */ +package org.apache.tools.ant.types; + +import java.net.URL; + +/** + *

Helper class to handle the <dtd> and + * <entity> nested elements. These correspond to + * the PUBLIC and URI catalog entry types, + * respectively, as defined in the + * OASIS "Open Catalog" standard.

+ * + *

Possible Future Enhancements: + *

    + *
  • Bring the Ant element names into conformance with the OASIS standard
  • + *
  • Add support for additional OASIS catalog entry types
  • + *
+ *

+ * + * @see org.apache.xml.resolver.Catalog + * @author Conor MacNeill + * @author dIon Gillard + * @author Craeg Strong + * @version $Id$ + */ +public class ResourceLocation { + + //-- Fields ---------------------------------------------------------------- + + /** + * name of the catalog entry type, as per OASIS spec. + */ + protected String name = null; + + /** publicId of the dtd/entity. */ + private String publicId = null; + + /** location of the dtd/entity - a file/resource/URL. */ + private String location = null; + + /** + * base URL of the dtd/entity, or null. If null, the Ant project + * basedir is assumed. If the location specifies a relative + * URL/pathname, it is resolved using the base. The default base + * for an external catalog file is the directory in which it is + * located. + */ + private String base = null; + + //-- Methods --------------------------------------------------------------- + + protected ResourceLocation(String name) { + this.name = name; + } + + /** + * @param publicId uniquely identifies the resource. + */ + public void setPublicId(String publicId) { + this.publicId = publicId; + } + + /** + * @param location the location of the resource associated with the + * publicId. + */ + public void setLocation(String location) { + this.location = location; + } + + /** + * @param base the base URL of the resource associated with the + * publicId. If the location specifies a relative URL/pathname, + * it is resolved using the base. The default base for an + * external catalog file is the directory in which it is located. + */ + public void setBase(String base) { + this.base = base; + } + + /** + * @return the publicId of the resource. + */ + public String getPublicId() { + return publicId; + } + + /** + * @return the location of the resource identified by the publicId. + */ + public String getLocation() { + return location; + } + + /** + * @return the base of the resource identified by the publicId. + */ + public String getBase() { + return base; + } + + /** + * @return the name of the catalog entry type. Currently this is + * one of PUBLIC or URI. + * + * @see org.apache.xml.resolver.Catalog + */ + public String getName() { + return name; + } + +} //-- ResourceLocation diff --git a/src/main/org/apache/tools/ant/types/XMLCatalog.java b/src/main/org/apache/tools/ant/types/XMLCatalog.java index aec564582..223dd1d9c 100644 --- a/src/main/org/apache/tools/ant/types/XMLCatalog.java +++ b/src/main/org/apache/tools/ant/types/XMLCatalog.java @@ -54,6 +54,8 @@ package org.apache.tools.ant.types; +import java.lang.reflect.Method; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -72,6 +74,7 @@ import javax.xml.transform.URIResolver; import javax.xml.transform.sax.SAXSource; import org.apache.tools.ant.AntClassLoader; import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.util.FileUtils; import org.xml.sax.EntityResolver; @@ -138,13 +141,14 @@ import org.xml.sax.XMLReader; * @author Craeg Strong * @version $Id$ */ -public class XMLCatalog extends DataType implements Cloneable, EntityResolver, URIResolver { +public class XMLCatalog extends DataType + implements Cloneable, EntityResolver, URIResolver { /** File utilities instance */ private FileUtils fileUtils = FileUtils.newFileUtils(); //-- Fields ---------------------------------------------------------------- - /** holds dtd/entity objects until needed */ + /** Holds dtd/entity objects and catalog filesets until needed. */ private Vector elements = new Vector(); /** @@ -152,6 +156,14 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U */ private Path classpath; + /** + * The name of the bridge to the Apache xml-commons resolver + * class, used to determine whether resolver.jar is present in the + * classpath. + */ + public static final String APACHE_RESOLVER + = "org.apache.tools.ant.types.resolver.ApacheCatalogResolver"; + //-- Methods --------------------------------------------------------------- public XMLCatalog() { @@ -159,9 +171,11 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U } /** - * Returns the elements of the catalog - DTDLocation objects. + * Returns the elements of the catalog - ResolverLocation and FileSet + * objects. * - * @return the elements of the catalog - DTDLocation objects + * @return the elements of the catalog - ResolverLocation and FileSet + * objects */ private Vector getElements() { return elements; @@ -177,14 +191,18 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U } /** - * Set the list of DTDLocation objects in the catalog. Not - * allowed if this catalog is itself a reference to another - * catalog -- that is, a catalog cannot both refer to another - * and contain elements or other attributes. + * Set the list of ResourceLocation objects and FileSets in the catalog. + * Not allowed if this catalog is itself a reference to another catalog -- + * that is, a catalog cannot both refer to another and contain + * elements or other attributes. * - * @param aVector the new list of DTD Locations to use in the catalog. + * @param aVector the new list of ResourceLocations and FileSets + * to use in the catalog. */ private void setElements(Vector aVector) { + if (isReference()) { + throw noChildrenAllowed(); + } elements = aVector; } @@ -237,6 +255,22 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U setChecked( false ); } + /** Creates the nested <catalogfiles> element. Not + * allowed if this catalog is itself a reference to another catalog -- that + * is, a catalog cannot both refer to another and contain elements + * or other attributes. + * + * @param fs the fileset of external catalogs. + * @exception BuildException + * if this is a reference and no nested elements are allowed. + */ + public void addCatalogfiles(FileSet fs) throws BuildException { + if (isReference()) { + throw noChildrenAllowed(); + } + getElements().addElement(fs); + } + /** * Creates the nested <dtd> element. Not * allowed if this catalog is itself a reference to another @@ -248,7 +282,7 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U * @exception BuildException if this is a reference and no nested * elements are allowed. */ - public void addDTD(DTDLocation dtd) throws BuildException { + public void addDTD(ResourceLocation dtd) throws BuildException { if (isReference()) { throw noChildrenAllowed(); } @@ -256,6 +290,9 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U getElements().addElement(dtd); setChecked( false ); } + public void addDTD(DTDLocation dtd) throws BuildException { + addDTD((ResourceLocation)dtd); + } /** * Creates the nested <entity> element. Not @@ -263,13 +300,34 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U * catalog -- that is, a catalog cannot both refer to another * and contain elements or other attributes. * - * @param dtd the information about the URI resource mapping to be - * added to the catalog + * @param entity the information about the URI resource mapping to + * be added to the catalog. * @exception BuildException if this is a reference and no nested * elements are allowed. */ - public void addEntity(DTDLocation dtd) throws BuildException { - addDTD(dtd); + public void addEntity(EntityLocation entity) throws BuildException { + if (isReference()) { + throw noChildrenAllowed(); + } + getElements().addElement(entity); + } + + /** + * Creates the nested <entity> element. Not + * allowed if this catalog is itself a reference to another + * catalog -- that is, a catalog cannot both refer to another + * and contain elements or other attributes. + * + * @param entity the information about the URI resource mapping to + * be added to the catalog. + * @exception BuildException if this is a reference and no nested + * elements are allowed. + */ + public void addEntity(DTDLocation entity) throws BuildException { + if (isReference()) { + throw noChildrenAllowed(); + } + getElements().addElement(entity); } /** @@ -337,17 +395,18 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { - if (!isChecked()) { - // make sure we don't have a circular reference here - Stack stk = new Stack(); - stk.push(this); - dieOnCircularReference(stk, getProject()); - } + if (!isChecked()) { + // make sure we don't have a circular reference here + Stack stk = new Stack(); + stk.push(this); + dieOnCircularReference(stk, getProject()); + } log("resolveEntity: '" + publicId + "': '" + systemId + "'", Project.MSG_DEBUG); - InputSource inputSource = resolveEntityImpl(publicId ); + InputSource inputSource = + getCatalogResolver().resolveEntity(publicId, systemId); if (inputSource == null) { log("No matching catalog entry found, parser will use: '" + @@ -365,12 +424,12 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U public Source resolve(String href, String base) throws TransformerException { - if (!isChecked()) { - // make sure we don't have a circular reference here - Stack stk = new Stack(); - stk.push(this); - dieOnCircularReference(stk, getProject()); - } + if (!isChecked()) { + // make sure we don't have a circular reference here + Stack stk = new Stack(); + stk.push(this); + dieOnCircularReference(stk, getProject()); + } SAXSource source = null; @@ -389,11 +448,11 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U // source = new SAXSource(); try - { - URL baseURL = new URL(base); - URL url = (uri.length() == 0 ? baseURL : new URL(baseURL, uri)); - source.setInputSource(new InputSource(url.toString())); - } + { + URL baseURL = new URL(base); + URL url = (uri.length() == 0 ? baseURL : new URL(baseURL, uri)); + source.setInputSource(new InputSource(url.toString())); + } catch (MalformedURLException ex) { // At this point we are probably in failure mode, but // try to use the bare URI as a last gasp @@ -406,25 +465,67 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U } /** - * Find a DTDLocation instance for the given publicId. + * The instance of the CatalogResolver strategy to use. + */ + private static CatalogResolver catalogResolver = null; + + /** + * Factory method for creating the appropriate CatalogResolver + * strategy implementation. + *

Until we query the classpath, we don't know whether the Apache + * resolver (Norm Walsh's library from xml-commons) is available or not. + * This method determines whether the library is available and creates the + * appropriate implementation of CatalogResolver based on the answer.

+ *

This is an application of the Gang of Four Strategy Pattern + * combined with Template Method.

* * @param publicId the publicId of the Resource for which local information * is required - * @return a DTDLocation instance with information on the local location + * @return a ResourceLocation instance with information on the local location * of the Resource or null if no such information is available */ - private DTDLocation findMatchingEntry(String publicId) { - Enumeration elements = getElements().elements(); - DTDLocation element = null; - while (elements.hasMoreElements()) { - element = (DTDLocation) elements.nextElement(); - if (element.getPublicId().equals(publicId)) { - return element; + private CatalogResolver getCatalogResolver() { + + if (catalogResolver == null) { + + AntClassLoader loader = null; + + loader = new AntClassLoader(project, Path.systemClasspath); + + try { + Class clazz = loader.forceLoadSystemClass(APACHE_RESOLVER); + Object obj = clazz.newInstance(); + // + // Success! The xml-commons resolver library is + // available, so use it. + // + catalogResolver = new ApacheResolver(clazz, obj); + } + catch (Throwable ex) { + // + // The xml-commons resolver library is not + // available, so we can't use it. + // + catalogResolver = new InternalResolver(); + // + // If any are specified, warn that they + // will be ignored. + // + Enumeration enum = getElements().elements(); + while (enum.hasMoreElements()) { + Object o = enum.nextElement(); + if (o instanceof FileSet) { + log("Warning: External catalogfiles will be ignored", + Project.MSG_WARN); + break; + } + } } } - return null; + return catalogResolver; } + /** *

This is called from the URIResolver to set an EntityResolver * on the SAX parser to be used for new XML documents that are @@ -464,6 +565,29 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U source.setXMLReader(reader); } + /** + * Find a ResourceLocation instance for the given publicId. + * + * @param publicId the publicId of the Resource for which local information is + * required. + * @return a ResourceLocation instance with information on the local location + * of the Resource or null if no such information is available. + */ + private ResourceLocation findMatchingEntry(String publicId) { + Enumeration enum = getElements().elements(); + ResourceLocation element = null; + while (enum.hasMoreElements()) { + Object o = enum.nextElement(); + if (o instanceof ResourceLocation) { + element = (ResourceLocation)o; + if (element.getPublicId().equals(publicId)) { + return element; + } + } + } + return null; + } + /** * Utility method to remove trailing fragment from a URI. * For example, @@ -484,17 +608,17 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U } /** - * Utility method to lookup a DTDLocation in the filesystem. + * Utility method to lookup a ResourceLocation in the filesystem. * * @return An InputSource for reading the file, or null * if the file does not exist or is not readable. */ - private InputSource filesystemLookup(DTDLocation matchingEntry) { + private InputSource filesystemLookup(ResourceLocation matchingEntry) { String uri = matchingEntry.getLocation(); // - // The DTDLocation may specify a relative path for its + // The ResourceLocation may specify a relative path for its // location attribute. This is resolved using the appropriate // base. // @@ -522,12 +646,12 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U } /** - * Utility method to lookup a DTDLocation in the classpath. + * Utility method to lookup a ResourceLocation in the classpath. * * @return An InputSource for reading the resource, or null * if the resource does not exist in the classpath or is not readable. */ - private InputSource classpathLookup(DTDLocation matchingEntry) { + private InputSource classpathLookup(ResourceLocation matchingEntry) { InputSource source = null; @@ -557,7 +681,7 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U } /** - * Utility method to lookup a DTDLocation in URL-space. + * Utility method to lookup a ResourceLocation in URL-space. * * @return An InputSource for reading the resource, or null * if the resource does not identify a valid URL or is not readable. @@ -602,31 +726,33 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U /** * Implements the guts of the resolveEntity() lookup strategy. */ - private InputSource resolveEntityImpl(String publicId) { + /* + private InputSource resolveEntityImpl(String publicId) { - InputSource result = null; + InputSource result = null; - DTDLocation matchingEntry = findMatchingEntry(publicId); + ResourceLocation matchingEntry = findMatchingEntry(publicId); - if (matchingEntry != null) { + if (matchingEntry != null) { - log("Matching catalog entry found for publicId: '" + - matchingEntry.getPublicId() + "' location: '" + - matchingEntry.getLocation() + "'", - Project.MSG_DEBUG); + log("Matching catalog entry found for publicId: '" + + matchingEntry.getPublicId() + "' location: '" + + matchingEntry.getLocation() + "'", + Project.MSG_DEBUG); - result = filesystemLookup(matchingEntry); + result = filesystemLookup(matchingEntry); - if (result == null) { - result = classpathLookup(matchingEntry); - } + if (result == null) { + result = classpathLookup(matchingEntry); + } - if (result == null) { - result = urlLookup(matchingEntry.getLocation(), null); - } - } - return result; - } + if (result == null) { + result = urlLookup(matchingEntry.getLocation(), null); + } + } + return result; + } + */ /** * Implements the guts of the resolve() lookup strategy. @@ -636,7 +762,7 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U SAXSource result = null; InputSource source = null; - DTDLocation matchingEntry = findMatchingEntry(href); + ResourceLocation matchingEntry = findMatchingEntry(href); if (matchingEntry != null) { @@ -661,4 +787,312 @@ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, U } return result; } + + /** + * Interface implemented by both the InternalResolver strategy and + * the ApacheResolver strategy. + */ + private interface CatalogResolver extends URIResolver, EntityResolver { + + InputSource resolveEntity(String publicId, String systemId); + + Source resolve(String href, String base) throws TransformerException; + } + + /** + * The InternalResolver strategy is used if the Apache resolver + * library (Norm Walsh's library from xml-commons) is not + * available. In this case, external catalog files will be + * ignored. + * + */ + private class InternalResolver implements CatalogResolver { + + public InternalResolver() { + log("Apache resolver library not found, internal resolver will be used", + Project.MSG_INFO); + } + + public InputSource resolveEntity(String publicId, + String systemId) { + + InputSource result = null; + + ResourceLocation matchingEntry = findMatchingEntry(publicId); + + if (matchingEntry != null) { + + log("Matching catalog entry found for publicId: '" + + matchingEntry.getPublicId() + "' location: '" + + matchingEntry.getLocation() + "'", + Project.MSG_DEBUG); + + result = filesystemLookup(matchingEntry); + + if (result == null) { + result = classpathLookup(matchingEntry); + } + + if (result == null) { + result = urlLookup(matchingEntry.getLocation(), null); + } + } + return result; + } + + + + public Source resolve(String href, String base) + throws TransformerException { + + SAXSource result = null; + InputSource source = null; + + ResourceLocation matchingEntry = findMatchingEntry(href); + + if (matchingEntry != null) { + + log("Matching catalog entry found for uri: '" + + matchingEntry.getPublicId() + "' location: '" + + matchingEntry.getLocation() + "'", + Project.MSG_DEBUG); + + source = filesystemLookup(matchingEntry); + + if (source == null) { + source = classpathLookup(matchingEntry); + } + + if (source == null) { + source = urlLookup(matchingEntry.getLocation(), base); + } + + if (source != null) { + result = new SAXSource(source); + } + } + return result; + } + } + + /** + * The ApacheResolver strategy is used if the Apache resolver + * library (Norm Walsh's library from xml-commons) is available in + * the classpath. The ApacheResolver is a essentially a superset + * of the InternalResolver. + * + */ + private class ApacheResolver implements CatalogResolver { + + private Method setXMLCatalog = null; + private Method parseCatalog = null; + private Method resolveEntity = null; + private Method resolve = null; + + /** The instance of the ApacheCatalogResolver bridge class */ + private Object resolverImpl = null; + + private boolean externalCatalogsProcessed = false; + + public ApacheResolver(Class resolverImplClass, + Object resolverImpl) { + + this.resolverImpl = resolverImpl; + + // + // Get Method instances for each of the methods we need to + // call on the resolverImpl using reflection. We can't + // call them directly, because they require on the + // xml-commons resolver library which may not be available + // in the classpath. + // + try { + setXMLCatalog = + resolverImplClass.getMethod("setXMLCatalog", + new Class[] + { XMLCatalog.class }); + + parseCatalog = + resolverImplClass.getMethod("parseCatalog", + new Class[] + { String.class }); + + resolveEntity = + resolverImplClass.getMethod("resolveEntity", + new Class[] + { String.class, String.class }); + + resolve = + resolverImplClass.getMethod("resolve", + new Class[] + { String.class, String.class }); + } + catch (NoSuchMethodException ex) { + throw new BuildException(ex); + } + + log("Apache resolver library found, xml-commons resolver will be used", + Project.MSG_INFO); + } + + public InputSource resolveEntity(String publicId, + String systemId) { + InputSource result = null; + + processExternalCatalogs(); + + ResourceLocation matchingEntry = findMatchingEntry(publicId); + + if (matchingEntry != null) { + + log("Matching catalog entry found for publicId: '" + + matchingEntry.getPublicId() + "' location: '" + + matchingEntry.getLocation() + "'", + Project.MSG_DEBUG); + + result = filesystemLookup(matchingEntry); + + if (result == null) { + result = classpathLookup(matchingEntry); + } + + if (result == null) { + try { + result = + (InputSource)resolveEntity.invoke(resolverImpl, + new Object[] + { publicId, systemId }); + } + catch (Exception ex) { + throw new BuildException(ex); + } + } + } + else { + // + // We didn't match a ResourceLocation, but since we + // only support PUBLIC and URI entry types, it is + // still possible that there is another entry in an + // external catalog that will match. We call Apache + // resolver's resolveEntity method to cover this + // possibility. + // + try { + result = + (InputSource)resolveEntity.invoke(resolverImpl, + new Object[] + { publicId, systemId }); + } + catch (Exception ex) { + throw new BuildException(ex); + } + } + + return result; + } + + public Source resolve(String href, String base) + throws TransformerException { + + SAXSource result = null; + InputSource source = null; + + processExternalCatalogs(); + + ResourceLocation matchingEntry = findMatchingEntry(href); + + if (matchingEntry != null) { + + log("Matching catalog entry found for uri: '" + + matchingEntry.getPublicId() + "' location: '" + + matchingEntry.getLocation() + "'", + Project.MSG_DEBUG); + + source = filesystemLookup(matchingEntry); + + if (source == null) { + source = classpathLookup(matchingEntry); + } + + if (source != null) { + result = new SAXSource(source); + } else { + try { + result = + (SAXSource)resolve.invoke(resolverImpl, + new Object[] + { href, base }); + } + catch (Exception ex) { + throw new BuildException(ex); + } + } + } + else { + // + // We didn't match a ResourceLocation, but since we + // only support PUBLIC and URI entry types, it is + // still possible that there is another entry in an + // external catalog that will match. We call Apache + // resolver's resolveEntity method to cover this + // possibility. + // + try { + result = + (SAXSource)resolve.invoke(resolverImpl, + new Object[] + { href, base }); + } + catch (Exception ex) { + throw new BuildException(ex); + } + } + return result; + } + + /** + * Process each external catalog file specified in a + * <catalogfiles> FileSet. It will be + * parsed by the resolver library, and the individual elements + * will be added back to us (that is, the controlling + * XMLCatalog instance) via a callback mechanism. + */ + private void processExternalCatalogs() { + + if (externalCatalogsProcessed == false) { + + try { + setXMLCatalog.invoke(resolverImpl, + new Object[] + { XMLCatalog.this }); + } + catch (Exception ex) { + throw new BuildException(ex); + } + + Enumeration enum = getElements().elements(); + while (enum.hasMoreElements()) { + Object o = enum.nextElement(); + if (o instanceof FileSet) { + FileSet fs = (FileSet)o; + DirectoryScanner ds = + fs.getDirectoryScanner(getProject()); + String[] files = ds.getIncludedFiles(); + for (int i = 0; i < files.length; i++) { + File catFile = new File(ds.getBasedir(), files[i]); + try { + parseCatalog.invoke(resolverImpl, + new Object[] + { catFile.getPath() }); + } + catch (Exception ex) { + throw new BuildException(ex); + } + } + } + } + } + externalCatalogsProcessed = true; + } + } } diff --git a/src/main/org/apache/tools/ant/types/resolver/ApacheCatalog.java b/src/main/org/apache/tools/ant/types/resolver/ApacheCatalog.java new file mode 100644 index 000000000..32dadc4ba --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resolver/ApacheCatalog.java @@ -0,0 +1,155 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 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 acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", 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 names without prior written + * permission of the Apache Group. + * + * 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. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.tools.ant.types.resolver; + +import org.apache.xml.resolver.Catalog; +import org.apache.xml.resolver.CatalogEntry; + +import org.apache.xml.resolver.helpers.Debug; +import org.apache.xml.resolver.helpers.PublicId; + +/** + * This class extends the Catalog class provided by Norman Walsh's + * resolver library in xml-commons in order to add classpath entity + * and URI resolution. Since XMLCatalog already does classpath + * resolution, we simply add all CatalogEntry instances back to the + * controlling XMLCatalog instance. This is done via a callback + * mechanism. ApacheCatalog is only used for external + * catalog files. Inline entries (currently <dtd> + * and <entity>) are not added to ApacheCatalog. + * See XMLCatalog.java for the details of the entity and URI + * resolution algorithms. + * + * @see org.apache.tools.ant.types.XMLCatalog.CatalogResolver + * @author Craeg Strong + * @version $Id$ + */ +public class ApacheCatalog extends Catalog { + + /** The resolver object to callback. */ + private ApacheCatalogResolver resolver = null; + + /** + *

Create a new ApacheCatalog instance.

+ * + *

This method overrides the superclass method of the same name + * in order to set the resolver object for callbacks. The reason + * we have to do this is that internally Catalog creates a new + * instance of itself for each external catalog file processed. + * That is, if two external catalog files are processed, there + * will be a total of two ApacheCatalog instances, and so on.

+ */ + protected Catalog newCatalog() { + ApacheCatalog cat = (ApacheCatalog)super.newCatalog(); + cat.setResolver(resolver); + return cat; + } + + /** Set the resolver object to callback. */ + public void setResolver(ApacheCatalogResolver resolver) { + this.resolver = resolver; + } + + /** + *

This method overrides the superclass method of the same name + * in order to add catalog entries back to the controlling + * XMLCatalog instance. In this way, we can add classpath lookup + * for these entries.

+ * + *

When we add an external catalog file, the entries inside it + * get parsed by this method. Therefore, we override it to add + * each of them back to the controlling XMLCatalog instance. This + * is done by performing a callback to the ApacheCatalogResolver, + * which in turn calls the XMLCatalog.

+ * + *

XMLCatalog currently only understands PUBLIC + * and URI entry types, so we ignore the other types.

+ * + * @param entry The CatalogEntry to process. + */ + public void addEntry(CatalogEntry entry) { + + int type = entry.getEntryType(); + + if (type == PUBLIC) { + + String publicid = PublicId.normalize(entry.getEntryArg(0)); + String systemid = normalizeURI(entry.getEntryArg(1)); + + if (resolver == null) { + Debug.message(1, "Internal Error: null ApacheCatalogResolver"); + } + else { + resolver.addPublicEntry(publicid, systemid, base.toExternalForm()); + } + + } else if (type == URI) { + + String uri = normalizeURI(entry.getEntryArg(0)); + String altURI = normalizeURI(entry.getEntryArg(1)); + + if (resolver == null) { + Debug.message(1, "Internal Error: null ApacheCatalogResolver"); + } + else { + resolver.addURIEntry(uri, altURI, base.toExternalForm()); + } + + } + + super.addEntry(entry); + } + +} //- ApacheCatalog diff --git a/src/main/org/apache/tools/ant/types/resolver/ApacheCatalogResolver.java b/src/main/org/apache/tools/ant/types/resolver/ApacheCatalogResolver.java new file mode 100644 index 000000000..18efb7c57 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resolver/ApacheCatalogResolver.java @@ -0,0 +1,207 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 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 acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", 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 names without prior written + * permission of the Apache Group. + * + * 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. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.tools.ant.types.resolver; + +import java.io.IOException; + +import java.net.MalformedURLException; + +import org.apache.tools.ant.BuildException; + +import org.apache.tools.ant.types.XMLCatalog; +import org.apache.tools.ant.types.DTDLocation; +import org.apache.tools.ant.types.EntityLocation; + +import org.apache.xml.resolver.Catalog; +import org.apache.xml.resolver.CatalogManager; + +import org.apache.xml.resolver.tools.CatalogResolver; + +/** + *

This class extends the CatalogResolver class provided by Norman + * Walsh's resolver library in xml-commons. It provides the bridge + * between the Ant XMLCatalog datatype and the xml-commons Catalog + * class. XMLCatalog calls methods in this class using Reflection in + * order to avoid requiring the xml-commons resolver library in the + * path.

+ * + *

The {@link org.apache.tools.ant.types.resolver.ApacheCatalog + * ApacheCatalog} class is used to parse external catalog files, which + * can be in either + * plain text format or + * XML format.

+ * + *

For each entry found in an external catalog file, if any, an + * instance of {@link org.apache.tools.ant.types.ResourceLocation + * ResourceLocation} is created and added to the controlling + * XMLCatalog datatype. In this way, these entries will be included + * in XMLCatalog's lookup algorithm. See XMLCatalog.java for more + * details.

+ * + * @see org.apache.tools.ant.types.XMLCatalog.CatalogResolver + * @see org.apache.xml.resolver.CatalogManager + * @author Craeg Strong + * @version $Id$ + */ + +public class ApacheCatalogResolver extends CatalogResolver { + + /** The XMLCatalog object to callback. */ + private XMLCatalog xmlCatalog = null; + + static + { + // + // If you don't do this, you get all sorts of annoying + // warnings about a missing properties file. However, it + // seems to work just fine with default values. Ultimately, + // we should probably include a "CatalogManager.properties" + // file in the ant jarfile with some default property + // settings. See CatalogManager.java for more details. + // + CatalogManager.ignoreMissingProperties(true); + + // + // Make sure CatalogResolver instantiates ApacheCatalog, + // rather than a plain Catalog + // + System.setProperty("xml.catalog.className", + ApacheCatalog.class.getName()); + + // debug + // System.setProperty("xml.catalog.verbosity", "4"); + } + + /** Set the XMLCatalog object to callback. */ + public void setXMLCatalog(XMLCatalog xmlCatalog) { + this.xmlCatalog = xmlCatalog; + } + + /** + * XMLCatalog calls this to add an external catalog file for each + * file within a <catalogfiles> fileset. + */ + public void parseCatalog(String file) { + + ApacheCatalog catalog = (ApacheCatalog)getCatalog(); + + // Pass in reference to ourselves so we can be called back. + catalog.setResolver(this); + + try { + catalog.parseCatalog(file); + } + catch(MalformedURLException ex) { + throw new BuildException(ex); + } + catch(IOException ex) { + throw new BuildException(ex); + } + } + + /** + *

Add a PUBLIC catalog entry to the controlling XMLCatalog instance. + * ApacheCatalog calls this for each PUBLIC entry found in an external + * catalog file.

+ * + * @param publicid The public ID of the resource + * @param systemid The system ID (aka location) of the resource + * @param base The base URL of the resource. If the systemid + * specifies a relative URL/pathname, it is resolved using the + * base. The default base for an external catalog file is the + * directory in which the catalog is located. + * + */ + public void addPublicEntry(String publicid, + String systemid, + String base) { + + DTDLocation dtd = new DTDLocation(); + dtd.setBase(base); + dtd.setPublicId(publicid); + dtd.setLocation(systemid); + + xmlCatalog.addDTD(dtd); + } + + /** + *

Add a URI catalog entry to the controlling XMLCatalog instance. + * ApacheCatalog calls this for each URI entry found in an external + * catalog file.

+ * + * @param URI The URI of the resource + * @param altURI The URI to which the resource should be mapped + * (aka the location) + * @param base The base URL of the resource. If the altURI + * specifies a relative URL/pathname, it is resolved using the + * base. The default base for an external catalog file is the + * directory in which the catalog is located. + * + */ + public void addURIEntry(String uri, + String altURI, + String base) { + + EntityLocation entity = new EntityLocation(); + entity.setBase(base); + entity.setPublicId(uri); + entity.setLocation(altURI); + + xmlCatalog.addEntity(entity); + } + +} //-- ApacheCatalogResolver diff --git a/src/main/org/apache/tools/ant/types/resolver/package.html b/src/main/org/apache/tools/ant/types/resolver/package.html new file mode 100644 index 000000000..944c69eb7 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resolver/package.html @@ -0,0 +1,23 @@ + +Ant integration with xml-commons resolver. + +

These classes enhance the <xmlcatalog> datatype +to support external catalog files using the xml-commons resolver, in +accordance with the + +OASIS "Open Catalog" standard. They will be used if and only if +the xml-commons resolver library is available on the classpath.

+ +@see Apache xml-commons Project + +@see org.apache.tools.ant.types.XMLCatalog +@see org.apache.tools.ant.types.resolver.ApacheCatalogResolver +@see org.apache.tools.ant.types.resolver.ApacheCatalog + +@author Craeg Strong + + +
+

Copyright © 2002 Apache Software Foundation. All rights +Reserved.

+ diff --git a/src/testcases/org/apache/tools/ant/taskdefs/optional/XmlValidateTest.java b/src/testcases/org/apache/tools/ant/taskdefs/optional/XmlValidateTest.java index 410e1d37a..60eeb50d7 100644 --- a/src/testcases/org/apache/tools/ant/taskdefs/optional/XmlValidateTest.java +++ b/src/testcases/org/apache/tools/ant/taskdefs/optional/XmlValidateTest.java @@ -121,6 +121,17 @@ public class XmlValidateTest extends BuildFileTest { executeTarget("xmlcatalog"); } + /** + * catalogfiles fileset should be ignored + * if resolver.jar is not present, but will + * be used if it is. either way, test should + * work b/c we have a nested dtd with the same + * entity + */ + public void testXmlCatalogFiles() { + executeTarget("xmlcatalogfiles"); + } + /** * Test nested xmlcatalog definitions */