Browse Source

upon Jose Alberto's request, updates to antlib

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271281 13f79535-47bb-0310-9956-ffa450edef68
master
Erik Hatcher 23 years ago
parent
commit
7ed2408117
10 changed files with 2813 additions and 300 deletions
  1. +60
    -0
      proposal/sandbox/antlib/build.xml
  2. +30
    -22
      proposal/sandbox/antlib/docs/manual/CoreTasks/antjar.html
  3. +39
    -8
      proposal/sandbox/antlib/docs/manual/CoreTasks/antlib.html
  4. +1342
    -0
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/Project.java
  5. +69
    -0
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/RoleAdapter.java
  6. +491
    -0
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/SymbolTable.java
  7. +168
    -0
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/TaskAdapter.java
  8. +475
    -0
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Ant.java
  9. +1
    -140
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antjar.java
  10. +138
    -130
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antlib.java

+ 60
- 0
proposal/sandbox/antlib/build.xml View File

@@ -0,0 +1,60 @@
<?xml version='1.0' ?>
<project name="antlib" default="all">
<property name='orig' location='../../..' />
<property name='orig-build' location='${orig}/build' />
<property name='orig-classes' location='${orig-build}/classes' />
<property name='build' location='build' />
<property name='dist' location='dist' />
<property name='classes' location='${build}/classes' />

<property name="debug" value="true" />
<property name="deprecation" value="false" />
<property name="optimize" value="true" />
<target name='init'>
<ant target='build' dir='${orig}' inheritAll='false' />
<mkdir dir='${classes}' />
<copy toDir='${classes}' preservelastmodified='true' >
<fileset dir='${orig-classes}'>
<include name='**' />
<exclude name='org/apache/tools/ant/Project.class' />
<exclude name='org/apache/tools/ant/TaskAdapter.class' />
<exclude name='org/apache/tools/ant/taskdefs/Ant.class' />
</fileset>
</copy>
</target>

<target name='all' depends='init, build' />

<target name='fullbuild' depends='init, compile'>
<ant target='internal_dist' dir='${orig}'>
<property name="build.dir" value="${build}"/>
<property name="dist.dir" value="${dist}"/>
</ant>
</target>

<target name='build' depends='init, compile'>
<ant target='dist-lite' dir='${orig}'>
<property name="build.dir" value="${build}"/>
<property name="dist.dir" value="${dist}"/>
</ant>
</target>

<target name='compile'>
<javac srcdir='src/main' destdir='${classes}'
debug="${debug}"
deprecation="${deprecation}"
optimize="${optimize}">
<include name='**/*.java'/>
</javac>
</target>

<target name='clean'>
<delete dir='${build}' />
</target>

<target name='cleanall' depends='clean'>
<delete dir='${dist}' />
</target>
</project>

+ 30
- 22
proposal/sandbox/antlib/docs/manual/CoreTasks/antjar.html View File

@@ -12,41 +12,50 @@
<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>&quot;http://jakarta.apache.org/ant/AntlibV1_0.dtd&quot;</b>.
This DTD is defined as follows:</p>
<p>
Descriptors must follow the following rules, although there is no fix DTD
for them:
<pre>
&lt;?xml version='1.0' encoding="UTF8" ?&gt;

&lt;!--
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.
--&gt;

&lt;!-- Root element for the Antlib descriptor. --&gt;
&lt;!ELEMENT antlib (task | type)* &gt;
&lt;!ATTLIST antlib
version CDATA #IMPLIED
&gt;
&lt;!ELEMENT antlib (role | <i>rolename</i>)* &gt;

&lt;!-- Declaration of tasks contained in the library. --&gt;
&lt;!ELEMENT task EMPTY&gt;
&lt;!ATTLIST task
&lt;!-- Declaration of roles contained in the library. --&gt;
&lt;!ELEMENT role EMPTY&gt;
&lt;!ATTLIST role
name CDATA #REQUIRED
class CDATA #REQUIRED
proxy CDATA #IMPLIED
&gt;

&lt;!-- Declaration of datatypes contained in the library --&gt;
&lt;!ELEMENT type EMPTY&gt;
&lt;!ATTLIST type
&lt;!ELEMENT <i>rolename</i> EMPTY&gt;
&lt;!ATTLIST <i>rolename</i>
name CDATA #REQUIRED
class CDATA #REQUIRED
&gt;

</pre>
There are two predefined roles: <i><b>task</b></i> and <i><b>datatype</b></i>.
<p>
<h4>Role definition</h4>
The <b>name</b> of the role. This name is used when specifying
elements for this role.
<p>
The <b>class</b> defining a role must be an interface containing a
unique void method with only one argument whose type is the that of
elements declared on the role.
<p>
The <b>proxy</b> defined in a role specifies a class that can be used
to bridge between the type expected by the role and the type of
elements declared for that role.
<h4>Element definition</h4>
Any element whose name is that of a role declares an element for that role.
<p>
The <b>name</b> defined the name of the element to use in the buildfile
to specify the element being declared.
<p>
The <b>class</b> the class defining the element.
<h3>Parameters</h3>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
@@ -78,7 +87,6 @@ in <code>META-INF/antlib.xml</code>.</p>
<p>Here is a sample <code>META-INF/antlib.xml</code>:</p>
<pre>
&lt;?xml version="1.0" encoding="UTF8" ?&gt;
&lt;!DOCTYPE antlib SYSTEM "http://jakarta.apache.org/ant/Antlib-V1_0.dtd" &gt;

&lt;antlib version="1.0" &gt;
&lt;task name="case" class="org.apache.ant.contrib.Case" /&gt;


+ 39
- 8
proposal/sandbox/antlib/docs/manual/CoreTasks/antlib.html View File

@@ -9,16 +9,38 @@

<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>Defines and loads elements 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>
Ant libraries can be loaded in the current classloader, which is more efficient,
Ant libraries are associated with ClassLoaders identified by the
<tt>loaderid</tt> attribute. If no loader is specified a default loader
will be used. Ant libraries specifying the same loader are loaded by the
same ClassLoader as long as the libraries are defined on the same project.
Classloaders with the same ID in a subproject have the corresponding
classloader in the parent project as their parent classloader.
<p>
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 <tt>useCurrentClassloader</tt> 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.
<p>
Ant libraries define objects of several types:
<ol>
<li> <b>Roles</b>: Define an interface to be implemented by elements
(usually tasks) that accept subelements of the specified role.
Roles may also define a proxy class which may be applied to an element
in order to make it compatible with the role.
</li>
<li> <b>Tasks</b>: define elements that belong to the predefined
role "task".
<li> <b>Data types</b>: define elements that belong to the predefined role
"datatype".
<li> <b>Other role elements</b>: declare elements for other roles that
have been previously defined.
</ol>
<h3>Parameters</h3>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
@@ -33,11 +55,13 @@ libraries the task is dependent on.
</tr>
<tr>
<td valign="top">library</td>
<td valign="top">The name of a library relative to ${ant.home}/lib.</td>
<td valign="top">The name of a library relative to ${ant.home}/antlib.</td>
</tr>
<tr>
<td valign="top">override</td>
<td valign="top">Replace any existing definition with the same name. (&quot;true&quot;/&quot;false&quot;). When &quot;false&quot; already defined tasks
<td valign="top">Replace any existing definition with the same name.
(&quot;true&quot;/&quot;false&quot;).
When &quot;false&quot; already defined tasks
and datatytes take precedence over those in the library.
Default is &quot;false&quot; when omitted.</td>
<td align="center" valign="top">No</td>
@@ -59,12 +83,20 @@ libraries the task is dependent on.
</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">loaderid</td>
<td valign="top">The ID of the ClassLoader to use to load the classes
defined in this library. If omitted a default per project ClassLoader
will be used.
</td>
<td valign="top" align="center">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>
descriptor. Applies only to element definitions (not role declarations).</p>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
<td valign="top"><b>Attribute</b></td>
@@ -85,10 +117,9 @@ descriptor.</p>
<p>Specifies the usage of a different name from that defined in the library
descriptor. This is used to deal with name clashes </p>

<h4>classpath</h4>
<h4>classpath</h4>

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

<h4>classpathref</h4>
A reference to an existing classpath.


+ 1342
- 0
proposal/sandbox/antlib/src/main/org/apache/tools/ant/Project.java
File diff suppressed because it is too large
View File


+ 69
- 0
proposal/sandbox/antlib/src/main/org/apache/tools/ant/RoleAdapter.java View File

@@ -0,0 +1,69 @@
/*
* 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
* <http://www.apache.org/>.
*/
package org.apache.tools.ant;

public interface RoleAdapter {

/**
* Set the object being adapted.
* @param o the object being adapted
*/
public void setProxy(Object o);
/**
* Get the object adapted by this class.
* @return the object being adapted, if any.
*/
public Object getProxy();
}

+ 491
- 0
proposal/sandbox/antlib/src/main/org/apache/tools/ant/SymbolTable.java View File

@@ -0,0 +1,491 @@
/*
* 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
* <http://www.apache.org/>.
*/
package org.apache.tools.ant;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;

import org.apache.tools.ant.types.Path;

public class SymbolTable {

/** Parent symbol table */
private SymbolTable parentTable;
/** Project associated with this symbol table */
private Project project;

/** The table of roles available to this Project */
private Hashtable roles = new Hashtable();

/** The table of loaders active on this Project */
private Hashtable loaders = new Hashtable();

/**
* Table of per role definitions.
*/
private Hashtable defs = new Hashtable();

/**
* Parameters for checking adapters.
*/
private static final Class[] CHECK_ADAPTER_PARAMS =
new Class[]{Class.class, Project.class};

/**
* Create a top level Symbol table.
*/
public SymbolTable() {
}

/**
* Create a symbol table inheriting the definitions
* from that defined in the calling Project.
* @param p the calling project
*/
public SymbolTable(Project p) {
parentTable = p.getSymbols();
}

/**
* Set the project associated with this symbol table.
* @param p the project for this symbol table
*/
public void setProject(Project p) {
this.project = p;
}

/**
* Find all the roles supported by a Class
* on this symbol table.
* @param clz the class to analyze
* @return an array of roles supported by the class
*/
public String[] findRoles(final Class clz) {
Vector list = new Vector();
findRoles(clz, list);
return (String[])list.toArray(new String[list.size()]);
}

/**
* Collect the roles for the class
* @param clz the class being inspected
* @param list the roles collected up to this point
*/
private void findRoles(final Class clz, Vector list) {
for (Enumeration e = roles.keys(); e.hasMoreElements();) {
String role = (String) e.nextElement();

if (((Role) roles.get(role)).isImplementedBy(clz)) {
list.addElement(role);
}
}
if (parentTable != null) findRoles(clz, list);
}
/**
* Get the Role definition
* @param role the name of the role
* @return the method used to support objects on this role
*/
public Role getRole(String role) {
Role r = (Role) roles.get(role);
if (r == null && parentTable != null) {
return parentTable.getRole(role);
}
return r;
}

/**
* Add a new role definition to this project.
* @param role the name of the role
* @param rclz the interface used to specify support for the role.
* @param aclz the optional adapter class
* @return whether the role replaced a different definition
*/
public boolean addRole(String role, Class rclz, Class aclz) {
// Check if role already declared
Role old = getRole(role);
if (old != null && old.isSameAsFor(rclz, aclz)
) {
project.log("Ignoring override for role " + role
+ ", it is already defined by the same definition.",
project.MSG_VERBOSE);
return false;
}
// Role interfaces should only contain one method
roles.put(role, new Role(rclz, aclz));
return (old != null);
}

/**
* Verify if the interface is valid.
* @param clz the interface to validate
* @return the method defined by the interface
*/
private Method validInterface(Class clz) {
Method m[] = clz.getDeclaredMethods();
if (m.length == 1
&& java.lang.Void.TYPE.equals(m[0].getReturnType())) {
Class args[] = m[0].getParameterTypes();
if (args.length == 1
&& !java.lang.String.class.equals(args[0])
&& !args[0].isArray()
&& !args[0].isPrimitive()) {
return m[0];
}
else {
throw new BuildException("Invalid role interface method in: "
+ clz.getName());
}
}
else {
throw new BuildException("More than one method on role interface");
}
}

/**
* Verify if the adapter is valid with respect to the interface.
* @param clz the class adapter to validate
* @param mtd the method whose only argument must match
* @return the static method to use for validating adaptees
*/
private Method validAdapter(Class clz, Method mtd) {
if (clz == null) return null;
checkClass(clz);
if (!mtd.getParameterTypes()[0].isAssignableFrom(clz)) {
String msg = "Adapter " + clz.getName() +
" is incompatible with role interface " +
mtd.getDeclaringClass().getName();
throw new BuildException(msg);
}
String msg = "Class " + clz.getName() + " is not an adapter: ";
if (!RoleAdapter.class.isAssignableFrom(clz)) {
throw new BuildException(msg + "does not implement RoleAdapter");
}
try {
Method chk = clz.getMethod("checkClass", CHECK_ADAPTER_PARAMS);
if (!Modifier.isStatic(chk.getModifiers())) {
throw new BuildException(msg + "checkClass() is not static");
}
return chk;
}
catch(NoSuchMethodException nme){
throw new BuildException(msg + "checkClass() not found", nme);
}
}

/**
* Get the specified loader for the project.
* @param name the name of the loader
* @return the corresponding ANT classloader
*/
private AntClassLoader getLoader(String name) {
AntClassLoader cl = (AntClassLoader) loaders.get(name);
if (cl == null && parentTable != null) {
return parentTable.getLoader(name);
}
return cl;
}

/**
* Add the specified class-path to a loader.
* If the loader is defined in an ancestor project then a new
* classloader inheritin from the one already existing
* will be created, otherwise the path willbe added to the existing
* ClassLoader.
* @param name the name of the loader to use.
* @param clspath the path to be added to the classloader
*/
public ClassLoader addToLoader(String name, Path clspath) {
// Find if the loader is already defined in the current project
AntClassLoader cl = (AntClassLoader) loaders.get(name);
if (cl == null) {
// Is it inherited from the calling project
if (parentTable != null) {
cl = parentTable.getLoader(name);
}
cl = new AntClassLoader(cl, project, clspath, true);
loaders.put(name, cl);
}
else {
// Add additional path to the existing definition
String[] pathElements = clspath.list();
for (int i = 0; i < pathElements.length; ++i) {
try {
cl.addPathElement(pathElements[i]);
}
catch (BuildException e) {
// ignore path elements invalid relative to the project
}
}
}
return cl;
}
/**
* Add a new type of element to a role.
* @param role the role for this Class.
* @param name the name of the element for this Class
* @param clz the Class being declared
* @return the old definition
*/
public Class add(String role, String name, Class clz) {
// Find the role definition
Role r = getRole(role);
if (r == null) {
throw new BuildException("Unknown role: " + role);
}
// Check if it is already defined
Class old = get(role, name);
if (old != null) {
if (old.equals(clz)) {
project.log("Ignoring override for "+ role + " " + name
+ ", it is already defined by the same class.",
project.MSG_VERBOSE);
return old;
}
else {
project.log("Trying to override old definition of " +
role + " " + name,
project.MSG_WARN);
}
}
checkClass(clz);
// Check that the Class is compatible with the role definition
r.verifyAdaptability(role, clz);
// Record the new type
Hashtable defTable = (Hashtable)defs.get(role);
if (defTable == null) {
defTable = new Hashtable();
defs.put(role, defTable);
}
defTable.put(name, clz);
return old;
}

/**
* Checks a class, whether it is suitable for serving in ANT.
* @throws BuildException and logs as Project.MSG_ERR for
* conditions, that will cause execution to fail.
*/
void checkClass(final Class clz)
throws BuildException {
if(!Modifier.isPublic(clz.getModifiers())) {
final String message = clz + " is not public";
project.log(message, Project.MSG_ERR);
throw new BuildException(message);
}
if(Modifier.isAbstract(clz.getModifiers())) {
final String message = clz + " is abstract";
project.log(message, Project.MSG_ERR);
throw new BuildException(message);
}
try {
// Class can have a "no arg" constructor or take a single
// Project argument.
// don't have to check for public, since
// getConstructor finds public constructors only.
try {
clz.getConstructor(new Class[0]);
} catch (NoSuchMethodException nse) {
clz.getConstructor(new Class[] {Project.class});
}
} catch(NoSuchMethodException e) {
final String message =
"No valid public constructor in " + clz;
project.log(message, Project.MSG_ERR);
throw new BuildException(message);
}
}

/**
* Get the class in the role identified with the element name.
* @param role the role to look into.
* @param name the name of the element to sea
* @return the Class implementation
*/
public Class get(String role, String name) {
Hashtable defTable = (Hashtable)defs.get(role);
if (defTable != null) {
Class clz = (Class)defTable.get(name);
if (clz != null) return clz;
}
if (parentTable != null) {
return parentTable.get(role, name);
}
return null;
}

/**
* Get a Hashtable that is usable for manipulating Tasks,
* @return a Hashtable that delegates to the Symbol table.
*/
public Hashtable getTaskDefinitions() {
return new SymbolHashtable("task");
}

/**
* Get a Hashtable that is usable for manipulating Datatypes,
* @return a Hashtable that delegates to the Symbol table.
*/
public Hashtable getDataTypeDefinitions() {
return new SymbolHashtable("datatype");
}

/**
* Hashtable implementation that delegates
* the search operations to the Symbol table
*/
private class SymbolHashtable extends Hashtable {
final String role;
SymbolHashtable(String role) {
this.role = role;
}

public synchronized Object put(Object key, Object value) {
return SymbolTable.this.add(role, (String) key, (Class) value);
}

public synchronized Object get(Object key) {
return SymbolTable.this.get(role, (String)key);
}
}

/**
* The definition of a role
*/
public class Role {
private Method interfaceMethod;
private Method adapterVerifier;
/**
* Creates a new Role object
* @param roleClz the class that defines the role
* @param adapterClz the class for the adapter, or null if none
*/
Role(Class roleClz, Class adapterClz) {
interfaceMethod = validInterface(roleClz);
adapterVerifier = validAdapter(adapterClz, interfaceMethod);
}

/**
* Get the method used to set on interface
*/
public Method getInterfaceMethod() {
return interfaceMethod;
}

/**
* Instantiate a new adapter for this role.
*/
public RoleAdapter createAdapter() {
if (adapterVerifier == null) return null;
try {
return (RoleAdapter)
adapterVerifier.getDeclaringClass().newInstance();
}
catch(BuildException be) {
throw be;
}
catch(Exception e) {
throw new BuildException(e);
}
}
/**
* Verify if the class can be adapted to use by the role
* @param role the name of the role to verify
* @param clz the class to verify
*/
public void verifyAdaptability(String role, Class clz) {
if (interfaceMethod.getParameterTypes()[0].isAssignableFrom(clz)) {
return;
}
if (adapterVerifier == null) {
String msg = "Class " + clz.getName() +
" incompatible with role: " + role;
throw new BuildException(msg);
}
try {
try {
adapterVerifier.invoke(null,
new Object[]{clz, project});
}
catch (InvocationTargetException ite) {
throw ite.getTargetException();
}
}
catch(BuildException be) { throw be; }
catch(Error err) {throw err; }
catch(Throwable t) {
throw new BuildException(t);
}
}
public boolean isSameAsFor(Class clz, Class pclz) {
return interfaceMethod.getDeclaringClass().equals(clz) &&
((adapterVerifier == null && pclz == null) ||
adapterVerifier.getDeclaringClass().equals(pclz));
}

public boolean isImplementedBy(Class clz) {
return interfaceMethod.getDeclaringClass().isAssignableFrom(clz);
}
}
}

+ 168
- 0
proposal/sandbox/antlib/src/main/org/apache/tools/ant/TaskAdapter.java View File

@@ -0,0 +1,168 @@
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following 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
* <http://www.apache.org/>.
*/

package org.apache.tools.ant;

import java.lang.reflect.Method;



/**
* Use introspection to "adapt" an arbitrary Bean ( not extending Task, but with similar
* patterns).
*
* @author costin@dnt.ro
* @author j_a_fernandez@yahoo.com
*/
public class TaskAdapter extends Task implements RoleAdapter {

Object proxy;
/**
* Checks a class, whether it is suitable to be adapted by TaskAdapter.
*
* Checks conditions only, which are additionally required for a tasks
* adapted by TaskAdapter. Thus, this method should be called by
* {@link Project#checkTaskClass}.
*
* Throws a BuildException and logs as Project.MSG_ERR for
* conditions, that will cause the task execution to fail.
* Logs other suspicious conditions with Project.MSG_WARN.
*/
public static void checkTaskClass(final Class taskClass, final Project project) {
// This code is for backward compatibility
checkClass(taskClass, project);
}

/**
* Checks a class, whether it is suitable to be adapted.
*
* Checks conditions only, which are additionally required for a tasks
* adapted by TaskAdapter.
*
* Throws a BuildException and logs as Project.MSG_ERR for
* conditions, that will cause the task execution to fail.
* Logs other suspicious conditions with Project.MSG_WARN.
*/
public static void checkClass(final Class taskClass, final Project project) {
// don't have to check for interface, since then
// taskClass would be abstract too.
try {
final Method executeM = taskClass.getMethod( "execute", null );
// don't have to check for public, since
// getMethod finds public method only.
// don't have to check for abstract, since then
// taskClass would be abstract too.
if(!Void.TYPE.equals(executeM.getReturnType())) {
final String message = "return type of execute() should be void but was \""+executeM.getReturnType()+"\" in " + taskClass;
project.log(message, Project.MSG_WARN);
}
} catch(NoSuchMethodException e) {
final String message = "No public execute() in " + taskClass;
project.log(message, Project.MSG_ERR);
throw new BuildException(message);
}
}
/**
* Do the execution.
*/
public void execute() throws BuildException {
Method setProjectM = null;
try {
Class c = proxy.getClass();
setProjectM =
c.getMethod( "setProject", new Class[] {Project.class});
if(setProjectM != null) {
setProjectM.invoke(proxy, new Object[] {project});
}
} catch (NoSuchMethodException e) {
// ignore this if the class being used as a task does not have
// a set project method.
} catch( Exception ex ) {
log("Error setting project in " + proxy.getClass(),
Project.MSG_ERR);
throw new BuildException( ex );
}


Method executeM=null;
try {
Class c=proxy.getClass();
executeM=c.getMethod( "execute", new Class[0] );
if( executeM == null ) {
log("No public execute() in " + proxy.getClass(), Project.MSG_ERR);
throw new BuildException("No public execute() in " + proxy.getClass());
}
executeM.invoke(proxy, null);
return;
} catch( Exception ex ) {
log("Error in " + proxy.getClass(), Project.MSG_ERR);
throw new BuildException( ex );
}

}
/**
* Set the target object class
*/
public void setProxy(Object o) {
this.proxy = o;
}

public Object getProxy() {
return this.proxy ;
}

}

+ 475
- 0
proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Ant.java View File

@@ -0,0 +1,475 @@
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-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
* <http://www.apache.org/>.
*/

package org.apache.tools.ant.taskdefs;

import org.apache.tools.ant.Task;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectComponent;
import org.apache.tools.ant.BuildListener;
import org.apache.tools.ant.DefaultLogger;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.ProjectHelper;
import org.apache.tools.ant.util.FileUtils;
import java.io.File;
import java.io.PrintStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;

/**
* Call Ant in a sub-project
*
* <pre>
* &lt;target name=&quot;foo&quot; depends=&quot;init&quot;&gt;
* &lt;ant antfile=&quot;build.xml&quot; target=&quot;bar&quot; &gt;
* &lt;property name=&quot;property1&quot; value=&quot;aaaaa&quot; /&gt;
* &lt;property name=&quot;foo&quot; value=&quot;baz&quot; /&gt;
* &lt;/ant&gt;</SPAN>
* &lt;/target&gt;</SPAN>
*
* &lt;target name=&quot;bar&quot; depends=&quot;init&quot;&gt;
* &lt;echo message=&quot;prop is ${property1} ${foo}&quot; /&gt;
* &lt;/target&gt;
* </pre>
*
*
* @author costin@dnt.ro
*/
public class Ant extends Task {

/** the basedir where is executed the build file */
private File dir = null;
/** the build.xml file (can be absolute) in this case dir will be ignored */
private String antFile = null;
/** the target to call if any */
private String target = null;
/** the output */
private String output = null;
/** should we inherit properties from the parent ? */
private boolean inheritAll = true;
/** should we inherit references from the parent ? */
private boolean inheritRefs = false;
/** the properties to pass to the new project */
private Vector properties = new Vector();
/** the references to pass to the new project */
private Vector references = new Vector();

/** the temporary project created to run the build file */
private Project newProject;

/**
* If true, inherit all properties from parent Project
* If false, inherit only userProperties and those defined
* inside the ant call itself
*/
public void setInheritAll(boolean value) {
inheritAll = value;
}

/**
* If true, inherit all references from parent Project
* If false, inherit only those defined
* inside the ant call itself
*/
public void setInheritRefs(boolean value) {
inheritRefs = value;
}

public void init() {
newProject = new Project(project);
newProject.setJavaVersionProperty();
// newProject.addTaskDefinition("property",
// (Class)project.getTaskDefinitions().get("property"));
}

private void reinit() {
init();
final int count = properties.size();
for (int i = 0; i < count; i++) {
Property p = (Property) properties.elementAt(i);
Property newP = (Property) newProject.createTask("property");
newP.setName(p.getName());
if (p.getValue() != null) {
newP.setValue(p.getValue());
}
if (p.getFile() != null) {
newP.setFile(p.getFile());
}
if (p.getResource() != null) {
newP.setResource(p.getResource());
}
properties.setElementAt(newP, i);
}
}

private void initializeProject() {
Vector listeners = project.getBuildListeners();
final int count = listeners.size();
for (int i = 0; i < count; i++) {
newProject.addBuildListener((BuildListener)listeners.elementAt(i));
}

if (output != null) {
try {
PrintStream out = new PrintStream(new FileOutputStream(output));
DefaultLogger logger = new DefaultLogger();
logger.setMessageOutputLevel(Project.MSG_INFO);
logger.setOutputPrintStream(out);
logger.setErrorPrintStream(out);
newProject.addBuildListener(logger);
}
catch( IOException ex ) {
log( "Ant: Can't set output to " + output );
}
}

// Hashtable taskdefs = project.getTaskDefinitions();
// Enumeration et = taskdefs.keys();
// while (et.hasMoreElements()) {
// String taskName = (String) et.nextElement();
// if (taskName.equals("property")) {
// // we have already added this taskdef in #init
// continue;
// }
// Class taskClass = (Class) taskdefs.get(taskName);
// newProject.addTaskDefinition(taskName, taskClass);
// }

// Hashtable typedefs = project.getDataTypeDefinitions();
// Enumeration e = typedefs.keys();
// while (e.hasMoreElements()) {
// String typeName = (String) e.nextElement();
// Class typeClass = (Class) typedefs.get(typeName);
// newProject.addDataTypeDefinition(typeName, typeClass);
// }

// set user-defined or all properties from calling project
Hashtable prop1;
if (inheritAll) {
prop1 = project.getProperties();
} else {
prop1 = project.getUserProperties();

// set Java built-in properties separately,
// b/c we won't inherit them.
newProject.setSystemProperties();
}
Enumeration e = prop1.keys();
while (e.hasMoreElements()) {
String arg = (String) e.nextElement();
if ("basedir".equals(arg) || "ant.file".equals(arg)) {
// basedir and ant.file get special treatment in execute()
continue;
}
String value = (String) prop1.get(arg);
if (inheritAll){
newProject.setProperty(arg, value);
} else {
newProject.setUserProperty(arg, value);
}
}
}

protected void handleOutput(String line) {
if (newProject != null) {
newProject.demuxOutput(line, false);
} else {
super.handleOutput(line);
}
}
protected void handleErrorOutput(String line) {
if (newProject != null) {
newProject.demuxOutput(line, true);
} else {
super.handleErrorOutput(line);
}
}
/**
* Do the execution.
*/
public void execute() throws BuildException {
try {
if (newProject == null) {
reinit();
}
if ( (dir == null) && (inheritAll) ) {
dir = project.getBaseDir();
}

initializeProject();

if (dir != null) {
newProject.setBaseDir(dir);
newProject.setUserProperty("basedir" , dir.getAbsolutePath());
} else {
dir = project.getBaseDir();
}

overrideProperties();

if (antFile == null) {
antFile = "build.xml";
}

File file = FileUtils.newFileUtils().resolveFile(dir, antFile);
antFile = file.getAbsolutePath();

newProject.setUserProperty( "ant.file" , antFile );
ProjectHelper.configureProject(newProject, new File(antFile));
if (target == null) {
target = newProject.getDefaultTarget();
}

addReferences();

// Are we trying to call the target in which we are defined?
if (newProject.getBaseDir().equals(project.getBaseDir()) &&
newProject.getProperty("ant.file").equals(project.getProperty("ant.file")) &&
getOwningTarget() != null &&
target.equals(this.getOwningTarget().getName())) {

throw new BuildException("ant task calling its own parent target");
}

newProject.executeTarget(target);
} finally {
// help the gc
newProject = null;
}
}

/**
* Override the properties in the new project with the one
* explicitly defined as nested elements here.
*/
private void overrideProperties() throws BuildException {
Enumeration e = properties.elements();
while (e.hasMoreElements()) {
Property p = (Property) e.nextElement();
p.setProject(newProject);
p.execute();
}
}

/**
* Add the references explicitly defined as nested elements to the
* new project. Also copy over all references that don't override
* existing references in the new project if inheritall has been
* requested.
*/
private void addReferences() throws BuildException {
Hashtable thisReferences = (Hashtable) project.getReferences().clone();
Hashtable newReferences = newProject.getReferences();
Enumeration e;
if (references.size() > 0) {
for(e = references.elements(); e.hasMoreElements();) {
Reference ref = (Reference)e.nextElement();
String refid = ref.getRefId();
if (refid == null) {
throw new BuildException("the refid attribute is required for reference elements");
}
if (!thisReferences.containsKey(refid)) {
log("Parent project doesn't contain any reference '"
+ refid + "'",
Project.MSG_WARN);
continue;
}

thisReferences.remove(refid);
String toRefid = ref.getToRefid();
if (toRefid == null) {
toRefid = refid;
}
copyReference(refid, toRefid);
}
}

// Now add all references that are not defined in the
// subproject, if inheritRefs is true
if (inheritRefs) {
for(e = thisReferences.keys(); e.hasMoreElements();) {
String key = (String)e.nextElement();
if (newReferences.containsKey(key)) {
continue;
}
copyReference(key, key);
}
}
}

/**
* Try to clone and reconfigure the object referenced by oldkey in
* the parent project and add it to the new project with the key
* newkey.
*
* <p>If we cannot clone it, copy the referenced object itself and
* keep our fingers crossed.</p>
*/
private void copyReference(String oldKey, String newKey) {
Object orig = project.getReference(oldKey);
Class c = orig.getClass();
Object copy = orig;
try {
Method cloneM = c.getMethod("clone", new Class[0]);
if (cloneM != null) {
copy = cloneM.invoke(orig, new Object[0]);
}
} catch (Exception e) {
// not Clonable
}

if (copy instanceof ProjectComponent) {
((ProjectComponent) copy).setProject(newProject);
} else {
try {
Method setProjectM =
c.getMethod( "setProject", new Class[] {Project.class});
if(setProjectM != null) {
setProjectM.invoke(copy, new Object[] {newProject});
}
} catch (NoSuchMethodException e) {
// ignore this if the class being referenced does not have
// a set project method.
} catch(Exception e2) {
String msg = "Error setting new project instance for reference with id "
+ oldKey;
throw new BuildException(msg, e2, location);
}
}
newProject.addReference(newKey, copy);
}

/**
* ...
*/
public void setDir(File d) {
this.dir = d;
}

/**
* set the build file, it can be either absolute or relative.
* If it is absolute, <tt>dir</tt> will be ignored, if it is
* relative it will be resolved relative to <tt>dir</tt>.
*/
public void setAntfile(String s) {
// @note: it is a string and not a file to handle relative/absolute
// otherwise a relative file will be resolved based on the current
// basedir.
this.antFile = s;
}

/**
* set the target to execute. If none is defined it will
* execute the default target of the build file
*/
public void setTarget(String s) {
this.target = s;
}

public void setOutput(String s) {
this.output = s;
}

/** create a property to pass to the new project as a 'user property' */
public Property createProperty() {
if (newProject == null) {
reinit();
}
Property p = new Property(true);
p.setProject(newProject);
p.setTaskName("property");
properties.addElement( p );
return p;
}

/**
* create a reference element that identifies a data type that
* should be carried over to the new project.
*/
public void addReference(Reference r) {
references.addElement(r);
}

/**
* Helper class that implements the nested &lt;reference&gt;
* element of &lt;ant&gt; and &lt;antcall&gt;.
*/
public static class Reference
extends org.apache.tools.ant.types.Reference {

public Reference() {super();}
private String targetid=null;
public void setToRefid(String targetid) { this.targetid=targetid; }
public String getToRefid() { return targetid; }
}
}

+ 1
- 140
proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antjar.java View File

@@ -107,9 +107,6 @@ public class Antjar extends Jar {
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()));
@@ -130,7 +127,7 @@ public class Antjar extends Jar {
throws IOException, BuildException {
// If no antxml file is specified, it's an error.
if (libraryDescriptor == null) {
throw new BuildException("webxml attribute is required", location);
throw new BuildException("antxml attribute is required", location);
}

super.initZipOutputStream(zOut);
@@ -177,140 +174,4 @@ public class Antjar extends Jar {
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. <P>
*
* 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
}
}


+ 138
- 130
proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antlib.java View File

@@ -76,9 +76,11 @@ import java.io.*;
* @since ant1.5
*/
public class Antlib extends Task {
/*
* implements DeclaringTask
/**
* The named classloader to use.
* Defaults to the default classLoader.
*/
private String loaderId = "";

/**
* library attribute
@@ -177,6 +179,15 @@ public class Antlib extends Task {
this.file = file;
}

/**
* Set the ClassLoader to use for this library.
*
* @param id the id for the ClassLoader to use,
* if other than the default.
*/
public void setLoaderid(String id) {
this.loaderId = id;
}

/**
* Set whether to override any existing definitions.
@@ -189,8 +200,9 @@ public class Antlib extends Task {


/**
* 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.
* 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 useCurrentClassloader if true the current classloader will
* be used to load the definitions.
@@ -264,7 +276,7 @@ public class Antlib extends Task {
String msg = "You cannot specify both file and library.";
throw new BuildException(msg, location);
}
// For the time being libraries live in $ANT_HOME/lib.
// For the time being libraries live in $ANT_HOME/antlib.
// The idea being that we would not load all the jars there anymore
String home = project.getProperty("ant.home");

@@ -272,7 +284,7 @@ public class Antlib extends Task {
throw new BuildException("ANT_HOME not set as required.");
}

realFile = new File(new File(home, "lib"), library);
realFile = new File(new File(home, "antlib"), library);
}
else if (file == null) {
String msg = "Must specify either library or file attribute.";
@@ -406,8 +418,7 @@ public class Antlib extends Task {
if (classpath != null) {
clspath.append(classpath);
}
AntClassLoader al = new AntClassLoader(project, clspath, true);
return al;
return project.getSymbols().addToLoader(loaderId, clspath);
}


@@ -473,30 +484,6 @@ public class Antlib extends Task {
}


/**
* 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
@@ -516,6 +503,14 @@ public class Antlib extends Task {
*/
private Locator locator = null;

private int level = 0;

private SymbolTable symbols = null;

private String name = null;
private String className = null;
private String adapter = null;

/**
* Constructor for the AntLibraryHandler object
*
@@ -525,9 +520,9 @@ public class Antlib extends Task {
AntLibraryHandler(ClassLoader classloader, Properties als) {
this.classloader = classloader;
this.aliasMap = als;
this.symbols = project.getSymbols();
}


/**
* Sets the DocumentLocator attribute of the AntLibraryHandler
* object
@@ -538,6 +533,35 @@ public class Antlib extends Task {
this.locator = locator;
}

private void parseAttributes(String tag, AttributeList attrs)
throws SAXParseException {
name = null;
className = null;
adapter = 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 if ("role".equals(tag) && key.equals("adapter")) {
adapter = value;
}
else {
throw new SAXParseException("Unexpected attribute \""
+ key + "\"", locator);
}
}
if (name == null || className == null) {
String msg = "Underspecified " + tag + " declaration.";
throw new SAXParseException(msg, locator);
}
}

/**
* SAX callback handler
@@ -548,121 +572,105 @@ public class Antlib extends Task {
*/
public void startElement(String tag, AttributeList attrs)
throws SAXParseException {
level ++;
if ("antlib".equals(tag)) {
if (level > 1) {
throw new SAXParseException("Unexpected element: " + tag,
locator);
}
// 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);
}
if (level == 1) {
throw new SAXParseException("Missing antlib root element",
locator);
}

// Must have the two attributes declared
parseAttributes(tag, attrs);

try {
if ("role".equals(tag)) {
if (isRoleInUse(name)) {
String msg = "Cannot override role: " + name;
log(msg, Project.MSG_WARN);
return;
}
// Defining a new role
symbols.addRole(name, loadClass(className),
(adapter == null?
null : loadClass(adapter)));
return;
}

// Defining a new element kind
//check for name alias
String alias = aliasMap.getProperty(name);
if (alias != null) {
name = alias;
}
//catch an attempted override of an existing name
if (!override && isInUse(tag, name)) {
String msg = "Cannot override " + tag + ": " + name;
log(msg, Project.MSG_WARN);
return;
}
symbols.add(tag, name, loadClass(className));
}
catch(BuildException be) {
throw new SAXParseException(be.getMessage(), locator, be);
}
}

public void endElement(String tag) {
level--;
}

private Class loadClass(String className)
throws SAXParseException {
try {
//load the named class
Class cls;
if(classloader==null) {
cls=Class.forName(className);
}
else {
cls=classloader.loadClass(className);
}
return 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);
}
}

/**
* test for a name being in use already
* test for a name being in use already on this role
*
* @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);
private boolean isInUse(String role, String name) {
return (symbols.get(role, 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".
* test for a role name being in use already
*
* @param publicId public ID (ignored)
* @param systemId system ID (matched against)
* @return local DTD instance
* @param name the name to test
* @return true if it is a task or a datatype
*/
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;
private boolean isRoleInUse(String name) {
return (symbols.getRole(name) != null);
}

//end inner class AntLibraryHandler
}



Loading…
Cancel
Save