Hi,
One big problem with taskdef is that each task is created in a separate
class loader. This patch solves this by keeping caching the classloader
by the refid.
It also allows to define multiple tasks from a properties file ( the same
as native ant tasks are defined, or <property> reads properties ).
( I'm not sure what's my status, I used to have commit access on ant, but
it's a long time since I looked at the code - so I think it's better to
send a patch for someone more familiar with the code to commit. Strangely,
I'm listed as author on this file - but I can hardly recognize few lines
of code, it looks to good :-)
Thanks,
Costin
Index: src/main/org/apache/tools/ant/AntClassLoader.java
===================================================================
RCS file:
/home/cvs/jakarta-ant/src/main/org/apache/tools/ant/AntClassLoader.java,v
retrieving revision 1.28
diff -u -r1.28 AntClassLoader.java
--- src/main/org/apache/tools/ant/AntClassLoader.java 2001/07/17 14:32:04
1.28
+++ src/main/org/apache/tools/ant/AntClassLoader.java 2001/07/17 21:26:48
@@ -573,7 +573,6 @@
if (file.isDirectory()) {
File resource = new File(file, resourceName);
-
if (resource.exists()) {
return new FileInputStream(resource);
}
Index: src/main/org/apache/tools/ant/taskdefs/Definer.java
===================================================================
RCS file:
/home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Definer.java,v
retrieving revision 1.5
diff -u -r1.5 Definer.java
--- src/main/org/apache/tools/ant/taskdefs/Definer.java 2001/07/11 16:11:39
1.5
+++ src/main/org/apache/tools/ant/taskdefs/Definer.java 2001/07/17 21:26:49
@@ -57,18 +57,28 @@
import org.apache.tools.ant.*;
import org.apache.tools.ant.types.*;
+import java.util.*;
+import java.io.*;
+
/**
* Base class for Taskdef and Typedef - does all the classpath
* handling and and class loading.
*
- * @author [EMAIL PROTECTED]
+ * @author Costin Manolache
* @author <a href="[EMAIL PROTECTED]">Stefan Bodewig</a>
*/
public abstract class Definer extends Task {
private String name;
private String value;
private Path classpath;
+ private File file;
+ private String resource;
+ // used to load in the same classloader if the same path is used
+ // this works for classpathRef
+ private String refId;
+ private static Hashtable classLoaders=new Hashtable();
+
public void setClasspath(Path classpath) {
if (this.classpath == null) {
this.classpath = classpath;
@@ -86,41 +96,96 @@
public void setClasspathRef(Reference r) {
createClasspath().setRefid(r);
+ refId=r.getRefId();
}
public void execute() throws BuildException {
- if (name==null || value==null ) {
- String msg = "name or classname attributes of "
- + getTaskName() + " element "
- + "are undefined";
- throw new BuildException(msg);
- }
- try {
- AntClassLoader al = null;
- if (classpath != null) {
- al = new AntClassLoader(project, classpath);
- } else {
- al = new AntClassLoader(project, Path.systemClasspath);
- }
- // need to load Task via system classloader or the new
- // task we want to define will never be a Task but always
- // be wrapped into a TaskAdapter.
- al.addSystemPackageRoot("org.apache.tools.ant");
-
- Class c = al.loadClass(value);
- AntClassLoader.initializeClass(c);
- addDefinition(name, c);
- } catch (ClassNotFoundException cnfe) {
- String msg = getTaskName()+" class " + value +
- " cannot be found";
- throw new BuildException(msg, cnfe, location);
- } catch (NoClassDefFoundError ncdfe) {
- String msg = getTaskName()+" class " + value +
- " cannot be found";
- throw new BuildException(msg, ncdfe, location);
- }
+ AntClassLoader al=createLoader();
+
+ if (file==null && resource==null ) {
+ // simple case - one definition
+ if ( name==null || value==null ) {
+ String msg = "name or classname attributes of "
+ + getTaskName() + " element "
+ + "are undefined";
+ throw new BuildException(msg);
+ }
+
+ addDefinition( al, name, value );
+ }
+
+ try {
+ Properties props=new Properties();
+ InputStream is=null;
+ if( file != null ) {
+ log("File Loading " + file, Project.MSG_VERBOSE);
+ is=new FileInputStream( file );
+ }
+ if( resource!=null ) {
+ log("Resource Loading " + resource, Project.MSG_VERBOSE);
+ is=al.getResourceAsStream( resource );
+ }
+ if( is!=null ) {
+ props.load( is );
+ Enumeration keys=props.keys();
+ while( keys.hasMoreElements() ) {
+ String n=(String)keys.nextElement();
+ String v=props.getProperty( n );
+ addDefinition( al, n, v );
+ }
+ }
+ } catch( IOException ex ) {
+ throw new BuildException( ex );
+ }
+
}
-
+
+ private void addDefinition( ClassLoader al, String name, String value ) {
+ try {
+ Class c = al.loadClass(value);
+ AntClassLoader.initializeClass(c);
+ addDefinition(name, c);
+ } catch (ClassNotFoundException cnfe) {
+ String msg = getTaskName()+" class " + value +
+ " cannot be found";
+ throw new BuildException(msg, cnfe, location);
+ } catch (NoClassDefFoundError ncdfe) {
+ String msg = getTaskName()+" class " + value +
+ " cannot be found";
+ throw new BuildException(msg, ncdfe, location);
+ }
+ }
+
+
+ private AntClassLoader createLoader() {
+ // XXX Why do we need a separate loader if no cpath is specified ??
+ AntClassLoader al = null;
+ if( refId != null )
+ al=(AntClassLoader)classLoaders.get( refId );
+ if( al!=null ) return al;
+ if (classpath != null) {
+ al = new AntClassLoader(project, classpath);
+ } else {
+ al = new AntClassLoader(project, Path.systemClasspath);
+ }
+ // need to load Task via system classloader or the new
+ // task we want to define will never be a Task but always
+ // be wrapped into a TaskAdapter.
+ al.addSystemPackageRoot("org.apache.tools.ant");
+
+ if( refId!=null )
+ classLoaders.put( refId, al );
+ return al;
+ }
+
+ public void setFile( File file ) {
+ this.file=file;
+ }
+
+ public void setResource( String res ) {
+ this.resource=res;
+ }
+
public void setName( String name) {
this.name = name;
}