[seam-commits] Seam SVN: r10910 - branches/community/Seam_2_1/src/wicket/org/jboss/seam/wicket/ioc.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Wed May 13 21:29:51 EDT 2009


Author: cpopetz
Date: 2009-05-13 21:29:51 -0400 (Wed, 13 May 2009)
New Revision: 10910

Modified:
   branches/community/Seam_2_1/src/wicket/org/jboss/seam/wicket/ioc/JavassistInstrumentor.java
   branches/community/Seam_2_1/src/wicket/org/jboss/seam/wicket/ioc/WicketClassLoader.java
   branches/community/Seam_2_1/src/wicket/org/jboss/seam/wicket/ioc/WicketInstrumentationTask.java
Log:
JBSEAM-4173

Modified: branches/community/Seam_2_1/src/wicket/org/jboss/seam/wicket/ioc/JavassistInstrumentor.java
===================================================================
--- branches/community/Seam_2_1/src/wicket/org/jboss/seam/wicket/ioc/JavassistInstrumentor.java	2009-05-13 20:31:38 UTC (rev 10909)
+++ branches/community/Seam_2_1/src/wicket/org/jboss/seam/wicket/ioc/JavassistInstrumentor.java	2009-05-14 01:29:51 UTC (rev 10910)
@@ -120,6 +120,11 @@
     * If true, only instrument classes annotated with @WicketComponent and their non-static inner classes.
     */
    private boolean scanAnnotations;
+
+   /**
+    * If we're only instrumenting a specific set of classes, these are the names of those classes
+    */
+   private Set<String> onlyTheseClasses;
    
    public JavassistInstrumentor(ClassPool classPool)
    {
@@ -173,13 +178,32 @@
     */
    public void instrumentClass(CtClass implementation) throws NotFoundException, CannotCompileException
    {
+      
       String className = implementation.getName();
       CtClass handlerClass = classPool.get(WicketHandler.class.getName());
       CtClass componentClass = classPool.get(WicketComponent.class.getName());
 
-      CtField handlerField = new CtField(handlerClass, "handler", implementation);
-      Initializer handlerInitializer = Initializer.byCall(handlerClass, "create");
-      implementation.addField(handlerField, handlerInitializer);
+      /*
+       * We only want one WicketHandler field per bean, so don't add that field to classes whose
+       * parent has been or is to be be instrumented.
+       */
+      CtClass superclass = implementation.getSuperclass();
+      if (!isInstrumented(superclass)) { 
+         if (!isInstrumentable(superclass)) {
+            //we're the top-most instrumentable class, so add the handler field
+	         CtField handlerField = new CtField(handlerClass, "handler", implementation);
+	         handlerField.setModifiers(Modifier.PROTECTED);
+	         Initializer handlerInitializer = Initializer.byCall(handlerClass, "create");
+	         implementation.addField(handlerField, handlerInitializer);
+	         CtMethod getHandlerMethod = CtNewMethod.getter("getHandler", handlerField);
+	         implementation.addMethod(getHandlerMethod);
+         }
+         else { 
+            //in order for the below code to make reference to the handler instance we need to 
+            //recursively instrument until we reach the top of the instrumentable class tree
+            instrumentClass(superclass);
+         }
+      }
 
       CtField wicketComponentField = new CtField(componentClass, "component", implementation);
       wicketComponentField.setModifiers(Modifier.STATIC);
@@ -189,10 +213,8 @@
       CtClass exception = classPool.get(Exception.class.getName());
 
       implementation.addInterface(getInstrumentedComponentInterface());
-      CtMethod getHandlerMethod = CtNewMethod.getter("getHandler", handlerField);
-      CtMethod getEnclosingInstance = CtNewMethod.make("public " + InstrumentedComponent.class.getName() + " getEnclosingInstance() { return handler == null ? null : handler.getEnclosingInstance(this); }", implementation);
+      CtMethod getEnclosingInstance = CtNewMethod.make("public " + InstrumentedComponent.class.getName() + " getEnclosingInstance() { return getHandler() == null ? null : getHandler().getEnclosingInstance(this); }", implementation);
       implementation.addMethod(getEnclosingInstance);
-      implementation.addMethod(getHandlerMethod);
 
       for (CtMethod method : implementation.getDeclaredMethods())
       {
@@ -216,9 +238,9 @@
          {
             {
                String constructorObject = createConstructorObject(className, constructor);
-               constructor.insertBeforeBody(constructorObject + "handler.beforeInvoke(this, constructor);");
-               constructor.addCatch("{" + constructorObject + "throw new RuntimeException(handler.handleException(this, constructor, e));}", exception, "e");
-               constructor.insertAfter(constructorObject + "handler.afterInvoke(this, constructor);");
+               constructor.insertBeforeBody(constructorObject + "getHandler().beforeInvoke(this, constructor);");
+               constructor.addCatch("{" + constructorObject + "throw new RuntimeException(getHandler().handleException(this, constructor, e));}", exception, "e");
+               constructor.insertAfter(constructorObject + "getHandler().afterInvoke(this, constructor);");
                log.trace("instrumented constructor " + constructor.getName());
             }
          }
@@ -235,7 +257,7 @@
     */
    private static String createBody(CtClass clazz, CtMethod method, CtMethod newMethod) throws NotFoundException
    {
-      String src = "{" + createMethodObject(clazz, method) + "if (this.handler != null) this.handler.beforeInvoke(this, method);" + createMethodDelegation(newMethod) + "if (this.handler != null) result = ($r) this.handler.afterInvoke(this, method, ($w) result); return ($r) result;}";
+      String src = "{" + createMethodObject(clazz, method) + "if (getHandler() != null) getHandler().beforeInvoke(this, method);" + createMethodDelegation(newMethod) + "if (this.handler != null) result = ($r) this.handler.afterInvoke(this, method, ($w) result); return ($r) result;}";
 
       log.trace("Creating method " + clazz.getName() + "." + newMethod.getName() + "(" + newMethod.getSignature() + ")" + src);
       return src;
@@ -269,7 +291,7 @@
     */
    private static String wrapInExceptionHandler(String src)
    {
-      return "try {" + src + "} catch (Exception e) { throw new RuntimeException(this.handler == null ? e : this.handler.handleException(this, method, e)); }";
+      return "try {" + src + "} catch (Exception e) { throw new RuntimeException(getHandler() == null ? e : getHandler().handleException(this, method, e)); }";
    }
 
    /**
@@ -390,6 +412,10 @@
       {
          return false;
       }
+      if (onlyTheseClasses != null && !onlyTheseClasses.contains(clazz.getName()))
+      {
+         return false;
+      }
 
       try
       {
@@ -417,9 +443,8 @@
          // do not instrument something we've already instrumented.
          // can't use 'isSubtype' because the superclass may be instrumented
          // while we are not
-         for (String inf : clazz.getClassFile2().getInterfaces())
-            if (inf.equals(getInstrumentedComponentInterface().getName()))
-               return false;
+         if (isInstrumented(clazz))
+            return false;
       }
       catch (Exception e)
       {
@@ -429,6 +454,14 @@
       return true;
    }
 
+   private boolean isInstrumented(CtClass clazz)
+   {
+      for (String inf : clazz.getClassFile2().getInterfaces())
+         if (inf.equals(getInstrumentedComponentInterface().getName()))
+            return true;
+      return false;
+   }
+
    /**
     * We have to look this up lazily because when our constructor is called we may not have the appropriate paths added to our ClassPool,
     * particularly if we are doing runtime instrumentation using WEB-INF/wicket
@@ -465,14 +498,18 @@
          {
             try
             {
-               CtClass result = instrumentClass(classfileBuffer);
-               if (result == null)
+               CtClass clazz = classPool.get(className);
+               if (clazz.isModified())
+                  return clazz.toBytecode();
+               clazz = instrumentClass(classfileBuffer);
+               if (clazz == null)
                   return null;
                else
-                  return result.toBytecode();
+                  return clazz.toBytecode();
             }
             catch (Exception e)
             {
+               e.printStackTrace();
                throw new RuntimeException(e);
             }
          }
@@ -529,4 +566,32 @@
       classPool.appendSystemPath();
       instrumentation.addTransformer(new JavassistInstrumentor(classPool, packagesToInstrument, scanAnnotations));
    }
+
+   /**
+    * This instruments a specific set of classes and writes their classes to the specified directory, if that
+    * directory is non-null
+    * @param toInstrument the set of class names to instrument
+    * @param path where to write the modified classes, or null to not write anything
+    * @throws CannotCompileException 
+    * @throws NotFoundException 
+    */
+   public void instrumentClassSet(Set<String> toInstrument, String path) throws CannotCompileException, NotFoundException 
+   {
+      this.onlyTheseClasses = toInstrument;
+      for (String className : toInstrument) 
+      {
+         CtClass clazz = instrumentClass(className);
+         if (path != null && clazz.isModified())
+         {
+            try 
+            { 
+               clazz.writeFile(path);
+            }
+            catch (IOException e) 
+            {
+               throw new RuntimeException(e);
+            }
+         }
+      }
+   }
 }

Modified: branches/community/Seam_2_1/src/wicket/org/jboss/seam/wicket/ioc/WicketClassLoader.java
===================================================================
--- branches/community/Seam_2_1/src/wicket/org/jboss/seam/wicket/ioc/WicketClassLoader.java	2009-05-13 20:31:38 UTC (rev 10909)
+++ branches/community/Seam_2_1/src/wicket/org/jboss/seam/wicket/ioc/WicketClassLoader.java	2009-05-14 01:29:51 UTC (rev 10910)
@@ -5,8 +5,8 @@
 import java.io.File;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
 
 import javassist.CannotCompileException;
 import javassist.ClassPool;
@@ -22,7 +22,7 @@
    
    private static LogProvider log = Logging.getLogProvider(WicketClassLoader.class);
    
-   private List<String> classes;
+   private Set<String> classes;
    private File wicketComponentDirectory;
    private ClassPool classPool;
    private ClassLoader parentLoader;
@@ -33,7 +33,7 @@
    public WicketClassLoader(ClassLoader parent, ClassPool classPool, File wicketComponentDirectory)
    {
       super(parent, classPool);
-      this.classes = new ArrayList<String>();
+      this.classes = new HashSet<String>();
       this.wicketComponentDirectory = wicketComponentDirectory;
       this.classPool = classPool;
       this.parentLoader = parent;
@@ -48,7 +48,8 @@
       // Scan for classes
       if (wicketComponentDirectory.exists()) 
       { 
-         handleDirectory(wicketComponentDirectory, null);
+         handleDirectory(wicketComponentDirectory, null, classes);
+         instrumentor.instrumentClassSet(classes,null);
       }
 
       // Ensure classes' static initializers have run, to register the classes
@@ -60,7 +61,15 @@
       return this;
    }
 
-   private void handleDirectory(File file, String path) throws NotFoundException, CannotCompileException
+   /**
+    * Recursively collect all class names for class files found in this directory.
+    * @param file which directory
+    * @param path parent path
+    * @param collectedClasses where to store the classes
+    * @throws NotFoundException
+    * @throws CannotCompileException
+    */
+   private void handleDirectory(File file, String path, Set<String> collectedClasses) throws NotFoundException, CannotCompileException
    {
       log.trace("directory: " + file);
       for (File child : file.listFiles())
@@ -68,22 +77,18 @@
          String newPath = path == null ? child.getName() : path + '/' + child.getName();
          if (child.isDirectory())
          {
-            handleDirectory(child, newPath);
+            handleDirectory(child, newPath, collectedClasses);
          }
          else
          {
-            handleItem(newPath);
+            if (newPath.endsWith(".class"))
+            {
+               collectedClasses.add(filenameToClassname(newPath));
+            }
          }
       }
    }
 
-   private void handleItem(String path) throws NotFoundException, CannotCompileException
-   {
-      if (path.endsWith(".class"))
-      {
-         classes.add(instrumentor.instrumentClass(filenameToClassname(path)).getName());
-      }
-   }
 
    @Override
    protected Class loadClassByDelegation(String name) throws ClassNotFoundException

Modified: branches/community/Seam_2_1/src/wicket/org/jboss/seam/wicket/ioc/WicketInstrumentationTask.java
===================================================================
--- branches/community/Seam_2_1/src/wicket/org/jboss/seam/wicket/ioc/WicketInstrumentationTask.java	2009-05-13 20:31:38 UTC (rev 10909)
+++ branches/community/Seam_2_1/src/wicket/org/jboss/seam/wicket/ioc/WicketInstrumentationTask.java	2009-05-14 01:29:51 UTC (rev 10910)
@@ -2,7 +2,9 @@
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import javassist.ClassPool;
 import javassist.CtClass;
@@ -75,18 +77,15 @@
 
          JavassistInstrumentor instrumentor = new JavassistInstrumentor(classPool,useAnnotations);
 
+         Set<String> toInstrument = new HashSet<String>();
          for (String file : fileset.getDirectoryScanner(getProject()).getIncludedFiles())
          {
             if (file.endsWith(".class"))
             {
-               instrumentedClasses.add(instrumentor.instrumentClass(filenameToClassname(file)));
+               toInstrument.add(filenameToClassname(file));
             }
          }
-
-         for (CtClass clazz : instrumentedClasses)
-         {
-            clazz.writeFile(outputDirectory.getPath());
-         }
+         instrumentor.instrumentClassSet(toInstrument,outputDirectory.getPath());
       }
       catch (Exception e)
       {




More information about the seam-commits mailing list