Bug 11560 - Taskdef does not apply reverseLoader policy on standard tasks
Summary: Taskdef does not apply reverseLoader policy on standard tasks
Status: REOPENED
Alias: None
Product: Ant
Classification: Unclassified
Component: Core tasks (show other bugs)
Version: 1.5
Hardware: All All
: P3 enhancement (vote)
Target Milestone: ---
Assignee: Ant Notifications List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2002-08-08 14:18 UTC by Lo
Modified: 2008-02-22 12:18 UTC (History)
0 users



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Lo 2002-08-08 14:18:26 UTC
When using 'reverseLoader="true"' within a 'taskdef', standard ant tasks are 
not reloaded using the specified classpath

Explanation:

When Definer creates an AntClassLoader, it specifies "org.apache.tools.ant" as 
a system package root to uniquely load org.apache.tools.ant.Task and friends 
(otherwise breakages are to be expected)

But not all classes inside org.apache.tools.ant package and furthermore inside 
sub-packages need to be loaded only once, but instead can benefit from being 
reloaded using an extended classpath:

        <taskdef name="javac" classname="org.apache.tools.ant.taskdefs.Javac"
            reverseLoader="true">
            <classpath>
                <!-- contains tools.jar -->
                <fileset dir="${system.JAVA_HOME}/lib" includes="*.jar,*.zip" />
                <!-- contains ant.jar -->
                <fileset dir="${build.lib}" includes="*.jar,*.zip" />
            </classpath>
        </taskdef>

Workaround:

Set CLASSPATH with an external script which requires to re-code some of ant 
features like fileset and classpath using a non-portable script language
(as is done today) or bootstrap ant itself using a second JVM - both are 
similarly inefficient

Solution:

Force the currently re-defined class (as Definer is not only used for tasks) to 
be loaded by the AntClassLoader by addLoaderPackageRoot when reverseLoader is 
defined

---8<--------------------------------------------------------------
--- Definer.java.old	Tue Jul 09 11:28:38 2002
+++ Definer.java	Thu Aug 08 15:37:24 2002
@@ -224,9 +224,15 @@
      * create the classloader then hand the definition off to the subclass;
      * @throws BuildException when the class wont load for any reason
      */
-    private void addDefinition(ClassLoader al, String name, String value)
+    private void addDefinition(AntClassLoader al, String name, String value)
         throws BuildException {
         try {
+            // allow reload even for ant classes
+            if (reverseLoader) {
+                al.addLoaderPackageRoot(
+                        value.substring(0, value.lastIndexOf('.')));
+            }
+            
             Class c = al.loadClass(value);
             AntClassLoader.initializeClass(c);
             addDefinition(name, c);
---8<--------------------------------------------------------------
Comment 1 Lo 2002-08-09 09:43:01 UTC
This patch does not really resolve all my problems, thus I changed it to 
INVALID state - I'm still investigation to find a proper solution based on a 
list of packages/classes for addLoaderPackageRoot()
Comment 2 Lo 2002-08-09 16:27:46 UTC
This new patch alloxs to alter the system and loader package root lists at 
classloader instantiation through new attributes and new elements.

---8<----------------------------------------------------------------- 
Definer.java.orig	Tue Jul 09 11:28:38 2002
+++ Definer.java.packageroots	Fri Aug 09 18:14:17 2002
@@ -63,6 +63,8 @@
 
 import java.util.Properties;
 import java.util.Enumeration;
+import java.util.Vector;
+import java.util.StringTokenizer;
 import java.io.File;
 import java.io.InputStream;
 import java.io.FileInputStream;
@@ -88,7 +90,63 @@
     private String classpathId = null;
     
     private static final String REUSE_LOADER_REF = "ant.reuse.loader";
+
+    private Vector systemPackageRootList = new Vector();
+    private Vector loaderPackageRootList = new Vector();
+
+    public static class PackageRoot {
+
+        public PackageRoot() {
+        }
+
+        private String name = null;
+
+        public void setName(String s) {
+            name = s;
+        }
+
+        public String getName() {
+            return name;
+        }
+        
+    }
     
+    public void setSystemPackageRoots(String s) {
+        setPackageRoots(false, s);
+    }
+
+    public void setLoaderPackageRoots(String s) {
+        setPackageRoots(true, s);
+    }
+
+    protected void setPackageRoots(boolean loaderPackageRoot, String s) {
+        StringTokenizer t = new StringTokenizer(s,",");
+        while (t.hasMoreTokens()) {
+            String p = t.nextToken().trim();
+            if (p != null && p.length() != 0) {
+                createPackageRoot(loaderPackageRoot).setName(p);
+            }
+        }
+    }
+
+    public PackageRoot createSystemPackageRoot() {
+        return createPackageRoot(false);
+    }
+
+    public PackageRoot createLoaderPackageRoot() {
+        return createPackageRoot(true);
+    }
+
+    protected PackageRoot createPackageRoot(boolean loaderPackageRoot) {
+        PackageRoot pr = new PackageRoot();
+        if (loaderPackageRoot) {
+            loaderPackageRootList.addElement(pr);
+        } else {
+            systemPackageRootList.addElement(pr);
+        }
+        return pr;
+    }
+
     /**
      * @deprecated stop using this attribute
      * @ant.attribute ignore="true"
@@ -282,6 +340,15 @@
         // be wrapped into a TaskAdapter.
         al.addSystemPackageRoot("org.apache.tools.ant");
 
+        for (int i = 0; i < systemPackageRootList.size(); i++) {
+            PackageRoot pr = (PackageRoot)systemPackageRootList.get(i);
+            al.addSystemPackageRoot(pr.getName());
+        }
+
+        for (int i = 0; i < loaderPackageRootList.size(); i++) {
+            PackageRoot pr = (PackageRoot)loaderPackageRootList.get(i);
+            al.addLoaderPackageRoot(pr.getName());
+        }
 
         // If the loader is new, record it for future uses by other
         // task/typedefs
---8<--------------------------------------------------------------

It solved my problem and is much more useable than my previous attempt.

I can now use:

        <taskdef name="javac" classname="org.apache.tools.ant.taskdefs.Javac">
            <loaderpackageroot name="org.apache.tools.ant.taskdefs" />
            <classpath>
                <!-- contains tools.jar -->
                <fileset dir="${SYSTEM.JAVA_HOME}/lib" includes="*.jar,*.zip" />
                <!-- contains ant.jar -->
                <fileset dir="${buildlibs}" includes="*.jar,*.zip" />
            </classpath>
        </taskdef>
        <javac destdir="${destdir}" srcdir="${srcdir}"
            classpathref="javac-classpath">
            <!-- referenciation needed to workaround bug
                 to be corrected in 1.5.1 -->
            <classpath id="javac-classpath">
                <!-- contains source dependencies -->
                <fileset dir="${dep.java.lib}" includes="*.jar,*.zip" />
            </classpath>
        </javac>
 
After the task redefinition bug is corrected, I won't need any launch script at 
all :)