Hi,
As I promised and since I have not received any comments from my previous
posting, here is a patch that implements the <antlib> functionality we have
been discussing.
This patch does not make any changes to the way core loads predefined tasks,
but it relies on the patch I sent last week that can be found here:
http://marc.theaimsgroup.com/?l=ant-dev&m=100293639829680&w=2
The patch defines an <antlib> task for loading libraries and an <antjar> task
for creating them. Antlib will usually create a new classloader to load from
the specified jar, but that can be controlled. There is also support for
aliases and for overloading existing definitions. A versioned DTD for the
library descriptor and manual pages for the tasks are also included.
Hope people like it or at least can be used as an starting point for where we
want to go.
Jose Alberto
BEGIN:VCARD
VERSION:2.1
N:Fernandez;Jose;Alberto
FN:Jose Alberto Fernandez
TEL;HOME;VOICE:+44.20.8805.0809
TEL;CELL;VOICE:+44.77.4767.3468
TEL;HOME;FAX:+44.20.8805.0809
ADR;HOME;ENCODING=QUOTED-PRINTABLE:;;2 Caroe Court=0D=0A1 Bury Street;London;;N9 7LE;UK
LABEL;HOME;ENCODING=QUOTED-PRINTABLE:2 Caroe Court=0D=0A1 Bury Street=0D=0ALondon N9 7LE=0D=0AUK
X-WAB-GENDER:2
URL:www.geocities.com/j_a_fernandez
BDAY:19600811
EMAIL;PREF;INTERNET:[EMAIL PROTECTED]
REV:20011016T152037Z
END:VCARD
Index: build.xml
===================================================================
RCS file: /home/cvspublic/jakarta-ant/build.xml,v
retrieving revision 1.186
diff -u -r1.186 build.xml
--- build.xml 2001/10/13 10:54:58 1.186
+++ build.xml 2001/10/16 14:58:23
@@ -253,6 +253,7 @@
<copy todir="${build.classes}">
<fileset dir="${java.dir}">
<include name="**/*.properties" />
+ <include name="**/*.dtd" />
</fileset>
</copy>
Index: docs/manual/coretasklist.html
===================================================================
RCS file: /home/cvspublic/jakarta-ant/docs/manual/coretasklist.html,v
retrieving revision 1.20
diff -u -r1.20 coretasklist.html
--- docs/manual/coretasklist.html 2001/09/08 01:05:17 1.20
+++ docs/manual/coretasklist.html 2001/10/16 14:58:29
@@ -25,6 +25,8 @@
<a href="CoreTasks/overview.html">Overview</a><br><br>
<a href="CoreTasks/ant.html">Ant</a><br>
<a href="CoreTasks/antcall.html">AntCall</a><br>
+<a href="CoreTasks/antlib.html">AntLib</a><br>
+<a href="CoreTasks/antjar.html">AntJar</a><br>
<a href="CoreTasks/antstructure.html">AntStructure</a><br>
<a href="CoreTasks/apply.html">Apply/<i>ExecOn</i></a><br>
<a href="CoreTasks/available.html">Available</a><br>
Index: docs/manual/CoreTasks/antjar.html
===================================================================
RCS file: antjar.html
diff -N antjar.html
--- /dev/null Tue Oct 16 07:55:58 2001
+++ antjar.html Tue Oct 16 07:58:30 2001
@@ -0,0 +1,94 @@
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<title>Ant User Manual</title>
+</head>
+
+<body>
+
+<h2><a name="antjar">AntJar</a></h2>
+<h3>Description</h3>
+<p>An extension of the <a href="jar.html">Jar</a> task with special
+treatment for the library descriptor file that should end up in the
+<code>META-INF</code> directory of the Ant Archive.</p>
+<p>This task validates the provided library descriptor making certain
+it specifies the following SYSTEM ID:
+<b>"http://jakarta.apache.org/ant/AntlibV1_0.dtd"</b>.
+This DTD is defined as follows:</p>
+<pre>
+<?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
+>
+
+</pre>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+ <tr>
+ <td valign="top"><b>Attribute</b></td>
+ <td valign="top"><b>Description</b></td>
+ <td align="center" valign="top"><b>Required</b></td>
+ </tr>
+ <tr>
+ <td valign="top">antxml</td>
+ <td valign="top">The library descriptor to use (META-INF/antlib.xml).</td>
+ <td valign="top" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td valign="top"><b>Others...</b></td>
+ <td valign="top">All attributes inherited form the
+ <a href="jar.html">Jar task</a>.</td>
+ <td valign="top" align="center"> </td>
+ </tr>
+</table>
+<h3>Nested elements</h3>
+See the nested elements of the <a href="jar.html">Jar task</a>.
+<h3>Examples</h3>
+<pre> <jar file="${dist}/lib/app.jar"
+ antxml="${src}/applib.xml"
basedir="${build}/classes"/></pre>
+<p>jars all files in the <code>${build}/classes</code> directory into a file
+called <code>app.jar</code> in the <code>${dist}/lib</code> directory and
+sets the content of <code>${src}/applib.xml</code> as the library descriptor
+in <code>META-INF/antlib.xml</code>.</p>
+<p>Here is a sample <code>META-INF/antlib.xml</code>:</p>
+<pre>
+<?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>
+
+</pre>
+<hr>
+<p align="center">Copyright © 2000,2001 Apache Software Foundation. All
rights
+Reserved.</p>
+
+</body>
+</html>
+
Index: docs/manual/CoreTasks/antlib.html
===================================================================
RCS file: antlib.html
diff -N antlib.html
--- /dev/null Tue Oct 16 07:55:58 2001
+++ antlib.html Tue Oct 16 07:58:30 2001
@@ -0,0 +1,92 @@
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<title>Ant User Manual</title>
+</head>
+
+<body>
+
+<h2><a name="antlib">AntLib</a></h2>
+<h3>Description</h3>
+<p>Defines and loads any tasks and datatypes contained in an ANT library.</p>
+<p>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.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+ <tr>
+ <td valign="top"><b>Attribute</b></td>
+ <td valign="top"><b>Description</b></td>
+ <td align="center" valign="top"><b>Required</b></td>
+ </tr>
+ <tr>
+ <td valign="top">file</td>
+ <td valign="top">The jar-file of the library.</td>
+ <td align="center" valign="middle" rowspan="2">at least one of the two</td>
+ </tr>
+ <tr>
+ <td valign="top">library</td>
+ <td valign="top">The name of a library relative to ${ant.home}/lib.</td>
+ </tr>
+ <tr>
+ <td valign="top">override</td>
+ <td valign="top">Replace 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.</td>
+ <td align="center" valign="top">No</td>
+ </tr>
+ <tr>
+ <td valign="top">oncurrent</td>
+ <td valign="top">Set to "true" to avoid using a separate
+ ClassLoader for the tasks in the library. Using this option assumes
+ that the library jar is already accessible by the ClassLoader of
+ the project. Default is "false".</td>
+ <td align="center" valign="top">No</td>
+ </tr>
+</table>
+<h3><a name="nested">Parameters specified as nested elements</a></h3>
+
+<h4>alias</h4>
+<p>Specifies the usage of a different name from that defined in the library
+descriptor.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+ <tr>
+ <td valign="top"><b>Attribute</b></td>
+ <td valign="top"><b>Description</b></td>
+ <td align="center" valign="top"><b>Required</b></td>
+ </tr>
+ <tr>
+ <td valign="top">name</td>
+ <td valign="top">The name used in the library descriptor.</td>
+ <td valign="top" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td valign="top">as</td>
+ <td valign="top">The alias to use in the project.</td>
+ <td valign="top" align="center">Yes</td>
+ </tr>
+</table>
+
+<h3>Examples</h3>
+<pre> <antlib file="${build}/lib/mylib.jar"/></pre>
+<p>loads the definitions from the library located at
+<code>${build}/lib/ant.jar</code>.</p>
+<pre> <antlib library="optional.jar"/></pre>
+<p>loads the definitions from the library <code>optional.jar</code>
+located at <code>${ant.home}/lib</code>.</p>
+<pre> <antlib file="${build}/lib/mylib.jar">
+ <alias name="echo" as="myecho"/>
+ </antlib>
+</pre>
+<p>loads the definitions from the library located at
+<code>${build}/lib/ant.jar</code> but uses the name
+"<code>myecho</code>" for the "<code>echo</code>" task
+declared in the library.</p>
+
+<hr><p align="center">Copyright © 2000,2001 Apache Software Foundation.
All rights
+Reserved.</p>
+
+</body>
+</html>
+
Index: src/main/org/apache/tools/ant/taskdefs/Antjar.java
===================================================================
RCS file: Antjar.java
diff -N Antjar.java
--- /dev/null Tue Oct 16 07:55:58 2001
+++ Antjar.java Tue Oct 16 07:58:39 2001
@@ -0,0 +1,242 @@
+/*
+ * 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 [EMAIL PROTECTED]
+ *
+ * 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
+ * <http://www.apache.org/>.
+ */
+
+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.
+ *
+ * @author <a href="mailto:[EMAIL PROTECTED]">Jose Alberto Fernandez</a>
+ */
+public class Antjar extends Jar {
+
+ private File libraryDescriptor;
+ private boolean descriptorAdded;
+
+ public Antjar() {
+ super();
+ archiveType = "jar";
+ emptyBehavior = "create";
+ }
+
+ public void setAntxml(File descr) {
+ libraryDescriptor = descr;
+ if (!libraryDescriptor.exists())
+ throw new BuildException("Deployment descriptor: " +
libraryDescriptor + " does not exist.");
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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 <fileset> 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 web.xml next time this task
+ * gets executed.
+ */
+ protected void cleanUp() {
+ descriptorAdded = false;
+ super.cleanUp();
+ }
+
+ 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 {
+
+ private boolean doctypePresent = false;
+ private Locator locator = null;
+
+ public void setDocumentLocator(Locator locator) {
+ this.locator = locator;
+ }
+
+ 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.
+ * <P>
+ * To allow for future versions of the DTD format it will
+ * search for any DTDs of the form "Antlib-V.*\.dtd".
+ */
+ public InputSource resolveEntity(String publicId,
+ String systemId) {
+
+ log("Looking for entiry 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(getClass().getResourceAsStream(resId));
+
+ is.setSystemId(systemId);
+ doctypePresent = true;
+ return is;
+ }
+ return null;
+ }
+ }
+}
Index: src/main/org/apache/tools/ant/taskdefs/Antlib-V1_0.dtd
===================================================================
RCS file: Antlib-V1_0.dtd
diff -N Antlib-V1_0.dtd
--- /dev/null Tue Oct 16 07:55:58 2001
+++ Antlib-V1_0.dtd Tue Oct 16 07:58:39 2001
@@ -0,0 +1,27 @@
+<?xml version='1.0' encoding="UTF8" ?>
+
+<!--
+This file defines the XML format for ANT library descriptors.
+Descriptors must especify a DOCTYPE using "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
+>
Index: src/main/org/apache/tools/ant/taskdefs/Antlib.java
===================================================================
RCS file: Antlib.java
diff -N Antlib.java
--- /dev/null Tue Oct 16 07:55:58 2001
+++ Antlib.java Tue Oct 16 07:58:42 2001
@@ -0,0 +1,441 @@
+/*
+ * 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 [EMAIL PROTECTED]
+ *
+ * 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
+ * <http://www.apache.org/>.
+ */
+
+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.
+ *
+ * <pre>
+ * <antlib library="libname.jar" >
+ * <alias name="nameOnLib" as="newName" />
+ * </antlib>
+ *
+ * <antlib file="libname.jar" override="true" />
+ * </pre>
+ * @author <a href="[EMAIL PROTECTED]">Jose Alberto Fernandez</a>
+ */
+public class Antlib extends Task implements DeclaringTask {
+
+ /** Location of destriptor 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/";
+ public static String ANTLIB_DTD_PREFIX = "Antlib-V";
+ public static String ANTLIB_DTD_VERSION = "1_0";
+ public static String ANTLIB_DTD_EXT = ".dtd";
+
+ private String library = null;
+ private File file = null;
+ private boolean override = false;
+ private boolean onCurrent = false;
+
+ private SAXParserFactory saxFactory;
+ private Vector aliases = new Vector();
+
+ public static String dtdVersion() {
+ return ANTLIB_DTD_URL + ANTLIB_DTD_PREFIX +
+ ANTLIB_DTD_VERSION + ANTLIB_DTD_EXT;
+ }
+
+ public static boolean matchDtdId(String systemId) {
+ return (systemId != null &&
+ systemId.startsWith(ANTLIB_DTD_URL + ANTLIB_DTD_PREFIX) &&
+ systemId.endsWith(ANTLIB_DTD_EXT));
+ }
+
+ public class Alias {
+ private String name;
+ private String as;
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setAs(String as) {
+ this.as = as;
+ }
+ }
+
+ public Antlib() {
+ super();
+ saxFactory = SAXParserFactory.newInstance();
+ saxFactory.setValidating(true);
+ }
+
+ 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 <code>false</code>.
+ * This property is mostly used by the core when loading core tasks.
+ * @param onCurrent if true the current classloader will be used to
+ * load the definitions.
+ */
+ public void setOncurrent(boolean onCurrent) {
+ this.onCurrent = onCurrent;
+ }
+
+ /** Create new Alias element. */
+ public Alias createAlias() {
+ Alias als = new Alias();
+ aliases.add(als);
+ return als;
+ }
+
+ 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 jar 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);
+ }
+
+ InputStream is = getDescriptor(realFile);
+
+ if (is == null) {
+ String msg = "Missing descriptor on library: " + realFile;
+ throw new BuildException(msg, location);
+ }
+
+ evaluateDescriptor(onCurrent? null : makeClassLoader(realFile),
+ processAliases(), is);
+ }
+
+ /**
+ * Load definitions directly from an external XML file.
+ * @param xmlfile XML file in the Antlib format.
+ */
+ 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.
+ */
+ public void loadDefinitions(InputStream is) throws BuildException {
+ evaluateDescriptor(null, processAliases(), is);
+ }
+
+ private InputStream getDescriptor(File file) {
+ try {
+ final ZipFile zipfile = new ZipFile(file);
+ ZipEntry entry = zipfile.getEntry(ANT_DESCRIPTOR);
+
+ if (entry == null) return null;
+
+ // Guarantee that when Entry is close 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);
+ }
+ }
+
+ 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;
+ }
+
+ protected ClassLoader makeClassLoader(File fl) throws BuildException {
+ Path clspath = new Path(project);
+ clspath.setLocation(fl);
+ AntClassLoader al = new AntClassLoader(project, clspath, true);
+ return al;
+ }
+
+ 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
+ }
+ }
+ }
+ }
+
+ /**
+ * Parses the document describing the content of the library.
+ */
+ private class AntLibraryHandler extends HandlerBase {
+
+ private final ClassLoader cl;
+ private final Properties aliasMap;
+ private Locator locator = null;
+
+ AntLibraryHandler(ClassLoader cl, Properties als) {
+ this.cl = cl;
+ this.aliasMap = als;
+ }
+
+ public void setDocumentLocator(Locator locator) {
+ this.locator = locator;
+ }
+
+ 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 {
+ String alias = aliasMap.getProperty(name);
+
+ if (alias != null) name = alias;
+ if (!override && inUse(name)) {
+ String msg = "Cannot override " + tag + ": " + name;
+ log(msg, Project.MSG_WARN);
+ return;
+ }
+
+ Class cls = (cl != null)?
+ cl.loadClass(className) : Class.forName(className);
+
+ 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);
+ }
+ }
+
+ 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.
+ * <P>
+ * To allow for future versions of the DTD format it will
+ * search for any DTDs of the form "Antlib-V.*\.dtd".
+ */
+ 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(getClass().getResourceAsStream(resId));
+
+ is.setSystemId(systemId);
+ return is;
+ }
+ return null;
+ }
+ }
+}
+
+
Index: src/main/org/apache/tools/ant/taskdefs/defaults.properties
===================================================================
RCS file:
/home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/defaults.properties,v
retrieving revision 1.91
diff -u -r1.91 defaults.properties
--- src/main/org/apache/tools/ant/taskdefs/defaults.properties 2001/09/13
08:31:21 1.91
+++ src/main/org/apache/tools/ant/taskdefs/defaults.properties 2001/10/16
14:58:46
@@ -53,6 +53,8 @@
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