aries-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From timothyjw...@apache.org
Subject svn commit: r1092368 [2/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
Added: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/InterfaceCombiningClassAdapter.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/InterfaceCombiningClassAdapter.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/InterfaceCombiningClassAdapter.java (added)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/InterfaceCombiningClassAdapter.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,243 @@
+/*
+ * 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.lang.reflect.Constructor;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.apache.aries.proxy.InvocationListener;
+import org.apache.aries.proxy.UnableToProxyException;
+import org.apache.aries.proxy.weaving.WovenProxy;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.EmptyVisitor;
+import org.objectweb.asm.commons.Method;
+
+/**
+ * This class is used to aggregate several interfaces into a real class which implements all of them
+ */
+public final class InterfaceCombiningClassAdapter extends EmptyVisitor implements Opcodes {
+
+  /** An implementation of ClassLoader that will be used to define our proxy class */
+  private static final class ProxyClassLoader extends ClassLoader {
+    /** A {@link Map} of classes we already know */
+    private final Map<String, Class<?>> classes = new ConcurrentHashMap<String, Class<?>>();
+    
+    /** The bytes of the proxy class */
+    private byte[] bytesToDefine;
+    /** The name of the proxy class */
+    private String classNameToDefine;
+    
+    public ProxyClassLoader(Collection<Class<?>> ifaces) {
+      for(Class<?> c : ifaces) {
+        classes.put(c.getName(), c);
+      }
+      classes.put(WovenProxy.class.getName(), WovenProxy.class);
+    }
+
+    @Override
+    protected Class<?> findClass(String className) {
+      Class<?> c = findLoadedClass(className);
+      
+      if(c == null) {
+        if(className.equals(classNameToDefine))
+          return defineClass(className, bytesToDefine, 0, bytesToDefine.length);
+        
+        c = classes.get(className);
+        
+        if(c == null) {
+          for(Class<?> iface : classes.values()) {
+            if(iface.getClassLoader() == null)
+              continue;
+            try {
+              c = iface.getClassLoader().loadClass(className);
+              break;
+            } catch (ClassNotFoundException cnfe) {
+              //No op
+            }
+          }
+        }
+      }
+      return c;
+    }
+  }
+  /** 
+   * A cache of previously created proxy classes. Because we cache then update
+   * the {@link InterfaceCombiningClassAdapter#accessList} we might temporarily 
+   * end up with more in the cache than the maximum size of the access list. 
+   * We therefore initialize this to be double the size of the access list so it
+   * should never be necessary to resize
+   */
+  private static final ConcurrentMap<HashSet<Class<?>>, Class<?>> cache = 
+    new ConcurrentHashMap<HashSet<Class<?>>, Class<?>>(256);
+  /**
+   * The access List that determines when we evict things from our cache, items
+   * are removed and re-added when accessed so a {@link LinkedBlockingQueue}
+   * is considerably faster 
+   */
+  private static final Queue<HashSet<Class<?>>> accessList = 
+    new LinkedBlockingQueue<HashSet<Class<?>>>(128);
+  
+  /** The interfaces we need to implement */
+  private final Collection<Class<?>> interfaces;
+  /** The {@link ClassWriter} we use to write our class */
+  private final ClassWriter writer;
+  /** The adapter we use to weave in our method implementations */
+  private final InterfaceUsingWovenProxyAdapter adapter;
+  /** Whether we have already written the class bytes */
+  private boolean done = false;
+  
+  /**
+   * Construct an {@link InterfaceCombiningClassAdapter} to combine the supplied
+   * interfaces into a class with the supplied name using the supplied classloader
+   * @param className
+   * @param loader
+   * @param interfaces
+   */
+  private InterfaceCombiningClassAdapter(String className,
+      ClassLoader loader, Collection<Class<?>> interfaces) {
+    writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
+    adapter = new InterfaceUsingWovenProxyAdapter(writer, className, loader);
+    
+    this.interfaces = interfaces;
+    String[] interfaceNames = new String[interfaces.size()];
+    
+    int i = 0;
+    for(Class<?> in : interfaces) {
+      interfaceNames[i] = Type.getType(in).getInternalName();
+      i++;
+    }
+    
+    adapter.visit(V1_6, ACC_PUBLIC | ACC_SYNTHETIC, className, null,
+        AbstractWovenProxyAdapter.OBJECT_TYPE.getInternalName(), interfaceNames);
+  }
+
+
+  @Override
+  public final MethodVisitor visitMethod(int access, String name, String desc,
+      String sig, String[] arg4) {
+    //We're going to implement this method, so make it non abstract!
+    access ^= ACC_ABSTRACT;
+    //If we already implement this method (from another interface) then we don't
+    //want a duplicate
+    if(adapter.knownMethods.contains(new Method(name, desc)))
+      return null;
+    else 
+      return adapter.visitMethod(access, name, desc, null, arg4);
+  }
+  
+  /**
+   * Generate the byte[] for our class
+   * @return
+   * @throws UnableToProxyException
+   */
+  private final byte[] generateBytes() throws UnableToProxyException {
+    if(!!!done) {
+      for(Class<?> c : interfaces) {
+        adapter.setCurrentInterface(Type.getType(c));
+        try {
+          ClassReader reader = new ClassReader(c.getResourceAsStream(
+              c.getSimpleName() + ".class"));
+          reader.accept(this, 
+              ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE);
+          
+        } catch (IOException e) {
+          throw new UnableToProxyException(c, e);
+        }
+      }
+      adapter.visitEnd();
+      done  = true;
+    }
+    return writer.toByteArray();
+  }
+
+  /**
+   * Generate a new proxy instance implementing the supplied interfaces and using the supplied
+   * dispatcher and listener
+   * @param ifaces
+   * @param dispatcher
+   * @param listener
+   * @return
+   * @throws UnableToProxyException
+   */
+  public static final Object getProxyInstance(Collection<Class<?>> ifaces, 
+      Callable<Object> dispatcher, InvocationListener listener) throws UnableToProxyException{
+    
+    Class<?> c;
+    
+    HashSet<Class<?>> classes = new HashSet<Class<?>>(ifaces);
+    
+    c = cache.get(classes);
+    
+    if(c == null) {
+      ProxyClassLoader cl = new ProxyClassLoader(classes);
+      
+      String className = "Proxy" + AbstractWovenProxyAdapter.getSanitizedUUIDString();
+      
+      InterfaceCombiningClassAdapter icca = new InterfaceCombiningClassAdapter(
+          className, cl, classes);
+      
+      try {
+        cl.bytesToDefine = icca.generateBytes();
+        cl.classNameToDefine = className;
+        c = cl.loadClass(className);
+        Class<?> tmp = cache.putIfAbsent(classes, c);
+        if(tmp != null) {
+          //Someone beat us to it, just update the location in the access list
+          c = tmp;
+          
+          if(accessList.remove(classes)) {
+            //If we removed it we re-add it
+            while(!!!accessList.offer(classes)) {
+              HashSet<Class<?>> key = accessList.poll();
+              cache.remove(key);
+            }
+          }
+        } else {
+          //We have added a new cache entry
+          while(!!!accessList.offer(classes)) {
+            HashSet<Class<?>> key = accessList.poll();
+            cache.remove(key);
+          }
+        }
+      } catch (Exception re) {
+        throw new UnableToProxyException(classes.iterator().next(), re);
+      }
+    }
+    
+    try {
+      Constructor<?> con = c.getDeclaredConstructor(Callable.class, InvocationListener.class);
+      con.setAccessible(true);
+      return con.newInstance(dispatcher, listener);
+    } catch (Exception e) {
+      throw new UnableToProxyException(classes.iterator().next(), e);
+    }
+  }
+}
\ No newline at end of file

Added: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/InterfaceUsingWovenProxyAdapter.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/InterfaceUsingWovenProxyAdapter.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/InterfaceUsingWovenProxyAdapter.java (added)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/InterfaceUsingWovenProxyAdapter.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,57 @@
+/*
+ * 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 org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.Method;
+
+/**
+ * Used to weave classes processed by the {@link ProxyWeavingHook}
+ */
+final class InterfaceUsingWovenProxyAdapter extends AbstractWovenProxyAdapter {
+
+  private Type currentIfaceType;
+  
+  public InterfaceUsingWovenProxyAdapter(ClassVisitor writer, String className,
+      ClassLoader loader) {
+    super(writer, className, loader);
+  }
+
+  public final void setCurrentInterface(Type type) {
+    currentIfaceType = type;
+  }
+  
+  /**
+   * Return a {@link MethodVisitor} that copes with interfaces
+   */ 
+  protected final MethodVisitor getWeavingMethodVisitor(int access, String name,
+      String desc, String signature, String[] exceptions, Method currentMethod,
+      String methodStaticFieldName) {
+    return new InterfaceUsingWovenProxyMethodAdapter(cv.visitMethod(
+        access, name, desc, signature, exceptions), access, name, desc,
+        methodStaticFieldName, currentMethod, typeBeingWoven, currentIfaceType);
+  }
+
+  @Override
+  protected final Type getDeclaringTypeForCurrentMethod() {
+    return currentIfaceType;
+  }
+}

Added: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/InterfaceUsingWovenProxyMethodAdapter.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/InterfaceUsingWovenProxyMethodAdapter.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/InterfaceUsingWovenProxyMethodAdapter.java (added)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/InterfaceUsingWovenProxyMethodAdapter.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,82 @@
+/*
+ * 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.AbstractWovenProxyAdapter.OBJECT_TYPE;
+
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.Method;
+
+class InterfaceUsingWovenProxyMethodAdapter extends AbstractWovenProxyMethodAdapter {
+
+  private final Type interfaceType;
+  public InterfaceUsingWovenProxyMethodAdapter(MethodVisitor mv, int access, String name,
+      String desc, String methodStaticFieldName, Method currentTransformMethod,
+      Type typeBeingWoven, Type interfaceType) {
+    super(mv, access, name, desc, methodStaticFieldName, currentTransformMethod,
+        typeBeingWoven);
+    this.interfaceType = interfaceType;
+  }
+
+  /**
+   * We write dispatch code here because we have no real method body
+   */
+  @Override
+  public final void visitCode()
+  {
+    //Notify our parent that the method code is starting. This must happen first
+    mv.visitCode();
+    
+    //unwrap for equals if we need to
+    if(currentTransformMethod.getName().equals("equals") && 
+        currentTransformMethod.getArgumentTypes().length == 1 && 
+        currentTransformMethod.getArgumentTypes()[0].equals(OBJECT_TYPE)) {
+      unwrapEqualsArgument();
+    }
+    //No null-check needed
+    //Write the dispatcher code in here
+    writeDispatcher();
+  }
+
+  @Override
+  public final void visitMaxs(int stack, int locals) {
+    mv.visitMaxs(stack, locals);
+  }
+  
+  /**
+   * We don't get the code and maxs calls for interfaces, so we add them here
+   */
+  @Override
+  public final void visitEnd() {
+    visitCode();
+    visitMaxs(0, 0);
+    mv.visitEnd();
+  }
+  
+  @Override
+  protected final Type getTypeToCastTo() {
+    return interfaceType;
+  }
+  
+  @Override
+  protected final boolean isTypeToCastToInterface() {
+    return true;
+  }
+}

Added: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/MethodCopyingClassAdapter.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/MethodCopyingClassAdapter.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/MethodCopyingClassAdapter.java (added)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/MethodCopyingClassAdapter.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,241 @@
+/*
+ * 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.util.Map;
+import java.util.Set;
+
+import org.apache.aries.proxy.FinalModifierException;
+import org.apache.aries.proxy.UnableToProxyException;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.EmptyVisitor;
+import org.objectweb.asm.commons.Method;
+
+/**
+ * This class is used to copy methods from a super-class into a sub-class, but
+ * then delegate up to the super-class implementation. We expect to be called
+ * with {@link ClassReader#SKIP_CODE}. This class is used when we can't weave
+ * all the way up the Class hierarchy and need to override methods on the first
+ * subclass we can weave.
+ */
+final class MethodCopyingClassAdapter extends EmptyVisitor implements Opcodes {
+  /** The sub-class visitor to write to */
+  private final ClassVisitor cv;
+  /** The super-class to copy from */
+  private final Class<?> superToCopy;
+  /** Is the sub-class in the same package as the super */
+  private final boolean samePackage;
+  /** The ASM {@link Type} of the sub-class */
+  private final Type overridingClassType;
+  /** 
+   * The Set of {@link Method}s that exist in the sub-class. This set must be
+   * live so modifications will be reflected in the parent and prevent clashes 
+   */
+  private final Set<Method> knownMethods;
+  /**
+   * The map of field names to methods being added
+   */
+  private final Map<String, TypeMethod> transformedMethods;
+  
+  public MethodCopyingClassAdapter(ClassVisitor cv, Class<?> superToCopy,
+      Type overridingClassType, Set<Method> knownMethods, 
+      Map<String, TypeMethod> transformedMethods) {
+    this.cv = cv;
+    this.superToCopy = superToCopy;
+    this.overridingClassType = overridingClassType;
+    this.knownMethods = knownMethods;
+    this.transformedMethods = transformedMethods;
+    
+    String overridingClassName = overridingClassType.getClassName();
+    int lastIndex1 = superToCopy.getName().lastIndexOf('.');
+    int lastIndex2 = overridingClassName.lastIndexOf('.');
+    
+    samePackage = (lastIndex1 == lastIndex2) &&
+       superToCopy.getName().substring(0, (lastIndex1 == -1)? 1 : lastIndex1)
+       .equals(overridingClassName.substring(0, (lastIndex2 == -1)? 1 : lastIndex2));
+  }
+  
+  @Override
+  public final MethodVisitor visitMethod(final int access, String name, String desc,
+      String sig, String[] exceptions) {
+    
+    MethodVisitor mv = null;
+    //As in WovenProxyAdapter, we only care about "real" methods.
+    if (!!!name.equals("<init>") && !!!name.equals("<clinit>")
+        && (access & (ACC_STATIC | ACC_PRIVATE | ACC_SYNTHETIC | ACC_ABSTRACT
+            | ACC_NATIVE | ACC_BRIDGE)) == 0) {
+
+      // identify the target method parameters and return type
+      Method currentTransformMethod = new Method(name, desc);
+      // We don't want to duplicate a method we already overrode! 
+      if(!!!knownMethods.add(currentTransformMethod))
+        return null;
+      
+      // found a method we should weave
+      // We can't override a final method
+      if((access & ACC_FINAL) != 0)
+        throw new RuntimeException(new FinalModifierException(
+            superToCopy, name));
+      // We can't call up to a package protected method if we aren't in the same
+      // package
+      if((access & (ACC_PUBLIC | ACC_PROTECTED | ACC_PRIVATE)) == 0) {
+        if(!!!samePackage)
+          throw new RuntimeException("The method " + name + " in class " + 
+              superToCopy.getName() + " cannot be called by " + overridingClassType.getClassName()
+              + " because it is in a different package", new UnableToProxyException(superToCopy));
+      }
+      //Safe to copy a call to this method!
+      Type superType = Type.getType(superToCopy);
+      
+      // identify the target method parameters and return type
+      String methodStaticFieldName = "methodField" + WovenProxyAdapter.getSanitizedUUIDString();
+      transformedMethods.put(methodStaticFieldName, new TypeMethod(
+          superType, currentTransformMethod));  
+      
+      //Remember we need to copy the fake method *and* weave it, use a 
+      //WovenProxyMethodAdapter as well as a CopyingMethodAdapter
+      mv = new CopyingMethodAdapter(new WovenProxyMethodAdapter(cv.visitMethod(
+          access, name, desc, sig, exceptions), access, name, desc,
+          methodStaticFieldName, currentTransformMethod, overridingClassType),
+          superType, currentTransformMethod);
+    }
+    
+    return mv;
+  }
+  
+  /**
+   * This class is used to prevent any method body being copied, instead replacing
+   * the body with a call to the super-types implementation. The original annotations
+   * attributes etc are all copied.
+   */
+  private static final class CopyingMethodAdapter extends EmptyVisitor {
+    /** The visitor to delegate to */
+    private final MethodVisitor mv;
+    /** The type that declares this method (not the one that will override it) */
+    private final Type superType;
+    /** The method we are weaving */
+    private final Method currentTransformMethod;
+    
+    public CopyingMethodAdapter(MethodVisitor mv, Type superType, 
+        Method currentTransformMethod) {
+      this.mv = mv;
+      this.superType = superType;
+      this.currentTransformMethod = currentTransformMethod;
+    }
+
+    @Override
+    public final AnnotationVisitor visitAnnotation(String arg0, boolean arg1) {
+      return mv.visitAnnotation(arg0, arg1);
+    }
+
+    @Override
+    public final AnnotationVisitor visitAnnotationDefault() {
+      return mv.visitAnnotationDefault();
+    }
+
+    @Override
+    public final AnnotationVisitor visitParameterAnnotation(int arg0, String arg1,
+        boolean arg2) {
+      return mv.visitParameterAnnotation(arg0, arg1, arg2);
+    }
+    
+    @Override
+    public final void visitAttribute(Attribute attr) {
+      mv.visitAttribute(attr);
+    }
+
+    /**
+     * We skip code for speed when processing super-classes, this means we
+     * need to manually drive some methods here!
+     */
+    @Override
+    public final void visitEnd() {
+      mv.visitCode();
+      writeBody();
+      mv.visitMaxs(currentTransformMethod.getArgumentTypes().length + 1, 0);
+      mv.visitEnd();
+    }
+    
+    /**
+     * This method loads this, any args, then invokes the super version of this
+     */
+    private final void writeBody() {
+      mv.visitVarInsn(ALOAD, 0);
+      
+      int nargs = currentTransformMethod.getArgumentTypes().length;
+      
+      for(int i = 1 ; i <= nargs ; i++) {
+        switch(currentTransformMethod.
+               getArgumentTypes()[i - 1].getSort()) {
+          case (Type.BOOLEAN) :
+          case (Type.BYTE) :
+          case (Type.CHAR) :
+          case (Type.SHORT) :
+          case (Type.INT) :
+            mv.visitVarInsn(ILOAD, i);
+            break;
+          case (Type.FLOAT) :
+            mv.visitVarInsn(FLOAD, i);
+            break;
+          case (Type.DOUBLE) :
+            mv.visitVarInsn(DLOAD, i);
+            break;
+          case (Type.LONG) :
+            mv.visitVarInsn(LLOAD, i);
+            break;
+          default :
+            mv.visitVarInsn(ALOAD, i);
+        }
+      }
+      
+      mv.visitMethodInsn(INVOKESPECIAL, superType.getInternalName(),
+          currentTransformMethod.getName(), currentTransformMethod.getDescriptor());
+      
+      switch(currentTransformMethod.getReturnType().getSort()) {
+        case (Type.BOOLEAN) :
+        case (Type.BYTE) :
+        case (Type.CHAR) :
+        case (Type.SHORT) :
+        case (Type.INT) :
+          mv.visitInsn(IRETURN);
+          break;
+        case (Type.VOID) :
+          mv.visitInsn(RETURN);
+          break;
+        case (Type.FLOAT) :
+          mv.visitInsn(FRETURN);
+          break;
+        case (Type.DOUBLE) :
+          mv.visitInsn(DRETURN);
+          break;
+        case (Type.LONG) :
+          mv.visitInsn(LRETURN);
+          break;
+        default :
+          mv.visitInsn(ARETURN);
+      }
+    }
+  }
+}
\ No newline at end of file

Added: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/ProxyWeavingHook.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/ProxyWeavingHook.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/ProxyWeavingHook.java (added)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/ProxyWeavingHook.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,88 @@
+/*
+ * 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.util.List;
+
+import org.apache.aries.proxy.UnableToProxyException;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.hooks.weaving.WeavingException;
+import org.osgi.framework.hooks.weaving.WeavingHook;
+import org.osgi.framework.hooks.weaving.WovenClass;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class ProxyWeavingHook implements WeavingHook {
+
+  private static final Logger LOGGER = LoggerFactory
+  .getLogger(ProxyWeavingHook.class);
+  /** An import of the WovenProxy package */
+  private static final String IMPORT_A = "org.apache.aries.proxy.weaving";
+  /** 
+   * An import for the InvocationListener class that we will need.
+   * This should automatically wire to the right thing because of the uses clause
+   * on the impl.weaving package
+   */
+  private static final String IMPORT_B = "org.apache.aries.proxy";
+  
+  public final void weave(WovenClass wovenClass) {
+    
+    Bundle b = wovenClass.getBundleWiring().getBundle();
+    
+    if(b.getBundleId() == 0 || 
+        b.getSymbolicName().startsWith("org.apache.aries.proxy") ||
+        b.getSymbolicName().startsWith("org.apache.aries.util")) {
+      return;
+    }
+    
+    if(wovenClass.getClassName().startsWith("org.objectweb.asm") || 
+        wovenClass.getClassName().startsWith("org.slf4j") || 
+        wovenClass.getClassName().startsWith("org.apache.log4j"))
+      return;
+    
+    byte[] bytes = null;
+    
+    try {
+      bytes = WovenProxyGenerator.getWovenProxy(wovenClass.getBytes(),
+          wovenClass.getClassName(), wovenClass.getBundleWiring().getClassLoader());
+      
+    } catch (Exception e) {
+      if(e instanceof RuntimeException && 
+          e.getCause() instanceof UnableToProxyException){
+        //This is a weaving failure that should be logged, but the class
+        //can still be loaded
+        LOGGER.info("The class " + wovenClass.getClassName() + " cannot be woven, it may" +
+        		"not be possible for the runtime to proxy this class. The failure was : ", e);
+      } else {
+        //This is a failure that should stop the class loading!
+        LOGGER.error("There was a serious error trying to weave the class " 
+            + wovenClass.getClassName(), e);
+        throw new WeavingException("There was a serious error trying to weave the class " 
+          + wovenClass.getClassName(), e);
+      }
+    }
+    
+    if(bytes != null && bytes.length != 0) {
+      wovenClass.setBytes(bytes);
+      List<String> imports = wovenClass.getDynamicImports();
+      imports.add(IMPORT_A);
+      imports.add(IMPORT_B);
+    }
+  }
+}

Added: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/TypeMethod.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/TypeMethod.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/TypeMethod.java (added)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/TypeMethod.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,36 @@
+/*
+ * 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 org.objectweb.asm.Type;
+import org.objectweb.asm.commons.Method;
+
+/**
+ * This object stores a {@link Method} and the class that declares it
+ */
+final class TypeMethod {
+  final Type declaringClass;
+  final Method method;
+  
+  public TypeMethod(Type declaringClass,
+      Method method) {
+    this.declaringClass = declaringClass;
+    this.method = method;
+  }
+}

Added: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/WovenProxyAdapter.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/WovenProxyAdapter.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/WovenProxyAdapter.java (added)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/WovenProxyAdapter.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,53 @@
+/*
+ * 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 org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.Method;
+
+/**
+ * Used to weave classes processed by the {@link ProxyWeavingHook}
+ */
+public final class WovenProxyAdapter extends AbstractWovenProxyAdapter {
+
+  public WovenProxyAdapter(ClassVisitor writer, String className,
+      ClassLoader loader) {
+    super(writer, className, loader);
+  }
+
+  /**
+   * Get the weaving visitor used to weave instance methods
+   */
+  protected final MethodVisitor getWeavingMethodVisitor(int access, String name,
+      String desc, String signature, String[] exceptions, Method currentMethod,
+      String methodStaticFieldName) {
+    MethodVisitor methodVisitorToReturn;
+    methodVisitorToReturn = new WovenProxyMethodAdapter(cv.visitMethod(
+        access, name, desc, signature, exceptions), access, name, desc,
+        methodStaticFieldName, currentMethod, typeBeingWoven);
+    return methodVisitorToReturn;
+  }
+  
+  @Override
+  protected final Type getDeclaringTypeForCurrentMethod() {
+    return typeBeingWoven;
+  }
+}
\ No newline at end of file

Added: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/WovenProxyGenerator.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/WovenProxyGenerator.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/WovenProxyGenerator.java (added)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/WovenProxyGenerator.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,54 @@
+/*
+ * 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.objectweb.asm.Opcodes.ACC_ANNOTATION;
+import static org.objectweb.asm.Opcodes.ACC_ENUM;
+import static org.objectweb.asm.Opcodes.ACC_INTERFACE;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * This class is used to weave the bytes of a class into a proxyable class
+ */
+public final class WovenProxyGenerator
+{
+  public static final byte[] getWovenProxy(byte[] original, String className, ClassLoader loader){
+    ClassReader cReader = new ClassReader(original);
+    //Don't weave interfaces, enums or annotations
+    if((cReader.getAccess() & (ACC_INTERFACE | ACC_ANNOTATION | ACC_ENUM)) != 0)
+      return null;
+    
+    //We need to know the class version, but ASM won't tell us yet!
+    int version = ((0xFF & original[6]) << 8) + (0xFF & original[7]);
+    
+    //If we are Java 1.6 + compiled then we need to compute stack frames, otherwise
+    //maxs are fine (and faster)
+    ClassWriter cWriter = new ClassWriter(cReader, (version > Opcodes.V1_5) ?
+        ClassWriter.COMPUTE_FRAMES : ClassWriter.COMPUTE_MAXS);
+    ClassVisitor weavingAdapter = new WovenProxyAdapter(cWriter, className, loader);
+    // If we are Java 1.6 + then we need to skip frames as they will be recomputed
+    cReader.accept(weavingAdapter, (version > Opcodes.V1_5) ? ClassReader.SKIP_FRAMES : 0);
+    
+    return cWriter.toByteArray();
+  }
+}
\ No newline at end of file

Added: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/WovenProxyMethodAdapter.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/WovenProxyMethodAdapter.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/WovenProxyMethodAdapter.java (added)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/weaving/WovenProxyMethodAdapter.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,86 @@
+/*
+ * 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.AbstractWovenProxyAdapter.DISPATCHER_FIELD;
+import static org.apache.aries.proxy.impl.weaving.AbstractWovenProxyAdapter.DISPATCHER_TYPE;
+import static org.apache.aries.proxy.impl.weaving.AbstractWovenProxyAdapter.OBJECT_TYPE;
+
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.Method;
+
+final class WovenProxyMethodAdapter extends AbstractWovenProxyMethodAdapter {
+
+  /** Jump here to start executing the original method body **/
+  private final Label executeDispatch = new Label();
+  
+  public WovenProxyMethodAdapter(MethodVisitor mv, int access, String name,
+      String desc, String methodStaticFieldName, Method currentTransformMethod,
+      Type typeBeingWoven) {
+    super(mv, access, name, desc, methodStaticFieldName, currentTransformMethod,
+        typeBeingWoven);
+  }
+
+  /**
+   * We weave instructions before the normal method body. We must be careful not
+   * to violate the "rules" of Java (e.g. that try blocks cannot intersect, but
+   * can be nested). We must also not violate the ordering that ASM expects, so
+   * we must not call visitMaxs, or define labels before a try/catch that uses 
+   * them!
+   */
+  @Override
+  public final void visitCode()
+  {
+    //Notify our parent that the method code is starting. This must happen first
+    mv.visitCode();
+    
+    //unwrap for equals if we need to
+    if(currentTransformMethod.getName().equals("equals") && 
+        currentTransformMethod.getArgumentTypes().length == 1 && 
+        currentTransformMethod.getArgumentTypes()[0].equals(OBJECT_TYPE)) {
+      unwrapEqualsArgument();
+    }
+    
+    //Check if we have a dispatcher, if so then we need to dispatch!
+    loadThis();
+    getField(typeBeingWoven, DISPATCHER_FIELD, DISPATCHER_TYPE);
+    ifNonNull(executeDispatch);
+  }
+
+  @Override
+  public final void visitMaxs(int stack, int locals) {
+    //Mark this location for continuing execution when a dispatcher is set
+    mark(executeDispatch);
+    //Write the dispatcher code in here
+    writeDispatcher();
+    mv.visitMaxs(stack, locals);
+  }
+  
+  @Override
+  protected final Type getTypeToCastTo() {
+    return typeBeingWoven;
+  }
+
+  @Override
+  protected final boolean isTypeToCastToInterface() {
+    return false;
+  }
+}
\ No newline at end of file

Added: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/weaving/WovenProxy.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/weaving/WovenProxy.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/weaving/WovenProxy.java (added)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/weaving/WovenProxy.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,43 @@
+/*
+ * 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.weaving;
+
+import java.util.concurrent.Callable;
+
+import org.apache.aries.proxy.InvocationListener;
+
+public interface WovenProxy {
+  
+  /**
+   * @return true if this instance has a non null dispatcher or listener
+   */
+  public boolean org_apache_aries_proxy_weaving_WovenProxy_isProxyInstance();
+  
+  /**
+   * @return the dispatcher, or null if no dispatcher is set
+   */
+  public Callable<Object> org_apache_aries_proxy_weaving_WovenProxy_unwrap();
+  
+  /**
+   * @return A new proxy instance that can be used for delegation. Note that this object should
+   *         not be used without setting a dispatcher!
+   */
+  public WovenProxy org_apache_aries_proxy_weaving_WovenProxy_createNewProxyInstance(
+      Callable<Object> dispatcher, InvocationListener listener);
+}
\ No newline at end of file

Added: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/weaving/packageinfo
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/weaving/packageinfo?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/weaving/packageinfo (added)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/weaving/packageinfo Thu Apr 14 16:01:42 2011
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+version 0.4

Added: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/AbstractProxyTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/AbstractProxyTest.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/AbstractProxyTest.java (added)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/AbstractProxyTest.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,340 @@
+/*
+ * 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.blueprint.proxy;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.concurrent.Callable;
+
+import org.apache.aries.proxy.InvocationListener;
+import org.apache.aries.proxy.impl.SingleInstanceDispatcher;
+import org.junit.Test;
+
+public abstract class AbstractProxyTest {
+
+  protected static class TestListener implements InvocationListener {
+  
+    boolean preInvoke = false;
+    boolean postInvoke = false;
+    boolean postInvokeExceptionalReturn = false;
+    private Method m;
+    private Object token;
+    private Throwable e;
+    
+    public Object preInvoke(Object proxy, Method m, Object[] args)
+        throws Throwable {
+      preInvoke = true;
+      token = new Object();
+      this.m = m;
+      return token;
+    }
+  
+    public void postInvoke(Object token, Object proxy, Method m,
+        Object returnValue) throws Throwable {
+      postInvoke = this.token == token && this.m == m;
+    }
+  
+    public void postInvokeExceptionalReturn(Object token, Object proxy,
+        Method m, Throwable exception) throws Throwable {
+      postInvokeExceptionalReturn = this.token == token && this.m == m;
+      e = exception;
+    }
+    
+    public void clear() {
+      preInvoke = false;
+      postInvoke = false;
+      postInvokeExceptionalReturn = false;
+      token = null;
+      m = null;
+      e = null;
+    }
+    
+    public Method getLastMethod() {
+      return m;
+    }
+    
+    public Throwable getLastThrowable() {
+      return e;
+    }
+  }
+
+  protected static final Class<?> TEST_CLASS = ProxyTestClassGeneral.class;
+  
+  protected abstract Object getProxyInstance(Class<?> proxyClass);
+  protected abstract Object getProxyInstance(Class<?> proxyClass, InvocationListener listener);
+  protected abstract Class<?> getProxyClass(Class<?> clazz);
+  protected abstract Object setDelegate(Object proxy, Callable<Object> dispatcher);
+  
+  /**
+   * This test uses the ProxySubclassGenerator to generate and load a subclass
+   * of the specified TEST_CLASS.
+   * 
+   * Once the subclass is generated we check that it wasn't null. We check
+   * that the InvocationHandler constructor doesn't return a null object
+   * either
+   * 
+   * Test method for
+   * {@link org.apache.aries.proxy.impl.ProxySubclassGenerator#generateAndLoadSubclass()}
+   * .
+   */
+  @Test
+  public void testGenerateAndLoadProxy() throws Exception
+  {
+    assertNotNull("Generated proxy subclass was null", getProxyClass(TEST_CLASS));
+    assertNotNull("Generated proxy subclass instance was null", getProxyInstance(getProxyClass(TEST_CLASS)));
+  }
+  /**
+   * Test a basic method invocation on the proxy subclass
+   */
+  @Test
+  public void testMethodInvocation() throws Exception {
+    Method m = getProxyClass(TEST_CLASS).getDeclaredMethod("testMethod", new Class[] { String.class,
+        int.class, Object.class });
+    String x = "x";
+    String returned = (String) m.invoke(getProxyInstance(getProxyClass(TEST_CLASS)), x, 1, new Object());
+    assertEquals("Object returned from invocation was not correct.", x, returned);
+  }
+  
+  /**
+   * Test different argument types on a method invocation
+   */
+  @Test
+  public void testMethodArgs() throws Exception
+  {
+    Method m = getProxyClass(TEST_CLASS).getDeclaredMethod("testArgs", new Class[] { double.class,
+        short.class, long.class, char.class, byte.class, boolean.class });
+    Character xc = Character.valueOf('x');
+    String x = xc.toString();
+    String returned = (String) m.invoke(getProxyInstance(getProxyClass(TEST_CLASS)), Double.MAX_VALUE, Short.MIN_VALUE, Long.MAX_VALUE, xc
+        .charValue(), Byte.MIN_VALUE, false);
+    assertEquals("Object returned from invocation was not correct.", x, returned);
+  }
+  
+  /**
+   * Test a method that returns void
+   */
+  @Test
+  public void testReturnVoid() throws Exception
+  {
+    Method m = getProxyClass(TEST_CLASS).getDeclaredMethod("testReturnVoid", new Class[] {});
+    //for these weaving tests we are loading the woven test classes on a different classloader
+    //to this class so we need to set the method accessible
+    m.setAccessible(true);
+    m.invoke(getProxyInstance(getProxyClass(TEST_CLASS)));
+  }
+
+  /**
+   * Test a method that returns an int
+   */
+  @Test
+  public void testReturnInt() throws Exception
+  {
+    Method m = getProxyClass(TEST_CLASS).getDeclaredMethod("testReturnInt", new Class[] {});
+    //for these weaving tests we are loading the woven test classes on a different classloader
+    //to this class so we need to set the method accessible
+    m.setAccessible(true);
+    Integer returned = (Integer) m.invoke(getProxyInstance(getProxyClass(TEST_CLASS)));
+    assertEquals("Expected object was not returned from invocation", Integer.valueOf(17), returned);
+  }
+
+  /**
+   * Test a method that returns an Integer
+   */
+  @Test
+  public void testReturnInteger() throws Exception
+  {
+    Method m = getProxyClass(TEST_CLASS).getDeclaredMethod("testReturnInteger", new Class[] {});
+    Integer returned = (Integer) m.invoke(getProxyInstance(getProxyClass(TEST_CLASS)));
+    assertEquals("Expected object was not returned from invocation", Integer.valueOf(1), returned);
+  }
+
+  /**
+   * Test a public method declared higher up the superclass hierarchy
+   */
+  @Test
+  public void testPublicHierarchyMethod() throws Exception
+  {
+    Method m = null;
+    try {
+      m = getProxyClass(TEST_CLASS).getDeclaredMethod("bMethod", new Class[] {});
+    } catch (NoSuchMethodException nsme) {
+      m = getProxyClass(TEST_CLASS).getSuperclass().getDeclaredMethod("bMethod", new Class[] {});
+    }
+    m.invoke(getProxyInstance(getProxyClass(TEST_CLASS)));
+  }
+
+  /**
+   * Test a protected method declared higher up the superclass hierarchy
+   */
+  @Test
+  public void testProtectedHierarchyMethod() throws Exception
+  {
+    Method m = null;
+    try {
+      m = getProxyClass(TEST_CLASS).getDeclaredMethod("bProMethod", new Class[] {});
+    } catch (NoSuchMethodException nsme) {
+      m = getProxyClass(TEST_CLASS).getSuperclass().getDeclaredMethod("bProMethod", new Class[] {});
+    }
+    //for these weaving tests we are loading the woven test classes on a different classloader
+    //to this class so we need to set the method accessible
+    m.setAccessible(true);
+    m.invoke(getProxyInstance(getProxyClass(TEST_CLASS)));
+  }
+  
+  /**
+   * Test a default method declared higher up the superclass hierarchy
+   */
+  @Test
+  public void testDefaultHierarchyMethod() throws Exception
+  {
+    Method m = null;
+    try {
+      m = getProxyClass(TEST_CLASS).getDeclaredMethod("bDefMethod", new Class[] {});
+    } catch (NoSuchMethodException nsme) {
+      m = getProxyClass(TEST_CLASS).getSuperclass().getDeclaredMethod("bDefMethod", new Class[] {});
+    }
+    //for these weaving tests we are loading the woven test classes on a different classloader
+    //to this class so we need to set the method accessible
+    m.setAccessible(true);
+    m.invoke(getProxyInstance(getProxyClass(TEST_CLASS)));
+  }
+
+  /**
+   * Test a covariant override method
+   */
+  @Test
+  public void testCovariant() throws Exception
+  {
+    Class<?> proxy = getProxyClass(ProxyTestClassCovariantOverride.class);
+    
+    Method m = proxy.getDeclaredMethod("getCovariant", new Class[] {});
+    Object returned = m.invoke(getProxyInstance(proxy));
+    assertTrue("Object was of wrong type: " + returned.getClass().getSimpleName(),
+        proxy.isInstance(returned));
+  }
+
+  /**
+   * Test a method with generics
+   */
+  @Test
+  public void testGenerics() throws Exception
+  {
+    Class<?> proxy = getProxyClass(ProxyTestClassGeneric.class);
+    
+    Object o = getProxyInstance(proxy);
+    Method m = proxy.getDeclaredMethod("setSomething",
+        new Class[] { String.class });
+    m.invoke(o, "aString");
+    
+    try {
+      m = proxy.getDeclaredMethod("getSomething", new Class[] {});
+    } catch (NoSuchMethodException nsme) {
+      m = proxy.getSuperclass().getDeclaredMethod("getSomething", new Class[] {});
+    }
+    Object returned = m.invoke(o);
+    assertTrue("Object was of wrong type", String.class.isInstance(returned));
+    assertEquals("String had wrong value", "aString", returned);
+  }
+  
+  /**
+   * Test that we don't generate classes twice
+   */
+  @Test
+  public void testRetrieveClass() throws Exception
+  {
+    Class<?> retrieved = getProxyClass(TEST_CLASS);
+    assertNotNull("The new class was null", retrieved);
+    assertEquals("The same class was not returned", retrieved, getProxyClass(TEST_CLASS));
+
+  }
+  
+  @Test
+  public void testEquals() throws IllegalAccessException, InstantiationException {
+    Object p1 = getProxyInstance(getProxyClass(TEST_CLASS));
+    Object p2 = getProxyInstance(getProxyClass(TEST_CLASS));
+    
+    assertFalse("Should not be equal", p1.equals(p2));
+    
+    Object p3 = getP3();
+    
+    p1 = setDelegate(p1, new SingleInstanceDispatcher(p3));
+    p2 = setDelegate(p2, new SingleInstanceDispatcher(p3));
+    
+    assertTrue("Should be equal", p1.equals(p2));
+    
+    Object p4 = getProxyInstance(getProxyClass(TEST_CLASS));
+    Object p5 = getProxyInstance(getProxyClass(TEST_CLASS));
+    
+    p4 = setDelegate(p4, new SingleInstanceDispatcher(p1));
+    p5 = setDelegate(p5, new SingleInstanceDispatcher(p2));
+    
+    assertTrue("Should be equal", p4.equals(p5));
+  }
+  
+  protected abstract Object getP3();
+  
+  @Test
+  public void testInterception() throws Throwable {
+    
+    TestListener tl = new TestListener();
+    Object obj = getProxyInstance(getProxyClass(TEST_CLASS), tl);
+    
+    assertCalled(tl, false, false, false);
+    
+    Method m = getProxyClass(TEST_CLASS).getDeclaredMethod("testReturnInteger", new Class[] {});
+    m.invoke(obj);
+    
+    assertCalled(tl, true, true, false);
+    
+    tl.clear();
+    assertCalled(tl, false, false, false);
+    
+    m = getProxyClass(TEST_CLASS).getDeclaredMethod("testException", new Class[] {});
+    try {
+      m.invoke(obj);
+      fail("Should throw an exception");
+    } catch (InvocationTargetException re) {
+      if(!!!re.getTargetException().getClass().equals(RuntimeException.class))
+        throw re.getTargetException();
+      assertCalled(tl, true, false, true);
+    }
+    
+    tl.clear();
+    assertCalled(tl, false, false, false);
+    
+    m = getProxyClass(TEST_CLASS).getDeclaredMethod("testInternallyCaughtException", new Class[] {});
+    try {
+      m.invoke(obj);
+    } finally {
+      assertCalled(tl, true, true, false);
+    }
+  }
+  
+  protected void assertCalled(TestListener listener, boolean pre, boolean post, boolean ex) {
+    assertEquals(pre, listener.preInvoke);
+    assertEquals(post, listener.postInvoke);
+    assertEquals(ex, listener.postInvokeExceptionalReturn);
+  }
+}

Added: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/InterfaceProxyingTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/InterfaceProxyingTest.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/InterfaceProxyingTest.java (added)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/InterfaceProxyingTest.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,190 @@
+/*
+ * 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.blueprint.proxy;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.Closeable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import org.apache.aries.blueprint.proxy.AbstractProxyTest.TestListener;
+import org.apache.aries.proxy.impl.weaving.InterfaceCombiningClassAdapter;
+import org.junit.Test;
+
+public class InterfaceProxyingTest {
+
+  public final static class TestCallable implements Callable<Object> {
+    
+    private Object list = new Callable<Object>() {
+
+      @Override
+      public Object call() throws Exception {
+        return null;
+      }
+    };
+    
+    public Object call() throws Exception {
+      return list;
+    }
+    
+    public void setReturn(Object o) {
+      list = o;
+    }
+  }
+  
+  @Test
+  public void testGetProxyInstance1() throws Exception{
+    
+    Collection<Class<?>> classes = new ArrayList<Class<?>>(Arrays.asList(Closeable.class));
+    
+    Object o = InterfaceCombiningClassAdapter.getProxyInstance(classes, 
+        new Callable<Object>() {
+
+          @Override
+          public Object call() throws Exception {
+            return null;
+          }
+    }, null);
+    
+    assertTrue(o instanceof Closeable);
+  }
+  
+  @Test
+  public void testGetProxyInstance2() throws Exception{
+    
+    Collection<Class<?>> classes = new ArrayList<Class<?>>(Arrays.asList(Closeable.class,
+        Iterable.class, Map.class));
+    
+    Object o = InterfaceCombiningClassAdapter.getProxyInstance(classes, 
+        new Callable<Object>() {
+
+          @Override
+          public Object call() throws Exception {
+            return null;
+          }
+    }, null);
+    
+    assertTrue(o instanceof Closeable);
+    assertTrue(o instanceof Iterable);
+    assertTrue(o instanceof Map);
+    
+  }
+
+  /**
+   * Test a class whose super couldn't be woven
+   */
+  @Test
+  public void testDelegationAndInterception() throws Exception
+  {
+    Collection<Class<?>> classes = new ArrayList<Class<?>>(Arrays.asList(Callable.class));
+    TestListener tl = new TestListener();
+    TestCallable tc = new TestCallable();
+    
+    Callable o = (Callable) InterfaceCombiningClassAdapter.getProxyInstance(classes, tc, tl);
+    
+    assertCalled(tl, false, false, false);
+    
+    assertNull(null, o.call());
+    
+    assertCalled(tl, true, true, false);
+    
+    assertEquals(Callable.class.getMethod("call"), 
+        tl.getLastMethod());
+
+    tl.clear();
+    assertCalled(tl, false, false, false);
+    
+    tc.setReturn(new Callable<Object>() {
+
+      @Override
+      public Object call() throws Exception {
+        throw new RuntimeException();
+      }
+    });
+    try {
+      o.call();
+      fail("Should throw an exception");
+    } catch (RuntimeException re) {
+      assertCalled(tl, true, false, true);
+      assertSame(re, tl.getLastThrowable());
+    }
+    
+    tl.clear();
+    assertCalled(tl, false, false, false);
+    
+    tc.setReturn(new Callable<Object>() {
+
+      @Override
+      public Object call() throws Exception {
+        try {
+          throw new RuntimeException();
+        } catch (RuntimeException re) {
+          return new Object();
+        }
+      }
+    });
+    
+    
+    try {
+      assertNotNull(o.call());
+    } finally {
+      assertCalled(tl, true, true, false);
+    }
+  }
+  
+  @Test
+  public void testCaching() throws Exception {
+    Collection<Class<?>> classes = new ArrayList<Class<?>>(Arrays.asList(Closeable.class));
+    
+    Object o1 = InterfaceCombiningClassAdapter.getProxyInstance(classes, 
+        new Callable<Object>() {
+
+          @Override
+          public Object call() throws Exception {
+            return null;
+          }
+    }, null);
+    
+    Object o2 = InterfaceCombiningClassAdapter.getProxyInstance(classes, 
+        new Callable<Object>() {
+
+          @Override
+          public Object call() throws Exception {
+            return null;
+          }
+    }, null);
+    
+    assertSame(o1.getClass(), o2.getClass());
+  }
+  
+  protected void assertCalled(TestListener listener, boolean pre, boolean post, boolean ex) {
+    assertEquals(pre, listener.preInvoke);
+    assertEquals(post, listener.postInvoke);
+    assertEquals(ex, listener.postInvokeExceptionalReturn);
+  }
+}

Modified: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java?rev=1092368&r1=1092367&r2=1092368&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java (original)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java Thu Apr 14 16:01:42 2011
@@ -24,20 +24,30 @@ import static org.junit.Assert.assertNot
 import static org.junit.Assert.assertTrue;
 
 import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.Callable;
 
 import org.apache.aries.proxy.FinalModifierException;
+import org.apache.aries.proxy.InvocationListener;
+import org.apache.aries.proxy.UnableToProxyException;
+import org.apache.aries.proxy.impl.AbstractProxyManager;
+import org.apache.aries.proxy.impl.AsmProxyManager;
+import org.apache.aries.proxy.impl.ProxyHandler;
+import org.apache.aries.proxy.impl.SingleInstanceDispatcher;
 import org.apache.aries.proxy.impl.gen.ProxySubclassGenerator;
 import org.apache.aries.proxy.impl.gen.ProxySubclassMethodHashSet;
 import org.junit.Before;
 import org.junit.Test;
 
-public class ProxySubclassGeneratorTest
+/**
+ * This class uses the {@link ProxySubclassGenerator} to test
+ */
+public class ProxySubclassGeneratorTest extends AbstractProxyTest
 {
-  private static final Class<?> TEST_CLASS = ProxyTestClassGeneral.class;
   private static final Class<?> FINAL_METHOD_CLASS = ProxyTestClassFinalMethod.class;
   private static final Class<?> FINAL_CLASS = ProxyTestClassFinal.class;
   private static final Class<?> GENERIC_CLASS = ProxyTestClassGeneric.class;
@@ -45,8 +55,8 @@ public class ProxySubclassGeneratorTest
   private static ProxySubclassMethodHashSet<String> expectedMethods = new ProxySubclassMethodHashSet<String>(
       12);
   private InvocationHandler ih = null;
-  private Class<?> generatedProxySubclass = null;
-  private Object o = null;
+  Class<?> generatedProxySubclass = null;
+  Object o = null;
 
   /**
    * @throws java.lang.Exception
@@ -57,27 +67,9 @@ public class ProxySubclassGeneratorTest
     ih = new FakeInvocationHandler();
     ((FakeInvocationHandler)ih).setDelegate(TEST_CLASS.newInstance());
     generatedProxySubclass = getGeneratedSubclass();
-    o = getSubclassInstance(generatedProxySubclass);
+    o = getProxyInstance(generatedProxySubclass);
   }
 
-  /**
-   * This test uses the ProxySubclassGenerator to generate and load a subclass
-   * of the specified TEST_CLASS.
-   * 
-   * Once the subclass is generated we check that it wasn't null. We check
-   * that the InvocationHandler constructor doesn't return a null object
-   * either
-   * 
-   * Test method for
-   * {@link org.apache.aries.proxy.impl.ProxySubclassGenerator#generateAndLoadSubclass()}
-   * .
-   */
-  @Test
-  public void testGenerateAndLoadSubclass() throws Exception
-  {
-    assertNotNull("Generated proxy subclass was null", generatedProxySubclass);
-    assertNotNull("Generated proxy subclass instance was null", o);
-  }
 
   /**
    * Test that the methods found declared on the generated proxy subclass are
@@ -143,129 +135,6 @@ public class ProxySubclassGeneratorTest
   }
 
   /**
-   * Test a basic method invocation on the proxy subclass
-   */
-  @Test
-  public void testMethodInvocation() throws Exception
-  {
-    Method m = generatedProxySubclass.getDeclaredMethod("testMethod", new Class[] { String.class,
-        int.class, Object.class });
-    String x = "x";
-    String returned = (String) m.invoke(o, x, 1, new Object());
-    assertEquals("Object returned from invocation was not correct.", x, returned);
-  }
-
-  /**
-   * Test different argument types on a method invocation
-   */
-  @Test
-  public void testMethodArgs() throws Exception
-  {
-    Method m = generatedProxySubclass.getDeclaredMethod("testArgs", new Class[] { double.class,
-        short.class, long.class, char.class, byte.class, boolean.class });
-    Character xc = Character.valueOf('x');
-    String x = xc.toString();
-    String returned = (String) m.invoke(o, Double.MAX_VALUE, Short.MIN_VALUE, Long.MAX_VALUE, xc
-        .charValue(), Byte.MIN_VALUE, false);
-    assertEquals("Object returned from invocation was not correct.", x, returned);
-  }
-
-  /**
-   * Test a method that returns void
-   */
-  @Test
-  public void testReturnVoid() throws Exception
-  {
-    Method m = generatedProxySubclass.getDeclaredMethod("testReturnVoid", new Class[] {});
-    m.invoke(o);
-  }
-
-  /**
-   * Test a method that returns an int
-   */
-  @Test
-  public void testReturnInt() throws Exception
-  {
-    Method m = generatedProxySubclass.getDeclaredMethod("testReturnInt", new Class[] {});
-    Integer returned = (Integer) m.invoke(o);
-    assertEquals("Expected object was not returned from invocation", Integer.valueOf(17), returned);
-  }
-
-  /**
-   * Test a method that returns an Integer
-   */
-  @Test
-  public void testReturnInteger() throws Exception
-  {
-    Method m = generatedProxySubclass.getDeclaredMethod("testReturnInteger", new Class[] {});
-    Integer returned = (Integer) m.invoke(o);
-    assertEquals("Expected object was not returned from invocation", Integer.valueOf(1), returned);
-  }
-
-  /**
-   * Test a public method declared higher up the superclass hierarchy
-   */
-  @Test
-  public void testPublicHierarchyMethod() throws Exception
-  {
-    Method m = generatedProxySubclass.getDeclaredMethod("bMethod", new Class[] {});
-    m.invoke(o);
-  }
-
-  /**
-   * Test a protected method declared higher up the superclass hierarchy
-   */
-  @Test
-  public void testProtectedHierarchyMethod() throws Exception
-  {
-    Method m = generatedProxySubclass.getDeclaredMethod("bProMethod", new Class[] {});
-    m.invoke(o);
-  }
-
-  /**
-   * Test a default method declared higher up the superclass hierarchy
-   */
-  @Test
-  public void testDefaultHierarchyMethod() throws Exception
-  {
-    Method m = generatedProxySubclass.getDeclaredMethod("bDefMethod", new Class[] {});
-    m.invoke(o);
-  }
-
-  /**
-   * Test a covariant override method
-   */
-  @Test
-  public void testCovariant() throws Exception
-  {
-    ((FakeInvocationHandler)ih).setDelegate(COVARIANT_CLASS.newInstance());
-    o = ProxySubclassGenerator.newProxySubclassInstance(COVARIANT_CLASS, ih);
-    generatedProxySubclass = o.getClass();
-    Method m = generatedProxySubclass.getDeclaredMethod("getCovariant", new Class[] {});
-    Object returned = m.invoke(o);
-    assertTrue("Object was of wrong type: " + returned.getClass().getSimpleName(), COVARIANT_CLASS
-        .isInstance(returned));
-  }
-
-  /**
-   * Test a method with generics
-   */
-  @Test
-  public void testGenerics() throws Exception
-  {
-    ((FakeInvocationHandler)ih).setDelegate(GENERIC_CLASS.newInstance());
-    o = ProxySubclassGenerator.newProxySubclassInstance(GENERIC_CLASS, ih);
-    generatedProxySubclass = o.getClass();
-    Method m = generatedProxySubclass.getDeclaredMethod("setSomething",
-        new Class[] { String.class });
-    m.invoke(o, "aString");
-    m = generatedProxySubclass.getDeclaredMethod("getSomething", new Class[] {});
-    Object returned = m.invoke(o);
-    assertTrue("Object was of wrong type", String.class.isInstance(returned));
-    assertEquals("String had wrong value", "aString", returned);
-  }
-
-  /**
    * Test a method marked final
    */
   @Test
@@ -292,18 +161,6 @@ public class ProxySubclassGeneratorTest
   }
 
   /**
-   * Test that we don't generate classes twice
-   */
-  @Test
-  public void testRetrieveClass() throws Exception
-  {
-    Class<?> retrieved = ProxySubclassGenerator.getProxySubclass(TEST_CLASS);
-    assertNotNull("The new class was null", retrieved);
-    assertEquals("The same class was not returned", generatedProxySubclass, retrieved);
-
-  }
-
-  /**
    * Test a private constructor
    */
   @Test
@@ -355,14 +212,34 @@ public class ProxySubclassGeneratorTest
 //  }
   
 
-  private Class<?> getGeneratedSubclass() throws Exception
+  /**
+   * Test a covariant override method
+   */
+  @Test
+  public void testCovariant() throws Exception
   {
-    return ProxySubclassGenerator.getProxySubclass(TEST_CLASS);
+    ((FakeInvocationHandler)ih).setDelegate(COVARIANT_CLASS.newInstance());
+    o = ProxySubclassGenerator.newProxySubclassInstance(COVARIANT_CLASS, ih);
+    generatedProxySubclass = o.getClass();
+    Method m = generatedProxySubclass.getDeclaredMethod("getCovariant", new Class[] {});
+    Object returned = m.invoke(o);
+    assertTrue("Object was of wrong type: " + returned.getClass().getSimpleName(), COVARIANT_CLASS
+        .isInstance(returned));
   }
-
-  private Object getSubclassInstance(Class<?> clazz) throws Exception
+  
+  /**
+   * Test a covariant override method
+   */
+  @Test
+  public void testGenerics() throws Exception
+  {
+    ((FakeInvocationHandler)ih).setDelegate(GENERIC_CLASS.newInstance());
+    super.testGenerics();
+  }
+  
+  private Class<?> getGeneratedSubclass() throws Exception
   {
-    return clazz.getConstructor(InvocationHandler.class).newInstance(ih);
+    return getProxyClass(TEST_CLASS);
   }
 
   private class FakeInvocationHandler implements InvocationHandler
@@ -376,8 +253,14 @@ public class ProxySubclassGeneratorTest
      */
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
     {
-      Object result = method.invoke(delegate, args);
+      try {
+      Object result = (delegate instanceof Callable) ? 
+          method.invoke(((Callable)delegate).call(), args) : 
+          method.invoke(delegate, args) ;
       return result;
+      } catch (InvocationTargetException ite) {
+        throw ite.getTargetException();
+      }
     }
 
     void setDelegate(Object delegate){
@@ -385,4 +268,47 @@ public class ProxySubclassGeneratorTest
     }
     
   }
+
+  @Override
+  protected Object getProxyInstance(Class<?> proxyClass) {
+    return getProxyInstance(proxyClass, ih);
+  }
+  
+  private Object getProxyInstance(Class<?> proxyClass, InvocationHandler ih) {
+    try {
+      return proxyClass.getConstructor(InvocationHandler.class).newInstance(ih);
+    } catch (Exception e) {
+      return null;
+    }
+  }
+
+  @Override
+  protected Class<?> getProxyClass(Class<?> clazz) {
+    try {
+      return ProxySubclassGenerator.getProxySubclass(clazz);
+    } catch (UnableToProxyException e) {
+      return null;
+    }
+  }
+
+
+  @Override
+  protected Object setDelegate(Object proxy, Callable<Object> dispatcher) {
+    AbstractProxyManager apm = new AsmProxyManager();
+    return getProxyInstance(proxy.getClass(), new ProxyHandler(apm, dispatcher, null));  
+  }
+
+
+  @Override
+  protected Object getProxyInstance(Class<?> proxyClass,
+      InvocationListener listener) {
+    AbstractProxyManager apm = new AsmProxyManager();
+    return getProxyInstance(proxyClass, new ProxyHandler(apm, new SingleInstanceDispatcher(getProxyInstance(proxyClass)), listener));  
+  }
+
+
+  @Override
+  protected Object getP3() {
+    return new ProxyTestClassGeneral();
+  }
 }

Modified: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassGeneral.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassGeneral.java?rev=1092368&r1=1092367&r2=1092368&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassGeneral.java (original)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassGeneral.java Thu Apr 14 16:01:42 2011
@@ -51,4 +51,23 @@ public class ProxyTestClassGeneral exten
 
   }
 
+  public boolean equals(Object o) {
+    return o == this;
+  }
+  
+  public void testException() {
+    throw new RuntimeException();
+  }
+  
+  public void testInternallyCaughtException() {
+    try {
+      try {
+        throw new RuntimeException();
+      } catch (RuntimeException re) {
+        // no op
+      }
+    } catch (Exception e) {
+      
+    }
+  }
 }

Modified: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassSuper.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassSuper.java?rev=1092368&r1=1092367&r2=1092368&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassSuper.java (original)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassSuper.java Thu Apr 14 16:01:42 2011
@@ -20,7 +20,10 @@ package org.apache.aries.blueprint.proxy
 
 public class ProxyTestClassSuper
 {
-
+  static {
+    System.out.println("The time is: " + System.currentTimeMillis());
+  }
+  
   public void bMethod()
   {
     aPrivateMethod();
@@ -40,5 +43,15 @@ public class ProxyTestClassSuper
   {
 
   }
+  
+  public Object getTargetObject() {
+    return null;
+  }
+  
+  private void doTarget() {
+    Object o = getTargetObject();
+    if(this != o)
+      ((ProxyTestClassSuper)o).doTarget();
+  }
 
 }

Added: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableChild.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableChild.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableChild.java (added)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableChild.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,27 @@
+/*
+ * 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.blueprint.proxy;
+
+public class ProxyTestClassUnweavableChild extends ProxyTestClassUnweavableSuper{
+
+  public ProxyTestClassUnweavableChild() {
+    super(1);
+  }
+
+}

Added: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableChildWithDefaultMethodWrongPackageParent.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableChildWithDefaultMethodWrongPackageParent.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableChildWithDefaultMethodWrongPackageParent.java (added)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableChildWithDefaultMethodWrongPackageParent.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,27 @@
+/*
+ * 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.blueprint.proxy;
+
+public class ProxyTestClassUnweavableChildWithDefaultMethodWrongPackageParent extends ProxyTestClassUnweavableSuperWithFinalMethod{
+
+  public ProxyTestClassUnweavableChildWithDefaultMethodWrongPackageParent() {
+    super(1);
+  }
+
+}

Added: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableChildWithFinalMethodParent.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableChildWithFinalMethodParent.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableChildWithFinalMethodParent.java (added)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableChildWithFinalMethodParent.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,27 @@
+/*
+ * 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.blueprint.proxy;
+
+public class ProxyTestClassUnweavableChildWithFinalMethodParent extends ProxyTestClassUnweavableSuperWithFinalMethod{
+
+  public ProxyTestClassUnweavableChildWithFinalMethodParent() {
+    super(1);
+  }
+
+}

Added: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableGrandParent.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableGrandParent.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableGrandParent.java (added)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableGrandParent.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,31 @@
+/*
+ * 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.blueprint.proxy;
+
+public class ProxyTestClassUnweavableGrandParent {
+
+  public ProxyTestClassUnweavableGrandParent(int i) {
+    
+  }
+  
+  public String doStuff() {
+    return "Hi!";
+  }
+  
+}

Added: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableSuper.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableSuper.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableSuper.java (added)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableSuper.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,31 @@
+/*
+ * 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.blueprint.proxy;
+
+public class ProxyTestClassUnweavableSuper extends ProxyTestClassUnweavableGrandParent {
+
+  public ProxyTestClassUnweavableSuper(int i) {
+    super(i);
+  }
+  
+  String doStuff2() {
+    return "Hello!";
+  }
+  
+}

Added: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableSuperWithFinalMethod.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableSuperWithFinalMethod.java?rev=1092368&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableSuperWithFinalMethod.java (added)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassUnweavableSuperWithFinalMethod.java Thu Apr 14 16:01:42 2011
@@ -0,0 +1,30 @@
+/*
+ * 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.blueprint.proxy;
+
+public class ProxyTestClassUnweavableSuperWithFinalMethod extends ProxyTestClassUnweavableGrandParent {
+
+  public ProxyTestClassUnweavableSuperWithFinalMethod(int i) {
+    super(i);
+  }
+  
+  public final String doStuff2() {
+    return "Hello!";
+  }
+}



Mime
View raw message