aries-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From timothyjw...@apache.org
Subject svn commit: r1092368 [1/3] - in /aries/trunk/proxy: proxy-api/ proxy-api/src/main/java/org/apache/aries/proxy/ proxy-bundle/ proxy-impl/ proxy-impl/src/main/java/org/apache/aries/proxy/impl/ proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/...
Date Thu, 14 Apr 2011 16:01:44 GMT
Author: timothyjward
Date: Thu Apr 14 16:01:42 2011
New Revision: 1092368

URL: http://svn.apache.org/viewvc?rev=1092368&view=rev
Log:
ARIES-633 : High speed proxy objects (weaving support)

Added:
    aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/InvocationListener.java
      - copied, changed from r1084973, aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/InvocationHandlerWrapper.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/SingleInstanceDispatcher.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/AbstractWovenProxyAdapter.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/AbstractWovenProxyMethodAdapter.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/InterfaceCombiningClassAdapter.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/InterfaceUsingWovenProxyAdapter.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/InterfaceUsingWovenProxyMethodAdapter.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/MethodCopyingClassAdapter.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/ProxyWeavingHook.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/TypeMethod.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/WovenProxyAdapter.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/WovenProxyGenerator.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/WovenProxyMethodAdapter.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/weaving/
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/weaving/WovenProxy.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/weaving/packageinfo
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/AbstractProxyTest.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/InterfaceProxyingTest.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableChild.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableChildWithDefaultMethodWrongPackageParent.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableChildWithFinalMethodParent.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableGrandParent.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableSuper.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableSuperWithFinalMethod.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/WovenProxyGeneratorTest.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/pkg/
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/pkg/ProxyTestClassUnweavableSuperWithDefaultMethodWrongPackageParent.java
    aries/trunk/proxy/proxy-itests/src/test/java/org/apache/aries/proxy/itests/AbstractProxyTest.java
    aries/trunk/proxy/proxy-itests/src/test/java/org/apache/aries/proxy/itests/WeavingProxyTest.java
    aries/trunk/proxy/proxy-itests/src/test/java/org/ops4j/
    aries/trunk/proxy/proxy-itests/src/test/java/org/ops4j/pax/
    aries/trunk/proxy/proxy-itests/src/test/java/org/ops4j/pax/runner/
    aries/trunk/proxy/proxy-itests/src/test/java/org/ops4j/pax/runner/platform/
    aries/trunk/proxy/proxy-itests/src/test/java/org/ops4j/pax/runner/platform/equinox/
    aries/trunk/proxy/proxy-itests/src/test/java/org/ops4j/pax/runner/platform/equinox/internal/
    aries/trunk/proxy/proxy-itests/src/test/java/org/ops4j/pax/runner/platform/equinox/internal/SsActivator.java
    aries/trunk/proxy/proxy-itests/src/test/resources/
    aries/trunk/proxy/proxy-itests/src/test/resources/META-INF/
    aries/trunk/proxy/proxy-itests/src/test/resources/META-INF/platform-equinox/
    aries/trunk/proxy/proxy-itests/src/test/resources/META-INF/platform-equinox/definition-3.7.0.V20110304.xml
    aries/trunk/proxy/proxy-itests/src/test/resources/ss-runner.properties
Removed:
    aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/InvocationHandlerWrapper.java
Modified:
    aries/trunk/proxy/proxy-api/pom.xml
    aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/ProxyManager.java
    aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/UnableToProxyException.java
    aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/packageinfo
    aries/trunk/proxy/proxy-bundle/pom.xml
    aries/trunk/proxy/proxy-impl/pom.xml
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AbstractProxyManager.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/DefaultWrapper.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/JdkProxyManager.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/ProxyHandler.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/ProxyManagerActivator.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassGeneral.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassSuper.java
    aries/trunk/proxy/proxy-itests/pom.xml
    aries/trunk/proxy/proxy-itests/src/test/java/org/apache/aries/proxy/itests/BasicProxyTest.java

Modified: aries/trunk/proxy/proxy-api/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-api/pom.xml?rev=1092368&r1=1092367&r2=1092368&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-api/pom.xml (original)
+++ aries/trunk/proxy/proxy-api/pom.xml Thu Apr 14 16:01:42 2011
@@ -29,7 +29,7 @@
     <artifactId>org.apache.aries.proxy.api</artifactId>
     <packaging>bundle</packaging>
     <name>Apache Aries Proxy API</name>
-    <version>0.3.1-SNAPSHOT</version>
+    <version>0.4-SNAPSHOT</version>
     <description>
         This bundle contains the Apache Aries Proxy service API.
     </description>

Copied: aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/InvocationListener.java (from r1084973, aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/InvocationHandlerWrapper.java)
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/InvocationListener.java?p2=aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/InvocationListener.java&p1=aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/InvocationHandlerWrapper.java&r1=1084973&r2=1092368&rev=1092368&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/InvocationHandlerWrapper.java (original)
+++ aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/InvocationListener.java Thu Apr 14 16:01:42 2011
@@ -18,10 +18,17 @@
  */
 package org.apache.aries.proxy;
 
-import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 
-public interface InvocationHandlerWrapper 
+/**
+ * An {@link InvocationListener} is used in conjunction with the {@link ProxyManager}
+ * to intercept method calls on the proxy object
+ */
+public interface InvocationListener 
 {
-  public Object invoke(Object proxy, Method m, Object[] args, InvocationHandler delegate) throws Throwable;
+  public Object preInvoke(Object proxy, Method m, Object[] args) throws Throwable;
+  
+  public void postInvoke(Object token, Object proxy, Method m, Object returnValue) throws Throwable;
+  
+  public void postInvokeExceptionalReturn(Object token, Object proxy, Method m, Throwable exception) throws Throwable;
 }
\ No newline at end of file

Modified: aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/ProxyManager.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/ProxyManager.java?rev=1092368&r1=1092367&r2=1092368&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/ProxyManager.java (original)
+++ aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/ProxyManager.java Thu Apr 14 16:01:42 2011
@@ -28,8 +28,54 @@ import org.osgi.framework.Bundle;
  */
 public interface ProxyManager 
 {
-  public Object createProxy(Bundle clientBundle, Collection<Class<?>> classes, Callable<Object> dispatcher) throws UnableToProxyException;
-  public Object createProxy(Bundle clientBundle, Collection<Class<?>> classes, Callable<Object> dispatcher, InvocationHandlerWrapper wrapper) throws UnableToProxyException;
+  /**
+   * Create a proxy that delegates to an object instance which may change
+   * over time
+   * 
+   * @param clientBundle The bundle providing the class to be proxied
+   * @param classes  The interfaces and/or classes to be proxied
+   * @param dispatcher A {@link Callable} that will called each time the proxy 
+   *                   is invoked to locate the object to delegate to
+   * @param template A template object for the proxy, may be null if only interfaces
+   *                 need to be proxied. Supplying a templates typically offer a 
+   *                 significant performance boost to the resulting proxy.
+   * @return A proxy object that delegates to real objects under the covers
+   * @throws UnableToProxyException
+   */
+  public Object createDelegatingProxy(Bundle clientBundle, Collection<Class<?>> classes, Callable<Object> dispatcher, Object template) throws UnableToProxyException;
+  
+  /**
+   * Creates a proxy that invokes the supplied {@link InvocationListener} 
+   * immediately before and after any non-private method is called.
+   * 
+   * @param clientBundle
+   * @param classes
+   * @param delegate
+   * @param wrapper
+   * @return
+   * @throws UnableToProxyException
+   */
+  public Object createInterceptingProxy(Bundle clientBundle, Collection<Class<?>> classes, 
+      Object delegate, InvocationListener wrapper) throws UnableToProxyException;
+  
+  /**
+   * Creates a single proxy that both delegates and intercepts. See
+   * {ProxyManager{@link #createDelegatingProxy(Bundle, Collection, Callable)} 
+   * and {ProxyManager{@link #createInterceptingProxy(Bundle, Collection, Object, InvocationListener)}
+   * 
+   * @param clientBundle
+   * @param classes
+   * @param dispatcher
+   * @param template A template object for the proxy, may be null if only interfaces
+   *                 need to be proxied. Supplying a templates typically offer a 
+   *                 significant performance boost to the resulting proxy.
+   * @param wrapper
+   * @return
+   * @throws UnableToProxyException
+   */
+  public Object createDelegatingInterceptingProxy(Bundle clientBundle, Collection<Class<?>> classes, 
+      Callable<Object> dispatcher, Object template, InvocationListener wrapper) throws UnableToProxyException;
+  
   /**
    * This method unwraps the provided proxy returning the target object.
    * 
@@ -39,7 +85,7 @@ public interface ProxyManager 
   public Callable<Object> unwrap(Object proxy);
   /**
    * Returns true if and only if the specified object was generated by the ProxyManager. See
-   * {@link ProxyManager#createProxy(Bundle,Collection,Callable)} for details on how to create a proxy. 
+   * {@link ProxyManager#createDelegatingProxy(Bundle,Collection,Callable)} for details on how to create a proxy. 
    * @param proxy The proxy object to test
    * @return      true if it is a proxy, false otherwise.
    */

Modified: aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/UnableToProxyException.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/UnableToProxyException.java?rev=1092368&r1=1092367&r2=1092368&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/UnableToProxyException.java (original)
+++ aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/UnableToProxyException.java Thu Apr 14 16:01:42 2011
@@ -42,6 +42,12 @@ public class UnableToProxyException exte
     super(e);
     this.className = className;
   }
+  
+  public UnableToProxyException(Object proxy, String msg)
+  {
+    super(msg);
+    this.className = proxy.getClass().getName();
+  }
 
   public String getClassName()
   {

Modified: aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/packageinfo
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/packageinfo?rev=1092368&r1=1092367&r2=1092368&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/packageinfo (original)
+++ aries/trunk/proxy/proxy-api/src/main/java/org/apache/aries/proxy/packageinfo Thu Apr 14 16:01:42 2011
@@ -16,4 +16,4 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-version 0.3.1
+version 0.4

Modified: aries/trunk/proxy/proxy-bundle/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-bundle/pom.xml?rev=1092368&r1=1092367&r2=1092368&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-bundle/pom.xml (original)
+++ aries/trunk/proxy/proxy-bundle/pom.xml Thu Apr 14 16:01:42 2011
@@ -29,7 +29,7 @@
     <artifactId>org.apache.aries.proxy</artifactId>
     <packaging>bundle</packaging>
     <name>Apache Aries Proxy Bundle</name>
-    <version>0.3.1-SNAPSHOT</version>
+    <version>0.4-SNAPSHOT</version>
     <description>
         This bundle contains the Apache Aries Proxy Service.
     </description>
@@ -47,10 +47,14 @@
             org.apache.aries.proxy.impl.ProxyManagerActivator
         </aries.osgi.activator>
         <aries.osgi.export.pkg>
-            org.apache.aries.proxy;
+            org.apache.aries.proxy;,
+            org.apache.aries.proxy.weaving;
         </aries.osgi.export.pkg>
         <aries.osgi.import.pkg>
             org.eclipse.*;resolution:=optional,
+            org.osgi.framework;version="[1.5,2)",
+            org.osgi.framework.hooks.weaving;version="[1.0,1.1)";resolution:=optional,
+            org.osgi.framework.wiring;version="[1.0,2)";resolution:=optional,
             *
         </aries.osgi.import.pkg>
         <aries.osgi.private.pkg>
@@ -83,12 +87,12 @@
         <dependency>
         	<groupId>org.apache.aries.proxy</groupId>
         	<artifactId>org.apache.aries.proxy.api</artifactId>
-            <version>0.3.1-SNAPSHOT</version>
+            <version>0.4-SNAPSHOT</version>
         </dependency>
         <dependency>
         	<groupId>org.apache.aries.proxy</groupId>
         	<artifactId>org.apache.aries.proxy.impl</artifactId>
-            <version>0.3.1-SNAPSHOT</version>
+            <version>0.4-SNAPSHOT</version>
         </dependency>
     </dependencies>
 

Modified: aries/trunk/proxy/proxy-impl/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/pom.xml?rev=1092368&r1=1092367&r2=1092368&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-impl/pom.xml (original)
+++ aries/trunk/proxy/proxy-impl/pom.xml Thu Apr 14 16:01:42 2011
@@ -29,7 +29,7 @@
     <artifactId>org.apache.aries.proxy.impl</artifactId>
     <packaging>bundle</packaging>
     <name>Apache Aries Proxy Service</name>
-    <version>0.3.1-SNAPSHOT</version>
+    <version>0.4-SNAPSHOT</version>
     <description>
         This bundle contains the proxy service implementation for Apache Aries
     </description>
@@ -42,13 +42,18 @@
 
 
     <properties>
-        <aries.osgi.export.pkg/>
+        <aries.osgi.export.pkg>
+          org.apache.aries.proxy.weaving;
+        </aries.osgi.export.pkg>
         <aries.osgi.activator>
             org.apache.aries.proxy.impl.ProxyManagerActivator
         </aries.osgi.activator>
         <aries.osgi.import.pkg>
             org.objectweb.asm;version=3.2;resolution:=optional,
             org.objectweb.asm.commons;version=3.2;resolution:=optional,
+            org.osgi.framework;version="[1.5,2)",
+            org.osgi.framework.hooks.weaving;version="[1.0,1.1)";resolution:=optional,
+            org.osgi.framework.wiring;version="[1.0,2)";resolution:=optional,
             *
         </aries.osgi.import.pkg>
         <aries.osgi.private.pkg>
@@ -72,20 +77,31 @@
             <artifactId>slf4j-simple</artifactId>
             <scope>test</scope>
         </dependency>
+        <!-- Use the Eclipse version of OSGi until the core 4.3 OSGi jar is available in Maven. -->        
         <dependency>
+            <groupId>org.eclipse</groupId>
+            <artifactId>osgi</artifactId>
+            <version>3.7M6</version>
+            <scope>system</scope>
+            <systemPath>${basedir}/../proxy-tmp/target/downloaded/org.eclipse.osgi_3.7.0.jar</systemPath>
+        </dependency>
+        
+        <!-- <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.core</artifactId>
-            <scope>provided</scope>
-        </dependency>
+            <version>4.3</version>
+        </dependency> -->
+        
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.compendium</artifactId>
             <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse</groupId>
-            <artifactId>osgi</artifactId>
-            <scope>provided</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.osgi</groupId>
+                    <artifactId>org.osgi.core</artifactId>                    
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>junit</groupId>
@@ -96,13 +112,27 @@
         	<groupId>org.apache.aries.proxy</groupId>
         	<artifactId>org.apache.aries.proxy.api</artifactId>
         	<scope>compile</scope>
-            <version>0.3.1-SNAPSHOT</version>
+            <version>0.4-SNAPSHOT</version>
+            
+            <exclusions>
+                <exclusion>
+                    <groupId>org.osgi</groupId>
+                    <artifactId>org.osgi.core</artifactId>                    
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
         	<groupId>org.apache.aries</groupId>
         	<artifactId>org.apache.aries.util</artifactId>
         	<scope>compile</scope>
             <version>0.4-SNAPSHOT</version>
+                        
+            <exclusions>
+                <exclusion>
+                    <groupId>org.osgi</groupId>
+                    <artifactId>org.osgi.core</artifactId>                    
+                </exclusion>
+            </exclusions>
         </dependency>
     </dependencies>
 

Modified: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AbstractProxyManager.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AbstractProxyManager.java?rev=1092368&r1=1092367&r2=1092368&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AbstractProxyManager.java (original)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AbstractProxyManager.java Thu Apr 14 16:01:42 2011
@@ -18,63 +18,100 @@
  */
 package org.apache.aries.proxy.impl;
 
+import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.util.Collection;
 import java.util.concurrent.Callable;
 
-import org.apache.aries.proxy.InvocationHandlerWrapper;
+import org.apache.aries.proxy.InvocationListener;
 import org.apache.aries.proxy.ProxyManager;
 import org.apache.aries.proxy.UnableToProxyException;
+import org.apache.aries.proxy.weaving.WovenProxy;
 import org.apache.aries.util.AriesFrameworkUtil;
-import org.apache.aries.util.nls.MessageUtil;
 import org.osgi.framework.Bundle;
 
 public abstract class AbstractProxyManager implements ProxyManager
 {
-  public final Object createProxy(Bundle clientBundle, Collection<Class<?>> classes,
-      Callable<Object> dispatcher) 
+  public final Object createDelegatingProxy(Bundle clientBundle, Collection<Class<?>> classes,
+      Callable<Object> dispatcher, Object template) 
     throws UnableToProxyException
   {
-    return createProxy(clientBundle, classes, dispatcher, null);
+    return createDelegatingInterceptingProxy(clientBundle, classes, dispatcher, template, null);
+  }
+  
+  public Object createInterceptingProxy(Bundle clientBundle,
+      Collection<Class<?>> classes, Object delegate, InvocationListener listener)
+      throws UnableToProxyException {
+    
+    if (delegate instanceof WovenProxy) {
+      WovenProxy proxy = ((WovenProxy) delegate).
+              org_apache_aries_proxy_weaving_WovenProxy_createNewProxyInstance(
+              new SingleInstanceDispatcher(delegate), listener);
+      return proxy;
+    } else {
+      return createDelegatingInterceptingProxy(clientBundle, classes, 
+          new SingleInstanceDispatcher(delegate), delegate, listener);
+    }
   }
 
-  public final Object createProxy(Bundle clientBundle, Collection<Class<?>> classes,
-      Callable<Object> dispatcher, InvocationHandlerWrapper wrapper)
+  public final Object createDelegatingInterceptingProxy(Bundle clientBundle, Collection<Class<?>> classes,
+      Callable<Object> dispatcher, Object template, InvocationListener listener)
       throws UnableToProxyException 
   {
-    InvocationHandler ih = new ProxyHandler(this, dispatcher, wrapper);
-    Object proxyObject = duplicateProxy(classes, ih);
+    if(dispatcher == null)
+      throw new NullPointerException("A dispatcher must be specified for a delegating proxy handler");
+    
+    if (template instanceof WovenProxy) {
+      WovenProxy proxy = ((WovenProxy) template).
+             org_apache_aries_proxy_weaving_WovenProxy_createNewProxyInstance(
+             dispatcher, listener);
+      return proxy;
+    }
+    
+    Object proxyObject = duplicateProxy(classes, dispatcher, template, listener);
     
     if (proxyObject == null) {
-      proxyObject = createNewProxy(clientBundle, classes, ih);
+      proxyObject = createNewProxy(clientBundle, classes, dispatcher, listener);
     }
     
     return proxyObject;
   }
-  
+   
   public final Callable<Object> unwrap(Object proxy) 
   {
     Callable<Object> target = null;
     
-    if (isProxy(proxy)) {
+    if(proxy instanceof WovenProxy) {
+      //Woven proxies are a bit different, they can be proxies without
+      //having a dispatcher, so we fake one up if we need to 
+      
+      WovenProxy wp = (WovenProxy) proxy;
+      if(wp.org_apache_aries_proxy_weaving_WovenProxy_isProxyInstance()) {
+        target = wp.org_apache_aries_proxy_weaving_WovenProxy_unwrap();
+        if(target == null) {
+          target = new SingleInstanceDispatcher(proxy);
+        }
+      }
+    } else {
       InvocationHandler ih = getInvocationHandler(proxy);
       
       if (ih instanceof ProxyHandler) {
         target = ((ProxyHandler)ih).getTarget();
       }
     }
-    
     return target;
   }
   
   public final boolean isProxy(Object proxy)
   {
-    return (proxy != null && getInvocationHandler(proxy) instanceof ProxyHandler);
+    return (proxy != null && 
+        ((proxy instanceof WovenProxy && ((WovenProxy)proxy).org_apache_aries_proxy_weaving_WovenProxy_isProxyInstance()) || 
+        getInvocationHandler(proxy) instanceof ProxyHandler));
   }
   
   protected abstract Object createNewProxy(Bundle clientBundle, Collection<Class<?>> classes,
-      InvocationHandler ih) throws UnableToProxyException;
+      Callable<Object> dispatcher, InvocationListener listener) throws UnableToProxyException;
   protected abstract InvocationHandler getInvocationHandler(Object proxy);
   protected abstract boolean isProxyClass(Class<?> clazz);
 
@@ -96,31 +133,45 @@ public abstract class AbstractProxyManag
     return cl;
   }
 
-  private Object duplicateProxy(Collection<Class<?>> classes, InvocationHandler handler)
+  private Object duplicateProxy(Collection<Class<?>> classes, Callable<Object> dispatcher, 
+      Object template, InvocationListener listener)
   {
     Object proxyObject = null;
+    Class<?> classToProxy = null;
     
-    if (classes.size() == 1) {
+    if (template != null) {
+      if(isProxyClass(template.getClass()))
+        classToProxy = template.getClass();
+    } else if (classes.size() == 1) {
 
-      Class<?> classToProxy = classes.iterator().next();
+      classToProxy = classes.iterator().next();
 
-      boolean isProxy = isProxyClass(classToProxy);
+      if(!!!isProxyClass(classToProxy))
+        classToProxy = null;
+    }
 
-      if (isProxy) {
-        try {
-          /*
-           * the class is already a proxy, we should just invoke
-           * the constructor to get a new instance of the proxy
-           * with a new Collaborator using the specified delegate
-           */
-          proxyObject = classToProxy.getConstructor(InvocationHandler.class).newInstance(handler);
-        } catch (InvocationTargetException e) {
-        } catch (NoSuchMethodException e) {
-        } catch (InstantiationException e) {
-        } catch (IllegalArgumentException e) {
-        } catch (SecurityException e) {
-        } catch (IllegalAccessException e) {
+    if (classToProxy != null) {
+      try {
+        /*
+         * the class is already a proxy, we should just invoke
+         * the constructor to get a new instance of the proxy
+         * with a new Collaborator using the specified delegate
+         */
+        if(WovenProxy.class.isAssignableFrom(classToProxy)) {
+          Constructor<?> c = classToProxy.getDeclaredConstructor(Callable.class, 
+              InvocationListener.class);
+          c.setAccessible(true);
+          proxyObject = c.newInstance(dispatcher, listener);
+        } else {
+          proxyObject = classToProxy.getConstructor(InvocationHandler.class).
+          newInstance(new ProxyHandler(this, dispatcher, listener));
         }
+      } catch (InvocationTargetException e) {
+      } catch (NoSuchMethodException e) {
+      } catch (InstantiationException e) {
+      } catch (IllegalArgumentException e) {
+      } catch (SecurityException e) {
+      } catch (IllegalAccessException e) {
       }
     }
     

Modified: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java?rev=1092368&r1=1092367&r2=1092368&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java (original)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java Thu Apr 14 16:01:42 2011
@@ -18,24 +18,29 @@
  */
 package org.apache.aries.proxy.impl;
 
+import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Proxy;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.concurrent.Callable;
 
+import org.apache.aries.proxy.InvocationListener;
 import org.apache.aries.proxy.ProxyManager;
 import org.apache.aries.proxy.UnableToProxyException;
 import org.apache.aries.proxy.impl.gen.ProxySubclassGenerator;
+import org.apache.aries.proxy.impl.weaving.InterfaceCombiningClassAdapter;
+import org.apache.aries.proxy.weaving.WovenProxy;
 import org.osgi.framework.Bundle;
 
 public final class AsmProxyManager extends AbstractProxyManager implements ProxyManager
 {
-  public Object createNewProxy(Bundle clientBundle, Collection<Class<?>> classes, InvocationHandler handler) 
-    throws UnableToProxyException
+  public Object createNewProxy(Bundle clientBundle, Collection<Class<?>> classes, 
+      Callable<Object> dispatcher, InvocationListener listener) throws UnableToProxyException
   {
     Object proxyObject = null;
-
+    
     // if we just have interfaces and no classes we default to using
     // the interface proxy because we can't dynamically
     // subclass more than one interface
@@ -78,10 +83,23 @@ public final class AsmProxyManager exten
           classToProxy = clazz;
         }
       }
-      proxyObject = ProxySubclassGenerator.newProxySubclassInstance(classToProxy, handler);
+      if(WovenProxy.class.isAssignableFrom(classToProxy)) {
+        try {
+          Constructor<?> c = classToProxy.getDeclaredConstructor(Callable.class, 
+              InvocationListener.class);
+          c.setAccessible(true);
+          proxyObject = c.newInstance(dispatcher, listener);
+        } catch (Exception e) {
+          //We will have to subclass this one, but we should always have a constructor
+          //to use
+          //TODO log that performance would be improved by using a non-null template
+        }
+      } 
+      if(proxyObject == null){
+        proxyObject = ProxySubclassGenerator.newProxySubclassInstance(classToProxy, new ProxyHandler(this, dispatcher, listener));
+      }
     } else {
-      // TODO there are some problems here. If we get a BundleToClassLoaderAdapter back and the bundle can't see all the classes referenced by the interface bad things happen (i.e. it fails).
-      proxyObject = Proxy.newProxyInstance(getClassLoader(clientBundle, classes), classes.toArray(new Class<?>[classes.size()]), handler);
+      proxyObject = InterfaceCombiningClassAdapter.getProxyInstance(classes, dispatcher, listener);
     }
 
     return proxyObject;
@@ -90,7 +108,7 @@ public final class AsmProxyManager exten
   @Override
   protected boolean isProxyClass(Class<?> clazz)
   {
-    return ProxySubclassGenerator.isProxySubclass(clazz) || Proxy.isProxyClass(clazz);
+    return WovenProxy.class.isAssignableFrom(clazz) || ProxySubclassGenerator.isProxySubclass(clazz) || Proxy.isProxyClass(clazz);
   }
 
   @Override

Modified: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/DefaultWrapper.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/DefaultWrapper.java?rev=1092368&r1=1092367&r2=1092368&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/DefaultWrapper.java (original)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/DefaultWrapper.java Thu Apr 14 16:01:42 2011
@@ -18,17 +18,24 @@
  */
 package org.apache.aries.proxy.impl;
 
-import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 
-import org.apache.aries.proxy.InvocationHandlerWrapper;
+import org.apache.aries.proxy.InvocationListener;
 
-public class DefaultWrapper implements InvocationHandlerWrapper {
+public class DefaultWrapper implements InvocationListener {
 
-  public Object invoke(Object proxy, Method m, Object[] args,
-      InvocationHandler delegate) throws Throwable 
-  {
-    return delegate.invoke(proxy, m, args);
+
+  public Object preInvoke(Object proxy, Method m, Object[] args)
+      throws Throwable {
+    return null;
+  }
+
+  public void postInvoke(Object token, Object proxy, Method m, Object returnValue)
+      throws Throwable {
+  }
+
+  public void postInvokeExceptionalReturn(Object token, Object proxy, Method m,
+      Throwable exception) throws Throwable {
   }
 
 }

Modified: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/JdkProxyManager.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/JdkProxyManager.java?rev=1092368&r1=1092367&r2=1092368&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/JdkProxyManager.java (original)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/JdkProxyManager.java Thu Apr 14 16:01:42 2011
@@ -21,15 +21,18 @@ package org.apache.aries.proxy.impl;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Proxy;
 import java.util.Collection;
+import java.util.concurrent.Callable;
 
+import org.apache.aries.proxy.InvocationListener;
 import org.apache.aries.proxy.ProxyManager;
 import org.osgi.framework.Bundle;
 
 public final class JdkProxyManager extends AbstractProxyManager implements ProxyManager
 {
-  public Object createNewProxy(Bundle clientBundle, Collection<Class<?>> classes, InvocationHandler handler) 
+  public Object createNewProxy(Bundle clientBundle, Collection<Class<?>> classes, 
+      Callable<Object> dispatcher, InvocationListener listener) 
   {
-    return Proxy.newProxyInstance(getClassLoader(clientBundle, classes), getInterfaces(classes), handler);
+    return Proxy.newProxyInstance(getClassLoader(clientBundle, classes), getInterfaces(classes), new ProxyHandler(this, dispatcher, listener));
   }
 
   private static final Class<?>[] getInterfaces(Collection<Class<?>> classes)

Modified: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/ProxyHandler.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/ProxyHandler.java?rev=1092368&r1=1092367&r2=1092368&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/ProxyHandler.java (original)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/ProxyHandler.java Thu Apr 14 16:01:42 2011
@@ -23,40 +23,80 @@ import java.lang.reflect.InvocationTarge
 import java.lang.reflect.Method;
 import java.util.concurrent.Callable;
 
-import org.apache.aries.proxy.InvocationHandlerWrapper;
+import org.apache.aries.proxy.InvocationListener;
 
 public final class ProxyHandler implements InvocationHandler {
   private final Callable<Object> target;
   private final InvocationHandler core;
-  private final InvocationHandlerWrapper wrapper;
   private final AbstractProxyManager proxyManager;
 
-  public ProxyHandler(AbstractProxyManager abstractProxyManager, Callable<Object> dispatcher, InvocationHandlerWrapper wrapper)
+  public ProxyHandler(AbstractProxyManager abstractProxyManager, Callable<Object> dispatcher, InvocationListener listener)
   {
     target = dispatcher;
     proxyManager = abstractProxyManager;
-    if (wrapper == null) {
-      this.wrapper = new DefaultWrapper();
+    final InvocationListener nonNullListener;
+    if (listener == null) {
+      nonNullListener = new DefaultWrapper();
     } else {
-      this.wrapper = wrapper;
+      nonNullListener = listener;
     }
     
     core = new InvocationHandler() {
       public Object invoke(Object proxy, Method method, Object[] args)
           throws Throwable 
       {
-          Object result;
+        Object result = null;
+        Object token = null;
+        boolean inInvoke = false;
+        try {
+          token = nonNullListener.preInvoke(proxy, method, args);
+          inInvoke = true;
+          result = method.invoke(target.call(), args);
+          inInvoke = false;
+          nonNullListener.postInvoke(token, proxy, method, result);
+
+        } catch (Throwable e) {
+          // whether the the exception is an error is an application decision
+          // if we catch an exception we decide carefully which one to
+          // throw onwards
+          Throwable exceptionToRethrow = null;
+          // if the exception came from a precall or postcall 
+          // we will rethrow it
+          if (!inInvoke) {
+            exceptionToRethrow = e;
+          }
+          // if the exception didn't come from precall or postcall then it
+          // came from invoke
+          // we will rethrow this exception if it is not a runtime
+          // exception, but we must unwrap InvocationTargetExceptions
+          else {
+            if (e instanceof InvocationTargetException) {
+              e = ((InvocationTargetException) e).getTargetException();
+            }
+            
+            if (!(e instanceof RuntimeException)) {
+              exceptionToRethrow = e;
+            }
+          }
           try {
-              result = method.invoke(target.call(), args);
-          } catch (InvocationTargetException ite) {
-              // We are invisible, so unwrap and throw the cause as
-              // though we called the method directly.
-              throw ite.getCause();
-          } catch (IllegalAccessException e) {
-              throw new IllegalAccessError(e.getMessage());
+            nonNullListener.postInvokeExceptionalReturn(token, proxy, method, e);
+          } catch (Exception f) {
+            // we caught an exception from
+            // postInvokeExceptionalReturn
+            // if we haven't already chosen an exception to rethrow then
+            // we will throw this exception
+            if (exceptionToRethrow == null) {
+              exceptionToRethrow = f;
+            }
           }
-
-          return result;
+          // if we made it this far without choosing an exception we
+          // should throw e
+          if (exceptionToRethrow == null) {
+            exceptionToRethrow = e;
+          }
+          throw exceptionToRethrow;
+        }
+        return result;
       }
     };
   }
@@ -65,7 +105,8 @@ public final class ProxyHandler implemen
   {
     // Unwrap calls for equals
     if (method.getName().equals("equals")
-            && method.getDeclaringClass() == Object.class) {
+            && method.getParameterTypes().length == 1 &&
+            method.getParameterTypes()[0] == Object.class) {
         Object targetObject = args[0];
         if (proxyManager.isProxy(targetObject)) {
           args[0] = proxyManager.unwrap(targetObject).call();
@@ -75,7 +116,7 @@ public final class ProxyHandler implemen
         return null;
     }
     
-    return wrapper.invoke(proxy, method, args, core);
+    return core.invoke(proxy, method, args);
   }
 
   public Callable<Object> getTarget() 

Modified: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/ProxyManagerActivator.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/ProxyManagerActivator.java?rev=1092368&r1=1092367&r2=1092368&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/ProxyManagerActivator.java (original)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/ProxyManagerActivator.java Thu Apr 14 16:01:42 2011
@@ -45,6 +45,16 @@ public class ProxyManagerActivator imple
   {
     if (ASM_PROXY_SUPPORTED) {
       managerService = new AsmProxyManager();
+      
+      try {
+        //if ASM is available then we should also try weaving
+        Class<?> cls = Class.forName("org.apache.aries.proxy.impl.weaving.ProxyWeavingHook");
+        context.registerService("org.osgi.framework.hooks.weaving.WeavingHook",
+            cls.newInstance(), null);
+      } catch (Throwable t) {
+        //We don't care about this, we just won't have registered the hook
+      }
+      
     } else {
       managerService = new JdkProxyManager();
     }

Added: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/SingleInstanceDispatcher.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/SingleInstanceDispatcher.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/SingleInstanceDispatcher.java (added)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/SingleInstanceDispatcher.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.proxy.impl;
+
+import java.util.concurrent.Callable;
+
+/**
+ * Dispatch to a single fixed instance
+ */
+public final class SingleInstanceDispatcher implements Callable<Object> {
+
+  private final Object delegate;
+  
+  public SingleInstanceDispatcher(Object delegate) {
+    this.delegate = delegate;
+  }
+  
+  public final Object call() throws Exception {
+    return delegate;
+  }
+}

Added: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/AbstractWovenProxyAdapter.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/AbstractWovenProxyAdapter.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/AbstractWovenProxyAdapter.java (added)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/AbstractWovenProxyAdapter.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,602 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.proxy.impl.weaving;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+
+import org.apache.aries.proxy.InvocationListener;
+import org.apache.aries.proxy.impl.gen.Constants;
+import org.apache.aries.proxy.weaving.WovenProxy;
+import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.GeneratorAdapter;
+import org.objectweb.asm.commons.Method;
+import org.objectweb.asm.commons.StaticInitMerger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This abstract superclass is responsible for providing proxy extensions to 
+ * classes being written. Classes processed by this adapter will implement 
+ * {@link WovenProxy}, and have a static initialiser that populates 
+ * {@link java.lang.reflect.Method} fields for use with the 
+ * {@link InvocationListener}. Known subclasses are {@link WovenProxyAdapter}, 
+ * used to weave classes being loaded by the framework, and {@link InterfaceCombiningClassAdapter}
+ * which is used to dynamically create objects that implement multiple interfaces
+ */
+abstract class AbstractWovenProxyAdapter extends ClassAdapter implements Opcodes {
+  private static final Logger LOGGER = LoggerFactory
+      .getLogger(AbstractWovenProxyAdapter.class);
+
+  /** Access modifier for a public generated method */
+  private static final int PUBLIC_GENERATED_METHOD_ACCESS = ACC_PUBLIC | ACC_FINAL
+      | ACC_SYNTHETIC;
+  /** The internal name for Throwable */
+  static final String THROWABLE_INAME = Type.getInternalName(Throwable.class);
+  /** A UUID for adding to our method names */
+  private static final String UU_ID = getSanitizedUUIDString();
+  /** A constant for No Args methods */
+  static final Type[] NO_ARGS = new Type[0];
+
+  /** The annotation types we should add to generated methods and fields */
+  private static final String[] annotationTypeDescriptors = new String[] { "Ljavax/persistence/Transient;" };
+
+  /** the name of the field used to store the {@link InvocationListener} */
+  static final String LISTENER_FIELD = "org_apache_aries_proxy_InvocationListener_"
+      + UU_ID;
+  /** the name of the field used to store the dispatcher */
+  static final String DISPATCHER_FIELD = "woven_proxy_dispatcher_" + UU_ID;
+
+  /* Useful ASM types */
+  /** The ASM type for the {@link InvocationListener} */
+  static final Type LISTENER_TYPE = Type.getType(InvocationListener.class);
+  /** The ASM type for the dispatcher */
+  static final Type DISPATCHER_TYPE = Type.getType(Callable.class);
+  private static final Type CLASS_TYPE = Type.getType(Class.class);
+  private static final Type CLASS_ARRAY_TYPE = Type.getType(Class[].class);
+  private static final Type STRING_TYPE = Type.getType(String.class);
+  static final Type OBJECT_TYPE = Type.getType(Object.class);
+  static final Type METHOD_TYPE = Type.getType(java.lang.reflect.Method.class);
+  /** The {@link Type} of the {@link WovenProxy} interface */
+  static final Type WOVEN_PROXY_IFACE_TYPE = Type.getType(WovenProxy.class);
+  private static final Type NPE_TYPE = Type.getType(NullPointerException.class);
+  
+  private static final Type[] DISPATCHER_LISTENER_METHOD_ARGS = new Type[] {
+    DISPATCHER_TYPE, LISTENER_TYPE };
+
+  private static final Method ARGS_CONSTRUCTOR = new Method("<init>", Type.VOID_TYPE,
+      DISPATCHER_LISTENER_METHOD_ARGS);
+  private static final Method NO_ARGS_CONSTRUCTOR = new Method("<init>", Type.VOID_TYPE,
+      NO_ARGS);
+  private static final Method NPE_CONSTRUCTOR = new Method("<init>", Type.VOID_TYPE,
+      new Type[] {STRING_TYPE});
+
+  // other new methods we will need
+  static final Method getInovcationTargetMethod = new Method(
+      "getInvocationTarget" + UU_ID, OBJECT_TYPE, NO_ARGS);
+  static final Method listenerPreInvokeMethod = new Method("getListener"
+      + UU_ID, OBJECT_TYPE, new Type[] { OBJECT_TYPE,
+      Type.getType(java.lang.reflect.Method.class),
+      Type.getType(Object[].class) });
+
+  /* Instance fields */
+
+  /** The type of this class */
+  protected final Type typeBeingWoven;
+  /** The type of this class's super */
+  private Type superType;
+  /** The {@link ClassLoader} loading this class */
+  private final ClassLoader loader;
+  /**
+   * A flag to indicate that we need to weave WovenProxy methods into this class
+   */
+  private boolean implementWovenProxy = false;
+  /** 
+   * A list of un-woven superclasses between this object and {@link Object}, 
+   * only populated for classes which will directly implement {@link WovenProxy}.
+   * This list is then used to override any methods that would otherwise be missed
+   * by the weaving process. 
+   */
+  private final List<Class<?>> nonObjectSupers = new ArrayList<Class<?>>();
+  
+  /**
+   * Methods we have transformed and need to create static fields for.
+   * Stored as field name to {@link TypeMethod} so we know which Class to reflect
+   * them off
+   */
+  private final Map<String, TypeMethod> transformedMethods = new HashMap<String, TypeMethod>();
+  
+  /**
+   *  A set of {@link Method} objects identifying the methods that are in this 
+   *  class. This is used to prevent us duplicating methods copied from 
+   *  {@link WovenProxyAdapter#nonObjectSupers} that are already overridden in 
+   *  this class.
+   */
+  final Set<Method> knownMethods = new HashSet<Method>();
+  /** 
+   * If our super does not have a no-args constructor then we need to be clever
+   * when writing our own constructor.
+   */
+  private boolean superHasNoArgsConstructor = false;
+
+  /**
+   * Create a new adapter for the supplied class
+   * 
+   * @param writer
+   *          The ClassWriter to delegate to
+   * @param className
+   *          The name of this class
+   * @param loader
+   *          The ClassLoader loading this class
+   */
+  public AbstractWovenProxyAdapter(ClassVisitor writer, String className,
+      ClassLoader loader) {
+    // We wrap the writer in a StaticInitMerger so we don't have to worry about
+    // our generated static init clashing with an existing one!
+    super(new StaticInitMerger("static_init_" + UU_ID, writer));
+    typeBeingWoven = Type.getType("L" + className.replace('.', '/') + ";");
+    this.loader = loader;
+  }
+
+  public final void visit(int version, int access, String name, String signature,
+      String superName, String[] interfaces) {
+    LOGGER.debug(Constants.LOG_ENTRY, "visit", new Object[] { version, access,
+        name, signature, superName, interfaces });
+
+    // We update to at least Java 1.5 because we add annotations and synthetic
+    // modifiers. Java 1.4 would not like this at all!
+    if (version < V1_5)
+      version = V1_5;
+
+    superType = Type.getType("L" + superName + ";");
+
+    try {
+      // we only want to implement WovenProxy once in the hierarchy.
+      // It's best to do this as high up as possible so we check the
+      // super. By loading it we may end up weaving it, but that's a good thing!
+      Class<?> superClass = Class.forName(superName.replace('/', '.'), false,
+          loader);
+
+      if (!!!WovenProxy.class.isAssignableFrom(superClass)) {
+
+        // We have found a type we need to add WovenProxy information to
+
+        implementWovenProxy = true;
+        
+        try {
+          superClass.getDeclaredConstructor();
+          superHasNoArgsConstructor = true;
+        } catch (NoSuchMethodException nsme) {
+          // This is a no-op here, but means we need to add a no-Args that
+          // delegates to Object#<init>() yuck :(
+        }
+        
+        if(superClass != Object.class) {
+          //If our superclass isn't Object, it means we didn't weave all the way
+          //to the top of the hierarchy. This means we need to override all the
+          //methods defined on our parent so that they can be intercepted!
+          nonObjectSupers.add(superClass);
+          Class<?> nextSuper = superClass.getSuperclass();
+          while(nextSuper != Object.class) {
+            nonObjectSupers.add(nextSuper);
+            nextSuper = nextSuper.getSuperclass();
+          }
+        }
+
+        // re-work the interfaces list to include WovenProxy
+        String[] interfacesPlusWovenProxy = new String[interfaces.length + 1];
+        System.arraycopy(interfaces, 0, interfacesPlusWovenProxy, 0, interfaces.length);
+        interfacesPlusWovenProxy[interfaces.length] = WOVEN_PROXY_IFACE_TYPE.getInternalName();
+
+        // Write the class header including WovenProxy.
+        cv.visit(version, access, name, signature, superName, interfacesPlusWovenProxy);
+
+      } else {
+        // Already has a woven proxy parent, but we still need to write the
+        // header!
+        cv.visit(version, access, name, signature, superName, interfaces);
+      }
+    } catch (ClassNotFoundException e) {
+      // If this happens we're about to hit bigger trouble on verify, so we can
+      // just throw it
+      throw new RuntimeException("Unable to load the super type "
+          + superName.replace('/', '.') + " for class "
+          + typeBeingWoven.getClassName(), e);
+    }
+  }
+
+  /**
+   * This method is called on each method implemented on this object (but not
+   * for superclass methods) Each of these methods is visited in turn and the
+   * code here generates the byte code for the calls to the InovcationListener
+   * around the existing method
+   */
+  public final MethodVisitor visitMethod(int access, String name, String desc,
+      String signature, String[] exceptions) {
+    LOGGER.debug(Constants.LOG_ENTRY, "visitMethod", new Object[] { access,
+        name, desc, signature, exceptions });
+
+    
+    Method currentMethod = new Method(name, desc);
+    
+    knownMethods.add(currentMethod);
+    
+    MethodVisitor methodVisitorToReturn = null;
+
+    // Only weave "real" instance methods. Not constructors, initializers or
+    // compiler generated ones.
+    if (!!!name.equals("<init>") && !!!name.equals("<clinit>")
+        && (access & (ACC_STATIC | ACC_PRIVATE | ACC_SYNTHETIC | ACC_ABSTRACT
+            | ACC_NATIVE | ACC_BRIDGE)) == 0) {
+
+      // found a method we should weave
+
+      //Create a field name and store it for later
+      String methodStaticFieldName = "methodField" + getSanitizedUUIDString();
+      transformedMethods.put(methodStaticFieldName, new TypeMethod(
+           getDeclaringTypeForCurrentMethod(), currentMethod));
+
+      // Surround the MethodVisitor with our weaver so we can manipulate the code
+      methodVisitorToReturn = getWeavingMethodVisitor(access, name, desc,
+          signature, exceptions, currentMethod, methodStaticFieldName);
+    } else {
+      //This isn't a method we want to weave, so just get the default visitor
+      methodVisitorToReturn = cv.visitMethod(access, name, desc, signature,
+          exceptions);
+    }
+
+    LOGGER.debug(Constants.LOG_EXIT, "visitMethod", methodVisitorToReturn);
+    return methodVisitorToReturn;
+  }
+
+  /**
+   * Our class may claim to implement WovenProxy, but doesn't have any
+   * implementations! We should fix this.
+   */
+  public final void visitEnd() {
+    LOGGER.debug(Constants.LOG_ENTRY, "visitEnd");
+
+    //first we need to override all the methods that were on non-object parents
+    for(Class<?> c : nonObjectSupers) {
+      try {
+        //Load the class bytes and copy methods across
+        ClassReader cReader = new ClassReader(c.getResourceAsStream(
+            c.getSimpleName() + ".class"));
+        //We don't need the method bodies, so skip them for speed
+        cReader.accept(new MethodCopyingClassAdapter(cv, c, typeBeingWoven,
+            knownMethods, transformedMethods), ClassReader.SKIP_CODE | 
+            ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
+      } catch (IOException e) {
+        //This should never happen!
+        throw new RuntimeException("Error processing " + c.getName() + " when weaving "
+            + typeBeingWoven.getClassName(), e);
+      }
+    }
+    // If we need to implement woven proxy in this class then write the methods
+    if (implementWovenProxy) {
+      writeFinalWovenProxyMethods();
+    }
+    
+    // this method is called when we reach the end of the class
+    // so it is time to make sure the static initialiser method is written
+    writeStaticInitMethod();
+
+    // Make sure we add the instance specific WovenProxy method to our class,
+    // and give ourselves a constructor to use
+    writeCreateNewProxyInstanceAndConstructor();
+
+    // now delegate to the cv
+    cv.visitEnd();
+
+    LOGGER.debug(Constants.LOG_EXIT, "visitEnd");
+  }
+  /**
+   * Get the {@link MethodVisitor} that will weave a given method
+   * @param access
+   * @param name
+   * @param desc
+   * @param signature
+   * @param exceptions
+   * @param currentMethod
+   * @param methodStaticFieldName
+   * @return
+   */
+  protected abstract MethodVisitor getWeavingMethodVisitor(int access, String name,
+  String desc, String signature, String[] exceptions, Method currentMethod,
+  String methodStaticFieldName);
+  
+  /**
+   * Get the Type which declares the method being currently processed. For class
+   * weaving this will be the {@link #typeBeingWoven}, for dynamic interface
+   * implementation this will be the interface type.
+   * @return
+   */
+  protected abstract Type getDeclaringTypeForCurrentMethod();
+
+  /**
+   * Write the methods we need for wovenProxies on the highest supertype
+   */
+  private final void writeFinalWovenProxyMethods() {
+    // add private fields for the Callable<Object> dispatcher
+    // and InvocationListener. These aren't static because we can have
+    // multiple instances of the same proxy class. These should not be
+    // serialized, or used in JPA or any other thing we can think of,
+    // so we annotate them as necessary
+
+    generateField(DISPATCHER_FIELD, Type.getDescriptor(Callable.class));
+    generateField(LISTENER_FIELD, Type.getDescriptor(InvocationListener.class));
+
+    // a general methodAdapter field that we will use to with GeneratorAdapters
+    // to create the methods required to implement WovenProxy
+    GeneratorAdapter methodAdapter;
+
+    // add a method for unwrapping the dispatcher
+    methodAdapter = getMethodGenerator(PUBLIC_GENERATED_METHOD_ACCESS, new Method(
+        "org_apache_aries_proxy_weaving_WovenProxy_unwrap", DISPATCHER_TYPE,
+        NO_ARGS));
+
+    // /////////////////////////////////////////////////////
+    // Implement the method
+
+    // load this to get the field
+    methodAdapter.loadThis();
+    // get the dispatcher field and return
+    methodAdapter.getField(typeBeingWoven, DISPATCHER_FIELD, DISPATCHER_TYPE);
+    methodAdapter.returnValue();
+    methodAdapter.endMethod();
+
+    // /////////////////////////////////////////////////////
+
+    // add a method for checking if the dispatcher is set
+    methodAdapter = getMethodGenerator(PUBLIC_GENERATED_METHOD_ACCESS, new Method(
+        "org_apache_aries_proxy_weaving_WovenProxy_isProxyInstance",
+        Type.BOOLEAN_TYPE, NO_ARGS));
+
+    // /////////////////////////////////////////////////////
+    // Implement the method
+
+    // load this to get the field
+    methodAdapter.loadThis();
+    // make a label for return true
+    Label returnTrueLabel = methodAdapter.newLabel();
+    // get the dispatcher field for the stack
+    methodAdapter.getField(typeBeingWoven, DISPATCHER_FIELD, DISPATCHER_TYPE);
+    // check if the dispatcher was non-null and goto return true if it was
+    methodAdapter.ifNonNull(returnTrueLabel);
+    methodAdapter.loadThis();
+    // get the listener field for the stack
+    methodAdapter.getField(typeBeingWoven, LISTENER_FIELD, LISTENER_TYPE);
+    // check if the listener field was non-null and goto return true if it was
+    methodAdapter.ifNonNull(returnTrueLabel);
+    // return false if we haven't jumped anywhere
+    methodAdapter.push(false);
+    methodAdapter.returnValue();
+    // mark the returnTrueLable
+    methodAdapter.mark(returnTrueLabel);
+    methodAdapter.push(true);
+    methodAdapter.returnValue();
+    // end the method
+    methodAdapter.endMethod();
+
+    // ///////////////////////////////////////////////////////
+  }
+
+  /**
+   * We write createNewProxyInstance separately because it isn't final, and is
+   * overridden on each class, we also write a constructor for this method to
+   * use if we don't have one.
+   */
+  private final void writeCreateNewProxyInstanceAndConstructor() {
+    GeneratorAdapter methodAdapter = getMethodGenerator(ACC_PUBLIC, new Method(
+        "org_apache_aries_proxy_weaving_WovenProxy_createNewProxyInstance",
+        WOVEN_PROXY_IFACE_TYPE, DISPATCHER_LISTENER_METHOD_ARGS));
+
+    // /////////////////////////////////////////////////////
+    // Implement the method
+
+    // Create and instantiate a new instance, then return it
+    methodAdapter.newInstance(typeBeingWoven);
+    methodAdapter.dup();
+    methodAdapter.loadArgs();
+    methodAdapter.invokeConstructor(typeBeingWoven, new Method("<init>",
+        Type.VOID_TYPE, DISPATCHER_LISTENER_METHOD_ARGS));
+    methodAdapter.returnValue();
+    methodAdapter.endMethod();
+    //////////////////////////////////////////////////////////
+
+    
+    // Write a protected no-args constructor for this class
+    methodAdapter = getMethodGenerator(ACC_PROTECTED, ARGS_CONSTRUCTOR);
+
+    // /////////////////////////////////////////////////////
+    // Implement the constructor
+
+    // For the top level supertype we need to invoke a no-args super, on object 
+    //if we have to
+    
+    if(implementWovenProxy) {
+      methodAdapter.loadThis();
+
+      if (superHasNoArgsConstructor)
+        methodAdapter.invokeConstructor(superType, NO_ARGS_CONSTRUCTOR);
+      else
+        methodAdapter.invokeConstructor(OBJECT_TYPE, NO_ARGS_CONSTRUCTOR);
+      
+      methodAdapter.loadThis();
+      methodAdapter.loadArg(0);
+      methodAdapter.putField(typeBeingWoven, DISPATCHER_FIELD, DISPATCHER_TYPE);
+      
+      methodAdapter.loadThis();
+      methodAdapter.loadArg(1);
+      methodAdapter.putField(typeBeingWoven, LISTENER_FIELD, LISTENER_TYPE);
+    } else {
+      //We just invoke the super with args
+      methodAdapter.loadThis();
+      methodAdapter.loadArgs();
+      methodAdapter.invokeConstructor(superType, ARGS_CONSTRUCTOR);
+    }
+    
+    //Throw an NPE if the dispatcher is null, return otherwise
+    methodAdapter.loadArg(0);
+    Label returnValue = methodAdapter.newLabel();
+    methodAdapter.ifNonNull(returnValue);
+    methodAdapter.newInstance(NPE_TYPE);
+    methodAdapter.dup();
+    methodAdapter.push("The dispatcher must never be null!");
+    methodAdapter.invokeConstructor(NPE_TYPE, NPE_CONSTRUCTOR);
+    methodAdapter.throwException();
+    
+    methodAdapter.mark(returnValue);
+    methodAdapter.returnValue();
+    methodAdapter.endMethod();
+    //////////////////////////////////////////////////////////
+  }
+
+  /**
+   * Create fields and an initialiser for {@link java.lang.reflect.Method}
+   * objects in our class
+   */
+  private final void writeStaticInitMethod() {
+    // we create a static field for each method we encounter with a *unique*
+    // random name
+    // since each method needs to be stored individually
+
+    for (String methodStaticFieldName : transformedMethods.keySet()) {
+      // add a private static field for the method
+      cv.visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC,
+          methodStaticFieldName, METHOD_TYPE.getDescriptor(), null, null)
+          .visitEnd();
+    }
+    GeneratorAdapter staticAdapter = new GeneratorAdapter(ACC_STATIC,
+        new Method("<clinit>", Type.VOID_TYPE, NO_ARGS), null, null, cv);
+
+    for (Entry<String, TypeMethod> entry : transformedMethods.entrySet()) {
+      // Add some more code to the static initializer
+
+      TypeMethod m = entry.getValue();
+      Type[] targetMethodParameters = m.method.getArgumentTypes();
+
+      String methodStaticFieldName = entry.getKey();
+
+      Label beginPopulate = staticAdapter.newLabel();
+      Label endPopulate = staticAdapter.newLabel();
+      Label catchHandler = staticAdapter.newLabel();
+      staticAdapter.visitTryCatchBlock(beginPopulate, endPopulate,
+          catchHandler, THROWABLE_INAME);
+
+      staticAdapter.mark(beginPopulate);
+      staticAdapter.push(m.declaringClass);
+
+      // push the method name string arg onto the stack
+      staticAdapter.push(m.method.getName());
+
+      // create an array of the method parm class[] arg
+      staticAdapter.push(targetMethodParameters.length);
+      staticAdapter.newArray(CLASS_TYPE);
+      int index = 0;
+      for (Type t : targetMethodParameters) {
+        staticAdapter.dup();
+        staticAdapter.push(index);
+        staticAdapter.push(t);
+        staticAdapter.arrayStore(CLASS_TYPE);
+        index++;
+      }
+
+      // invoke the getMethod
+      staticAdapter.invokeVirtual(CLASS_TYPE,
+          new Method("getDeclaredMethod", METHOD_TYPE, new Type[] {
+              STRING_TYPE, CLASS_ARRAY_TYPE}));
+
+      // store the reflected method in the static field
+      staticAdapter.putStatic(typeBeingWoven, methodStaticFieldName,
+          METHOD_TYPE);
+
+      Label afterCatch = staticAdapter.newLabel();
+      staticAdapter.mark(endPopulate);
+      staticAdapter.goTo(afterCatch);
+
+      staticAdapter.mark(catchHandler);
+      // We don't care about the exception, so pop it off
+      staticAdapter.pop();
+      // store the reflected method in the static field
+      staticAdapter.visitInsn(ACONST_NULL);
+      staticAdapter.putStatic(typeBeingWoven, methodStaticFieldName,
+          METHOD_TYPE);
+      staticAdapter.mark(afterCatch);
+
+    }
+    staticAdapter.returnValue();
+    staticAdapter.endMethod();
+  }
+
+  /**
+   * Get a new UUID suitable for use in method and field names
+   * 
+   * @return
+   */
+  static final String getSanitizedUUIDString() {
+    return UUID.randomUUID().toString().replace('-', '_');
+  }
+
+  /**
+   * Generate an instance field that should be "invisible" to normal code
+   * 
+   * @param fieldName
+   * @param fieldDescriptor
+   */
+  private final void generateField(String fieldName, String fieldDescriptor) {
+    FieldVisitor fv = cv.visitField(ACC_PROTECTED | ACC_TRANSIENT | ACC_SYNTHETIC
+        | ACC_FINAL, fieldName, fieldDescriptor, null, null);
+    for (String s : annotationTypeDescriptors)
+      fv.visitAnnotation(s, true).visitEnd();
+    fv.visitEnd();
+  }
+
+  /**
+   * Get a generator for a method, this be annotated with the "invisibility"
+   * annotations (and ensured synthetic)
+   * 
+   * @param methodSignature
+   * @return
+   */
+  private final GeneratorAdapter getMethodGenerator(int access, Method method) {
+    access = access | ACC_SYNTHETIC;
+    GeneratorAdapter ga = new GeneratorAdapter(access, method, null, null, cv);
+    for (String s : annotationTypeDescriptors)
+      ga.visitAnnotation(s, true).visitEnd();
+    ga.visitCode();
+    return ga;
+  }
+}
\ No newline at end of file

Added: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/AbstractWovenProxyMethodAdapter.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/AbstractWovenProxyMethodAdapter.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/AbstractWovenProxyMethodAdapter.java (added)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/AbstractWovenProxyMethodAdapter.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,482 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.proxy.impl.weaving;
+
+import static org.apache.aries.proxy.impl.weaving.WovenProxyAdapter.DISPATCHER_FIELD;
+import static org.apache.aries.proxy.impl.weaving.WovenProxyAdapter.DISPATCHER_TYPE;
+import static org.apache.aries.proxy.impl.weaving.WovenProxyAdapter.LISTENER_FIELD;
+import static org.apache.aries.proxy.impl.weaving.WovenProxyAdapter.LISTENER_TYPE;
+import static org.apache.aries.proxy.impl.weaving.WovenProxyAdapter.METHOD_TYPE;
+import static org.apache.aries.proxy.impl.weaving.WovenProxyAdapter.NO_ARGS;
+import static org.apache.aries.proxy.impl.weaving.WovenProxyAdapter.OBJECT_TYPE;
+import static org.apache.aries.proxy.impl.weaving.WovenProxyAdapter.THROWABLE_INAME;
+import static org.objectweb.asm.Opcodes.ACONST_NULL;
+import static org.objectweb.asm.Opcodes.IFNE;
+
+import java.util.Arrays;
+
+import org.apache.aries.proxy.InvocationListener;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.GeneratorAdapter;
+import org.objectweb.asm.commons.Method;
+/**
+ * This class weaves dispatch and listener code into a method, there are two known
+ * subclasses {@link WovenProxyMethodAdapter} is used for weaving instance methods
+ * {@link InterfaceUsingWovenProxyMethodAdapter} is used to provide a delegating
+ * implementation of an interface method.
+ * 
+ * Roughly (but not exactly because it's easier to write working bytecode
+ * if you don't have to exactly recreate the Java!) this is trying to 
+ * do the following: <code>
+ * 
+ *      
+    if(dispatcher != null) {
+      int returnValue;
+      Object token = null;
+      boolean inInvoke = false;
+      try {
+        Object toInvoke = dispatcher.call();
+        if(listener != null)
+          token = listener.preInvoke(toInvoke, method, args);
+        
+        inInvoke = true;
+        returnValue = ((Template) toInvoke).doStuff(args);
+        inInvoke = false;
+        
+        if(listener != null)
+          listener.postInvoke(token, toInvoke, method, args);
+        
+      } catch (Throwable e){
+        // whether the the exception is an error is an application decision
+        // if we catch an exception we decide carefully which one to
+        // throw onwards
+        Throwable exceptionToRethrow = null;
+        // if the exception came from a precall or postcall 
+        // we will rethrow it
+        if (!inInvoke) {
+          exceptionToRethrow = e;
+        }
+        // if the exception didn't come from precall or postcall then it
+        // came from invoke
+        // we will rethrow this exception if it is not a runtime
+        // exception, but we must unwrap InvocationTargetExceptions
+        else {
+          if (!(e instanceof RuntimeException)) {
+            exceptionToRethrow = e;
+          }
+        }
+        try {
+          if(listener != null)
+            listener.postInvokeExceptionalReturn(token, method, null, e);
+        } catch (Throwable f) {
+          // we caught an exception from
+          // postInvokeExceptionalReturn
+          // if we haven't already chosen an exception to rethrow then
+          // we will throw this exception
+          if (exceptionToRethrow == null) {
+            exceptionToRethrow = f;
+          }
+        }
+        // if we made it this far without choosing an exception we
+        // should throw e
+        if (exceptionToRethrow == null) {
+          exceptionToRethrow = e;
+        }
+        throw exceptionToRethrow;
+      }
+    }
+    
+    //...original method body
+      </code>
+ *  
+ *   
+ */
+abstract class AbstractWovenProxyMethodAdapter extends GeneratorAdapter
+{
+  /** The type of a RuntimeException */
+  private static final Type RUNTIME_EX_TYPE = Type.getType(RuntimeException.class);
+  private static final Type THROWABLE_TYPE = Type.getType(Throwable.class);
+  
+  /** The postInvoke method of an {@link InvocationListener} */
+  private static final Method POST_INVOKE_METHOD = getAsmMethodFromClass(InvocationListener.class, "postInvoke", Object.class,
+      Object.class, java.lang.reflect.Method.class, Object.class);
+  /** The postInvokeExceptionalReturn method of an {@link InvocationListener} */
+  private static final Method POST_INVOKE_EXCEPTIONAL_METHOD = getAsmMethodFromClass(InvocationListener.class, 
+      "postInvokeExceptionalReturn", Object.class, Object.class,
+      java.lang.reflect.Method.class, Throwable.class);
+  /** The preInvoke method of an {@link InvocationListener} */
+  private static final Method PRE_INVOKE_METHOD = getAsmMethodFromClass(InvocationListener.class, "preInvoke", Object.class,
+      java.lang.reflect.Method.class, Object[].class);
+  
+  
+  /** The name of the static field that stores our {@link java.lang.reflect.Method} */
+  private final String methodStaticFieldName;
+  /** The current method */
+  protected final Method currentTransformMethod;
+  /** The type of <code>this</code> */
+  protected final Type typeBeingWoven;
+  /** True if this is a void method */
+  private final boolean isVoid;
+
+  //ints for local store
+  /** The local we use to store the {@link InvocationListener} token */
+  private int preInvokeReturnedToken;
+  /** The local we use to note whether we are in the original method body or not */
+  private int inNormalMethod;
+  /** The local we use to store the invocation target to dispatch to */
+  private int dispatchTarget;
+  /** The local for storing our method's result */
+  private int normalResult;
+
+  //the Labels we need for jumping around the pre/post/postexception and current method code
+  /** This marks the start of the try/catch around the pre/postInvoke*/
+  private final Label beginTry = new Label();
+  /** This marks the end of the try/catch around the pre/postInvoke*/
+  private final Label endTry = new Label();
+
+  /** The return type of this method */
+  private final Type returnType;
+  
+  /**
+   * Construct a new method adapter
+   * @param mv - the method visitor to write to
+   * @param access - the access modifiers on this method
+   * @param name - the name of this method
+   * @param desc - the descriptor of this method
+   * @param methodStaticFieldName - the name of the static field that will hold
+   *                                the {@link java.lang.reflect.Method} representing
+   *                                this method.
+   * @param currentTransformMethod - the ASM representation of this method
+   * @param proxyType - the type being woven that contains this method
+   */
+  public AbstractWovenProxyMethodAdapter(MethodVisitor mv, int access, String name, String desc,
+      String methodStaticFieldName, Method currentTransformMethod, Type typeBeingWoven)
+  {
+    super(mv, access, name, desc);
+    this.methodStaticFieldName = methodStaticFieldName;
+    this.currentTransformMethod = currentTransformMethod;
+    returnType = currentTransformMethod.getReturnType();
+    isVoid = returnType.getSort() == Type.VOID;
+    this.typeBeingWoven = typeBeingWoven;
+  }
+
+  @Override
+  public abstract void visitCode();
+
+  @Override
+  public abstract void visitMaxs(int stack, int locals);
+  
+  /**
+   * Write out the bytecode instructions necessary to do the dispatch.
+   * We know the dispatcher is non-null, and we need a try/catch around the
+   * invocation and listener calls.
+   */
+  protected final void writeDispatcher() {
+    // Setup locals we will use in the dispatch
+    setupLocals();
+    
+    //Write the try catch block
+    visitTryCatchBlock(beginTry, endTry, endTry, THROWABLE_INAME);
+    mark(beginTry);
+    
+    //Start dispatching, get the target object and store it
+    loadThis();
+    getField(typeBeingWoven, DISPATCHER_FIELD, DISPATCHER_TYPE);
+    invokeInterface(DISPATCHER_TYPE, new Method("call", OBJECT_TYPE, NO_ARGS));
+    storeLocal(dispatchTarget);
+    
+    //Pre-invoke, invoke, post-invoke, return
+    writePreInvoke();
+    //Start the real method
+    push(true);
+    storeLocal(inNormalMethod);
+    
+    //Dispatch the method and store the result (null for void)
+    loadLocal(dispatchTarget);
+    checkCast(getTypeToCastTo());
+    loadArgs();
+    if(isTypeToCastToInterface()) {
+      invokeInterface(getTypeToCastTo(), currentTransformMethod);
+    } else {
+      invokeVirtual(getTypeToCastTo(), currentTransformMethod);
+    }
+    if(isVoid) {
+      visitInsn(ACONST_NULL);
+    }
+    storeLocal(normalResult);
+    
+    // finish the real method and post-invoke
+    push(false);
+    storeLocal(inNormalMethod);
+    writePostInvoke();
+    
+    //Return, with the return value if necessary
+    if(!!!isVoid) {
+      loadLocal(normalResult);
+    }
+    returnValue();
+    
+    //End of our try, start of our catch
+    mark(endTry);
+    writeMethodCatchHandler();
+  }
+  
+  /**
+   * Get the type to which the class should be cast for delegation
+   * @return
+   */
+  protected abstract Type getTypeToCastTo();
+  
+  protected abstract boolean isTypeToCastToInterface();
+  
+  /**
+   * Setup the normalResult, inNormalMethod, preInvokeReturnedToken and
+   * dispatch target locals.
+   */
+  private final void setupLocals() {
+    if (isVoid){
+      normalResult = newLocal(WovenProxyAdapter.OBJECT_TYPE);
+    } else{
+      normalResult = newLocal(returnType);
+    }
+    
+    preInvokeReturnedToken = newLocal(OBJECT_TYPE);
+    visitInsn(ACONST_NULL);
+    storeLocal(preInvokeReturnedToken);
+    
+    inNormalMethod = newLocal(Type.BOOLEAN_TYPE);
+    push(false);
+    storeLocal(inNormalMethod);
+    
+    dispatchTarget = newLocal(OBJECT_TYPE);
+    visitInsn(ACONST_NULL);
+    storeLocal(dispatchTarget);
+  }
+
+  /**
+   * Begin trying to invoke the listener, if the listener is
+   * null the bytecode will branch to the supplied label, other
+   * otherwise it will load the listener onto the stack.
+   * @param l The label to branch to
+   */
+  private final void beginListenerInvocation(Label l) {
+    //If there's no listener then skip invocation
+    loadThis();
+    getField(typeBeingWoven, LISTENER_FIELD, LISTENER_TYPE);
+    ifNull(l);
+    loadThis();
+    getField(typeBeingWoven, LISTENER_FIELD, LISTENER_TYPE);
+  }
+
+  /**
+   * Write out the preInvoke. This copes with the listener being null
+   */
+  private final void writePreInvoke() {
+    //The place to go if the listener is null
+    Label nullListener = newLabel();
+    beginListenerInvocation(nullListener);
+
+    // The listener is on the stack, we need (target, method, args)
+    
+    loadLocal(dispatchTarget);
+    getStatic(typeBeingWoven, methodStaticFieldName, METHOD_TYPE);
+    loadArgArray();
+    
+    //invoke it and store the token returned
+    invokeInterface(WovenProxyAdapter.LISTENER_TYPE, PRE_INVOKE_METHOD);
+    storeLocal(preInvokeReturnedToken);
+    
+    mark(nullListener);
+  }
+  
+  /**
+   * Write out the postInvoke. This copes with the listener being null
+   */
+  private final void writePostInvoke() {
+    //The place to go if the listener is null
+    Label nullListener = newLabel();
+    beginListenerInvocation(nullListener);
+    
+    // The listener is on the stack, we need (token, target, method, result)
+    
+    loadLocal(preInvokeReturnedToken);
+    loadLocal(dispatchTarget);
+    getStatic(typeBeingWoven, methodStaticFieldName, WovenProxyAdapter.METHOD_TYPE);
+    loadLocal(normalResult);
+    
+    //If the result a primitive then we need to box it
+    if (!!!isVoid && returnType.getSort() != Type.OBJECT && returnType.getSort() != Type.ARRAY){
+      box(returnType);
+    }
+    
+    //invoke the listener
+    invokeInterface(WovenProxyAdapter.LISTENER_TYPE, POST_INVOKE_METHOD);
+    
+    mark(nullListener);
+  }
+  
+  /**
+   * Write the catch handler for our method level catch, this runs the exceptional
+   * post-invoke if there is a listener, and throws the correct exception at the
+   * end
+   */
+  private final void writeMethodCatchHandler() {
+    
+    //Store the original exception
+    int originalException = newLocal(THROWABLE_TYPE);
+    storeLocal(originalException);
+    
+    //Start by initialising exceptionToRethrow
+    int exceptionToRethrow = newLocal(THROWABLE_TYPE);
+    visitInsn(ACONST_NULL);
+    storeLocal(exceptionToRethrow);
+    
+    //We need another try catch around the postInvokeExceptionalReturn, so here 
+    //are some labels and the declaration for it
+    Label beforeInvoke = newLabel();
+    Label afterInvoke = newLabel();
+    visitTryCatchBlock(beforeInvoke, afterInvoke, afterInvoke, THROWABLE_INAME);
+    
+    //If we aren't in normal flow then set exceptionToRethrow = originalException
+    loadLocal(inNormalMethod);
+    Label inNormalMethodLabel = newLabel();
+    // Jump if not zero (false)
+    visitJumpInsn(IFNE, inNormalMethodLabel);
+    loadLocal(originalException);
+    storeLocal(exceptionToRethrow);
+    goTo(beforeInvoke);
+    
+    mark(inNormalMethodLabel);
+    //We are in normal method flow so set exceptionToRethrow = originalException
+    //if originalException is not a runtime exception
+    loadLocal(originalException);
+    instanceOf(RUNTIME_EX_TYPE);
+    //If false then store original in toThrow, otherwise go to beforeInvoke
+    visitJumpInsn(IFNE, beforeInvoke);
+    loadLocal(originalException);
+    storeLocal(exceptionToRethrow);
+    goTo(beforeInvoke);
+    //Setup of variables finished, begin try/catch
+       
+    //Mark the start of our try
+    mark(beforeInvoke);
+    //Begin invocation of the listener, jump to throw if null
+    Label throwSelectedException = newLabel();
+    beginListenerInvocation(throwSelectedException);
+    
+    //We have a listener, so call it (token, target, method, exception)
+    loadLocal(preInvokeReturnedToken);
+    loadLocal(dispatchTarget);
+    getStatic(typeBeingWoven, methodStaticFieldName, METHOD_TYPE);
+    loadLocal(originalException);
+    invokeInterface(WovenProxyAdapter.LISTENER_TYPE, POST_INVOKE_EXCEPTIONAL_METHOD);
+    goTo(throwSelectedException);
+    
+    mark(afterInvoke);
+    //catching another exception replaces the original
+    storeLocal(originalException);
+
+    //Throw exceptionToRethrow if it isn't null, or the original if it is
+    Label throwException = newLabel();
+    mark(throwSelectedException);
+    loadLocal(exceptionToRethrow);
+    ifNonNull(throwException);
+    loadLocal(originalException);
+    storeLocal(exceptionToRethrow);
+    
+    mark(throwException);
+    loadLocal(exceptionToRethrow);
+    throwException();
+  }
+  
+  /**
+   * This method unwraps woven proxy instances for use in the right-hand side
+   * of equals methods
+   */
+  protected final void unwrapEqualsArgument() {
+    
+    //Create and initialize a local for our work
+    int unwrapLocal = newLocal(WovenProxyAdapter.OBJECT_TYPE);
+    visitInsn(ACONST_NULL);
+    storeLocal(unwrapLocal);
+    
+    Label startUnwrap = newLabel();
+    mark(startUnwrap);
+    //Load arg and check if it is a WovenProxy instances
+    loadArg(0);
+    instanceOf(WovenProxyAdapter.WOVEN_PROXY_IFACE_TYPE);
+    Label unwrapFinished = newLabel();
+    //Jump if zero (false)
+    visitJumpInsn(Opcodes.IFEQ, unwrapFinished);
+    //Arg is a wovenProxy, if it is the same as last time then we're done
+    loadLocal(unwrapLocal);
+    loadArg(0);
+    ifCmp(WovenProxyAdapter.OBJECT_TYPE, EQ, unwrapFinished);
+    //Not the same, store current arg in unwrapLocal for next loop
+    loadArg(0);
+    storeLocal(unwrapLocal);
+    
+    //So arg is a WovenProxy, but not the same as last time, cast it and store 
+    //the result of unwrap.call in the arg
+    loadArg(0);
+    checkCast(WovenProxyAdapter.WOVEN_PROXY_IFACE_TYPE);
+    //Now unwrap
+    invokeInterface(WovenProxyAdapter.WOVEN_PROXY_IFACE_TYPE, new Method("org_apache_aries_proxy_weaving_WovenProxy_unwrap",
+        WovenProxyAdapter.DISPATCHER_TYPE, WovenProxyAdapter.NO_ARGS));
+    
+    //Now we may have a Callable to invoke
+    int callable = newLocal(WovenProxyAdapter.DISPATCHER_TYPE);
+    storeLocal(callable);
+    loadLocal(callable);
+    ifNull(unwrapFinished);
+    loadLocal(callable);
+    invokeInterface(WovenProxyAdapter.DISPATCHER_TYPE, new Method("call",
+        WovenProxyAdapter.OBJECT_TYPE, WovenProxyAdapter.NO_ARGS));
+    //Store the result and we're done (for this iteration)
+    storeArg(0);
+    goTo(startUnwrap);
+    
+    mark(unwrapFinished);
+  }
+
+  /**
+   * A utility method for getting an ASM method from a Class
+   * @param clazz the class to search
+   * @param name The method name
+   * @param argTypes The method args
+   * @return
+   */
+  private static final Method getAsmMethodFromClass(Class<?> clazz, String name, Class<?>... argTypes)
+  {
+    //get the java.lang.reflect.Method to get the types
+    java.lang.reflect.Method ilMethod = null;
+    try {
+      ilMethod = clazz.getMethod(name, argTypes);
+    } catch (Exception e) {
+      //Should be impossible!
+      throw new RuntimeException("Error finding Invocation Listener method " + name
+          + " " + Arrays.toString(argTypes), e);
+    }
+    //get the ASM method
+    return new Method(name, Type.getReturnType(ilMethod), Type.getArgumentTypes(ilMethod));
+  }
+}



Mime
View raw message