Browse Source

for Jose Alberto

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271672 13f79535-47bb-0310-9956-ffa450edef68
master
Erik Hatcher 23 years ago
parent
commit
8dfa7abd4d
7 changed files with 452 additions and 365 deletions
  1. +119
    -140
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/Project.java
  2. +0
    -5
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/RoleAdapter.java
  3. +143
    -211
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/SymbolTable.java
  4. +0
    -1
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/TaskAdapter.java
  5. +137
    -0
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/antlib.xml
  6. +23
    -1
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Ant.java
  7. +30
    -7
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antlib.java

+ 119
- 140
proposal/sandbox/antlib/src/main/org/apache/tools/ant/Project.java View File

@@ -63,15 +63,12 @@ import java.util.Properties;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Stack; import java.util.Stack;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;




import org.apache.tools.ant.types.DataTypeAdapterTask; import org.apache.tools.ant.types.DataTypeAdapterTask;
import org.apache.tools.ant.types.FilterSet; import org.apache.tools.ant.types.FilterSet;
import org.apache.tools.ant.types.FilterSetCollection; import org.apache.tools.ant.types.FilterSetCollection;
import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.types.Path;


/** /**
* Central representation of an Ant project. This class defines a * Central representation of an Ant project. This class defines a
@@ -171,26 +168,30 @@ public class Project {
fileUtils = FileUtils.newFileUtils(); fileUtils = FileUtils.newFileUtils();
symbols = new SymbolTable(); symbols = new SymbolTable();
symbols.setProject(this); symbols.setProject(this);
loadDefinitions();
} }
/** /**
* create a new ant project that inherits from caler project * create a new ant project that inherits from caler project
* @param p the calling project * @param p the calling project
*/ */
private Project(Project p) {
public Project(Project p) {
fileUtils = FileUtils.newFileUtils(); fileUtils = FileUtils.newFileUtils();
symbols = new SymbolTable(p.getSymbols());
symbols = new SymbolTable(p);
symbols.setProject(this); symbols.setProject(this);
} }
/** /**
* Loads the core definitions into the Root project.
* Initialise the project.
*
* This involves setting the default task definitions and loading the
* system properties.
*/ */
private void loadDefinitions() {
// Initialize symbol table just in case
symbols.addRole(TASK_ROLE, TaskContainer.class, TaskAdapter.class);
symbols.addRole(DATATYPE_ROLE, TaskContainer.class,
public void init() throws BuildException {
setJavaVersionProperty();
// Initialize simbol table just in case
symbols.addRole("task", TaskContainer.class, TaskAdapter.class);
symbols.addRole("datatype", TaskContainer.class,
DataTypeAdapterTask.class); DataTypeAdapterTask.class);


String defs = "/org/apache/tools/ant/taskdefs/defaults.properties"; String defs = "/org/apache/tools/ant/taskdefs/defaults.properties";
@@ -250,23 +251,7 @@ public class Project {
} catch (IOException ioe) { } catch (IOException ioe) {
throw new BuildException("Can't load default datatype list"); throw new BuildException("Can't load default datatype list");
} }
}

/**
* Creates a subproject of the current project.
*/
public Project createSubProject() {
return new Project(this);
}


/**
* Initialise the project.
*
* This involves setting the default task definitions and loading the
* system properties.
*/
public void init() throws BuildException {
setJavaVersionProperty();
setSystemProperties(); setSystemProperties();
} }


@@ -293,7 +278,7 @@ public class Project {
/** /**
* Get the symbols associated with this project. * Get the symbols associated with this project.
*/ */
private SymbolTable getSymbols() { // Package protected on purpose
public SymbolTable getSymbols() {
return symbols; return symbols;
} }


@@ -622,20 +607,6 @@ public class Project {
log("Detected OS: " + System.getProperty("os.name"), MSG_VERBOSE); log("Detected OS: " + System.getProperty("os.name"), MSG_VERBOSE);
} }


/**
* turn all the system properties into ant properties.
* user properties still override these values
*/
public void setSystemProperties() {
Properties systemP = System.getProperties();
Enumeration e = systemP.keys();
while (e.hasMoreElements()) {
Object name = e.nextElement();
String value = systemP.get(name).toString();
this.setPropertyInternal(name.toString(), value);
}
}

public ClassLoader addToLoader(String loader, Path path) { public ClassLoader addToLoader(String loader, Path path) {
return symbols.addToLoader(loader, path); return symbols.addToLoader(loader, path);
} }
@@ -676,6 +647,20 @@ public class Project {
return (symbols.get(role, name) != null); return (symbols.get(role, name) != null);
} }
/**
* turn all the system properties into ant properties.
* user properties still override these values
*/
public void setSystemProperties() {
Properties systemP = System.getProperties();
Enumeration e = systemP.keys();
while (e.hasMoreElements()) {
Object name = e.nextElement();
String value = systemP.get(name).toString();
this.setPropertyInternal(name.toString(), value);
}
}

/** /**
* add a new task definition, complain if there is an overwrite attempt * add a new task definition, complain if there is an overwrite attempt
* @param taskName name of the task * @param taskName name of the task
@@ -685,14 +670,21 @@ public class Project {
*/ */
public void addTaskDefinition(String taskName, Class taskClass) public void addTaskDefinition(String taskName, Class taskClass)
throws BuildException { throws BuildException {
addDefinitionOnRole(TASK_ROLE, taskName, taskClass);
Class old = symbols.add("task", taskName, taskClass);
if (null != old && !old.equals(taskClass)) {
invalidateCreatedTasks(taskName);
}

String msg =
" +User task: " + taskName + " " + taskClass.getName();
log(msg, MSG_DEBUG);
checkTaskClass(taskClass);
} }


/** /**
* Checks a class, whether it is suitable for serving as ant task. * Checks a class, whether it is suitable for serving as ant task.
* @throws BuildException and logs as Project.MSG_ERR for * @throws BuildException and logs as Project.MSG_ERR for
* conditions, that will cause the task execution to fail. * conditions, that will cause the task execution to fail.
* @deprecated this is done now when added to SymbolTable
*/ */
public void checkTaskClass(final Class taskClass) throws BuildException { public void checkTaskClass(final Class taskClass) throws BuildException {
if( !Task.class.isAssignableFrom(taskClass) ) { if( !Task.class.isAssignableFrom(taskClass) ) {
@@ -704,7 +696,7 @@ public class Project {
* get the current task definition hashtable * get the current task definition hashtable
*/ */
public Hashtable getTaskDefinitions() { public Hashtable getTaskDefinitions() {
return symbols.getDefinitions(TASK_ROLE);
return symbols.getTaskDefinitions();
} }


/** /**
@@ -713,14 +705,18 @@ public class Project {
* @param typeClass full datatype classname * @param typeClass full datatype classname
*/ */
public void addDataTypeDefinition(String typeName, Class typeClass) { public void addDataTypeDefinition(String typeName, Class typeClass) {
addDefinitionOnRole(DATATYPE_ROLE, typeName, typeClass);
symbols.add("datatype", typeName, typeClass);

String msg =
" +User datatype: " + typeName + " " + typeClass.getName();
log(msg, MSG_DEBUG);
} }


/** /**
* get the current task definition hashtable * get the current task definition hashtable
*/ */
public Hashtable getDataTypeDefinitions() { public Hashtable getDataTypeDefinitions() {
return symbols.getDefinitions(DATATYPE_ROLE);
return symbols.getDataTypeDefinitions();
} }


/** /**
@@ -748,7 +744,7 @@ public class Project {
* in the project. * in the project.
* @see Project#addOrReplaceTarget to replace existing Targets. * @see Project#addOrReplaceTarget to replace existing Targets.
*/ */
public void addTarget(String targetName, Target target)
public void addTarget(String targetName, Target target)
throws BuildException { throws BuildException {
if (targets.get(targetName) != null) { if (targets.get(targetName) != null) {
throw new BuildException("Duplicate target: `"+targetName+"'"); throw new BuildException("Duplicate target: `"+targetName+"'");
@@ -784,88 +780,6 @@ public class Project {
return targets; return targets;
} }


/**
* Create a new element instance on a Role
* @param role name of the role to use
* @param type name of the element to create
* @return null if element unknown on this role
*/
public Object createForRole(String role, String type) {
SymbolTable.Factory f = symbols.get(role, type);
if (f == null) return null;

try {
Object o = f.create(this);
// Do special book keeping for ProjectComponents
if ( o instanceof ProjectComponent ) {
((ProjectComponent)o).setProject(this);
if (o instanceof Task) {
Task task = (Task) o;
task.setTaskType(type);
// set default value, can be changed by the user
task.setTaskName(type);
addCreatedTask(type, task);
}
}
String msg = " +" + role + ": " + type;
log (msg, MSG_DEBUG);
return o;
}
catch (Throwable t) {
String msg = "Could not create " + role + " of type: "
+ type + " due to " + t;
throw new BuildException(msg, t);
}
}

/**
*
*/
public Object createInRole(Object container, String type) {
Class clz = container.getClass();
String roles[] = symbols.findRoles(clz);
Object theOne = null;
Method add = null;

for(int i = 0; i < roles.length; i++) {
Object o = createForRole(roles[i], type);
if (o != null) {
if (theOne != null) {
String msg = "Element " + type +
" is ambiguous for container " + clz.getName();
if (theOne instanceof RoleAdapter)
theOne = ((RoleAdapter)theOne).getProxy();
if (o instanceof RoleAdapter)
o = ((RoleAdapter)o).getProxy();
log(msg, MSG_ERR);
log("cannot distinguish between " +
theOne.getClass().getName() +
" and " + o.getClass().getName(), MSG_ERR);
throw new BuildException(msg);
}
theOne = o;
add = symbols.getRole(roles[i]).getInterfaceMethod();
}
}
if (theOne != null) {
try {
add.invoke(container, new Object[]{theOne});
}
catch(InvocationTargetException ite) {
if (ite.getTargetException() instanceof BuildException) {
throw (BuildException)ite.getTargetException();
}
throw new BuildException(ite.getTargetException());
}
catch(Exception e) {
throw new BuildException(e);
}
}
return theOne;
}

/** /**
* create a new task instance * create a new task instance
* @param taskType name of the task * @param taskType name of the task
@@ -873,7 +787,39 @@ public class Project {
* @return null if the task name is unknown * @return null if the task name is unknown
*/ */
public Task createTask(String taskType) throws BuildException { public Task createTask(String taskType) throws BuildException {
return (Task) createForRole(TASK_ROLE, taskType);
Class c = symbols.get("task", taskType);

if (c == null) {
return null;
}
try {
Object o = c.newInstance();
Task task = null;
if( o instanceof Task ) {
task=(Task)o;
} else {
// "Generic" Bean - use the setter pattern
// and an Adapter
TaskAdapter taskA=new TaskAdapter();
taskA.setProxy( o );
task=taskA;
}
task.setProject(this);
task.setTaskType(taskType);

// set default value, can be changed by the user
task.setTaskName(taskType);

String msg = " +Task: " + taskType;
log (msg, MSG_DEBUG);
addCreatedTask(taskType, task);
return task;
} catch (Throwable t) {
String msg = "Could not create task of type: "
+ taskType + " due to " + t;
throw new BuildException(msg, t);
}
} }


/** /**
@@ -917,11 +863,47 @@ public class Project {
* @return null if the datatype name is unknown * @return null if the datatype name is unknown
*/ */
public Object createDataType(String typeName) throws BuildException { public Object createDataType(String typeName) throws BuildException {
// This is to make the function backward compatible
// Since we know if it returning an adapter for it
DataTypeAdapterTask dt =
(DataTypeAdapterTask) createForRole(DATATYPE_ROLE, typeName);
return (dt != null? dt.getProxy() : null);
Class c = symbols.get("datatype", typeName);

if (c == null) {
return null;
}

try {
java.lang.reflect.Constructor ctor = null;
boolean noArg = false;
// DataType can have a "no arg" constructor or take a single
// Project argument.
try {
ctor = c.getConstructor(new Class[0]);
noArg = true;
} catch (NoSuchMethodException nse) {
ctor = c.getConstructor(new Class[] {Project.class});
noArg = false;
}

Object o = null;
if (noArg) {
o = ctor.newInstance(new Object[0]);
} else {
o = ctor.newInstance(new Object[] {this});
}
if (o instanceof ProjectComponent) {
((ProjectComponent)o).setProject(this);
}
String msg = " +DataType: " + typeName;
log (msg, MSG_DEBUG);
return o;
} catch (java.lang.reflect.InvocationTargetException ite) {
Throwable t = ite.getTargetException();
String msg = "Could not create datatype of type: "
+ typeName + " due to " + t;
throw new BuildException(msg, t);
} catch (Throwable t) {
String msg = "Could not create datatype of type: "
+ typeName + " due to " + t;
throw new BuildException(msg, t);
}
} }


/** /**
@@ -1288,10 +1270,7 @@ public class Project {
} }


public void addReference(String name, Object value) { public void addReference(String name, Object value) {
Object o = references.get(name);
if (null != o && o != value
&& (!(o instanceof RoleAdapter)
|| ((RoleAdapter)o).getProxy() != value)) {
if (null != references.get(name)) {
log("Overriding previous definition of reference to " + name, log("Overriding previous definition of reference to " + name,
MSG_WARN); MSG_WARN);
} }


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

@@ -55,11 +55,6 @@ package org.apache.tools.ant;


public interface RoleAdapter { public interface RoleAdapter {


/**
* Obtain the id in case it is needed.
*/
public void setId(String id);

/** /**
* Set the object being adapted. * Set the object being adapted.
* @param o the object being adapted * @param o the object being adapted


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

@@ -54,7 +54,6 @@
package org.apache.tools.ant; package org.apache.tools.ant;


import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.*; import java.util.*;
@@ -97,8 +96,8 @@ public class SymbolTable {
* from that defined in the calling Project. * from that defined in the calling Project.
* @param p the calling project * @param p the calling project
*/ */
public SymbolTable(SymbolTable st) {
parentTable = st;
public SymbolTable(Project p) {
parentTable = p.getSymbols();
} }


/** /**
@@ -109,54 +108,6 @@ public class SymbolTable {
this.project = p; this.project = p;
} }


/**
* 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;
}
/** /**
* Find all the roles supported by a Class * Find all the roles supported by a Class
* on this symbol table. * on this symbol table.
@@ -182,13 +133,13 @@ public class SymbolTable {
list.addElement(role); list.addElement(role);
} }
} }
if (parentTable != null) parentTable.findRoles(clz, list);
if (parentTable != null) findRoles(clz, list);
} }
/** /**
* Get the Role definition * Get the Role definition
* @param role the name of the role * @param role the name of the role
* @return the Role description
* @return the method used to support objects on this role
*/ */
public Role getRole(String role) { public Role getRole(String role) {
Role r = (Role) roles.get(role); Role r = (Role) roles.get(role);
@@ -220,6 +171,112 @@ public class SymbolTable {
return (old != null); 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. * Add a new type of element to a role.
* @param role the role for this Class. * @param role the role for this Class.
@@ -234,13 +291,13 @@ public class SymbolTable {
throw new BuildException("Unknown role: " + role); throw new BuildException("Unknown role: " + role);
} }
// Check if it is already defined // Check if it is already defined
Factory old = get(role, name);
Class old = get(role, name);
if (old != null) { if (old != null) {
if (old.getOriginalClass().equals(clz)) {
if (old.equals(clz)) {
project.log("Ignoring override for "+ role + " " + name project.log("Ignoring override for "+ role + " " + name
+ ", it is already defined by the same class.", + ", it is already defined by the same class.",
project.MSG_VERBOSE); project.MSG_VERBOSE);
return old.getOriginalClass();
return old;
} }
else { else {
project.log("Trying to override old definition of " + project.log("Trying to override old definition of " +
@@ -248,33 +305,26 @@ public class SymbolTable {
project.MSG_WARN); project.MSG_WARN);
} }
} }
Factory f = checkClass(clz);
checkClass(clz);
// Check that the Class is compatible with the role definition // Check that the Class is compatible with the role definition
f = r.verifyAdaptability(role, f);
r.verifyAdaptability(role, clz);
// Record the new type // Record the new type
Hashtable defTable = (Hashtable)defs.get(role); Hashtable defTable = (Hashtable)defs.get(role);
if (defTable == null) { if (defTable == null) {
defTable = new Hashtable(); defTable = new Hashtable();
defs.put(role, defTable); defs.put(role, defTable);
} }
defTable.put(name, f);

String msg =
" +User " + role + ": " + name + " " + clz.getName();
project.log(msg, project.MSG_DEBUG);
return (old != null ? old.getOriginalClass() : null);
defTable.put(name, clz);
return old;
} }


/** /**
* Checks a class, whether it is suitable for serving in ANT. * Checks a class, whether it is suitable for serving in ANT.
* @return the factory to use when instantiating the class
* @throws BuildException and logs as Project.MSG_ERR for * @throws BuildException and logs as Project.MSG_ERR for
* conditions, that will cause execution to fail. * conditions, that will cause execution to fail.
*/ */
Factory checkClass(final Class clz) // Package on purpose
void checkClass(final Class clz)
throws BuildException { throws BuildException {
if (clz == null) return null;

if(!Modifier.isPublic(clz.getModifiers())) { if(!Modifier.isPublic(clz.getModifiers())) {
final String message = clz + " is not public"; final String message = clz + " is not public";
project.log(message, Project.MSG_ERR); project.log(message, Project.MSG_ERR);
@@ -292,37 +342,8 @@ public class SymbolTable {
// getConstructor finds public constructors only. // getConstructor finds public constructors only.
try { try {
clz.getConstructor(new Class[0]); clz.getConstructor(new Class[0]);
return new Factory(){
public Object create(Project p) {
try {
return clz.newInstance();
}
catch(Exception e) {
throw new BuildException(e);
}
}

public Class getOriginalClass() {
return clz;
}
};
} catch (NoSuchMethodException nse) { } catch (NoSuchMethodException nse) {
final Constructor c =
clz.getConstructor(new Class[] {Project.class});
return new Factory(){
public Object create(Project p) {
try {
return c.newInstance(new Object[]{p});
}
catch(Exception e) {
throw new BuildException(e);
}
}

public Class getOriginalClass() {
return clz;
}
};
clz.getConstructor(new Class[] {Project.class});
} }
} catch(NoSuchMethodException e) { } catch(NoSuchMethodException e) {
final String message = final String message =
@@ -338,11 +359,11 @@ public class SymbolTable {
* @param name the name of the element to sea * @param name the name of the element to sea
* @return the Class implementation * @return the Class implementation
*/ */
public Factory get(String role, String name) {
public Class get(String role, String name) {
Hashtable defTable = (Hashtable)defs.get(role); Hashtable defTable = (Hashtable)defs.get(role);
if (defTable != null) { if (defTable != null) {
Factory f = (Factory)defTable.get(name);
if (f != null) return f;
Class clz = (Class)defTable.get(name);
if (clz != null) return clz;
} }
if (parentTable != null) { if (parentTable != null) {
return parentTable.get(role, name); return parentTable.get(role, name);
@@ -351,12 +372,19 @@ public class SymbolTable {
} }


/** /**
* Get a Hashtable that is usable for manipulating elements on Role.
* @param role the role of the elements in the table
* Get a Hashtable that is usable for manipulating Tasks,
* @return a Hashtable that delegates to the Symbol table. * @return a Hashtable that delegates to the Symbol table.
*/ */
Hashtable getDefinitions(String role) { // package scope on purpose
return new SymbolHashtable(role);
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");
} }


/** /**
@@ -374,43 +402,16 @@ public class SymbolTable {
} }


public synchronized Object get(Object key) { public synchronized Object get(Object key) {
Factory f = SymbolTable.this.get(role, (String)key);
return (f == null? null : f.getOriginalClass());
return SymbolTable.this.get(role, (String)key);
} }
} }


/**
* Factory for creating ANT objects.
* Class objects are not instanciated directly but through a Factory
* which is able to resolve issues such as proxys and such.
*/
public static interface Factory {
/**
* Creates an object for the Role
* @param the project in which it is created
* @return the instantiated object with a proxy if necessary
*/
public Object create(Project p);

/**
* Creates an object for the Role, adapted if necessary
* for a particular interface.
*/
// public Object adaptFor(Class clz, Project p, Object o);

/**
* The original class of the object without proxy.
*/
public Class getOriginalClass();
}

/** /**
* The definition of a role * The definition of a role
*/ */
public class Role { public class Role {
private Method interfaceMethod; private Method interfaceMethod;
private Method adapterVerifier; private Method adapterVerifier;
private Factory adapterFactory;
/** /**
* Creates a new Role object * Creates a new Role object
@@ -419,7 +420,6 @@ public class SymbolTable {
*/ */
Role(Class roleClz, Class adapterClz) { Role(Class roleClz, Class adapterClz) {
interfaceMethod = validInterface(roleClz); interfaceMethod = validInterface(roleClz);
adapterFactory = checkClass(adapterClz);
adapterVerifier = validAdapter(adapterClz, interfaceMethod); adapterVerifier = validAdapter(adapterClz, interfaceMethod);
} }


@@ -433,11 +433,12 @@ public class SymbolTable {
/** /**
* Instantiate a new adapter for this role. * Instantiate a new adapter for this role.
*/ */
public RoleAdapter createAdapter(Project p) {
if (adapterFactory == null) return null;
public RoleAdapter createAdapter() {
if (adapterVerifier == null) return null;
try { try {
return (RoleAdapter) adapterFactory.create(p);
return (RoleAdapter)
adapterVerifier.getDeclaringClass().newInstance();
} }
catch(BuildException be) { catch(BuildException be) {
throw be; throw be;
@@ -450,12 +451,11 @@ public class SymbolTable {
/** /**
* Verify if the class can be adapted to use by the role * Verify if the class can be adapted to use by the role
* @param role the name of the role to verify * @param role the name of the role to verify
* @param f the factory for the class to verify
* @param clz the class to verify
*/ */
public Factory verifyAdaptability(String role, final Factory f) {
final Class clz = f.getOriginalClass();
public void verifyAdaptability(String role, Class clz) {
if (interfaceMethod.getParameterTypes()[0].isAssignableFrom(clz)) { if (interfaceMethod.getParameterTypes()[0].isAssignableFrom(clz)) {
return f;
return;
} }
if (adapterVerifier == null) { if (adapterVerifier == null) {
String msg = "Class " + clz.getName() + String msg = "Class " + clz.getName() +
@@ -464,18 +464,8 @@ public class SymbolTable {
} }
try { try {
try { try {
adapterVerifier.invoke(null, new Object[]{clz, project});
return new Factory(){
public Object create(Project p) {
RoleAdapter ra = createAdapter(p);
ra.setProxy(f.create(p));
return ra;
}

public Class getOriginalClass() {
return clz;
}
};
adapterVerifier.invoke(null,
new Object[]{clz, project});
} }
catch (InvocationTargetException ite) { catch (InvocationTargetException ite) {
throw ite.getTargetException(); throw ite.getTargetException();
@@ -497,63 +487,5 @@ public class SymbolTable {
public boolean isImplementedBy(Class clz) { public boolean isImplementedBy(Class clz) {
return interfaceMethod.getDeclaringClass().isAssignableFrom(clz); return interfaceMethod.getDeclaringClass().isAssignableFrom(clz);
} }

/**
* 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;
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);
}
}
} }
} }

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

@@ -165,5 +165,4 @@ public class TaskAdapter extends Task implements RoleAdapter {
return this.proxy ; return this.proxy ;
} }


public void setId(String id) {}
} }

+ 137
- 0
proposal/sandbox/antlib/src/main/org/apache/tools/ant/antlib.xml View File

@@ -0,0 +1,137 @@
<?xml version='1.0' ?>
<!--
* 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/>.
-->
<antlib version="1.5" >
<task name="mkdir" class="org.apache.tools.ant.taskdefs.Mkdir"/>
<task name="javac" class="org.apache.tools.ant.taskdefs.Javac"/>
<task name="chmod" class="org.apache.tools.ant.taskdefs.Chmod"/>
<task name="delete" class="org.apache.tools.ant.taskdefs.Delete"/>
<task name="copy" class="org.apache.tools.ant.taskdefs.Copy"/>
<task name="move" class="org.apache.tools.ant.taskdefs.Move"/>
<task name="jar" class="org.apache.tools.ant.taskdefs.Jar"/>
<task name="rmic" class="org.apache.tools.ant.taskdefs.Rmic"/>
<task name="cvs" class="org.apache.tools.ant.taskdefs.Cvs"/>
<task name="unzip" class="org.apache.tools.ant.taskdefs.Expand"/>
<task name="unjar" class="org.apache.tools.ant.taskdefs.Expand"/>
<task name="unwar" class="org.apache.tools.ant.taskdefs.Expand"/>
<task name="echo" class="org.apache.tools.ant.taskdefs.Echo"/>
<task name="javadoc" class="org.apache.tools.ant.taskdefs.Javadoc"/>
<task name="zip" class="org.apache.tools.ant.taskdefs.Zip"/>
<task name="gzip" class="org.apache.tools.ant.taskdefs.GZip"/>
<task name="gunzip" class="org.apache.tools.ant.taskdefs.GUnzip"/>
<task name="replace" class="org.apache.tools.ant.taskdefs.Replace"/>
<task name="java" class="org.apache.tools.ant.taskdefs.Java"/>
<task name="tstamp" class="org.apache.tools.ant.taskdefs.Tstamp"/>
<task name="property" class="org.apache.tools.ant.taskdefs.Property"/>
<task name="taskdef" class="org.apache.tools.ant.taskdefs.Taskdef"/>
<task name="ant" class="org.apache.tools.ant.taskdefs.Ant"/>
<task name="exec" class="org.apache.tools.ant.taskdefs.ExecTask"/>
<task name="tar" class="org.apache.tools.ant.taskdefs.Tar"/>
<task name="untar" class="org.apache.tools.ant.taskdefs.Untar"/>
<task name="available" class="org.apache.tools.ant.taskdefs.Available"/>
<task name="filter" class="org.apache.tools.ant.taskdefs.Filter"/>
<task name="fixcrlf" class="org.apache.tools.ant.taskdefs.FixCRLF"/>
<task name="patch" class="org.apache.tools.ant.taskdefs.Patch"/>
<task name="style" class="org.apache.tools.ant.taskdefs.XSLTProcess"/>
<task name="touch" class="org.apache.tools.ant.taskdefs.Touch"/>
<task name="signjar" class="org.apache.tools.ant.taskdefs.SignJar"/>
<task name="genkey" class="org.apache.tools.ant.taskdefs.GenerateKey"/>
<task name="antstructure" class="org.apache.tools.ant.taskdefs.AntStructure"/>
<task name="execon" class="org.apache.tools.ant.taskdefs.ExecuteOn"/>
<task name="antcall" class="org.apache.tools.ant.taskdefs.CallTarget"/>
<task name="sql" class="org.apache.tools.ant.taskdefs.SQLExec"/>
<task name="mail" class="org.apache.tools.ant.taskdefs.email.EmailTask"/>
<task name="fail" class="org.apache.tools.ant.taskdefs.Exit"/>
<task name="war" class="org.apache.tools.ant.taskdefs.War"/>
<task name="uptodate" class="org.apache.tools.ant.taskdefs.UpToDate"/>
<task name="apply" class="org.apache.tools.ant.taskdefs.Transform"/>
<task name="record" class="org.apache.tools.ant.taskdefs.Recorder"/>
<task name="cvspass" class="org.apache.tools.ant.taskdefs.CVSPass"/>
<task name="typedef" class="org.apache.tools.ant.taskdefs.Typedef"/>
<task name="sleep" class="org.apache.tools.ant.taskdefs.Sleep"/>
<task name="pathconvert" class="org.apache.tools.ant.taskdefs.PathConvert"/>
<task name="ear" class="org.apache.tools.ant.taskdefs.Ear"/>
<task name="parallel" class="org.apache.tools.ant.taskdefs.Parallel"/>
<task name="sequential" class="org.apache.tools.ant.taskdefs.Sequential"/>
<task name="condition" class="org.apache.tools.ant.taskdefs.ConditionTask"/>
<task name="dependset" class="org.apache.tools.ant.taskdefs.DependSet"/>
<task name="bzip2" class="org.apache.tools.ant.taskdefs.BZip2"/>
<task name="bunzip2" class="org.apache.tools.ant.taskdefs.BUnzip2"/>
<task name="checksum" class="org.apache.tools.ant.taskdefs.Checksum"/>
<task name="waitfor" class="org.apache.tools.ant.taskdefs.WaitFor"/>
<task name="input" class="org.apache.tools.ant.taskdefs.Input"/>
<task name="loadfile" class="org.apache.tools.ant.taskdefs.LoadFile"/>
<task name="manifest" class="org.apache.tools.ant.taskdefs.Manifest"/>
<task name="antjar" class="org.apache.tools.ant.taskdefs.Antjar"/>
<task name="antlib" class="org.apache.tools.ant.taskdefs.Antlib"/>

<data-type name="path" class="org.apache.tools.ant.types.Path"/>
<data-type name="fileset" class="org.apache.tools.ant.types.FileSet"/>
<data-type name="filelist" class="org.apache.tools.ant.types.FileList"/>
<data-type name="patternset" class="org.apache.tools.ant.types.PatternSet"/>
<data-type name="mapper" class="org.apache.tools.ant.types.Mapper"/>
<data-type name="filterset" class="org.apache.tools.ant.types.FilterSet"/>
<data-type name="description" class="org.apache.tools.ant.types.Description"/>
<data-type name="substitution" class="org.apache.tools.ant.types.Substitution"/>
<data-type name="regexp" class="org.apache.tools.ant.types.RegularExpression"/>

<!-- deprecated ant tasks (kept for back compatibility) -->

<task name="javadoc2" class="org.apache.tools.ant.taskdefs.Javadoc"/>
<task name="copydir" class="org.apache.tools.ant.taskdefs.Copydir"/>
<task name="copyfile" class="org.apache.tools.ant.taskdefs.Copyfile"/>
<task name="deltree" class="org.apache.tools.ant.taskdefs.Deltree"/>
<task name="rename" class="org.apache.tools.ant.taskdefs.Rename"/>

</antlib>

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

@@ -138,8 +138,10 @@ public class Ant extends Task {
} }


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


private void reinit() { private void reinit() {
@@ -183,6 +185,26 @@ public class Ant extends Task {
} }
} }


// 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 // set user-defined or all properties from calling project
Hashtable prop1; Hashtable prop1;
if (inheritAll) { if (inheritAll) {


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

@@ -418,7 +418,7 @@ public class Antlib extends Task {
if (classpath != null) { if (classpath != null) {
clspath.append(classpath); clspath.append(classpath);
} }
return project.addToLoader(loaderId, clspath);
return project.getSymbols().addToLoader(loaderId, clspath);
} }




@@ -505,6 +505,8 @@ public class Antlib extends Task {


private int level = 0; private int level = 0;


private SymbolTable symbols = null;

private String name = null; private String name = null;
private String className = null; private String className = null;
private String adapter = null; private String adapter = null;
@@ -518,6 +520,7 @@ public class Antlib extends Task {
AntLibraryHandler(ClassLoader classloader, Properties als) { AntLibraryHandler(ClassLoader classloader, Properties als) {
this.classloader = classloader; this.classloader = classloader;
this.aliasMap = als; this.aliasMap = als;
this.symbols = project.getSymbols();
} }


/** /**
@@ -588,15 +591,15 @@ public class Antlib extends Task {


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


@@ -607,12 +610,12 @@ public class Antlib extends Task {
name = alias; name = alias;
} }
//catch an attempted override of an existing name //catch an attempted override of an existing name
if (!override && project.isDefinedOnRole(tag, name)) {
if (!override && isInUse(tag, name)) {
String msg = "Cannot override " + tag + ": " + name; String msg = "Cannot override " + tag + ": " + name;
log(msg, Project.MSG_WARN); log(msg, Project.MSG_WARN);
return; return;
} }
project.addDefinitionOnRole(tag, name, loadClass(className));
symbols.add(tag, name, loadClass(className));
} }
catch(BuildException be) { catch(BuildException be) {
throw new SAXParseException(be.getMessage(), locator, be); throw new SAXParseException(be.getMessage(), locator, be);
@@ -648,6 +651,26 @@ public class Antlib extends Task {
} }
} }


/**
* 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 isInUse(String role, String name) {
return (symbols.get(role, name) != null);
}

/**
* test for a role name being in use already
*
* @param name the name to test
* @return true if it is a task or a datatype
*/
private boolean isRoleInUse(String name) {
return (symbols.getRole(name) != null);
}

//end inner class AntLibraryHandler //end inner class AntLibraryHandler
} }




Loading…
Cancel
Save