git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271710 13f79535-47bb-0310-9956-ffa450edef68master
@@ -6,21 +6,24 @@ | |||
<property name='build' location='build' /> | |||
<property name='dist' location='dist' /> | |||
<property name='classes' location='${build}/classes' /> | |||
<property name='testcases' location='src/testcases' /> | |||
<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' /> | |||
<exclude name='org/apache/tools/ant/Project.class' /> | |||
<exclude name='org/apache/tools/ant/ProjectHelper.class' /> | |||
<exclude name='org/apache/tools/ant/IntrospectionHelper.class' /> | |||
<exclude name='org/apache/tools/ant/TaskAdapter.class' /> | |||
<exclude name='org/apache/tools/ant/taskdefs/Ant.class' /> | |||
</fileset> | |||
</copy> | |||
</target> | |||
@@ -39,6 +42,32 @@ | |||
<property name="build.dir" value="${build}"/> | |||
<property name="dist.dir" value="${dist}"/> | |||
</ant> | |||
<!-- | |||
Rejar things to use lib descriptors | |||
It needs to work with the original ANT processor | |||
--> | |||
<path id="newtasks"> | |||
<pathelement location="${classes}" /> | |||
</path> | |||
<taskdef name="antjar" classname="org.apache.tools.ant.taskdefs.Antjar" | |||
classpathref="newtasks" /> | |||
<taskdef name="antlib" classname="org.apache.tools.ant.taskdefs.Antlib" | |||
classpathref="newtasks" /> | |||
<mkdir dir='${dist}/autolib' /> | |||
<antjar antxml="src/main/org/apache/tools/ant/opt-antlib.xml" | |||
destfile="${dist}/autolib/optional.jar" > | |||
<zipfileset src="${dist}/lib/optional.jar" > | |||
<include name="**/*" /> | |||
</zipfileset> | |||
</antjar> | |||
<antjar antxml="src/main/org/apache/tools/ant/antlib.xml" | |||
destfile="${dist}/lib/newant.jar" > | |||
<zipfileset src="${dist}/lib/ant.jar" > | |||
<include name="**/*" /> | |||
</zipfileset> | |||
</antjar> | |||
<delete file="${dist}/lib/optional.jar" /> | |||
<move file="${dist}/lib/newant.jar" tofile="${dist}/lib/ant.jar"/> | |||
</target> | |||
<target name='compile'> | |||
@@ -48,6 +77,11 @@ | |||
optimize="${optimize}"> | |||
<include name='**/*.java'/> | |||
</javac> | |||
<copy toDir='${classes}' preservelastmodified='true' > | |||
<fileset dir='src/main'> | |||
<include name='**/*.xml' /> | |||
</fileset> | |||
</copy> | |||
</target> | |||
<target name='clean'> | |||
@@ -56,7 +90,7 @@ | |||
<target name='test'> | |||
<ant dir='${testcases}' inheritAll='false'/> | |||
<ant dir='${testcases}' | |||
<ant dir='${testcases}' | |||
antfile='${testcases}/case.xml' inheritAll='false'/> | |||
</target> | |||
@@ -114,7 +114,7 @@ public class ProjectHelper { | |||
private void parse() throws BuildException { | |||
FileInputStream inputStream = null; | |||
InputSource inputSource = null; | |||
try { | |||
SAXParser saxParser = getParserFactory().newSAXParser(); | |||
parser = saxParser.getParser(); | |||
@@ -123,7 +123,7 @@ public class ProjectHelper { | |||
for (int index = uri.indexOf('#'); index != -1; index = uri.indexOf('#')) { | |||
uri = uri.substring(0, index) + "%23" + uri.substring(index+1); | |||
} | |||
inputStream = new FileInputStream(buildFile); | |||
inputSource = new InputSource(inputStream); | |||
inputSource.setSystemId(uri); | |||
@@ -145,7 +145,7 @@ public class ProjectHelper { | |||
} | |||
throw be; | |||
} | |||
throw new BuildException(exc.getMessage(), t, location); | |||
} | |||
catch(SAXException exc) { | |||
@@ -231,20 +231,20 @@ public class ProjectHelper { | |||
*/ | |||
public InputSource resolveEntity(String publicId, | |||
String systemId) { | |||
project.log("resolving systemId: " + systemId, Project.MSG_VERBOSE); | |||
if (systemId.startsWith("file:")) { | |||
String path = systemId.substring(5); | |||
int index = path.indexOf("file:"); | |||
// we only have to handle these for backward compatibility | |||
// since they are in the FAQ. | |||
while (index != -1) { | |||
path = path.substring(0, index) + path.substring(index + 5); | |||
index = path.indexOf("file:"); | |||
} | |||
String entitySystemId = path; | |||
index = path.indexOf("%23"); | |||
// convert these to # | |||
@@ -257,13 +257,13 @@ public class ProjectHelper { | |||
if (!file.isAbsolute()) { | |||
file = new File(buildFileParent, path); | |||
} | |||
try { | |||
InputSource inputSource = new InputSource(new FileInputStream(file)); | |||
inputSource.setSystemId("file:" + entitySystemId); | |||
return inputSource; | |||
} catch (FileNotFoundException fne) { | |||
project.log(file.getAbsolutePath()+" could not be found", | |||
project.log(file.getAbsolutePath()+" could not be found", | |||
Project.MSG_WARN); | |||
} | |||
} | |||
@@ -316,10 +316,10 @@ public class ProjectHelper { | |||
} | |||
if (def == null) { | |||
throw new SAXParseException("The default attribute of project is required", | |||
throw new SAXParseException("The default attribute of project is required", | |||
locator); | |||
} | |||
project.setDefaultTarget(def); | |||
@@ -360,6 +360,8 @@ public class ProjectHelper { | |||
handleTopTask(name, attrs); | |||
} else if (name.equals("target")) { | |||
handleTarget(name, attrs); | |||
} else if (name.equals("description")) { | |||
handleDescription(name, attrs); | |||
} else if (project.isDefinedOnRole(Project.DATATYPE_ROLE, name)) { | |||
handleTopTask(name, attrs); | |||
} else { | |||
@@ -367,9 +369,9 @@ public class ProjectHelper { | |||
} | |||
} | |||
private void handleTopTask(String name, AttributeList attrs) | |||
throws SAXParseException { | |||
InmediateTarget target = new InmediateTarget(name); | |||
private void handleTopTask(String name, AttributeList attrs) | |||
throws SAXParseException { | |||
InmediateTarget target = new InmediateTarget(name); | |||
(new TaskHandler(this, target, null, target)).init(name, attrs); | |||
} | |||
@@ -377,6 +379,10 @@ public class ProjectHelper { | |||
new TargetHandler(this).init(tag, attrs); | |||
} | |||
private void handleDescription(String tag, AttributeList attrs) throws SAXParseException { | |||
new DescriptionHandler(this).init(tag, attrs); | |||
} | |||
} | |||
/** | |||
@@ -441,8 +447,13 @@ public class ProjectHelper { | |||
} | |||
public void startElement(String name, AttributeList attrs) throws SAXParseException { | |||
new TaskHandler(this, target, null, target).init(name, attrs); | |||
} | |||
if (name.equals("description")) { | |||
new DescriptionHandler(this).init(name, attrs); | |||
} | |||
else { | |||
new TaskHandler(this, target, null, target).init(name, attrs); | |||
} | |||
} | |||
} | |||
/** | |||
@@ -466,7 +477,7 @@ public class ProjectHelper { | |||
try { | |||
task = (Task)project.createInRole(container, tag); | |||
} catch (BuildException e) { | |||
// swallow here, will be thrown again in | |||
// swallow here, will be thrown again in | |||
// UnknownElement.maybeConfigure if the problem persists. | |||
} | |||
@@ -475,21 +486,21 @@ public class ProjectHelper { | |||
task.setProject(project); | |||
task.setTaskType(tag); | |||
task.setTaskName(tag); | |||
container.addTask(task); | |||
container.addTask(task); | |||
} | |||
task.setLocation(new Location(buildFile.toString(), | |||
locator.getLineNumber(), | |||
locator.getColumnNumber())); | |||
task.setLocation(new Location(buildFile.toString(), | |||
locator.getLineNumber(), | |||
locator.getColumnNumber())); | |||
configureId(task, attrs); | |||
task.setOwningTarget(target); | |||
task.init(); | |||
wrapper = task.getRuntimeConfigurableWrapper(); | |||
wrapper.setAttributes(attrs); | |||
if (parentWrapper != null) { | |||
parentWrapper.addChild(wrapper); | |||
} | |||
task.setOwningTarget(target); | |||
task.init(); | |||
wrapper = task.getRuntimeConfigurableWrapper(); | |||
wrapper.setAttributes(attrs); | |||
if (parentWrapper != null) { | |||
parentWrapper.addChild(wrapper); | |||
} | |||
} | |||
protected void finished() { | |||
@@ -531,7 +542,7 @@ public class ProjectHelper { | |||
private RuntimeConfigurable childWrapper = null; | |||
private Target target; | |||
public NestedElementHandler(DocumentHandler parentHandler, | |||
public NestedElementHandler(DocumentHandler parentHandler, | |||
Object parent, | |||
RuntimeConfigurable parentWrapper, | |||
Target target) { | |||
@@ -548,7 +559,7 @@ public class ProjectHelper { | |||
public void init(String propType, AttributeList attrs) throws SAXParseException { | |||
Class parentClass = parent.getClass(); | |||
IntrospectionHelper ih = | |||
IntrospectionHelper ih = | |||
IntrospectionHelper.getHelper(parentClass); | |||
try { | |||
@@ -557,9 +568,9 @@ public class ProjectHelper { | |||
UnknownElement uc = new UnknownElement(elementName); | |||
uc.setProject(project); | |||
((UnknownElement) parent).addChild(uc); | |||
// Set this parameters just in case is a Task | |||
uc.setTaskType(elementName); | |||
uc.setTaskName(elementName); | |||
// Set this parameters just in case is a Task | |||
uc.setTaskType(elementName); | |||
uc.setTaskName(elementName); | |||
child = uc; | |||
} else { | |||
child = ih.createElement(project, parent, elementName); | |||
@@ -594,7 +605,7 @@ public class ProjectHelper { | |||
public void startElement(String name, AttributeList attrs) throws SAXParseException { | |||
if (child instanceof TaskContainer) { | |||
// taskcontainer nested element can contain other tasks - no other | |||
// taskcontainer nested element can contain other tasks - no other | |||
// nested elements possible | |||
new TaskHandler(this, (TaskContainer)child, childWrapper, target).init(name, attrs); | |||
} | |||
@@ -604,39 +615,64 @@ public class ProjectHelper { | |||
} | |||
} | |||
/** | |||
* Handler to perform appropriate semantics for the special | |||
* <description> element on tasks. | |||
*/ | |||
private class DescriptionHandler extends AbstractHandler { | |||
public DescriptionHandler(DocumentHandler parent) { | |||
super(parent); | |||
} | |||
public void init(String tag, AttributeList attrs) throws SAXParseException { | |||
if (attrs.getLength() > 0) { | |||
throw new SAXParseException("No attributes allowed on " + tag, locator); | |||
} | |||
} | |||
public void characters(char[] buf, int start, int end) throws SAXParseException { | |||
String desc = project.getDescription(); | |||
if (desc == null) { | |||
desc = ""; | |||
} | |||
project.setDescription(desc + new String(buf, start, end)); | |||
} | |||
} | |||
/** | |||
* Special target type for top level Tasks and Datatypes. | |||
* This will allow eliminating special cases. | |||
*/ | |||
private class InmediateTarget extends Target { | |||
/** | |||
* Create a target for a top level task or datatype. | |||
* @param name the name of the task to be run on this target. | |||
*/ | |||
InmediateTarget(String name) { | |||
super(); | |||
setProject(project); | |||
setName("Top level " + name); | |||
} | |||
/** | |||
* Create a target for a top level task or datatype. | |||
* @param name the name of the task to be run on this target. | |||
*/ | |||
InmediateTarget(String name) { | |||
super(); | |||
setProject(project); | |||
setName("Top level " + name); | |||
} | |||
} | |||
public static void configure(Object target, AttributeList attrs, | |||
public static void configure(Object target, AttributeList attrs, | |||
Project project) throws BuildException { | |||
if( target instanceof RoleAdapter ) { | |||
target=((RoleAdapter)target).getProxy(); | |||
} | |||
IntrospectionHelper ih = | |||
IntrospectionHelper ih = | |||
IntrospectionHelper.getHelper(target.getClass()); | |||
project.addBuildListener(ih); | |||
for (int i = 0; i < attrs.getLength(); i++) { | |||
// reflect these into the target | |||
String value=replaceProperties(project, attrs.getValue(i), | |||
String value=replaceProperties(project, attrs.getValue(i), | |||
project.getProperties() ); | |||
try { | |||
ih.setAttribute(project, target, | |||
ih.setAttribute(project, target, | |||
attrs.getName(i).toLowerCase(Locale.US), value); | |||
} catch (BuildException be) { | |||
@@ -674,7 +710,7 @@ public class ProjectHelper { | |||
} | |||
/** | |||
* Stores a configured child element into its parent object | |||
* Stores a configured child element into its parent object | |||
*/ | |||
public static void storeChild(Project project, Object parent, Object child, String tag) { | |||
IntrospectionHelper ih = IntrospectionHelper.getHelper(parent.getClass()); | |||
@@ -719,23 +755,23 @@ public class ProjectHelper { | |||
if (!keys.containsKey(propertyName)) { | |||
project.log("Property ${" + propertyName + "} has not been set", Project.MSG_VERBOSE); | |||
} | |||
fragment = (keys.containsKey(propertyName)) ? (String) keys.get(propertyName) | |||
: "${" + propertyName + "}"; | |||
fragment = (keys.containsKey(propertyName)) ? (String) keys.get(propertyName) | |||
: "${" + propertyName + "}"; | |||
} | |||
sb.append(fragment); | |||
} | |||
} | |||
return sb.toString(); | |||
} | |||
/** | |||
* This method will parse a string containing ${value} style | |||
* This method will parse a string containing ${value} style | |||
* property values into two lists. The first list is a collection | |||
* of text fragments, while the other is a set of string property names | |||
* null entries in the first list indicate a property reference from the | |||
* second list. | |||
*/ | |||
public static void parsePropertyString(String value, Vector fragments, Vector propertyRefs) | |||
public static void parsePropertyString(String value, Vector fragments, Vector propertyRefs) | |||
throws BuildException { | |||
int prev = 0; | |||
int pos; | |||
@@ -754,7 +790,7 @@ public class ProjectHelper { | |||
} else { | |||
int endName = value.indexOf('}', pos); | |||
if (endName < 0) { | |||
throw new BuildException("Syntax error in property: " | |||
throw new BuildException("Syntax error in property: " | |||
+ value ); | |||
} | |||
String propertyName = value.substring(pos + 2, endName); | |||
@@ -779,17 +815,17 @@ public class ProjectHelper { | |||
/** | |||
* Scan AttributeList for the id attribute and maybe add a | |||
* reference to project. | |||
* reference to project. | |||
* | |||
* <p>Moved out of {@link #configure configure} to make it happen | |||
* at parser time.</p> | |||
* at parser time.</p> | |||
*/ | |||
private void configureId(Object target, AttributeList attr) { | |||
String id = attr.getValue("id"); | |||
if (id != null) { | |||
if( target instanceof RoleAdapter ) { | |||
((RoleAdapter)target).setId(id); | |||
} | |||
if( target instanceof RoleAdapter ) { | |||
((RoleAdapter)target).setId(id); | |||
} | |||
project.addReference(id, target); | |||
} | |||
} | |||
@@ -55,6 +55,11 @@ 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,6 +54,7 @@ | |||
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.*; | |||
@@ -64,7 +65,7 @@ public class SymbolTable { | |||
/** Parent symbol table */ | |||
private SymbolTable parentTable; | |||
/** Project associated with this symbol table */ | |||
private Project project; | |||
@@ -82,8 +83,8 @@ public class SymbolTable { | |||
/** | |||
* Parameters for checking adapters. | |||
*/ | |||
private static final Class[] CHECK_ADAPTER_PARAMS = | |||
new Class[]{Class.class, Project.class}; | |||
private static final Class[] CHECK_ADAPTER_PARAMS = | |||
new Class[]{Class.class, Project.class}; | |||
/** | |||
* Create a top level Symbol table. | |||
@@ -96,8 +97,8 @@ public class SymbolTable { | |||
* from that defined in the calling Project. | |||
* @param p the calling project | |||
*/ | |||
public SymbolTable(Project p) { | |||
parentTable = p.getSymbols(); | |||
public SymbolTable(SymbolTable st) { | |||
parentTable = st; | |||
} | |||
/** | |||
@@ -105,7 +106,55 @@ public class SymbolTable { | |||
* @param p the project for this symbol table | |||
*/ | |||
public void setProject(Project p) { | |||
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; | |||
} | |||
/** | |||
@@ -115,9 +164,9 @@ public class SymbolTable { | |||
* @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()]); | |||
Vector list = new Vector(); | |||
findRoles(clz, list); | |||
return (String[])list.toArray(new String[list.size()]); | |||
} | |||
/** | |||
@@ -126,27 +175,27 @@ public class SymbolTable { | |||
* @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); | |||
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) parentTable.findRoles(clz, list); | |||
} | |||
/** | |||
* Get the Role definition | |||
* @param role the name of the role | |||
* @return the method used to support objects on this role | |||
* @return the Role description | |||
*/ | |||
public Role getRole(String role) { | |||
Role r = (Role) roles.get(role); | |||
if (r == null && parentTable != null) { | |||
return parentTable.getRole(role); | |||
} | |||
return r; | |||
Role r = (Role) roles.get(role); | |||
if (r == null && parentTable != null) { | |||
return parentTable.getRole(role); | |||
} | |||
return r; | |||
} | |||
/** | |||
@@ -157,126 +206,19 @@ public class SymbolTable { | |||
* @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; | |||
// 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); | |||
} | |||
/** | |||
* 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. | |||
@@ -285,46 +227,53 @@ public class SymbolTable { | |||
* @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 { | |||
// Find the role definition | |||
Role r = getRole(role); | |||
if (r == null) { | |||
throw new BuildException("Unknown role: " + role); | |||
} | |||
// Check if it is already defined | |||
Factory old = get(role, name); | |||
if (old != null) { | |||
if (old.getOriginalClass().equals(clz)) { | |||
project.log("Ignoring override for "+ role + " " + name | |||
+ ", it is already defined by the same class.", | |||
project.MSG_VERBOSE); | |||
return old.getOriginalClass(); | |||
} | |||
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; | |||
role + " " + name, | |||
project.MSG_WARN); | |||
} | |||
} | |||
Factory f = checkClass(clz); | |||
// Check that the Class is compatible with the role definition | |||
f = r.verifyAdaptability(role, f); | |||
// 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); | |||
} | |||
/** | |||
* 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. | |||
*/ | |||
void checkClass(final Class clz) | |||
throws BuildException { | |||
Factory checkClass(final Class clz) // Package on purpose | |||
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); | |||
@@ -336,21 +285,53 @@ public class SymbolTable { | |||
throw new BuildException(message); | |||
} | |||
try { | |||
// Class can have a "no arg" constructor or take a single | |||
// 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]); | |||
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) { | |||
clz.getConstructor(new Class[] {Project.class}); | |||
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; | |||
} | |||
}; | |||
} | |||
} catch(NoSuchMethodException e) { | |||
final String message = | |||
"No valid public constructor in " + clz; | |||
final String message = "No valid public constructor in " + clz; | |||
project.log(message, Project.MSG_ERR); | |||
throw new BuildException(message); | |||
} | |||
catch (NoClassDefFoundError ncdfe) { | |||
final String msg = "Class cannot be loaded: " + ncdfe.getMessage(); | |||
throw new BuildException(msg, ncdfe); | |||
} | |||
} | |||
/** | |||
@@ -359,32 +340,25 @@ public class SymbolTable { | |||
* @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"); | |||
public Factory 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; | |||
} | |||
if (parentTable != null) { | |||
return parentTable.get(role, name); | |||
} | |||
return null; | |||
} | |||
/** | |||
* Get a Hashtable that is usable for manipulating Datatypes, | |||
* Get a Hashtable that is usable for manipulating elements on Role. | |||
* @param role the role of the elements in the table | |||
* @return a Hashtable that delegates to the Symbol table. | |||
*/ | |||
public Hashtable getDataTypeDefinitions() { | |||
return new SymbolHashtable("datatype"); | |||
Hashtable getDefinitions(String role) { // package scope on purpose | |||
return new SymbolHashtable(role); | |||
} | |||
/** | |||
@@ -392,100 +366,196 @@ public class SymbolTable { | |||
* 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); | |||
} | |||
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) { | |||
Factory f = SymbolTable.this.get(role, (String)key); | |||
return (f == null? null : f.getOriginalClass()); | |||
} | |||
} | |||
/** | |||
* 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; | |||
/** | |||
* 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); | |||
} | |||
private Method interfaceMethod; | |||
private Method adapterVerifier; | |||
private Factory adapterFactory; | |||
/** | |||
* 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); | |||
adapterFactory = checkClass(adapterClz); | |||
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(Project p) { | |||
if (adapterFactory == null) return null; | |||
try { | |||
return (RoleAdapter) adapterFactory.create(p); | |||
} | |||
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 f the factory for the class to verify | |||
*/ | |||
public Factory verifyAdaptability(String role, final Factory f) { | |||
final Class clz = f.getOriginalClass(); | |||
if (interfaceMethod.getParameterTypes()[0].isAssignableFrom(clz)) { | |||
return f; | |||
} | |||
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}); | |||
return new Factory(){ | |||
public Object create(Project p) { | |||
RoleAdapter ra = createAdapter(p); | |||
ra.setProxy(f.create(p)); | |||
return ra; | |||
} | |||
public Class getOriginalClass() { | |||
return clz; | |||
} | |||
}; | |||
} | |||
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); | |||
} | |||
/** | |||
* 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); | |||
} | |||
} | |||
} | |||
} |
@@ -1,7 +1,7 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2000-2001 The Apache Software Foundation. All rights | |||
* Copyright (c) 2000-2001 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
@@ -9,7 +9,7 @@ | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* 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 | |||
@@ -17,15 +17,15 @@ | |||
* distribution. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* 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 | |||
* 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" | |||
@@ -55,6 +55,7 @@ | |||
package org.apache.tools.ant; | |||
import java.lang.reflect.Method; | |||
import java.lang.reflect.InvocationTargetException; | |||
@@ -68,7 +69,7 @@ import java.lang.reflect.Method; | |||
public class TaskAdapter extends Task implements RoleAdapter { | |||
Object proxy; | |||
/** | |||
* Checks a class, whether it is suitable to be adapted by TaskAdapter. | |||
* | |||
@@ -81,15 +82,15 @@ public class TaskAdapter extends Task implements RoleAdapter { | |||
* 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); | |||
// 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. | |||
* adapted by TaskAdapter. | |||
* | |||
* Throws a BuildException and logs as Project.MSG_ERR for | |||
* conditions, that will cause the task execution to fail. | |||
@@ -114,7 +115,7 @@ public class TaskAdapter extends Task implements RoleAdapter { | |||
throw new BuildException(message); | |||
} | |||
} | |||
/** | |||
* Do the execution. | |||
*/ | |||
@@ -122,7 +123,7 @@ public class TaskAdapter extends Task implements RoleAdapter { | |||
Method setProjectM = null; | |||
try { | |||
Class c = proxy.getClass(); | |||
setProjectM = | |||
setProjectM = | |||
c.getMethod( "setProject", new Class[] {Project.class}); | |||
if(setProjectM != null) { | |||
setProjectM.invoke(proxy, new Object[] {project}); | |||
@@ -131,7 +132,7 @@ public class TaskAdapter extends Task implements RoleAdapter { | |||
// 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(), | |||
log("Error setting project in " + proxy.getClass(), | |||
Project.MSG_ERR); | |||
throw new BuildException( ex ); | |||
} | |||
@@ -146,14 +147,20 @@ public class TaskAdapter extends Task implements RoleAdapter { | |||
throw new BuildException("No public execute() in " + proxy.getClass()); | |||
} | |||
executeM.invoke(proxy, null); | |||
return; | |||
return; | |||
} catch( InvocationTargetException ite ) { | |||
Throwable t = ite.getTargetException(); | |||
if (t instanceof BuildException) { | |||
throw (BuildException) t; | |||
} | |||
throw new BuildException(t); | |||
} catch( Exception ex ) { | |||
log("Error in " + proxy.getClass(), Project.MSG_ERR); | |||
throw new BuildException( ex ); | |||
} | |||
} | |||
/** | |||
* Set the target object class | |||
*/ | |||
@@ -165,4 +172,5 @@ public class TaskAdapter extends Task implements RoleAdapter { | |||
return this.proxy ; | |||
} | |||
public void setId(String id) {} | |||
} |
@@ -138,10 +138,8 @@ public class Ant extends Task { | |||
} | |||
public void init() { | |||
newProject = new Project(project); | |||
newProject = project.createSubProject(); | |||
newProject.setJavaVersionProperty(); | |||
// newProject.addTaskDefinition("property", | |||
// (Class)project.getTaskDefinitions().get("property")); | |||
} | |||
private void reinit() { | |||
@@ -185,26 +183,6 @@ 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) { | |||
@@ -104,7 +104,8 @@ public class Antjar extends Jar { | |||
public void setAntxml(File descriptor) { | |||
libraryDescriptor = descriptor; | |||
if (!libraryDescriptor.exists()) { | |||
throw new BuildException("Deployment descriptor: " + libraryDescriptor + " does not exist."); | |||
throw new BuildException("Deployment descriptor: " + | |||
libraryDescriptor + " does not exist."); | |||
} | |||
// Create a ZipFileSet for this file, and pass it up. | |||
@@ -127,7 +128,8 @@ public class Antjar extends Jar { | |||
throws IOException, BuildException { | |||
// If no antxml file is specified, it's an error. | |||
if (libraryDescriptor == null) { | |||
throw new BuildException("antxml attribute is required", location); | |||
throw new BuildException("antxml attribute is required", | |||
location); | |||
} | |||
super.initZipOutputStream(zOut); | |||
@@ -149,10 +151,12 @@ public class Antjar extends Jar { | |||
// meaning the same file is specified by the "antxml" attribute and in | |||
// a <fileset> element. | |||
if (vPath.equalsIgnoreCase(Antlib.ANT_DESCRIPTOR)) { | |||
if (libraryDescriptor == null || !libraryDescriptor.equals(file) || descriptorAdded) { | |||
if (libraryDescriptor == null || | |||
!libraryDescriptor.equals(file) || descriptorAdded) { | |||
log("Warning: selected " + archiveType + " files include a " + | |||
Antlib.ANT_DESCRIPTOR + " which will be ignored " + | |||
"(please use antxml attribute to " + archiveType + " task)", Project.MSG_WARN); | |||
Antlib.ANT_DESCRIPTOR + " which will be ignored " + | |||
"(please use antxml attribute to " + archiveType + | |||
" task)", Project.MSG_WARN); | |||
} | |||
else { | |||
super.zipFile(file, zOut, vPath); | |||
@@ -55,12 +55,14 @@ package org.apache.tools.ant.taskdefs; | |||
import org.apache.tools.ant.*; | |||
import org.apache.tools.ant.types.*; | |||
import org.apache.tools.ant.taskdefs.*; | |||
import org.xml.sax.*; | |||
import javax.xml.parsers.*; | |||
import java.util.*; | |||
import java.util.zip.*; | |||
import java.io.*; | |||
import java.net.*; | |||
/** | |||
* Make available the tasks and types from an Ant library. <pre> | |||
@@ -76,16 +78,18 @@ import java.io.*; | |||
* @since ant1.5 | |||
*/ | |||
public class Antlib extends Task { | |||
/** | |||
* Location of descriptor in library | |||
*/ | |||
public static final String ANT_DESCRIPTOR = "META-INF/antlib.xml"; | |||
/** | |||
* The named classloader to use. | |||
* Defaults to the default classLoader. | |||
*/ | |||
private String loaderId = ""; | |||
/** | |||
* library attribute | |||
*/ | |||
private String library = null; | |||
/** | |||
* file attribute | |||
*/ | |||
@@ -95,62 +99,200 @@ public class Antlib extends Task { | |||
*/ | |||
private boolean override = false; | |||
/** | |||
* attribute to control classloader use | |||
* attribute to control failure when loading | |||
*/ | |||
private boolean useCurrentClassloader = false; | |||
private FailureAction onerror = new FailureAction(); | |||
/** | |||
* classpath to build up | |||
*/ | |||
private Path classpath = null; | |||
/** | |||
* the manufacture set of classes to load | |||
*/ | |||
private Path loaderPath = null; | |||
/** | |||
* our little xml parse | |||
*/ | |||
private SAXParserFactory saxFactory; | |||
/** | |||
* table of aliases | |||
*/ | |||
private Vector aliases = new Vector(); | |||
/** | |||
* Location of descriptor in library | |||
* Some internal constants. | |||
*/ | |||
public static String ANT_DESCRIPTOR = "META-INF/antlib.xml"; | |||
private static final int FAIL = 0, REPORT = 1, IGNORE = 2; | |||
/** | |||
* Prefix name for DTD of descriptor | |||
*/ | |||
public static String ANTLIB_DTD_URL = | |||
"http://jakarta.apache.org/ant/"; | |||
/** | |||
* prefix of the antlib | |||
*/ | |||
public static String ANTLIB_DTD_PREFIX = "Antlib-V"; | |||
/** | |||
* version counter | |||
* Posible actions when classes are not found | |||
*/ | |||
public static String ANTLIB_DTD_VERSION = "1_0"; | |||
/** | |||
* dtd file extension | |||
*/ | |||
public static String ANTLIB_DTD_EXT = ".dtd"; | |||
public static class FailureAction extends EnumeratedAttribute { | |||
public String[] getValues() { | |||
return new String[]{"fail", "report", "ignore"}; | |||
} | |||
} | |||
private static class DescriptorEnumeration implements Enumeration { | |||
/** | |||
* The name of the resource being searched for. | |||
*/ | |||
private String resourceName; | |||
/** | |||
* The index of the next file to search. | |||
*/ | |||
private int index; | |||
/** | |||
* The list of files to search | |||
*/ | |||
private File files[]; | |||
/** | |||
* The URL of the next resource to return in the enumeration. If this | |||
* field is <code>null</code> then the enumeration has been completed, | |||
* i.e., there are no more elements to return. | |||
*/ | |||
private URL nextDescriptor; | |||
/** | |||
* Construct a new enumeration of resources of the given name found | |||
* within this class loader's classpath. | |||
* | |||
* @param name the name of the resource to search for. | |||
*/ | |||
DescriptorEnumeration(String fileNames[], String name) { | |||
this.resourceName = name; | |||
this.index = 0; | |||
this.files = new File[fileNames.length]; | |||
for (int i = 0; i < files.length; i++) { | |||
files[i] = new File(fileNames[i]); | |||
} | |||
findNextDescriptor(); | |||
} | |||
/** | |||
* Indicates whether there are more elements in the enumeration to | |||
* return. | |||
* | |||
* @return <code>true</code> if there are more elements in the | |||
* enumeration; <code>false</code> otherwise. | |||
*/ | |||
public boolean hasMoreElements() { | |||
return (this.nextDescriptor != null); | |||
} | |||
/** | |||
* Returns the next resource in the enumeration. | |||
* | |||
* @return the next resource in the enumeration. | |||
*/ | |||
public Object nextElement() { | |||
URL ret = this.nextDescriptor; | |||
findNextDescriptor(); | |||
return ret; | |||
} | |||
/** | |||
* Locates the next descriptor of the correct name in the files and | |||
* sets <code>nextDescriptor</code> to the URL of that resource. If no | |||
* more resources can be found, <code>nextDescriptor</code> is set to | |||
* <code>null</code>. | |||
*/ | |||
private void findNextDescriptor() { | |||
URL url = null; | |||
while (index < files.length && url == null) { | |||
try { | |||
url = getDescriptorURL(files[index], this.resourceName); | |||
index++; | |||
} | |||
catch (BuildException e) { | |||
// ignore path elements which are not valid relative to the | |||
// project | |||
} | |||
} | |||
this.nextDescriptor = url; | |||
} | |||
/** | |||
* Get an URL to a given resource in the given file which may | |||
* either be a directory or a zip file. | |||
* | |||
* @param file the file (directory or jar) in which to search for | |||
* the resource. Must not be <code>null</code>. | |||
* @param resourceName the name of the resource for which a URL | |||
* is required. Must not be <code>null</code>. | |||
* | |||
* @return a URL to the required resource or <code>null</code> if the | |||
* resource cannot be found in the given file object | |||
* @todo This code is extracted from AntClassLoader.getResourceURL | |||
* I hate when that happens but the code there is too tied to | |||
* the ClassLoader internals. Maybe we can find a nice place | |||
* to put it where both can use it. | |||
*/ | |||
private URL getDescriptorURL(File file, String resourceName) { | |||
try { | |||
if (!file.exists()) { | |||
return null; | |||
} | |||
if (file.isDirectory()) { | |||
File resource = new File(file, resourceName); | |||
if (resource.exists()) { | |||
try { | |||
return new URL("file:"+resource.toString()); | |||
} catch (MalformedURLException ex) { | |||
return null; | |||
} | |||
} | |||
} | |||
else { | |||
ZipFile zipFile = new ZipFile(file); | |||
try { | |||
ZipEntry entry = zipFile.getEntry(resourceName); | |||
if (entry != null) { | |||
try { | |||
return new URL("jar:file:"+file.toString()+"!/"+entry); | |||
} catch (MalformedURLException ex) { | |||
return null; | |||
} | |||
} | |||
} | |||
finally { | |||
zipFile.close(); | |||
} | |||
} | |||
} | |||
catch (Exception e) { | |||
e.printStackTrace(); | |||
} | |||
return null; | |||
} | |||
} | |||
/** | |||
* constructor creates a validating sax parser | |||
*/ | |||
public Antlib() { | |||
super(); | |||
// Default error action | |||
onerror.setValue("report"); | |||
saxFactory = SAXParserFactory.newInstance(); | |||
saxFactory.setValidating(true); | |||
saxFactory.setValidating(false); | |||
} | |||
/** | |||
* constructor binds to a project as well as setting up internal state | |||
* constructor binds to a project and sets ignore mode on errors | |||
* | |||
* @param p Description of Parameter | |||
*/ | |||
@@ -161,12 +303,12 @@ public class Antlib extends Task { | |||
/** | |||
* Set name of library to load. The library is located in $ANT_HOME/lib. | |||
* Set name of library to load. The library is located in $ANT_HOME/antlib. | |||
* | |||
* @param lib the name of library relative to $ANT_HOME/lib. | |||
* @param lib the name of library relative to $ANT_HOME/antlib. | |||
*/ | |||
public void setLibrary(String lib) { | |||
this.library = lib; | |||
setFile(libraryFile("antlib", lib)); | |||
} | |||
@@ -180,13 +322,13 @@ public class Antlib extends Task { | |||
} | |||
/** | |||
* Set the ClassLoader to use for this library. | |||
* Set the ID of the ClassLoader to use for this library. | |||
* | |||
* @param id the id for the ClassLoader to use, | |||
* if other than the default. | |||
* @param id the id for the ClassLoader to use, | |||
* <code>null</code> means use ANT's core classloader. | |||
*/ | |||
public void setLoaderid(String id) { | |||
this.loaderId = id; | |||
this.loaderId = id; | |||
} | |||
/** | |||
@@ -200,15 +342,26 @@ public class Antlib extends Task { | |||
/** | |||
* Set whether to use a new classloader or not. | |||
* Default is <code>false</code>. | |||
* Get what to do if a definition cannot be loaded | |||
* This method is mostly used by the core when loading core tasks. | |||
* | |||
* @return what to do if a definition cannot be loaded | |||
*/ | |||
final protected FailureAction getOnerror() { | |||
return this.onerror; | |||
} | |||
/** | |||
* Set whether to fail if a definition cannot be loaded | |||
* Default is <code>true</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. | |||
* @param failedonerror if true loading will stop if classes | |||
* cannot be instantiated | |||
*/ | |||
public void setUseCurrentClassloader(boolean useCurrentClassloader) { | |||
this.useCurrentClassloader = useCurrentClassloader; | |||
public void setOnerror(FailureAction onerror) { | |||
this.onerror = onerror; | |||
} | |||
@@ -262,78 +415,97 @@ public class Antlib extends Task { | |||
} | |||
/** | |||
* Obtain library file from ANT_HOME directory. | |||
* | |||
* @param lib the library name. | |||
* @return the File instance of the library | |||
*/ | |||
private File libraryFile(String homeSubDir, String lib) { | |||
// For the time being libraries live in $ANT_HOME/antlib. | |||
// The idea being that not to load all the jars there anymore | |||
String home = project.getProperty("ant.home"); | |||
if (home == null) { | |||
throw new BuildException("ANT_HOME not set as required."); | |||
} | |||
return new File(new File(home, homeSubDir), lib); | |||
} | |||
/** | |||
* actually do the work of loading the library | |||
* | |||
* @exception BuildException Description of Exception | |||
* @todo maybe have failonerror support for missing file? | |||
*/ | |||
public void execute() | |||
throws BuildException { | |||
File realFile = file; | |||
if (library != null) { | |||
if (file != null) { | |||
String msg = "You cannot specify both file and library."; | |||
throw new BuildException(msg, location); | |||
} | |||
// For the time being libraries live in $ANT_HOME/antlib. | |||
// The idea being that we would not load all the jars there anymore | |||
String home = project.getProperty("ant.home"); | |||
if (home == null) { | |||
throw new BuildException("ANT_HOME not set as required."); | |||
} | |||
realFile = new File(new File(home, "antlib"), library); | |||
} | |||
else if (file == null) { | |||
String msg = "Must specify either library or file attribute."; | |||
if (file == null && classpath == null) { | |||
String msg = | |||
"Must specify either library or file attribute or classpath."; | |||
throw new BuildException(msg, location); | |||
} | |||
if (!realFile.exists()) { | |||
String msg = "Cannot find library: " + realFile; | |||
if (file != null && !file.exists()) { | |||
String msg = "Cannot find library: " + file; | |||
throw new BuildException(msg, location); | |||
} | |||
//open the descriptor | |||
InputStream is = getDescriptor(realFile); | |||
if (is == null) { | |||
String msg = "Missing descriptor on library: " + realFile; | |||
throw new BuildException(msg, location); | |||
} | |||
loadDefinitions(); | |||
} | |||
ClassLoader classloader=null; | |||
if (useCurrentClassloader && classpath != null) { | |||
log("ignoring the useCurrentClassloader option as a classpath is defined", | |||
Project.MSG_WARN); | |||
useCurrentClassloader=false; | |||
} | |||
if (!useCurrentClassloader) { | |||
classloader = makeClassLoader(realFile); | |||
} | |||
//parse it and evaluate it. | |||
evaluateDescriptor(classloader, processAliases(), is); | |||
/** | |||
* Load definitions in library and classpath | |||
* | |||
* @exception BuildException failure to access the resource | |||
*/ | |||
public boolean loadDefinitions() throws BuildException { | |||
return loadDefinitions(ANT_DESCRIPTOR); | |||
} | |||
/** | |||
* Load definitions directly from an external XML file. | |||
* Load definitions from resource name in library and classpath | |||
* | |||
* @param xmlfile XML file in the Antlib format. | |||
* @exception BuildException failure to open the file | |||
* @param res the name of the resources to load | |||
* @exception BuildException failure to access the resource | |||
*/ | |||
public void loadDefinitions(File xmlfile) | |||
final protected boolean loadDefinitions(String res) | |||
throws BuildException { | |||
Path path = makeLoaderClasspath(); | |||
ClassLoader cl = makeClassLoader(path); | |||
boolean found = false; | |||
try { | |||
InputStream is = new FileInputStream(xmlfile); | |||
loadDefinitions(is); | |||
for (Enumeration e = getDescriptors(path, res); e.hasMoreElements(); ) { | |||
URL resURL = (URL)e.nextElement(); | |||
InputStream is = resURL.openStream(); | |||
loadDefinitions(cl, is); | |||
found = true; | |||
} | |||
if (!found && onerror.getIndex() != IGNORE) { | |||
String sPath = path.toString(); | |||
if ("".equals(sPath.trim())) { | |||
sPath = System.getProperty("java.classpath"); | |||
} | |||
String msg = "Cannot find any " + res + | |||
" antlib descriptors in: " + sPath; | |||
switch (onerror.getIndex()) { | |||
case FAIL: | |||
throw new BuildException(msg); | |||
case REPORT: | |||
log(msg, project.MSG_WARN); | |||
} | |||
} | |||
} | |||
catch (IOException io) { | |||
throw new BuildException("Cannot read file: " + file, io); | |||
String msg = "Cannot load definitions from: " + res; | |||
switch (onerror.getIndex()) { | |||
case FAIL: | |||
throw new BuildException(msg, io); | |||
case REPORT: | |||
log(io.getMessage(), project.MSG_WARN); | |||
} | |||
} | |||
return found; | |||
} | |||
@@ -343,46 +515,29 @@ public class Antlib extends Task { | |||
* @param is InputStream for the Antlib descriptor. | |||
* @exception BuildException trouble | |||
*/ | |||
public void loadDefinitions(InputStream is) | |||
private void loadDefinitions(ClassLoader cl, InputStream is) | |||
throws BuildException { | |||
evaluateDescriptor(null, processAliases(), is); | |||
evaluateDescriptor(cl, processAliases(), is); | |||
} | |||
/** | |||
* get a descriptor from the library file | |||
* get an Enumeration of URLs for all resouces corresponding to the | |||
* descriptor name. | |||
* | |||
* @param file jarfile to open | |||
* @return input stream to the Descriptor | |||
* @param res the name of the resource to collect | |||
* @return input stream to the Descriptor or null if none existent | |||
* @exception BuildException io trouble, or it isnt a zipfile | |||
*/ | |||
private InputStream getDescriptor(File file) | |||
throws BuildException { | |||
try { | |||
final ZipFile zipfile = new ZipFile(file); | |||
ZipEntry entry = zipfile.getEntry(ANT_DESCRIPTOR); | |||
if (entry == null) { | |||
return null; | |||
} | |||
// Guarantee that when Entry is closed so does the zipfile instance. | |||
return | |||
new FilterInputStream(zipfile.getInputStream(entry)) { | |||
public void close() | |||
throws IOException { | |||
super.close(); | |||
zipfile.close(); | |||
} | |||
}; | |||
} | |||
catch (ZipException ze) { | |||
throw new BuildException("Not a library file.", ze, location); | |||
} | |||
catch (IOException ioe) { | |||
throw new BuildException("Cannot read library content.", | |||
ioe, location); | |||
private Enumeration getDescriptors(Path path, final String res) | |||
throws BuildException, IOException { | |||
if (loaderId == null) { | |||
// Path cannot be added to the CoreLoader so simply | |||
// ask for all instances of the resource descriptors | |||
return project.getCoreLoader().getResources(res); | |||
} | |||
return new DescriptorEnumeration(path.list(), res); | |||
} | |||
@@ -410,18 +565,34 @@ public class Antlib extends Task { | |||
* @return classloader using te | |||
* @exception BuildException trouble creating the classloader | |||
*/ | |||
protected ClassLoader makeClassLoader(File file) | |||
protected ClassLoader makeClassLoader(Path clspath) | |||
throws BuildException { | |||
if (loaderId == null) { | |||
log("Loading definitions from CORE, <classpath> ignored", | |||
project.MSG_VERBOSE); | |||
return project.getCoreLoader(); | |||
} | |||
log("Using ClassLoader '" + loaderId + "' to load path: " + clspath, | |||
project.MSG_VERBOSE); | |||
return project.addToLoader(loaderId, clspath); | |||
} | |||
/** | |||
* Constructs the Path to add to the ClassLoader | |||
*/ | |||
private Path makeLoaderClasspath() | |||
{ | |||
Path clspath = new Path(project); | |||
clspath.setLocation(file); | |||
if (file != null) clspath.setLocation(file); | |||
//append any build supplied classpath | |||
if (classpath != null) { | |||
clspath.append(classpath); | |||
} | |||
return project.getSymbols().addToLoader(loaderId, clspath); | |||
return clspath; | |||
} | |||
/** | |||
* parse the antlib descriptor | |||
* | |||
@@ -431,8 +602,8 @@ public class Antlib extends Task { | |||
* @exception BuildException trouble | |||
*/ | |||
protected void evaluateDescriptor(ClassLoader cl, | |||
Properties als, InputStream is) | |||
throws BuildException { | |||
Properties als, InputStream is) | |||
throws BuildException { | |||
try { | |||
SAXParser saxParser = saxFactory.newSAXParser(); | |||
Parser parser = saxParser.getParser(); | |||
@@ -440,7 +611,7 @@ public class Antlib extends Task { | |||
InputSource inputSource = new InputSource(is); | |||
//inputSource.setSystemId(uri); //URI is nasty for jar entries | |||
project.log("parsing descriptor for library: " + file, | |||
Project.MSG_VERBOSE); | |||
Project.MSG_VERBOSE); | |||
saxParser.parse(inputSource, new AntLibraryHandler(cl, als)); | |||
} | |||
catch (ParserConfigurationException exc) { | |||
@@ -485,8 +656,8 @@ public class Antlib extends Task { | |||
/** | |||
* Parses the document describing the content of the | |||
* library. An inner class for access to Project.log | |||
* Parses the document describing the content of the | |||
* library. An inner class for access to Project.log | |||
*/ | |||
private class AntLibraryHandler extends HandlerBase { | |||
@@ -503,13 +674,11 @@ public class Antlib extends Task { | |||
*/ | |||
private Locator locator = null; | |||
private int level = 0; | |||
private SymbolTable symbols = null; | |||
private int level = 0; | |||
private String name = null; | |||
private String className = null; | |||
private String adapter = null; | |||
private String name = null; | |||
private String className = null; | |||
private String adapter = null; | |||
/** | |||
* Constructor for the AntLibraryHandler object | |||
@@ -520,7 +689,6 @@ public class Antlib extends Task { | |||
AntLibraryHandler(ClassLoader classloader, Properties als) { | |||
this.classloader = classloader; | |||
this.aliasMap = als; | |||
this.symbols = project.getSymbols(); | |||
} | |||
/** | |||
@@ -533,35 +701,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); | |||
} | |||
} | |||
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 | |||
@@ -572,103 +740,105 @@ public class Antlib extends Task { | |||
*/ | |||
public void startElement(String tag, AttributeList attrs) | |||
throws SAXParseException { | |||
level ++; | |||
level ++; | |||
if ("antlib".equals(tag)) { | |||
if (level > 1) { | |||
throw new SAXParseException("Unexpected element: " + tag, | |||
locator); | |||
} | |||
if (level > 1) { | |||
throw new SAXParseException("Unexpected element: " + tag, | |||
locator); | |||
} | |||
// No attributes to worry about | |||
return; | |||
} | |||
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); | |||
} | |||
} | |||
if (level == 1) { | |||
throw new SAXParseException("Missing antlib root element", | |||
locator); | |||
} | |||
/** | |||
* 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); | |||
// Must have the two attributes declared | |||
parseAttributes(tag, attrs); | |||
try { | |||
if ("role".equals(tag)) { | |||
if (project.isRoleDefined(name)) { | |||
String msg = "Cannot override role: " + name; | |||
log(msg, Project.MSG_WARN); | |||
return; | |||
} | |||
// Defining a new role | |||
Class clz = loadClass(className); | |||
if (clz != null) { | |||
project.addRoleDefinition(name, clz, | |||
(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 && project.isDefinedOnRole(tag, name)) { | |||
String msg = "Cannot override " + tag + ": " + name; | |||
log(msg, Project.MSG_WARN); | |||
return; | |||
} | |||
Class clz = loadClass(className); | |||
if (clz != null) | |||
project.addDefinitionOnRole(tag, name, clz); | |||
} | |||
catch(BuildException be) { | |||
switch (onerror.getIndex()) { | |||
case FAIL: | |||
throw new SAXParseException(be.getMessage(), locator, be); | |||
case REPORT: | |||
project.log(be.getMessage(), project.MSG_WARN); | |||
break; | |||
default: | |||
project.log(be.getMessage(), project.MSG_DEBUG); | |||
} | |||
} | |||
} | |||
/** | |||
* 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); | |||
public void endElement(String tag) { | |||
level--; | |||
} | |||
private Class loadClass(String className) | |||
throws SAXParseException { | |||
String msg = null; | |||
try { | |||
//load the named class | |||
Class cls; | |||
if(classloader==null) { | |||
cls=Class.forName(className); | |||
} | |||
else { | |||
cls=classloader.loadClass(className); | |||
} | |||
return cls; | |||
} | |||
catch (ClassNotFoundException cnfe) { | |||
msg = "Class " + className + " cannot be found"; | |||
if (onerror.getIndex() == FAIL) | |||
throw new SAXParseException(msg, locator, cnfe); | |||
} | |||
catch (NoClassDefFoundError ncdfe) { | |||
msg = "Class " + className + " cannot be loaded"; | |||
if (onerror.getIndex() == FAIL) | |||
throw new SAXParseException(msg, locator); | |||
} | |||
if (onerror.getIndex() == REPORT) { | |||
project.log(msg, project.MSG_WARN); | |||
} | |||
else { | |||
project.log(msg, project.MSG_DEBUG); | |||
} | |||
return null; | |||
} | |||
//end inner class AntLibraryHandler | |||
@@ -712,7 +882,7 @@ public class Antlib extends Task { | |||
} | |||
//end inner class alias | |||
} | |||
//end class Antlib | |||
} | |||
@@ -66,6 +66,7 @@ import org.apache.tools.ant.*; | |||
public class DataTypeAdapterTask extends Task implements RoleAdapter { | |||
Object proxy; | |||
String id = null; | |||
/** | |||
* Checks a class, whether it is suitable to be adapted. | |||
@@ -83,14 +84,27 @@ public class DataTypeAdapterTask extends Task implements RoleAdapter { | |||
* Do the execution. | |||
*/ | |||
public void execute() throws BuildException { | |||
if (id != null) { | |||
// Need to re-register this reference | |||
// The container has register the Adapter instead | |||
project.addReference(id, proxy); | |||
} | |||
} | |||
/** | |||
* Propagate configuration of Project | |||
*/ | |||
public void setProject(Project p) { | |||
super.setProject(p); | |||
// Check to see if the DataType has a setProject method to set | |||
if (proxy instanceof ProjectComponent) { | |||
((ProjectComponent)proxy).setProject(project); | |||
((ProjectComponent)proxy).setProject(p); | |||
return; | |||
} | |||
// This may not be needed | |||
// We are trying to set project even it is was not declared | |||
// We are trying to set project even if is was not declared | |||
// just like TaskAdapter does for beans, this is not done | |||
// by the original code | |||
Method setProjectM = null; | |||
@@ -99,7 +113,7 @@ public class DataTypeAdapterTask extends Task implements RoleAdapter { | |||
setProjectM = | |||
c.getMethod( "setProject", new Class[] {Project.class}); | |||
if(setProjectM != null) { | |||
setProjectM.invoke(proxy, new Object[] {project}); | |||
setProjectM.invoke(proxy, new Object[] {p}); | |||
} | |||
} catch (NoSuchMethodException e) { | |||
// ignore this if the class being used as a task does not have | |||
@@ -122,4 +136,8 @@ public class DataTypeAdapterTask extends Task implements RoleAdapter { | |||
return this.proxy ; | |||
} | |||
public void setId(String id) { | |||
log("Setting adapter id to: " + id, Project.MSG_DEBUG); | |||
this.id = id; | |||
} | |||
} |