Return-Path: Delivered-To: apmail-jakarta-ant-dev-archive@jakarta.apache.org Received: (qmail 9919 invoked by uid 500); 21 Jul 2001 17:19:17 -0000 Mailing-List: contact ant-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk Reply-To: ant-dev@jakarta.apache.org list-help: list-unsubscribe: list-post: Delivered-To: mailing list ant-dev@jakarta.apache.org Received: (qmail 9910 invoked from network); 21 Jul 2001 17:19:16 -0000 Message-ID: <005101c1120a$2c26ae70$f5fa07d5@pete> From: "Stefan Reich" To: Subject: [PATCH] Lazy task class loading Date: Sat, 21 Jul 2001 19:25:43 +0200 MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="----=_NextPart_000_004E_01C1121A.EF661960" X-Priority: 3 X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook Express 5.00.3018.1300 X-MimeOLE: Produced By Microsoft MimeOLE V5.00.3018.1300 X-Spam-Rating: h31.sny.collab.net 1.6.2 0/1000/N This is a multi-part message in MIME format. ------=_NextPart_000_004E_01C1121A.EF661960 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Hi, currently Ant loads all taskdef classes (as defined in = defaults.properties) on startup. This mechanism has at least 3 = drawbacks: -It can take up to one second or longer (if you use ant for everyday = development, you will notice the difference) -It wastes memory -It completely lacks descriptive error messages. For example, if you use = , but junit.jar isn't in your classpath, you only get a default = message telling you something about optional.jar. I've been puzzled as = to why tasks couldn't be loaded more than once. I would like to submit a patch that solves all three problems. I also = took care to ensure that the public interface of = org.apache.tools.ant.Project is backward compatible. -Stefan Here is the patch against recent CVS (I already added @author tags for = your convenience ;-): Index: main/org/apache/tools/ant/Project.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: = /home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/Project.java,v retrieving revision 1.64 diff -u -r1.64 Project.java --- main/org/apache/tools/ant/Project.java 2001/07/17 12:12:39 1.64 +++ main/org/apache/tools/ant/Project.java 2001/07/21 17:03:14 @@ -68,6 +68,7 @@ * file paths at runtime as well as defining various project = properties. * * @author duncan@x180.com + * @author Stefan Reich doc@drjava.de */ =20 public class Project { @@ -101,7 +102,8 @@ private Hashtable references =3D new Hashtable(); private String defaultTarget; private Hashtable dataClassDefinitions =3D new Hashtable(); - private Hashtable taskClassDefinitions =3D new Hashtable(); + private TaskDefinitionHashtable taskClassDefinitions =3D new = TaskDefinitionHashtable(); + =20 private Hashtable targets =3D new Hashtable(); private Hashtable filters =3D new Hashtable(); private File baseDir; @@ -114,6 +116,27 @@ /** The system classloader - may be null */ =20 private ClassLoader systemLoader =3D null; =20 + public static class TaskDefinitionHashtable extends Hashtable { + /** lazily call Class.forName */ + public Object get(Object key) { + Object value =3D super.get(key); + if (value instanceof String) { + try { + value =3D Class.forName((String) value); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e.toString()); + } catch (NoClassDefFoundError e) { + throw new RuntimeException(e.toString()); + } + } + return value; + } + =20 + public String getClassName(Object key) { + return (String) super.get(key); + } + } + =20 static { =20 // Determine the Java version by looking at available classes @@ -161,19 +184,23 @@ props.load(in); in.close(); =20 + long startTime =3D System.currentTimeMillis(); Enumeration enum =3D props.propertyNames(); while (enum.hasMoreElements()) { String key =3D (String) enum.nextElement(); String value =3D props.getProperty(key); - try { + /*try { Class taskClass =3D Class.forName(value); addTaskDefinition(key, taskClass); } catch (NoClassDefFoundError ncdfe) { // ignore... } catch (ClassNotFoundException cnfe) { // ignore... - } + }*/ + addTaskDefinition(key, value); } + long endTime =3D System.currentTimeMillis(); + System.out.println("Class loading took = "+(endTime-startTime)+" ms"); } catch (IOException ioe) { throw new BuildException("Can't load default task list"); } @@ -367,13 +394,19 @@ log("Detected OS: " + System.getProperty("os.name"), = MSG_VERBOSE); } =20 + public void addTaskDefinition(String taskName, String taskClass) { + String msg =3D " +User task: " + taskName + " " + = taskClass; + log(msg, MSG_DEBUG); + taskClassDefinitions.put(taskName, taskClass); + } + public void addTaskDefinition(String taskName, Class taskClass) { String msg =3D " +User task: " + taskName + " " + = taskClass.getName(); log(msg, MSG_DEBUG); taskClassDefinitions.put(taskName, taskClass); } =20 - public Hashtable getTaskDefinitions() { + public TaskDefinitionHashtable getTaskDefinitions() { return taskClassDefinitions; } =20 @@ -445,7 +478,12 @@ } =20 public Task createTask(String taskType) throws BuildException { - Class c =3D (Class) taskClassDefinitions.get(taskType); + Class c; + try { + c =3D (Class) taskClassDefinitions.get(taskType); + } catch (RuntimeException e) { + throw new BuildException(e.getMessage()); + } =20 if (c =3D=3D null) return null; Index: main/org/apache/tools/ant/taskdefs/Ant.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: = /home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Ant.ja= va,v retrieving revision 1.23 diff -u -r1.23 Ant.java --- main/org/apache/tools/ant/taskdefs/Ant.java 2001/07/06 11:57:29 1.23 +++ main/org/apache/tools/ant/taskdefs/Ant.java 2001/07/21 17:03:15 @@ -76,6 +76,7 @@ * * * @author costin@dnt.ro + * @author Stefan Reich doc@drjava.de */ public class Ant extends Task { =20 @@ -143,11 +144,11 @@ } } =20 - Hashtable taskdefs =3D project.getTaskDefinitions(); + Project.TaskDefinitionHashtable taskdefs =3D = project.getTaskDefinitions(); Enumeration et =3D taskdefs.keys(); while (et.hasMoreElements()) { String taskName =3D (String) et.nextElement(); - Class taskClass =3D (Class) taskdefs.get(taskName); + String taskClass =3D taskdefs.getClassName(taskName); p1.addTaskDefinition(taskName, taskClass); } ------=_NextPart_000_004E_01C1121A.EF661960 Content-Type: text/html; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable
Hi,
 
currently Ant loads all taskdef classes = (as defined=20 in defaults.properties) on startup. This mechanism has at least 3=20 drawbacks:
 
-It can take up to one second or longer = (if you use=20 ant for everyday development, you will notice the = difference)
-It wastes memory
-It completely lacks descriptive error = messages.=20 For example, if you use <junit>, but junit.jar isn't in your = classpath,=20 you only get a default message telling you something about optional.jar. = I've=20 been puzzled as to why tasks couldn't be loaded more than = once.
 
I would like to submit a patch that = solves all=20 three problems. I also took care = to ensure=20 that the public interface of org.apache.tools.ant.Project is backward=20 compatible.
 
-Stefan
 
Here is the patch against recent CVS (I = already=20 added @author tags for your convenience ;-):
 
Index:=20 main/org/apache/tools/ant/Project.java
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D
RCS=20 file:=20 /home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/Project.java,v<= BR>retrieving=20 revision 1.64
diff -u -r1.64 Project.java
---=20 main/org/apache/tools/ant/Project.java 2001/07/17 = 12:12:39 1.64
+++=20 main/org/apache/tools/ant/Project.java 2001/07/21 17:03:14
@@ = -68,6=20 +68,7 @@
  * file paths at runtime as well as defining various = project=20 properties.
  *
  * @author duncan@x180.com
+ * @author = Stefan Reich=20 <a href=3D"mailto:doc@drjava.d= e">doc@drjava.de</a>
 =20 */
 
 public class Project {
@@ -101,7 +102,8=20 @@
     private Hashtable references =3D new=20 Hashtable();
     private String=20 defaultTarget;
     private Hashtable=20 dataClassDefinitions =3D new Hashtable();
-    private = Hashtable=20 taskClassDefinitions =3D new Hashtable();
+    private = TaskDefinitionHashtable taskClassDefinitions =3D new=20 TaskDefinitionHashtable();
+    =
    =20 private Hashtable targets =3D new = Hashtable();
     private=20 Hashtable filters =3D new Hashtable();
     = private File=20 baseDir;
@@ -114,6 +116,27 @@
     /** The = system=20 classloader - may be null */    =
    =20 private ClassLoader systemLoader =3D null;
    =20
+    public static class TaskDefinitionHashtable = extends=20 Hashtable {
+      /** lazily call = Class.forName=20 */
+      public Object get(Object key)=20 {
+        Object value =3D=20 super.get(key);
+        if (value = instanceof String) = {
+         =20 try = {
+            = value =3D Class.forName((String)=20 value);
+          } = catch=20 (ClassNotFoundException e)=20 {
+            = throw=20 new=20 RuntimeException(e.toString());
+      &= nbsp;  =20 } catch (NoClassDefFoundError e)=20 {
+            = throw=20 new=20 RuntimeException(e.toString());
+      &= nbsp;  =20 }
+       =20 }
+        return=20 value;
+      = }
+     =20
+      public String getClassName(Object = key)=20 {
+        return (String)=20 super.get(key);
+      = }
+   =20 }
+   
     static=20 {
 
         // = Determine the=20 Java version by looking at available classes
@@ -161,19 +184,23=20 @@
           &= nbsp;=20 props.load(in);
         =    =20 in.close();
 
+        = ;    long startTime =3D=20 System.currentTimeMillis();
       =      =20 Enumeration enum =3D=20 props.propertyNames();
        = ;    =20 while (enum.hasMoreElements())=20 {
           &n= bsp;    =20 String key =3D (String)=20 enum.nextElement();
        &n= bsp;       =20 String value =3D=20 props.getProperty(key);
-       &nb= sp;       =20 try=20 {
+           &= nbsp;   =20 /*try=20 {
           &n= bsp;        =20 Class taskClass =3D=20 Class.forName(value);
        =              = addTaskDefinition(key,=20 taskClass);
         &nbs= p;      =20 } catch (NoClassDefFoundError ncdfe)=20 {
           &n= bsp;        =20 //=20 ignore...
          =       =20 } catch (ClassNotFoundException cnfe)=20 {
           &n= bsp;        =20 //=20 ignore...
-          = ;     =20 }
+           &= nbsp;   =20 }*/
+           = ;    =20 addTaskDefinition(key,=20 value);
          &n= bsp; =20 }
+           &= nbsp;long endTime =3D=20 System.currentTimeMillis();
+       = ;    =20 System.out.println("Class = loading took=20 "+(endTime-startTime)+"=20 ms");
         } catch = (IOException=20 ioe)=20 {
           &n= bsp;=20 throw new BuildException("Can't load default task=20 list");
         }
@@ = -367,13=20 +394,19 @@
         = log("Detected OS:=20 " + System.getProperty("os.name"), = MSG_VERBOSE);
    =20 }
 
+    public void addTaskDefinition(String=20 taskName, String taskClass) = {
+       =20 String msg =3D " +User task: " + taskName + "     " = +=20 taskClass;
+        log(msg,=20 MSG_DEBUG);
+       =20 taskClassDefinitions.put(taskName, taskClass);
+   =20 }
+
     public void addTaskDefinition(String=20 taskName, Class taskClass) = {
        =20 String msg =3D " +User task: " + taskName + "     " = +=20 taskClass.getName();
         = log(msg, MSG_DEBUG);
         = taskClassDefinitions.put(taskName, = taskClass);
    =20 }
 
-    public Hashtable getTaskDefinitions() = {
+    public TaskDefinitionHashtable = getTaskDefinitions()=20 {
         return=20 taskClassDefinitions;
     }
 
@@ = -445,7=20 +478,12 @@
     = }
 
    =20 public Task createTask(String taskType) throws BuildException=20 {
-        Class c =3D (Class)=20 taskClassDefinitions.get(taskType);
+     &nb= sp; =20 Class c;
+        try=20 {
+          c =3D = (Class)=20 taskClassDefinitions.get(taskType);
+     &nb= sp; =20 } catch (RuntimeException e)=20 {
+          throw new=20 BuildException(e.getMessage());
+      &= nbsp;=20 }
 
         if (c = =3D=3D=20 null)
          &nbs= p; =20 return null;
Index:=20 main/org/apache/tools/ant/taskdefs/Ant.java
=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D
RCS=20 file:=20 /home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Ant.ja= va,v
retrieving=20 revision 1.23
diff -u -r1.23 Ant.java
---=20 main/org/apache/tools/ant/taskdefs/Ant.java 2001/07/06=20 11:57:29 1.23
+++=20 main/org/apache/tools/ant/taskdefs/Ant.java 2001/07/21 = 17:03:15
@@ -76,6=20 +76,7 @@
  *
  *
  * @author costin@dnt.ro
+ * @author Stefan = Reich <a=20 href=3D"mailto:doc@drjava.d= e">doc@drjava.de</a>
 =20 */
 public class Ant extends Task {
 
@@ -143,11 = +144,11=20 @@
           &= nbsp;=20 }
        =20 }
 
-        Hashtable = taskdefs =3D=20 project.getTaskDefinitions();
+      &nb= sp;=20 Project.TaskDefinitionHashtable taskdefs =3D=20 project.getTaskDefinitions();
      &nbs= p; =20 Enumeration et =3D=20 taskdefs.keys();
         = while=20 (et.hasMoreElements())=20 {
           &n= bsp;=20 String taskName =3D (String)=20 et.nextElement();
-        &nb= sp;  =20 Class taskClass =3D (Class)=20 taskdefs.get(taskName);
+       &nb= sp;   =20 String taskClass =3D=20 taskdefs.getClassName(taskName);
      &= nbsp;     =20 p1.addTaskDefinition(taskName,=20 taskClass);
         = }
 
 
------=_NextPart_000_004E_01C1121A.EF661960--