From 1e469669cfcdd6bdd88556938d4352618459725f Mon Sep 17 00:00:00 2001 From: Steve Loughran Date: Mon, 12 Nov 2001 07:46:27 +0000 Subject: [PATCH] Jose Alberto Fernandez's ant descriptor loader git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@269898 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/CoreTasks/antjar.html | 94 +++ docs/manual/CoreTasks/antlib.html | 117 +++ docs/manual/coretasklist.html | 2 + .../org/apache/tools/ant/taskdefs/Antjar.java | 316 ++++++++ .../apache/tools/ant/taskdefs/Antlib-V1_0.dtd | 27 + .../org/apache/tools/ant/taskdefs/Antlib.java | 711 ++++++++++++++++++ .../tools/ant/taskdefs/defaults.properties | 2 + 7 files changed, 1269 insertions(+) create mode 100644 docs/manual/CoreTasks/antjar.html create mode 100644 docs/manual/CoreTasks/antlib.html create mode 100644 src/main/org/apache/tools/ant/taskdefs/Antjar.java create mode 100644 src/main/org/apache/tools/ant/taskdefs/Antlib-V1_0.dtd create mode 100644 src/main/org/apache/tools/ant/taskdefs/Antlib.java diff --git a/docs/manual/CoreTasks/antjar.html b/docs/manual/CoreTasks/antjar.html new file mode 100644 index 000000000..517a0db42 --- /dev/null +++ b/docs/manual/CoreTasks/antjar.html @@ -0,0 +1,94 @@ + + + + +Ant User Manual + + + + +

AntJar

+

Description

+

An extension of the Jar task with special +treatment for the library descriptor file that should end up in the +META-INF directory of the Ant Archive.

+

This task validates the provided library descriptor making certain +it specifies the following SYSTEM ID: +"http://jakarta.apache.org/ant/AntlibV1_0.dtd". +This DTD is defined as follows:

+
+<?xml version='1.0' encoding="UTF8" ?>
+
+<!-- 
+This file defines the XML format for ANT library descriptors.
+Descriptors must especify a DOCTYPE of 
+"http://jakarta.apache.org/ant/Antlib-V1_0.dtd"
+as the SystemId for the document.
+-->
+
+<!-- Root element for the Antlib descriptor.                 -->
+<!ELEMENT antlib (task | type)* >
+<!ATTLIST antlib
+          version  CDATA #IMPLIED
+>
+
+<!-- Declaration of tasks contained in the library.          -->
+<!ELEMENT task EMPTY>
+<!ATTLIST task 
+          name     CDATA #REQUIRED
+          class    CDATA #REQUIRED
+>
+
+<!-- Declaration of datatypes contained in the library       -->
+<!ELEMENT type EMPTY>
+<!ATTLIST type 
+          name     CDATA #REQUIRED
+          class    CDATA #REQUIRED
+>
+
+
+

Parameters

+ + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
antxmlThe library descriptor to use (META-INF/antlib.xml).Yes
Others...All attributes inherited form the + Jar task.
+

Nested elements

+See the nested elements of the Jar task. +

Examples

+
  <jar file="${dist}/lib/app.jar" 
+       antxml="${src}/applib.xml" basedir="${build}/classes"/>
+

jars all files in the ${build}/classes directory into a file +called app.jar in the ${dist}/lib directory and +sets the content of ${src}/applib.xml as the library descriptor +in META-INF/antlib.xml.

+

Here is a sample META-INF/antlib.xml:

+
+<?xml version="1.0" encoding="UTF8" ?>
+<!DOCTYPE antlib  SYSTEM "http://jakarta.apache.org/ant/Antlib-V1_0.dtd" >
+
+<antlib version="1.0" >
+  <task name="case" class="org.apache.ant.contrib.Case" />
+</antlib>
+
+
+
+

Copyright © 2000,2001 Apache Software Foundation. All rights +Reserved.

+ + + + diff --git a/docs/manual/CoreTasks/antlib.html b/docs/manual/CoreTasks/antlib.html new file mode 100644 index 000000000..ec1c7c83b --- /dev/null +++ b/docs/manual/CoreTasks/antlib.html @@ -0,0 +1,117 @@ + + + + +Ant User Manual + + + + +

AntLib

+

Description

+

Defines and loads any tasks and datatypes contained in an ANT library.

+

It also allows the aliasing of the names being defined in order to avoid +collisions and provides means to override definitions with the ones defined +in the library.

+Ant libraries can be loaded in the current classloader, which is more efficient, +but requires the tasks to be in the path already (such as in the ant lib +directory) - set useCurrentClassloader to true to enable this. +It is also possible to add more libraries to the path, such as any +libraries the task is dependent on. + +

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
fileThe jar-file of the library.at least one of the two
libraryThe name of a library relative to ${ant.home}/lib.
overrideReplace any existing definition with the same name. ("true"/"false"). When "false" already defined tasks + and datatytes take precedence over those in the library. + Default is "false" when omitted.No
useCurrentClassloaderSet to "true" to avoid using a separate + ClassLoader for the tasks in the library. Using this option requires + that the library jar is already accessible by the ClassLoader of + the project. Default is "false". + No
classpathA + classpath + for extra libraries to pull in. + No
+

Parameters specified as nested elements

+ +

alias

+

Specifies the usage of a different name from that defined in the library +descriptor.

+ + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
nameThe name used in the library descriptor.Yes
asThe alias to use in the project.Yes
+

Specifies the usage of a different name from that defined in the library +descriptor. This is used to deal with name clashes

+ +

classpath

+

classpath

+ +A classpath of extra libraries to import to support this task. + +

classpathref

+A reference to an existing classpath. + +

Examples

+
  <antlib file="${build}/lib/mylib.jar"/>
+

loads the definitions from the library located at +${build}/lib/ant.jar.

+
  <antlib library="optional.jar"/>
+

loads the definitions from the library optional.jar +located at ${ant.home}/lib.

+
  <antlib file="${build}/lib/mylib.jar">
+    <alias name="echo" as="myecho"/>
+  </antlib>
+
+

loads the definitions from the library located at +${build}/lib/ant.jar but uses the name +"myecho" for the "echo" task +declared in the library.

+ +

Copyright © 2000,2001 Apache Software Foundation. All rights +Reserved.

+ + + + diff --git a/docs/manual/coretasklist.html b/docs/manual/coretasklist.html index 31bff46b0..c79c8befd 100644 --- a/docs/manual/coretasklist.html +++ b/docs/manual/coretasklist.html @@ -25,6 +25,8 @@ Overview

Ant
AntCall
+AntLib
+AntJar
AntStructure
Apply/ExecOn
Available
diff --git a/src/main/org/apache/tools/ant/taskdefs/Antjar.java b/src/main/org/apache/tools/ant/taskdefs/Antjar.java new file mode 100644 index 000000000..e0113476a --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/Antjar.java @@ -0,0 +1,316 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000 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.taskdefs; + +import org.xml.sax.*; +import javax.xml.parsers.*; + +import org.apache.tools.ant.*; +import org.apache.tools.ant.types.ZipFileSet; +import org.apache.tools.zip.*; + +import java.io.*; +import java.util.*; + +/** + * Creates a ANTLIB archive. Code is similar to the War class, but with + * bonus dtd validation. + * + * @author doc and layout changes by steve loughran, steve_l@iseran.com + * @author Jose Alberto Fernandez + * @author Stefan Bodewig + * + * @since ant1.5 + */ +public class Antjar extends Jar { + + /** + * location of the xml descriptor (antxml attribute) + */ + private File libraryDescriptor; + + /** + * status flag + */ + private boolean descriptorAdded; + + + /** + * Constructor for the Antjar object + */ + public Antjar() { + super(); + archiveType = "jar"; + emptyBehavior = "create"; + } + + + /** + * Sets the Antxml attribute of the Antjar object + * + * @param descriptor The new Antxml value + */ + public void setAntxml(File descriptor) { + libraryDescriptor = descriptor; + if (!libraryDescriptor.exists()) { + throw new BuildException("Deployment descriptor: " + libraryDescriptor + " does not exist."); + } + + //check + validateDescriptor(); + + // Create a ZipFileSet for this file, and pass it up. + ZipFileSet fs = new ZipFileSet(); + fs.setDir(new File(libraryDescriptor.getParent())); + fs.setIncludes(libraryDescriptor.getName()); + fs.setFullpath(Antlib.ANT_DESCRIPTOR); + super.addFileset(fs); + } + + + /** + * override of superclass method; add check for + * valid descriptor + * @param zOut stream to init + * @exception IOException io trouble + * @exception BuildException other trouble + */ + protected void initZipOutputStream(ZipOutputStream zOut) + throws IOException, BuildException { + // If no antxml file is specified, it's an error. + if (libraryDescriptor == null) { + throw new BuildException("webxml attribute is required", location); + } + + super.initZipOutputStream(zOut); + } + + + /** + * override of parent method; warn if a second descriptor is added + * + * @param file file to add + * @param zOut stream to add to + * @param vPath the path to add it to in the zipfile + * @exception IOException io trouble + */ + protected void zipFile(File file, ZipOutputStream zOut, String vPath) + throws IOException { + // If the file being added is META-INF/antlib.xml, we warn if it's not the + // one specified in the "antxml" attribute - or if it's being added twice, + // meaning the same file is specified by the "antxml" attribute and in + // a element. + if (vPath.equalsIgnoreCase(Antlib.ANT_DESCRIPTOR)) { + if (libraryDescriptor == null || !libraryDescriptor.equals(file) || descriptorAdded) { + log("Warning: selected " + archiveType + " files include a " + + Antlib.ANT_DESCRIPTOR + " which will be ignored " + + "(please use antxml attribute to " + archiveType + " task)", Project.MSG_WARN); + } + else { + super.zipFile(file, zOut, vPath); + descriptorAdded = true; + } + } + else { + super.zipFile(file, zOut, vPath); + } + } + + + /** + * Make sure we don't think we already have a descriptor next time this + * task gets executed. + */ + protected void cleanUp() { + descriptorAdded = false; + super.cleanUp(); + } + + + /** + * validate the descriptor against the DTD + * + * @exception BuildException failure to validate + */ + protected void validateDescriptor() + throws BuildException { + SAXParserFactory saxFactory = SAXParserFactory.newInstance(); + saxFactory.setValidating(true); + InputStream is = null; + try { + SAXParser saxParser = saxFactory.newSAXParser(); + Parser parser = saxParser.getParser(); + is = new FileInputStream(libraryDescriptor); + InputSource inputSource = new InputSource(is); + inputSource.setSystemId("file:" + libraryDescriptor); + project.log("Validating library descriptor: " + libraryDescriptor, + Project.MSG_VERBOSE); + saxParser.parse(inputSource, new AntLibraryValidator()); + } + catch (ParserConfigurationException exc) { + throw new BuildException("Parser has not been configured correctly", exc); + } + catch (SAXParseException exc) { + Location location = + new Location(libraryDescriptor.toString(), + exc.getLineNumber(), exc.getColumnNumber()); + + Throwable t = exc.getException(); + if (t instanceof BuildException) { + BuildException be = (BuildException) t; + if (be.getLocation() == Location.UNKNOWN_LOCATION) { + be.setLocation(location); + } + throw be; + } + + throw new BuildException(exc.getMessage(), t, location); + } + catch (SAXException exc) { + Throwable t = exc.getException(); + if (t instanceof BuildException) { + throw (BuildException) t; + } + throw new BuildException(exc.getMessage(), t); + } + catch (IOException exc) { + throw new BuildException("Error reading library descriptor", exc); + } + finally { + if (is != null) { + try { + is.close(); + } + catch (IOException ioe) { + // ignore this + } + } + } + } + + + /** + * Parses the document describing the content of the library. + */ + private class AntLibraryValidator extends HandlerBase { + + /** + * flag to track whether the DOCTYPE was hit in the prolog + */ + private boolean doctypePresent = false; + + /** + * doc locator + */ + private Locator locator = null; + + /** + * Sets the DocumentLocator attribute of the AntLibraryValidator + * object + * + * @param locator The new DocumentLocator value + */ + public void setDocumentLocator(Locator locator) { + this.locator = locator; + } + + /** + * SAX callback handler + * + * @param tag XML tag + * @param attrs attributes + * @exception SAXParseException parse trouble + */ + public void startElement(String tag, AttributeList attrs) + throws SAXParseException { + // By the time an element is found + // the DOCTYPE should have been found. + if (!doctypePresent) { + String msg = "Missing DOCTYPE declaration or wrong SYSTEM ID"; + throw new SAXParseException(msg, locator); + } + } + + /** + * Recognizes the DTD declaration for antlib and returns the corresponding + * DTD definition from a resource.

+ * + * To allow for future versions of the DTD format it will search + * for any DTDs of the form "Antlib-V.*\.dtd". + * + * @param publicId public ID (ignored) + * @param systemId system ID (matched against) + * @return local DTD instance + */ + public InputSource resolveEntity(String publicId, + String systemId) { + + log("Looking for entity with PublicID=" + publicId + + " and SystemId=" + systemId, Project.MSG_VERBOSE); + if (Antlib.matchDtdId(systemId)) { + String resId = + systemId.substring(Antlib.ANTLIB_DTD_URL.length()); + InputSource is = + new InputSource(this.getClass().getResourceAsStream(resId)); + + is.setSystemId(systemId); + doctypePresent = true; + return is; + } + return null; + } + //end inner class AntLibraryValidator + } +} + diff --git a/src/main/org/apache/tools/ant/taskdefs/Antlib-V1_0.dtd b/src/main/org/apache/tools/ant/taskdefs/Antlib-V1_0.dtd new file mode 100644 index 000000000..66da10858 --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/Antlib-V1_0.dtd @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + diff --git a/src/main/org/apache/tools/ant/taskdefs/Antlib.java b/src/main/org/apache/tools/ant/taskdefs/Antlib.java new file mode 100644 index 000000000..57c117f47 --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/Antlib.java @@ -0,0 +1,711 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999 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.taskdefs; + +import org.apache.tools.ant.*; +import org.apache.tools.ant.types.*; +import org.xml.sax.*; +import javax.xml.parsers.*; + +import java.util.*; +import java.util.zip.*; +import java.io.*; + +/** + * Make available the tasks and types from an Ant library.

+ * <antlib library="libname.jar" >
+ *   <alias name="nameOnLib" as="newName" />
+ * </antlib>
+ *
+ * <antlib file="libname.jar" override="true" />
+ * 
+ * + * @author minor changes by steve loughran, steve_l@iseran.com + * @author Jose Alberto Fernandez + * @since ant1.5 + */ +public class Antlib extends Task { + /* + * implements DeclaringTask + */ + + /** + * library attribute + */ + private String library = null; + /** + * file attribute + */ + private File file = null; + /** + * override attribute + */ + private boolean override = false; + /** + * attribute to control classloader use + */ + private boolean useCurrentClassloader = false; + /** + * classpath to build up + */ + private Path classpath = null; + + /** + * our little xml parse + */ + private SAXParserFactory saxFactory; + + /** + * table of aliases + */ + private Vector aliases = new Vector(); + + /** + * Location of descriptor in library + */ + public static String ANT_DESCRIPTOR = "META-INF/antlib.xml"; + + /** + * Prefix name for DTD of descriptor + */ + public static String ANTLIB_DTD_URL = + "http://jakarta.apache.org/ant/"; + /** + * prefix of the antlib + */ + public static String ANTLIB_DTD_PREFIX = "Antlib-V"; + + /** + * version counter + */ + public static String ANTLIB_DTD_VERSION = "1_0"; + + /** + * dtd file extension + */ + public static String ANTLIB_DTD_EXT = ".dtd"; + + + /** + * constructor creates a validating sax parser + */ + public Antlib() { + super(); + saxFactory = SAXParserFactory.newInstance(); + saxFactory.setValidating(true); + } + + + /** + * constructor binds to a project as well as setting up internal state + * + * @param p Description of Parameter + */ + public Antlib(Project p) { + this(); + setProject(p); + } + + + /** + * Set name of library to load. The library is located in $ANT_HOME/lib. + * + * @param lib the name of library relative to $ANT_HOME/lib. + */ + public void setLibrary(String lib) { + this.library = lib; + } + + + /** + * Set file location of library to load. + * + * @param file the jar file for the library. + */ + public void setFile(File file) { + this.file = file; + } + + + /** + * Set whether to override any existing definitions. + * + * @param override if true new definitions will replace existing ones. + */ + public void setOverride(boolean override) { + this.override = override; + } + + + /** + * Set whether to use a new classloader or not. Default is false + * . This property is mostly used by the core when loading core tasks. + * + * @param useCurrentClassloader if true the current classloader will + * be used to load the definitions. + */ + public void setUseCurrentClassloader(boolean useCurrentClassloader) { + this.useCurrentClassloader = useCurrentClassloader; + } + + + /** + * Create new Alias element. + * + * @return Description of the Returned Value + */ + public Alias createAlias() { + Alias als = new Alias(); + aliases.add(als); + return als; + } + + + /** + * Set the classpath to be used for this compilation + * + * @param cp The new Classpath value + */ + public void setClasspath(Path cp) { + if (classpath == null) { + classpath = cp; + } + else { + classpath.append(cp); + } + } + + + /** + * create a nested classpath element. + * + * @return classpath to use + */ + public Path createClasspath() { + if (classpath == null) { + classpath = new Path(project); + } + return classpath.createPath(); + } + + + /** + * Adds a reference to a CLASSPATH defined elsewhere + * + * @param r The new ClasspathRef value + */ + public void setClasspathRef(Reference r) { + createClasspath().setRefid(r); + } + + + /** + * actually do the work of loading the library + * + * @exception BuildException Description of Exception + * @todo maybe have failonerror support for missing file? + */ + public void execute() + throws BuildException { + File realFile = file; + if (library != null) { + if (file != null) { + String msg = "You cannot specify both file and library."; + throw new BuildException(msg, location); + } + // For the time being libraries live in $ANT_HOME/lib. + // The idea being that we would not load all the jars there anymore + String home = project.getProperty("ant.home"); + + if (home == null) { + throw new BuildException("ANT_HOME not set as required."); + } + + realFile = new File(new File(home, "lib"), library); + } + else if (file == null) { + String msg = "Must specify either library or file attribute."; + throw new BuildException(msg, location); + } + if (!realFile.exists()) { + String msg = "Cannot find library: " + realFile; + throw new BuildException(msg, location); + } + + //open the descriptor + InputStream is = getDescriptor(realFile); + + if (is == null) { + String msg = "Missing descriptor on library: " + realFile; + throw new BuildException(msg, location); + } + + + ClassLoader classloader=null; + if (useCurrentClassloader && classpath != null) { + log("ignoring the useCurrentClassloader option as a classpath is defined", + Project.MSG_WARN); + useCurrentClassloader=false; + } + if (!useCurrentClassloader) { + classloader = makeClassLoader(realFile); + } + + //parse it and evaluate it. + evaluateDescriptor(classloader, processAliases(), is); + } + + + /** + * Load definitions directly from an external XML file. + * + * @param xmlfile XML file in the Antlib format. + * @exception BuildException failure to open the file + */ + public void loadDefinitions(File xmlfile) + throws BuildException { + try { + InputStream is = new FileInputStream(xmlfile); + loadDefinitions(is); + } + catch (IOException io) { + throw new BuildException("Cannot read file: " + file, io); + } + } + + + /** + * Load definitions directly from InputStream. + * + * @param is InputStream for the Antlib descriptor. + * @exception BuildException trouble + */ + public void loadDefinitions(InputStream is) + throws BuildException { + evaluateDescriptor(null, processAliases(), is); + } + + + /** + * get a descriptor from the library file + * + * @param file jarfile to open + * @return input stream to the Descriptor + * @exception BuildException io trouble, or it isnt a zipfile + */ + private InputStream getDescriptor(File file) + throws BuildException { + try { + final ZipFile zipfile = new ZipFile(file); + ZipEntry entry = zipfile.getEntry(ANT_DESCRIPTOR); + + if (entry == null) { + return null; + } + + // Guarantee that when Entry is closed so does the zipfile instance. + return + new FilterInputStream(zipfile.getInputStream(entry)) { + public void close() + throws IOException { + super.close(); + zipfile.close(); + } + }; + } + catch (ZipException ze) { + throw new BuildException("Not a library file.", ze, location); + } + catch (IOException ioe) { + throw new BuildException("Cannot read library content.", + ioe, location); + } + } + + + /** + * turn the alias list to a property hashtable + * + * @return generated property hashtable + */ + private Properties processAliases() { + Properties p = new Properties(); + + for (Enumeration e = aliases.elements(); e.hasMoreElements(); ) { + Alias a = (Alias) e.nextElement(); + p.put(a.name, a.as); + } + return p; + } + + + /** + * create the classpath for this library from the file passed in and + * any classpath parameters + * + * @param file library file to use + * @return classloader using te + * @exception BuildException trouble creating the classloader + */ + protected ClassLoader makeClassLoader(File file) + throws BuildException { + Path clspath = new Path(project); + clspath.setLocation(file); + //append any build supplied classpath + if (classpath != null) { + clspath.append(classpath); + } + AntClassLoader al = new AntClassLoader(project, clspath, true); + return al; + } + + + /** + * parse the antlib descriptor + * + * @param cl optional classloader + * @param als alias list as property hashtable + * @param is input stream to descriptor + * @exception BuildException trouble + */ + protected void evaluateDescriptor(ClassLoader cl, + Properties als, InputStream is) + throws BuildException { + try { + SAXParser saxParser = saxFactory.newSAXParser(); + Parser parser = saxParser.getParser(); + + InputSource inputSource = new InputSource(is); + //inputSource.setSystemId(uri); //URI is nasty for jar entries + project.log("parsing descriptor for library: " + file, + Project.MSG_VERBOSE); + saxParser.parse(inputSource, new AntLibraryHandler(cl, als)); + } + catch (ParserConfigurationException exc) { + throw new BuildException("Parser has not been configured correctly", exc); + } + catch (SAXParseException exc) { + Location location = + new Location(ANT_DESCRIPTOR, + exc.getLineNumber(), exc.getColumnNumber()); + + Throwable t = exc.getException(); + if (t instanceof BuildException) { + BuildException be = (BuildException) t; + if (be.getLocation() == Location.UNKNOWN_LOCATION) { + be.setLocation(location); + } + throw be; + } + throw new BuildException(exc.getMessage(), t, location); + } + catch (SAXException exc) { + Throwable t = exc.getException(); + if (t instanceof BuildException) { + throw (BuildException) t; + } + throw new BuildException(exc.getMessage(), t); + } + catch (IOException exc) { + throw new BuildException("Error reading library descriptor", exc); + } + finally { + if (is != null) { + try { + is.close(); + } + catch (IOException ioe) { + // ignore this + } + } + } + } + + + /** + * get a DTD URI from url, prefix and extension + * + * @return URI for this dtd version + */ + public static String dtdVersion() { + return ANTLIB_DTD_URL + ANTLIB_DTD_PREFIX + + ANTLIB_DTD_VERSION + ANTLIB_DTD_EXT; + } + + + /** + * compare system ID with the dtd string + * -ignoring any version number + * @param systemId Description of Parameter + * @return true if this is a an ant library descriptor + */ + public static boolean matchDtdId(String systemId) { + return (systemId != null && + systemId.startsWith(ANTLIB_DTD_URL + ANTLIB_DTD_PREFIX) && + systemId.endsWith(ANTLIB_DTD_EXT)); + } + + + /** + * Parses the document describing the content of the + * library. An inner class for access to Project.log + */ + private class AntLibraryHandler extends HandlerBase { + + /** + * our classloader + */ + private final ClassLoader classloader; + /** + * the aliases + */ + private final Properties aliasMap; + /** + * doc locator + */ + private Locator locator = null; + + /** + * Constructor for the AntLibraryHandler object + * + * @param cl optional classloader + * @param als alias list + */ + AntLibraryHandler(ClassLoader classloader, Properties als) { + this.classloader = classloader; + this.aliasMap = als; + } + + + /** + * Sets the DocumentLocator attribute of the AntLibraryHandler + * object + * + * @param locator The new DocumentLocator value + */ + public void setDocumentLocator(Locator locator) { + this.locator = locator; + } + + + /** + * SAX callback handler + * + * @param tag XML tag + * @param attrs attributes + * @exception SAXParseException parse trouble + */ + public void startElement(String tag, AttributeList attrs) + throws SAXParseException { + if ("antlib".equals(tag)) { + // No attributes to worry about + return; + } + if ("task".equals(tag) || "type".equals(tag)) { + String name = null; + String className = null; + + for (int i = 0, last = attrs.getLength(); i < last; i++) { + String key = attrs.getName(i); + String value = attrs.getValue(i); + + if (key.equals("name")) { + name = value; + } + else if (key.equals("class")) { + className = value; + } + else { + throw new SAXParseException("Unexpected attribute \"" + + key + "\"", locator); + } + } + if (name == null || className == null) { + String msg = "Underspecified " + tag + " declaration."; + throw new SAXParseException(msg, locator); + } + + try { + //check for name alias + String alias = aliasMap.getProperty(name); + if (alias != null) { + name = alias; + } + //catch an attempted override of an existing name + if (!override && inUse(name)) { + String msg = "Cannot override " + tag + ": " + name; + log(msg, Project.MSG_WARN); + return; + } + + //load the named class + Class cls; + if(classloader==null) { + cls=Class.forName(className); + } + else { + cls=classloader.loadClass(className); + } + + //register it as a task or a datatype + if (tag.equals("task")) { + project.addTaskDefinition(name, cls); + } + else { + project.addDataTypeDefinition(name, cls); + } + } + catch (ClassNotFoundException cnfe) { + String msg = "Class " + className + + " cannot be found"; + throw new SAXParseException(msg, locator, cnfe); + } + catch (NoClassDefFoundError ncdfe) { + String msg = "Class " + className + + " cannot be found"; + throw new SAXParseException(msg, locator); + } + } + else { + throw new SAXParseException("Unexpected element \"" + + tag + "\"", + locator); + } + } + + + /** + * test for a name being in use already + * + * @param name the name to test + * @return true if it is a task or a datatype + */ + private boolean inUse(String name) { + return (project.getTaskDefinitions().get(name) != null || + project.getDataTypeDefinitions().get(name) != null); + } + + + /** + * Recognizes the DTD declaration for antlib and returns the corresponding + * DTD definition from a resource.

+ * + * To allow for future versions of the DTD format it will search + * for any DTDs of the form "Antlib-V.*\.dtd". + * + * @param publicId public ID (ignored) + * @param systemId system ID (matched against) + * @return local DTD instance + */ + public InputSource resolveEntity(String publicId, + String systemId) { + + log("Looking for entiry with PublicID=" + publicId + + " and SystemId=" + systemId, Project.MSG_VERBOSE); + if (matchDtdId(systemId)) { + String resId = systemId.substring(ANTLIB_DTD_URL.length()); + InputSource is = + new InputSource(this.getClass().getResourceAsStream(resId)); + + is.setSystemId(systemId); + return is; + } + return null; + } + //end inner class AntLibraryHandler + } + + + /** + * this class is used for alias elements + * + * @author slo + * @created 11 November 2001 + */ + public static class Alias { + /** + * Description of the Field + */ + private String name; + /** + * Description of the Field + */ + private String as; + + + /** + * Sets the Name attribute of the Alias object + * + * @param name The new Name value + */ + public void setName(String name) { + this.name = name; + } + + + /** + * Sets the As attribute of the Alias object + * + * @param as The new As value + */ + public void setAs(String as) { + this.as = as; + } + //end inner class alias + } + +//end class Antlib +} + + diff --git a/src/main/org/apache/tools/ant/taskdefs/defaults.properties b/src/main/org/apache/tools/ant/taskdefs/defaults.properties index 1b90ed811..3deaae9dc 100644 --- a/src/main/org/apache/tools/ant/taskdefs/defaults.properties +++ b/src/main/org/apache/tools/ant/taskdefs/defaults.properties @@ -53,6 +53,8 @@ parallel=org.apache.tools.ant.taskdefs.Parallel sequential=org.apache.tools.ant.taskdefs.Sequential condition=org.apache.tools.ant.taskdefs.ConditionTask dependset=org.apache.tools.ant.taskdefs.DependSet +antlib=org.apache.tools.ant.taskdefs.Antlib +antjar=org.apache.tools.ant.taskdefs.Antjar # optional tasks script=org.apache.tools.ant.taskdefs.optional.Script