git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271672 13f79535-47bb-0310-9956-ffa450edef68master
@@ -63,15 +63,12 @@ import java.util.Properties; | |||
import java.util.Enumeration; | |||
import java.util.Stack; | |||
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.FilterSet; | |||
import org.apache.tools.ant.types.FilterSetCollection; | |||
import org.apache.tools.ant.util.FileUtils; | |||
import org.apache.tools.ant.types.Path; | |||
/** | |||
* Central representation of an Ant project. This class defines a | |||
@@ -171,26 +168,30 @@ public class Project { | |||
fileUtils = FileUtils.newFileUtils(); | |||
symbols = new SymbolTable(); | |||
symbols.setProject(this); | |||
loadDefinitions(); | |||
} | |||
/** | |||
* create a new ant project that inherits from caler project | |||
* @param p the calling project | |||
*/ | |||
private Project(Project p) { | |||
public Project(Project p) { | |||
fileUtils = FileUtils.newFileUtils(); | |||
symbols = new SymbolTable(p.getSymbols()); | |||
symbols = new SymbolTable(p); | |||
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); | |||
String defs = "/org/apache/tools/ant/taskdefs/defaults.properties"; | |||
@@ -250,23 +251,7 @@ public class Project { | |||
} catch (IOException ioe) { | |||
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(); | |||
} | |||
@@ -293,7 +278,7 @@ public class Project { | |||
/** | |||
* Get the symbols associated with this project. | |||
*/ | |||
private SymbolTable getSymbols() { // Package protected on purpose | |||
public SymbolTable getSymbols() { | |||
return symbols; | |||
} | |||
@@ -622,20 +607,6 @@ public class Project { | |||
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) { | |||
return symbols.addToLoader(loader, path); | |||
} | |||
@@ -676,6 +647,20 @@ public class Project { | |||
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 | |||
* @param taskName name of the task | |||
@@ -685,14 +670,21 @@ public class Project { | |||
*/ | |||
public void addTaskDefinition(String taskName, Class taskClass) | |||
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. | |||
* @throws BuildException and logs as Project.MSG_ERR for | |||
* 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 { | |||
if( !Task.class.isAssignableFrom(taskClass) ) { | |||
@@ -704,7 +696,7 @@ public class Project { | |||
* get the current task definition hashtable | |||
*/ | |||
public Hashtable getTaskDefinitions() { | |||
return symbols.getDefinitions(TASK_ROLE); | |||
return symbols.getTaskDefinitions(); | |||
} | |||
/** | |||
@@ -713,14 +705,18 @@ public class Project { | |||
* @param typeClass full datatype classname | |||
*/ | |||
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 | |||
*/ | |||
public Hashtable getDataTypeDefinitions() { | |||
return symbols.getDefinitions(DATATYPE_ROLE); | |||
return symbols.getDataTypeDefinitions(); | |||
} | |||
/** | |||
@@ -748,7 +744,7 @@ public class Project { | |||
* in the project. | |||
* @see Project#addOrReplaceTarget to replace existing Targets. | |||
*/ | |||
public void addTarget(String targetName, Target target) | |||
public void addTarget(String targetName, Target target) | |||
throws BuildException { | |||
if (targets.get(targetName) != null) { | |||
throw new BuildException("Duplicate target: `"+targetName+"'"); | |||
@@ -784,88 +780,6 @@ public class Project { | |||
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 | |||
* @param taskType name of the task | |||
@@ -873,7 +787,39 @@ public class Project { | |||
* @return null if the task name is unknown | |||
*/ | |||
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 | |||
*/ | |||
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) { | |||
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, | |||
MSG_WARN); | |||
} | |||
@@ -55,11 +55,6 @@ package org.apache.tools.ant; | |||
public interface RoleAdapter { | |||
/** | |||
* Obtain the id in case it is needed. | |||
*/ | |||
public void setId(String id); | |||
/** | |||
* Set the object being adapted. | |||
* @param o the object being adapted | |||
@@ -54,7 +54,6 @@ | |||
package org.apache.tools.ant; | |||
import java.lang.reflect.InvocationTargetException; | |||
import java.lang.reflect.Constructor; | |||
import java.lang.reflect.Method; | |||
import java.lang.reflect.Modifier; | |||
import java.util.*; | |||
@@ -97,8 +96,8 @@ public class SymbolTable { | |||
* from that defined in 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; | |||
} | |||
/** | |||
* 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 | |||
* on this symbol table. | |||
@@ -182,13 +133,13 @@ public class SymbolTable { | |||
list.addElement(role); | |||
} | |||
} | |||
if (parentTable != null) parentTable.findRoles(clz, list); | |||
if (parentTable != null) findRoles(clz, list); | |||
} | |||
/** | |||
* Get the Role definition | |||
* @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) { | |||
Role r = (Role) roles.get(role); | |||
@@ -220,6 +171,112 @@ public class SymbolTable { | |||
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. | |||
@@ -234,13 +291,13 @@ public class SymbolTable { | |||
throw new BuildException("Unknown role: " + role); | |||
} | |||
// Check if it is already defined | |||
Factory old = get(role, name); | |||
Class old = get(role, name); | |||
if (old != null) { | |||
if (old.getOriginalClass().equals(clz)) { | |||
if (old.equals(clz)) { | |||
project.log("Ignoring override for "+ role + " " + name | |||
+ ", it is already defined by the same class.", | |||
project.MSG_VERBOSE); | |||
return old.getOriginalClass(); | |||
return old; | |||
} | |||
else { | |||
project.log("Trying to override old definition of " + | |||
@@ -248,33 +305,26 @@ public class SymbolTable { | |||
project.MSG_WARN); | |||
} | |||
} | |||
Factory f = checkClass(clz); | |||
checkClass(clz); | |||
// Check that the Class is compatible with the role definition | |||
f = r.verifyAdaptability(role, f); | |||
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, 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. | |||
* @return the factory to use when instantiating the class | |||
* @throws BuildException and logs as Project.MSG_ERR for | |||
* conditions, that will cause execution to fail. | |||
*/ | |||
Factory checkClass(final Class clz) // Package on purpose | |||
void checkClass(final Class clz) | |||
throws BuildException { | |||
if (clz == null) return null; | |||
if(!Modifier.isPublic(clz.getModifiers())) { | |||
final String message = clz + " is not public"; | |||
project.log(message, Project.MSG_ERR); | |||
@@ -292,37 +342,8 @@ public class SymbolTable { | |||
// getConstructor finds public constructors only. | |||
try { | |||
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) { | |||
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) { | |||
final String message = | |||
@@ -338,11 +359,11 @@ public class SymbolTable { | |||
* @param name the name of the element to sea | |||
* @return the Class implementation | |||
*/ | |||
public Factory get(String role, String name) { | |||
public Class get(String role, String name) { | |||
Hashtable defTable = (Hashtable)defs.get(role); | |||
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) { | |||
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. | |||
*/ | |||
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) { | |||
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 | |||
*/ | |||
public class Role { | |||
private Method interfaceMethod; | |||
private Method adapterVerifier; | |||
private Factory adapterFactory; | |||
/** | |||
* Creates a new Role object | |||
@@ -419,7 +420,6 @@ public class SymbolTable { | |||
*/ | |||
Role(Class roleClz, Class adapterClz) { | |||
interfaceMethod = validInterface(roleClz); | |||
adapterFactory = checkClass(adapterClz); | |||
adapterVerifier = validAdapter(adapterClz, interfaceMethod); | |||
} | |||
@@ -433,11 +433,12 @@ public class SymbolTable { | |||
/** | |||
* 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 { | |||
return (RoleAdapter) adapterFactory.create(p); | |||
return (RoleAdapter) | |||
adapterVerifier.getDeclaringClass().newInstance(); | |||
} | |||
catch(BuildException be) { | |||
throw be; | |||
@@ -450,12 +451,11 @@ public class SymbolTable { | |||
/** | |||
* Verify if the class can be adapted to use by the role | |||
* @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)) { | |||
return f; | |||
return; | |||
} | |||
if (adapterVerifier == null) { | |||
String msg = "Class " + clz.getName() + | |||
@@ -464,18 +464,8 @@ public class SymbolTable { | |||
} | |||
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) { | |||
throw ite.getTargetException(); | |||
@@ -497,63 +487,5 @@ public class SymbolTable { | |||
public boolean isImplementedBy(Class 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); | |||
} | |||
} | |||
} | |||
} |
@@ -165,5 +165,4 @@ public class TaskAdapter extends Task implements RoleAdapter { | |||
return this.proxy ; | |||
} | |||
public void setId(String id) {} | |||
} |
@@ -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> |
@@ -138,8 +138,10 @@ public class Ant extends Task { | |||
} | |||
public void init() { | |||
newProject = project.createSubProject(); | |||
newProject = new Project(project); | |||
newProject.setJavaVersionProperty(); | |||
// newProject.addTaskDefinition("property", | |||
// (Class)project.getTaskDefinitions().get("property")); | |||
} | |||
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 | |||
Hashtable prop1; | |||
if (inheritAll) { | |||
@@ -418,7 +418,7 @@ public class Antlib extends Task { | |||
if (classpath != null) { | |||
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 SymbolTable symbols = null; | |||
private String name = null; | |||
private String className = null; | |||
private String adapter = null; | |||
@@ -518,6 +520,7 @@ public class Antlib extends Task { | |||
AntLibraryHandler(ClassLoader classloader, Properties als) { | |||
this.classloader = classloader; | |||
this.aliasMap = als; | |||
this.symbols = project.getSymbols(); | |||
} | |||
/** | |||
@@ -588,15 +591,15 @@ public class Antlib extends Task { | |||
try { | |||
if ("role".equals(tag)) { | |||
if (project.isRoleDefined(name)) { | |||
if (isRoleInUse(name)) { | |||
String msg = "Cannot override role: " + name; | |||
log(msg, Project.MSG_WARN); | |||
return; | |||
} | |||
// 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; | |||
} | |||
@@ -607,12 +610,12 @@ public class Antlib extends Task { | |||
name = alias; | |||
} | |||
//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; | |||
log(msg, Project.MSG_WARN); | |||
return; | |||
} | |||
project.addDefinitionOnRole(tag, name, loadClass(className)); | |||
symbols.add(tag, name, loadClass(className)); | |||
} | |||
catch(BuildException 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 | |||
} | |||