Browse Source

once again for Jose Alberto - think I got it right this time

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271710 13f79535-47bb-0310-9956-ffa450edef68
master
Erik Hatcher 23 years ago
parent
commit
6252354506
10 changed files with 1971 additions and 1201 deletions
  1. +40
    -6
      proposal/sandbox/antlib/build.xml
  2. +993
    -546
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/Project.java
  3. +96
    -60
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/ProjectHelper.java
  4. +5
    -0
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/RoleAdapter.java
  5. +358
    -288
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/SymbolTable.java
  6. +22
    -14
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/TaskAdapter.java
  7. +1
    -23
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Ant.java
  8. +9
    -5
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antjar.java
  9. +426
    -256
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antlib.java
  10. +21
    -3
      proposal/sandbox/antlib/src/main/org/apache/tools/ant/types/DataTypeAdapterTask.java

+ 40
- 6
proposal/sandbox/antlib/build.xml View File

@@ -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>



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


+ 96
- 60
proposal/sandbox/antlib/src/main/org/apache/tools/ant/ProjectHelper.java View File

@@ -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);
}
}


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

@@ -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


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

@@ -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);
}
}

}
}

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

@@ -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) {}
}

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

@@ -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) {


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

@@ -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);


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

@@ -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
}



+ 21
- 3
proposal/sandbox/antlib/src/main/org/apache/tools/ant/types/DataTypeAdapterTask.java View File

@@ -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;
}
}

Loading…
Cancel
Save