diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/XMLValidateTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/XMLValidateTask.java index d02d208e9..e20b4a5d3 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/XMLValidateTask.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/XMLValidateTask.java @@ -65,7 +65,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; -import org.apache.tools.ant.types.DTDLocation; +import org.apache.tools.ant.types.ResourceLocation; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; @@ -248,8 +248,8 @@ public class XMLValidateTask extends Task { * This stores the location of a DTD. The DTD is identified * by its public Id. */ - public DTDLocation createDTD() { - DTDLocation dtdLocation = new DTDLocation(); + public ResourceLocation createDTD() { + ResourceLocation dtdLocation = new ResourceLocation(); xmlCatalog.addDTD(dtdLocation); return dtdLocation; } diff --git a/src/main/org/apache/tools/ant/types/DTDLocation.java b/src/main/org/apache/tools/ant/types/DTDLocation.java index 977fa3c51..a81a1f1c6 100644 --- a/src/main/org/apache/tools/ant/types/DTDLocation.java +++ b/src/main/org/apache/tools/ant/types/DTDLocation.java @@ -70,9 +70,4 @@ package org.apache.tools.ant.types; * @version $Id$ */ public class DTDLocation extends ResourceLocation { - - public DTDLocation() { - super("PUBLIC"); - } - } diff --git a/src/main/org/apache/tools/ant/types/EntityLocation.java b/src/main/org/apache/tools/ant/types/EntityLocation.java index c5351f989..80ec037a3 100644 --- a/src/main/org/apache/tools/ant/types/EntityLocation.java +++ b/src/main/org/apache/tools/ant/types/EntityLocation.java @@ -69,9 +69,4 @@ package org.apache.tools.ant.types; * @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 index c23eeaf39..c52cba8f0 100644 --- a/src/main/org/apache/tools/ant/types/ResourceLocation.java +++ b/src/main/org/apache/tools/ant/types/ResourceLocation.java @@ -76,6 +76,9 @@ import java.net.URL; * @author Craeg Strong * @version $Id$ */ + +import java.net.URL; + public class ResourceLocation { //-- Fields ---------------------------------------------------------------- @@ -98,14 +101,10 @@ public class ResourceLocation { * for an external catalog file is the directory in which it is * located. */ - private String base = null; + private URL base = null; //-- Methods --------------------------------------------------------------- - protected ResourceLocation(String name) { - this.name = name; - } - /** * @param publicId uniquely identifies the resource. */ @@ -127,7 +126,7 @@ public class ResourceLocation { * 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) { + public void setBase(URL base) { this.base = base; } @@ -148,18 +147,8 @@ public class ResourceLocation { /** * @return the base of the resource identified by the publicId. */ - public String getBase() { + public URL 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 223dd1d9c..b403a80d0 100644 --- a/src/main/org/apache/tools/ant/types/XMLCatalog.java +++ b/src/main/org/apache/tools/ant/types/XMLCatalog.java @@ -76,7 +76,7 @@ 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.apache.tools.ant.util.JAXPUtils; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -95,6 +95,19 @@ import org.xml.sax.XMLReader; * in the Java API for XML * Processing Specification.

* + *

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 classpath. 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 * correspond to OASIS catalog entry types PUBLIC and @@ -108,6 +121,8 @@ import org.xml.sax.XMLReader; *   <dtd publicId="" location="/path/to/file2.jar" />
*   <entity publicId="" location="/path/to/file3.jar" />
*   <entity publicId="" location="/path/to/file4.jar" />
+ *   <catalogfiles dir="${basedir}" includes="**\catalog" />
+ *   <catalogfiles dir="/opt/catalogs/" includes="**\catalog.xml" />
* </xmlcatalog>
* *

@@ -123,6 +138,7 @@ import org.xml.sax.XMLReader; *

    *
  1. In the local filesystem
  2. *
  3. In the classpath
  4. + *
  5. Using the Apache xml-commons resolver (if it is available)
  6. *
  7. In URL-space
  8. *
*

@@ -133,8 +149,7 @@ import org.xml.sax.XMLReader; * support for XMLCatalogs.

* *

Possible future extension could provide for additional OASIS - * entry types to be specified inline, and external catalog files - * using the xml-commons resolver library

+ * entry types to be specified inline.

* * @author dIon Gillard * @author Erik Hatcher @@ -143,8 +158,6 @@ import org.xml.sax.XMLReader; */ public class XMLCatalog extends DataType implements Cloneable, EntityResolver, URIResolver { - /** File utilities instance */ - private FileUtils fileUtils = FileUtils.newFileUtils(); //-- Fields ---------------------------------------------------------------- @@ -171,10 +184,10 @@ public class XMLCatalog extends DataType } /** - * Returns the elements of the catalog - ResolverLocation and FileSet + * Returns the elements of the catalog - ResourceLocation and FileSet * objects. * - * @return the elements of the catalog - ResolverLocation and FileSet + * @return the elements of the catalog - ResourceLocation and FileSet * objects */ private Vector getElements() { @@ -255,10 +268,11 @@ public class XMLCatalog extends DataType 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. + /** + * 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 @@ -290,9 +304,6 @@ public class XMLCatalog extends DataType getElements().addElement(dtd); setChecked( false ); } - public void addDTD(DTDLocation dtd) throws BuildException { - addDTD((ResourceLocation)dtd); - } /** * Creates the nested <entity> element. Not @@ -300,34 +311,13 @@ public class XMLCatalog extends DataType * 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. + * @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(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); + public void addEntity(ResourceLocation entity) throws BuildException { + addDTD(entity); } /** @@ -432,12 +422,12 @@ public class XMLCatalog extends DataType } SAXSource source = null; - + String uri = removeFragment(href); log("resolve: '" + uri + "' with base: '" + base + "'", Project.MSG_DEBUG); - source = resolveImpl(uri, base); + source = (SAXSource)getCatalogResolver().resolve(uri, base); if (source == null) { log("No matching catalog entry found, parser will use: '" + @@ -447,12 +437,17 @@ public class XMLCatalog extends DataType // setEntityResolver (see setEntityResolver javadoc comment) // 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 = null; + try { + if (base == null) { + baseURL = getProject().getBaseDir().toURL(); + } + else { + 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 @@ -467,7 +462,7 @@ public class XMLCatalog extends DataType /** * The instance of the CatalogResolver strategy to use. */ - private static CatalogResolver catalogResolver = null; + private CatalogResolver catalogResolver = null; /** * Factory method for creating the appropriate CatalogResolver @@ -478,11 +473,6 @@ public class XMLCatalog extends DataType * 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 ResourceLocation instance with information on the local location - * of the Resource or null if no such information is available */ private CatalogResolver getCatalogResolver() { @@ -490,7 +480,7 @@ public class XMLCatalog extends DataType AntClassLoader loader = null; - loader = new AntClassLoader(project, Path.systemClasspath); + loader = new AntClassLoader(getProject(), Path.systemClasspath); try { Class clazz = loader.forceLoadSystemClass(APACHE_RESOLVER); @@ -525,7 +515,6 @@ public class XMLCatalog extends DataType 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 @@ -568,8 +557,8 @@ public class XMLCatalog extends DataType /** * Find a ResourceLocation instance for the given publicId. * - * @param publicId the publicId of the Resource for which local information is - * required. + * @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. */ @@ -616,32 +605,54 @@ public class XMLCatalog extends DataType private InputSource filesystemLookup(ResourceLocation matchingEntry) { String uri = matchingEntry.getLocation(); + URL baseURL = null; // // The ResourceLocation may specify a relative path for its // location attribute. This is resolved using the appropriate // base. // - File resFile = getProject().resolveFile(uri); - InputSource source = null; - - if (resFile.exists() && resFile.canRead()) { + if (matchingEntry.getBase() != null) { + baseURL = matchingEntry.getBase(); + } else { try { - source = new InputSource(new FileInputStream(resFile)); - URL resFileURL = fileUtils.getFileURL(resFile); - String sysid = resFileURL.toExternalForm(); - source.setSystemId(sysid); - log("catalog entry matched a readable file: '" + - sysid + "'", Project.MSG_DEBUG); - } catch(FileNotFoundException ex) { - // ignore - } catch(MalformedURLException ex) { - // ignore - } catch(IOException ex) { - // ignore + baseURL = getProject().getBaseDir().toURL(); + } + catch (MalformedURLException ex) { + throw new BuildException("Project basedir cannot be converted to a URL"); + } + } + + InputSource source = null; + URL url = null; + + try { + url = new URL(baseURL, uri); + } + catch (MalformedURLException ex) { + // ignore + } + + if (url != null) { + String fileName = url.getFile(); + if (fileName != null) { + log("fileName"+fileName, Project.MSG_DEBUG); + File resFile = new File(fileName); + if (resFile.exists() && resFile.canRead()) { + try { + source = new InputSource(new FileInputStream(resFile)); + String sysid = JAXPUtils.getSystemId(resFile); + source.setSystemId(sysid); + log("catalog entry matched a readable file: '" + + sysid + "'", Project.MSG_DEBUG); + } catch(FileNotFoundException ex) { + // ignore + } catch(IOException ex) { + // ignore + } + } } } - return source; } @@ -686,19 +697,32 @@ public class XMLCatalog extends DataType * @return An InputSource for reading the resource, or null * if the resource does not identify a valid URL or is not readable. */ - private InputSource urlLookup(String uri, String base) { + private InputSource urlLookup(ResourceLocation matchingEntry) { + + String uri = matchingEntry.getLocation(); + URL baseURL = null; + + // + // The ResourceLocation may specify a relative url for its + // location attribute. This is resolved using the appropriate + // base. + // + if (matchingEntry.getBase() != null) { + baseURL = matchingEntry.getBase(); + } else { + try { + baseURL = getProject().getBaseDir().toURL(); + } + catch (MalformedURLException ex) { + throw new BuildException("Project basedir cannot be converted to a URL"); + } + } InputSource source = null; URL url = null; try { - if (base == null) { - url = new URL(uri); - } - else { - URL baseURL = new URL(base); - url = (uri.length() == 0 ? baseURL : new URL(baseURL, uri)); - } + url = new URL(baseURL, uri); } catch (MalformedURLException ex) { // ignore @@ -723,71 +747,6 @@ public class XMLCatalog extends DataType } - /** - * Implements the guts of the resolveEntity() lookup strategy. - */ - /* - private InputSource resolveEntityImpl(String publicId) { - - 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; - } - */ - - /** - * Implements the guts of the resolve() lookup strategy. - */ - private SAXSource resolveImpl(String href, String base) { - - 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; - } - /** * Interface implemented by both the InternalResolver strategy and * the ApacheResolver strategy. @@ -815,9 +774,7 @@ public class XMLCatalog extends DataType public InputSource resolveEntity(String publicId, String systemId) { - InputSource result = null; - ResourceLocation matchingEntry = findMatchingEntry(publicId); if (matchingEntry != null) { @@ -834,14 +791,12 @@ public class XMLCatalog extends DataType } if (result == null) { - result = urlLookup(matchingEntry.getLocation(), null); + result = urlLookup(matchingEntry); } } return result; } - - public Source resolve(String href, String base) throws TransformerException { @@ -857,14 +812,38 @@ public class XMLCatalog extends DataType matchingEntry.getLocation() + "'", Project.MSG_DEBUG); - source = filesystemLookup(matchingEntry); + // + // Use the passed in base in preference to the base + // from matchingEntry, which is either null or the + // directory in which the external catalog file from + // which it was obtained is located. We make a copy + // so matchingEntry's original base is untouched. + // + // This is the standard behavior as per my reading of + // the JAXP and XML Catalog specs. CKS 11/7/2002 + // + ResourceLocation entryCopy = matchingEntry; + if (base != null) { + try { + URL baseURL = new URL(base); + entryCopy = new ResourceLocation(); + entryCopy.setBase(baseURL); + } + catch (MalformedURLException ex) { + // ignore + } + } + entryCopy.setPublicId(matchingEntry.getPublicId()); + entryCopy.setLocation(matchingEntry.getLocation()); + + source = filesystemLookup(entryCopy); if (source == null) { - source = classpathLookup(matchingEntry); + source = classpathLookup(entryCopy); } if (source == null) { - source = urlLookup(matchingEntry.getLocation(), base); + source = urlLookup(entryCopy); } if (source != null) { @@ -971,11 +950,11 @@ public class XMLCatalog extends DataType 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. + // only support PUBLIC and URI entry types internally, + // 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 = @@ -1008,10 +987,36 @@ public class XMLCatalog extends DataType matchingEntry.getLocation() + "'", Project.MSG_DEBUG); - source = filesystemLookup(matchingEntry); + // + // Use the passed in base in preference to the base + // from matchingEntry, which is either null or the + // directory in which the external catalog file from + // which it was obtained is located. We make a copy + // so matchingEntry's original base is untouched. Of + // course, if there is no base, no need to make a + // copy... + // + // This is the standard behavior as per my reading of + // the JAXP and XML Catalog specs. CKS 11/7/2002 + // + ResourceLocation entryCopy = matchingEntry; + if (base != null) { + try { + URL baseURL = new URL(base); + entryCopy = new ResourceLocation(); + entryCopy.setBase(baseURL); + } + catch (MalformedURLException ex) { + // ignore + } + } + entryCopy.setPublicId(matchingEntry.getPublicId()); + entryCopy.setLocation(matchingEntry.getLocation()); + + source = filesystemLookup(entryCopy); if (source == null) { - source = classpathLookup(matchingEntry); + source = classpathLookup(entryCopy); } if (source != null) { @@ -1031,11 +1036,11 @@ public class XMLCatalog extends DataType 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. + // only support PUBLIC and URI entry types internally, + // 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 = @@ -1095,4 +1100,5 @@ public class XMLCatalog extends DataType externalCatalogsProcessed = true; } } -} + +} //-- XMLCatalog diff --git a/src/main/org/apache/tools/ant/types/resolver/ApacheCatalog.java b/src/main/org/apache/tools/ant/types/resolver/ApacheCatalog.java index 32dadc4ba..fd5abf7fa 100644 --- a/src/main/org/apache/tools/ant/types/resolver/ApacheCatalog.java +++ b/src/main/org/apache/tools/ant/types/resolver/ApacheCatalog.java @@ -132,7 +132,7 @@ public class ApacheCatalog extends Catalog { Debug.message(1, "Internal Error: null ApacheCatalogResolver"); } else { - resolver.addPublicEntry(publicid, systemid, base.toExternalForm()); + resolver.addPublicEntry(publicid, systemid, base); } } else if (type == URI) { @@ -144,7 +144,7 @@ public class ApacheCatalog extends Catalog { Debug.message(1, "Internal Error: null ApacheCatalogResolver"); } else { - resolver.addURIEntry(uri, altURI, base.toExternalForm()); + resolver.addURIEntry(uri, altURI, base); } } diff --git a/src/main/org/apache/tools/ant/types/resolver/ApacheCatalogResolver.java b/src/main/org/apache/tools/ant/types/resolver/ApacheCatalogResolver.java index 18efb7c57..65277bcc4 100644 --- a/src/main/org/apache/tools/ant/types/resolver/ApacheCatalogResolver.java +++ b/src/main/org/apache/tools/ant/types/resolver/ApacheCatalogResolver.java @@ -57,12 +57,12 @@ package org.apache.tools.ant.types.resolver; import java.io.IOException; import java.net.MalformedURLException; +import java.net.URL; 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.tools.ant.types.ResourceLocation; import org.apache.xml.resolver.Catalog; import org.apache.xml.resolver.CatalogManager; @@ -168,9 +168,9 @@ public class ApacheCatalogResolver extends CatalogResolver { */ public void addPublicEntry(String publicid, String systemid, - String base) { + URL base) { - DTDLocation dtd = new DTDLocation(); + ResourceLocation dtd = new ResourceLocation(); dtd.setBase(base); dtd.setPublicId(publicid); dtd.setLocation(systemid); @@ -194,9 +194,9 @@ public class ApacheCatalogResolver extends CatalogResolver { */ public void addURIEntry(String uri, String altURI, - String base) { + URL base) { - EntityLocation entity = new EntityLocation(); + ResourceLocation entity = new ResourceLocation(); entity.setBase(base); entity.setPublicId(uri); entity.setLocation(altURI); diff --git a/src/testcases/org/apache/tools/ant/taskdefs/optional/XsltTest.java b/src/testcases/org/apache/tools/ant/taskdefs/optional/XsltTest.java index 8819f0dfa..7c05b5329 100644 --- a/src/testcases/org/apache/tools/ant/taskdefs/optional/XsltTest.java +++ b/src/testcases/org/apache/tools/ant/taskdefs/optional/XsltTest.java @@ -98,12 +98,12 @@ public class XsltTest extends BuildFileTest { /** * A unit test for JUnit + */ public void testCatchNoDtd() throws Exception { expectBuildExceptionContaining("testCatchNoDtd", - "expected failure", - "Fatal error during transformation"); + "expected failure", + "Fatal error during transformation"); } - */ /** * A unit test for JUnit