You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by zo...@apache.org on 2011/02/27 18:47:18 UTC

svn commit: r1075094 [12/17] - in /aries/tags/blueprint-0.1-incubating: ./ blueprint-api/ blueprint-api/src/ blueprint-api/src/main/ blueprint-api/src/main/appended-resources/ blueprint-api/src/main/appended-resources/META-INF/ blueprint-api/src/main/j...

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassAdapter.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassAdapter.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassAdapter.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassAdapter.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,618 @@
+/*
+ * 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 java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ProxySubclassAdapter extends ClassAdapter implements Opcodes
+{
+
+  private static final Type STRING_TYPE = Type.getType(String.class);
+  private static final Type CLASS_TYPE = Type.getType(Class.class);
+  private static final Type OBJECT_TYPE = Type.getType(Object.class);
+  private static final Type METHOD_TYPE = Type.getType(java.lang.reflect.Method.class);
+  private static final Type IH_TYPE = Type.getType(InvocationHandler.class);
+  private static final Type[] NO_ARGS = new Type[] {};
+
+  private static final String IH_FIELD = "ih";
+
+  private static Logger LOGGER = LoggerFactory.getLogger(ProxySubclassAdapter.class);
+
+  private String newClassName = null;
+  private String superclassBinaryName = null;
+  private Class<?> superclassClass = null;
+  private ClassLoader loader = null;
+  private Type newClassType = null;
+  private GeneratorAdapter staticAdapter = null;
+  private String currentlyAnalysedClassName = null;
+  private Class<?> currentlyAnalysedClass = null;
+  private String currentClassFieldName = null;
+
+  public ProxySubclassAdapter(ClassVisitor writer, String newClassName, ClassLoader loader)
+  {
+    // call the superclass constructor
+    super(writer);
+    // the writer is now the cv in the superclass of ClassAdapter
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "ProxySubclassAdapter", new Object[] { this, writer,
+        newClassName });
+
+    // set the newClassName field
+    this.newClassName = newClassName;
+    // set the newClassType descriptor
+    newClassType = Type.getType("L" + newClassName + ";");
+
+    // set the classloader
+    this.loader = loader;
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "ProxySubclassAdapter", this);
+  }
+
+  /*
+   * This method visits the class to generate the new subclass.
+   * 
+   * The following things happen here: 1. The class is renamed to a dynamic
+   * name 2. The existing class name is changed to be the superclass name so
+   * that the generated class extends the original class. 3. A private field
+   * is added to store an invocation handler 4. A constructor is added that
+   * takes an invocation handler as an argument 5. The constructor method
+   * instantiates an instance of the superclass 6. The constructor method sets
+   * the invocation handler so the invoke method can be called from all the
+   * subsequently rewritten methods 7. Add a getInvocationHandler() method 8.
+   * store a static Class object of the superclass so we can reflectively find
+   * methods later
+   */
+  public void visit(int version, int access, String name, String signature, String superName,
+      String[] interfaces)
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "visit", new Object[] { version, access, name,
+        signature, superName, interfaces });
+
+    // store the superclass binary name
+    this.superclassBinaryName = name.replaceAll("/", "\\.");
+
+    try {
+      this.superclassClass = Class.forName(superclassBinaryName, false, loader);
+    } catch (ClassNotFoundException cnfe) {
+      throw new TypeNotPresentException(superclassBinaryName, cnfe);
+    }
+
+    // move the existing class name to become the superclass
+    // modify the version of the dynamic subclass to be Java 1.6
+    int newVersion = Opcodes.V1_6;
+    // keep the same access and signature as the superclass
+    // remove all the superclass interfaces because they will be inherited
+    // from the superclass anyway
+    cv.visit(newVersion, access, newClassName, signature, name, null);
+
+    // add a private field for the invocation handler
+    // this isn't static in case we have multiple instances of the same
+    // proxy
+    cv.visitField(ACC_PRIVATE, IH_FIELD, Type.getDescriptor(InvocationHandler.class), null, null);
+
+    // create a static adapter for generating a static initialiser method in
+    // the generated subclass
+    staticAdapter = new GeneratorAdapter(ACC_STATIC,
+        new Method("<clinit>", Type.VOID_TYPE, NO_ARGS), null, null, cv);
+
+    // add a constructor method that takes an invocation handler as an
+    // argument
+    Method m = new Method("<init>", Type.VOID_TYPE, new Type[] { IH_TYPE });
+    GeneratorAdapter methodAdapter = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cv);
+    // loadthis
+    methodAdapter.loadThis();
+    // if we have java.* as a supertype call that zero args constructor
+    if (superclassBinaryName.startsWith("java.") || superclassBinaryName.startsWith("javax.")) {
+      methodAdapter.invokeConstructor(Type.getType(superclassClass), new Method("<init>",
+          Type.VOID_TYPE, NO_ARGS));
+    }
+    // otherwise invoke the java.lang.Object no args constructor
+    else {
+      methodAdapter.invokeConstructor(OBJECT_TYPE, new Method("<init>", Type.VOID_TYPE, NO_ARGS));
+    }
+    // call from the constructor to setInvocationHandler
+    Method setter = new Method("setInvocationHandler", Type.VOID_TYPE, new Type[] { IH_TYPE });
+    // load this
+    methodAdapter.loadThis();
+    // load the supplied invocation handler arg
+    methodAdapter.loadArgs();
+    // invoke the setter method
+    methodAdapter.invokeVirtual(newClassType, setter);
+    methodAdapter.returnValue();
+    methodAdapter.endMethod();
+
+    // add a method for getting the invocation handler
+    m = new Method("getInvocationHandler", IH_TYPE, NO_ARGS);
+    methodAdapter = new GeneratorAdapter(ACC_PUBLIC | ACC_FINAL, m, null, null, cv);
+    // load this to get the field
+    methodAdapter.loadThis();
+    // get the ih field and return
+    methodAdapter.getField(newClassType, IH_FIELD, IH_TYPE);
+    methodAdapter.returnValue();
+    methodAdapter.endMethod();
+
+    // add a method for setting the invocation handler
+    methodAdapter = new GeneratorAdapter(ACC_PUBLIC | ACC_FINAL, setter, null, null, cv);
+    // load this to put the field
+    methodAdapter.loadThis();
+    // load the method arguments (i.e. the invocation handler) to the stack
+    methodAdapter.loadArgs();
+    // set the ih field using the method argument
+    methodAdapter.putField(newClassType, IH_FIELD, IH_TYPE);
+    methodAdapter.returnValue();
+    methodAdapter.endMethod();
+
+    // loop through the class hierarchy to get any needed methods off the
+    // supertypes
+    // start by finding the methods declared on the class of interest (the
+    // superclass of our dynamic subclass)
+    java.lang.reflect.Method[] observedMethods = superclassClass.getDeclaredMethods();
+    // add the methods to a set of observedMethods
+    ProxySubclassMethodHashSet<String> setOfObservedMethods = new ProxySubclassMethodHashSet<String>(
+        observedMethods.length);
+    setOfObservedMethods.addMethodArray(observedMethods);
+    // get the next superclass in the hierarchy
+    Class<?> nextSuperClass = superclassClass.getSuperclass();
+    while (nextSuperClass != null) {
+      // set the fields for the current class
+      setCurrentAnalysisClassFields(nextSuperClass);
+
+      // add a static field and static initializer code to the generated
+      // subclass
+      // for each of the superclasses in the hierarchy
+      addClassStaticField(currentlyAnalysedClassName);
+
+      LOGGER.debug("Class currently being analysed: {} {}", currentlyAnalysedClassName,
+          currentlyAnalysedClass);
+
+      // now find the methods declared on the current class and add them
+      // to a set of foundMethods
+      java.lang.reflect.Method[] foundMethods = currentlyAnalysedClass.getDeclaredMethods();
+      ProxySubclassMethodHashSet<String> setOfFoundMethods = new ProxySubclassMethodHashSet<String>(
+          foundMethods.length);
+      setOfFoundMethods.addMethodArray(foundMethods);
+      // remove from the set of foundMethods any methods we saw on a
+      // subclass
+      // because we want to use the lowest level declaration of a method
+      setOfFoundMethods.removeAll(setOfObservedMethods);
+      try {
+        // read the current class and use a
+        // ProxySubclassHierarchyAdapter
+        // to process only methods on that class that are in the list
+        ClassReader cr = new ClassReader(loader.getResourceAsStream(currentlyAnalysedClass
+            .getName().replaceAll("\\.", "/")
+            + ".class"));
+        ClassVisitor hierarchyAdapter = new ProxySubclassHierarchyAdapter(this, setOfFoundMethods);
+        cr.accept(hierarchyAdapter, ClassReader.SKIP_DEBUG);
+      } catch (IOException e) {
+        throw new TypeNotPresentException(currentlyAnalysedClassName, e);
+      }
+      // now add the foundMethods to the overall list of observed methods
+      setOfObservedMethods.addAll(setOfFoundMethods);
+      // get the next class up in the hierarchy and go again
+      nextSuperClass = currentlyAnalysedClass.getSuperclass();
+    }
+
+    // we've finished looking at the superclass hierarchy
+    // set the fields for the immediate superclass of our dynamic subclass
+    setCurrentAnalysisClassFields(superclassClass);
+
+    // add the class static field
+    addClassStaticField(currentlyAnalysedClassName);
+    // we do the lowest class last because we are already visiting the class
+    // when in this adapter code
+    // now we are ready to visit all the methods on the lowest class
+    // which will happen by the ASM ClassVisitor implemented in this adapter
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "visit");
+  }
+
+  public void visitSource(String source, String debug)
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "visitSource", new Object[] { source, debug });
+
+    // set the source to null since the class is generated on the fly and
+    // not compiled
+    cv.visitSource(null, null);
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "visitSource");
+  }
+
+  public void visitEnd()
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "visitEnd");
+
+    // this method is called when we reach the end of the class
+    // so it is time to make sure the static initialiser method is closed
+    staticAdapter.returnValue();
+    staticAdapter.endMethod();
+    // now delegate to the cv
+    cv.visitEnd();
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "visitEnd");
+  }
+
+  /*
+   * This method is called on each method of the superclass (and all parent
+   * classes up to Object) Each of these methods is visited in turn and the
+   * code here generates the byte code for the InvocationHandler to call the
+   * methods on the superclass.
+   */
+  public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+      String[] exceptions)
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "visitMethod", new Object[] { access, name, desc,
+        signature, exceptions });
+
+    /*
+     * Check the method access and handle the method types we don't want to
+     * copy: final methods (issue warnings if these are not methods from
+     * java.* classes) static methods (initialiser and others) private
+     * methods constructors (for now we don't copy any constructors)
+     * abstract (we don't proxy/implement but we must copy the method or the
+     * subclass is invalid) everything else we process to proxy
+     */
+
+    LOGGER.debug("Method name: {} with descriptor: {}", name, desc);
+
+    MethodVisitor methodVisitorToReturn = null;
+
+    if (name.equals("<init>")) {
+      // we may need to do something extra with constructors later
+      // e.g. include bytecode for calling super with the same args
+      // since we currently rely on the super having a zero args
+      // constructor
+      // we need to issue an error if we don't find one
+
+      // for now we return null to ignore them
+      methodVisitorToReturn = null;
+    } else if (name.equals("<clinit>")) {
+      // don't copy static initialisers from the superclass into the new
+      // subclass
+      methodVisitorToReturn = null;
+    } else if ((access & ACC_FINAL) != 0) {
+      // since we check for final methods in the ProxySubclassGenerator we
+      // should never get here
+      methodVisitorToReturn = null;
+    } else if ((access & ACC_SYNTHETIC) != 0) {
+      // synthetic methods are generated by the compiler for covariance
+      // etc
+      // we shouldn't copy them or we will have duplicate methods
+      methodVisitorToReturn = null;
+    } else if ((access & ACC_PRIVATE) != 0) {
+      // don't copy private methods from the superclass
+      methodVisitorToReturn = null;
+    } else if ((access & ACC_STATIC) != 0) {
+      // don't copy static methods
+      methodVisitorToReturn = null;
+    } else if ((access & ACC_ABSTRACT) != 0) {
+      // if we find an abstract method we need to copy it as is to make
+      // the subclass valid
+      methodVisitorToReturn = cv.visitMethod(access, name, desc, signature, exceptions);
+    } else if (!(((access & ACC_PUBLIC) != 0) || ((access & ACC_PROTECTED) != 0) || ((access & ACC_PRIVATE) != 0))) {
+      // the default (package) modifier value is 0, so by using & with any
+      // of the other
+      // modifier values and getting a result of zero means that we have
+      // default accessibility
+
+      // check the package in which the method is declared against the
+      // package
+      // where the generated subclass will be
+      // if they are the same process the method otherwise ignore it
+      if (currentlyAnalysedClass.getPackage().equals(superclassClass.getPackage())) {
+        processMethod(access, name, desc, signature, exceptions);
+        methodVisitorToReturn = null;
+      } else {
+        methodVisitorToReturn = null;
+      }
+    } else {
+      processMethod(access, name, desc, signature, exceptions);
+      // return null because we don't want the original method code from
+      // the superclass
+      methodVisitorToReturn = null;
+    }
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "visitMethod", methodVisitorToReturn);
+
+    return methodVisitorToReturn;
+
+  }
+
+  private void processMethod(int access, String name, String desc, String signature,
+      String[] exceptions)
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "processMethod", new Object[] { access, name, desc,
+        signature, exceptions });
+
+    LOGGER.debug("Processing method: {} with descriptor {}", name, desc);
+
+    // identify the target method parameters and return type
+    Method currentTransformMethod = new Method(name, desc);
+    Type[] targetMethodParameters = currentTransformMethod.getArgumentTypes();
+    Type returnType = currentTransformMethod.getReturnType();
+
+    // we create a static field for each method we encounter with a name
+    // like method_parm1_parm2...
+    StringBuilder methodStaticFieldNameBuilder = new StringBuilder(name);
+    // for each a parameter get the name and add it to the field removing
+    // the dots first
+    for (Type t : targetMethodParameters) {
+      methodStaticFieldNameBuilder.append("_");
+      methodStaticFieldNameBuilder.append(t.getClassName().replaceAll("\\[\\]", "Array")
+          .replaceAll("\\.", ""));
+    }
+    String methodStaticFieldName = methodStaticFieldNameBuilder.toString();
+
+    // add a private static field for the method
+    cv.visitField(ACC_PRIVATE | ACC_STATIC, methodStaticFieldName, METHOD_TYPE.getDescriptor(),
+        null, null);
+
+    // visit the method using the class writer, delegated through the method
+    // visitor and generator
+    // modify the method access so that any native methods aren't
+    // described as native
+    // since they won't be native in proxy form
+    // also stop methods being marked synchronized on the proxy as they will
+    // be sync
+    // on the real object
+    int newAccess = access & (~ACC_NATIVE) & (~ACC_SYNCHRONIZED);
+    MethodVisitor mv = cv.visitMethod(newAccess, name, desc, signature, exceptions);
+    // use a GeneratorAdapter to build the invoke call directly in byte code
+    GeneratorAdapter methodAdapter = new GeneratorAdapter(mv, newAccess, name, desc);
+
+    /*
+     * Stage 1 creates the bytecode for adding the reflected method of the
+     * superclass to a static field in the subclass: private static Method
+     * methodName_parm1_parm2... = null; static{ methodName_parm1_parm2... =
+     * superClass.getDeclaredMethod(methodName,new Class[]{method args}; }
+     * 
+     * Stage 2 is to call the ih.invoke(this,methodName_parm1_parm2,args) in
+     * the new subclass methods Stage 3 is to cast the return value to the
+     * correct type
+     */
+
+    /*
+     * Stage 1 use superClass.getMethod(methodName,new Class[]{method args}
+     * from the Class object on the stack
+     */
+
+    // load the static superclass Class onto the stack
+    staticAdapter.getStatic(newClassType, currentClassFieldName, CLASS_TYPE);
+
+    // push the method name string arg onto the stack
+    staticAdapter.push(name);
+
+    // 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);
+      switch (t.getSort())
+      {
+        case Type.BOOLEAN:
+          staticAdapter.getStatic(Type.getType(java.lang.Boolean.class), "TYPE", CLASS_TYPE);
+          break;
+        case Type.BYTE:
+          staticAdapter.getStatic(Type.getType(java.lang.Byte.class), "TYPE", CLASS_TYPE);
+          break;
+        case Type.CHAR:
+          staticAdapter.getStatic(Type.getType(java.lang.Character.class), "TYPE", CLASS_TYPE);
+          break;
+        case Type.DOUBLE:
+          staticAdapter.getStatic(Type.getType(java.lang.Double.class), "TYPE", CLASS_TYPE);
+          break;
+        case Type.FLOAT:
+          staticAdapter.getStatic(Type.getType(java.lang.Float.class), "TYPE", CLASS_TYPE);
+          break;
+        case Type.INT:
+          staticAdapter.getStatic(Type.getType(java.lang.Integer.class), "TYPE", CLASS_TYPE);
+          break;
+        case Type.LONG:
+          staticAdapter.getStatic(Type.getType(java.lang.Long.class), "TYPE", CLASS_TYPE);
+          break;
+        case Type.SHORT:
+          staticAdapter.getStatic(Type.getType(java.lang.Short.class), "TYPE", CLASS_TYPE);
+          break;
+        default:
+        case Type.OBJECT:
+          staticAdapter.push(t);
+          break;
+      }
+      staticAdapter.arrayStore(CLASS_TYPE);
+      index++;
+    }
+
+    // invoke the getMethod
+    staticAdapter.invokeVirtual(CLASS_TYPE, new Method("getDeclaredMethod", METHOD_TYPE,
+        new Type[] { STRING_TYPE, Type.getType(java.lang.Class[].class) }));
+
+    // store the reflected method in the static field
+    staticAdapter.putStatic(newClassType, methodStaticFieldName, METHOD_TYPE);
+
+    /*
+     * Stage 2 call the ih.invoke(this,supermethod,parms)
+     */
+
+    // load this to get the ih field
+    methodAdapter.loadThis();
+    // load the invocation handler from the field (the location of the
+    // InvocationHandler.invoke)
+    methodAdapter.getField(newClassType, IH_FIELD, IH_TYPE);
+    // loadThis (the first arg of the InvocationHandler.invoke)
+    methodAdapter.loadThis();
+    // load the method to invoke (the second arg of the
+    // InvocationHandler.invoke)
+    methodAdapter.getStatic(newClassType, methodStaticFieldName, METHOD_TYPE);
+    // load all the method arguments onto the stack as an object array (the
+    // third arg of the InvocationHandler.invoke)
+    methodAdapter.loadArgArray();
+    // generate the invoke method
+    Method invocationHandlerInvokeMethod = new Method("invoke", OBJECT_TYPE, new Type[] {
+        OBJECT_TYPE, METHOD_TYPE, Type.getType(java.lang.Object[].class) });
+    // call the invoke method of the invocation handler
+    methodAdapter.invokeInterface(IH_TYPE, invocationHandlerInvokeMethod);
+
+    /*
+     * Stage 3 the returned object is now on the top of the stack We need to
+     * check the type and cast as necessary
+     */
+    switch (returnType.getSort())
+    {
+      case Type.BOOLEAN:
+        methodAdapter.cast(OBJECT_TYPE, Type.getType(Boolean.class));
+        methodAdapter.unbox(Type.BOOLEAN_TYPE);
+        break;
+      case Type.BYTE:
+        methodAdapter.cast(OBJECT_TYPE, Type.getType(Byte.class));
+        methodAdapter.unbox(Type.BYTE_TYPE);
+        break;
+      case Type.CHAR:
+        methodAdapter.cast(OBJECT_TYPE, Type.getType(Character.class));
+        methodAdapter.unbox(Type.CHAR_TYPE);
+        break;
+      case Type.DOUBLE:
+        methodAdapter.cast(OBJECT_TYPE, Type.getType(Double.class));
+        methodAdapter.unbox(Type.DOUBLE_TYPE);
+        break;
+      case Type.FLOAT:
+        methodAdapter.cast(OBJECT_TYPE, Type.getType(Float.class));
+        methodAdapter.unbox(Type.FLOAT_TYPE);
+        break;
+      case Type.INT:
+        methodAdapter.cast(OBJECT_TYPE, Type.getType(Integer.class));
+        methodAdapter.unbox(Type.INT_TYPE);
+        break;
+      case Type.LONG:
+        methodAdapter.cast(OBJECT_TYPE, Type.getType(Long.class));
+        methodAdapter.unbox(Type.LONG_TYPE);
+        break;
+      case Type.SHORT:
+        methodAdapter.cast(OBJECT_TYPE, Type.getType(Short.class));
+        methodAdapter.unbox(Type.SHORT_TYPE);
+        break;
+      case Type.VOID:
+        methodAdapter.cast(OBJECT_TYPE, Type.getType(Void.class));
+        methodAdapter.unbox(Type.VOID_TYPE);
+        break;
+      default:
+      case Type.OBJECT:
+        // in this case check the cast and cast the object to the return
+        // type
+        methodAdapter.checkCast(returnType);
+        methodAdapter.cast(OBJECT_TYPE, returnType);
+        break;
+    }
+    // return the (appropriately cast) result of the invocation from the
+    // stack
+    methodAdapter.returnValue();
+    // end the method
+    methodAdapter.endMethod();
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "processMethod");
+  }
+
+  private void addClassStaticField(String classBinaryName)
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "addClassStaticField",
+        new Object[] { classBinaryName });
+
+    currentClassFieldName = classBinaryName.replaceAll("\\.", "_");
+
+    /*
+     * use Class.forName on the superclass so we can reflectively find
+     * methods later
+     * 
+     * produces bytecode for retrieving the superclass and storing in a
+     * private static field: private static Class superClass = null; static{
+     * superClass = Class.forName(superclass); }
+     */
+
+    // add a private static field for the superclass Class
+    cv.visitField(ACC_PRIVATE | ACC_STATIC, currentClassFieldName, CLASS_TYPE.getDescriptor(),
+        null, null);
+
+    // push the String arg for the Class.forName onto the stack
+    staticAdapter.push(classBinaryName);
+
+    // invoke the Class forName putting the Class on the stack
+    staticAdapter.invokeStatic(CLASS_TYPE, new Method("forName", CLASS_TYPE,
+        new Type[] { STRING_TYPE }));
+
+    // put the Class in the static field
+    staticAdapter.putStatic(newClassType, currentClassFieldName, CLASS_TYPE);
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "addClassStaticField");
+  }
+
+  private void setCurrentAnalysisClassFields(Class<?> aClass)
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "setCurrentAnalysisClassFields",
+        new Object[] { aClass });
+
+    currentlyAnalysedClassName = aClass.getName();
+    currentlyAnalysedClass = aClass;
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "setCurrentAnalysisClassFields");
+  }
+
+  // we don't want to copy fields from the class into the proxy
+  public FieldVisitor visitField(int access, String name, String desc, String signature,
+      Object value)
+  {
+    return null;
+  }
+
+  // for now we don't do any processing in these methods
+  public AnnotationVisitor visitAnnotation(String desc, boolean visible)
+  {
+    return null;
+  }
+
+  public void visitAttribute(Attribute attr)
+  {
+    // no-op
+  }
+
+  public void visitInnerClass(String name, String outerName, String innerName, int access)
+  {
+    // no-op
+  }
+
+  public void visitOuterClass(String owner, String name, String desc)
+  {
+    // no-op
+  }
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassGenerator.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassGenerator.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassGenerator.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassGenerator.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,359 @@
+/*
+ * 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 java.lang.reflect.Modifier.isFinal;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.ProtectionDomain;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ProxySubclassGenerator
+{
+
+  private final static Logger LOGGER = LoggerFactory.getLogger(ProxySubclassGenerator.class);
+
+  // This map holds references to the names of classes created by this Class
+  // It is a weak map (so when a ClassLoader is garbage collected we remove
+  // the map of
+  // Class names to sub-Class names)
+  private static final Map<ClassLoader, ConcurrentMap<String, String>> proxyClassesByClassLoader;
+
+  static {
+    // Ensure that this is a synchronized map as we may use it from multiple
+    // threads concurrently
+    //
+    proxyClassesByClassLoader = Collections
+        .synchronizedMap(new WeakHashMap<ClassLoader, ConcurrentMap<String, String>>());
+  }
+
+  private static final char FINAL_MODIFIER = '!';
+  private static final char UNABLE_TO_PROXY = '#';
+
+  public static Class<?> getProxySubclass(Class<?> aClass) throws UnableToProxyException
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "getProxySubclass", new Object[] { aClass });
+
+    ClassLoader loader = aClass.getClassLoader();
+    // in the special case where the loader is null we use the thread
+    // ContextClassLoader
+    // this is for subclassing java.* or javax.* packages
+    if (loader == null) loader = Thread.currentThread().getContextClassLoader();
+
+    ConcurrentMap<String, String> proxyMap;
+    synchronized (loader) {
+      proxyMap = proxyClassesByClassLoader.get(loader);
+      if (proxyMap == null) {
+        proxyMap = new ConcurrentHashMap<String, String>();
+        proxyClassesByClassLoader.put(loader, proxyMap);
+      }
+    }
+
+    // check the map to see if we have already generated a subclass for this
+    // class
+    // if we have return the mapped class object
+    // if we haven't generate the subclass and return it
+    Class<?> classToReturn = null;
+    synchronized (aClass) {
+      String key = aClass.getName();
+      String className = proxyMap.get(key);
+      if (className != null) {
+
+        LOGGER.debug("Found proxy subclass with key {} and name {}.", key, className);
+
+        if (className.charAt(0) == FINAL_MODIFIER) {
+          String[] exceptionParts = className.substring(1).split(":");
+          if (exceptionParts.length == 1) {
+            throw new FinalModifierException(aClass);
+          } else {
+            throw new FinalModifierException(aClass, exceptionParts[1]);
+          }
+        } else if (className.charAt(0) == UNABLE_TO_PROXY) {
+          throw new UnableToProxyException(aClass);
+        }
+
+        try {
+          classToReturn = loader.loadClass(className);
+        } catch (ClassNotFoundException cnfe) {
+          LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, cnfe);
+          throw new UnableToLoadProxyException(className, cnfe);
+        }
+      } else {
+
+        LOGGER.debug("Need to generate subclass. Using key {}.", key);
+        try {
+          scanForFinalModifiers(aClass);
+
+          classToReturn = generateAndLoadSubclass(aClass, loader);
+
+          if (classToReturn != null) {
+            proxyMap.put(key, classToReturn.getName());
+          } else {
+            proxyMap.put(key, UNABLE_TO_PROXY + aClass.getName());
+            throw new UnableToProxyException(aClass);
+          }
+        } catch (FinalModifierException e) {
+          if (e.isFinalClass()) {
+            proxyMap.put(key, FINAL_MODIFIER + e.getClassName());
+            throw e;
+          } else {
+            proxyMap.put(key, FINAL_MODIFIER + e.getClassName() + ':' + e.getFinalMethods());
+            throw e;
+          }
+        }
+
+      }
+    }
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "getProxySubclass", classToReturn);
+
+    return classToReturn;
+  }
+
+  public static Object newProxySubclassInstance(Class<?> classToProxy, InvocationHandler ih)
+      throws UnableToProxyException
+  {
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "newProxySubclassInstance", new Object[] {
+        classToProxy, ih });
+
+    Object proxySubclassInstance = null;
+    try {
+      Class<?> generatedProxySubclass = getProxySubclass(classToProxy);
+      LOGGER.debug("Getting the proxy subclass constructor");
+      Constructor<?> subclassConstructor = generatedProxySubclass
+          .getConstructor(new Class[] { InvocationHandler.class });
+      LOGGER.debug("Invoking the proxy subclass constructor");
+      proxySubclassInstance = subclassConstructor.newInstance(ih);
+      LOGGER.debug("Invoked proxy subclass constructor");
+    } catch (NoSuchMethodException nsme) {
+      LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, nsme);
+      throw new ProxyClassInstantiationException(classToProxy, nsme);
+    } catch (InvocationTargetException ite) {
+      LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, ite);
+      throw new ProxyClassInstantiationException(classToProxy, ite);
+    } catch (InstantiationException ie) {
+      LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, ie);
+      throw new ProxyClassInstantiationException(classToProxy, ie);
+    } catch (IllegalAccessException iae) {
+      LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, iae);
+      throw new ProxyClassInstantiationException(classToProxy, iae);
+    }
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "newProxySubclassInstance", proxySubclassInstance);
+
+    return proxySubclassInstance;
+  }
+
+  private static Class<?> generateAndLoadSubclass(Class<?> aClass, ClassLoader loader)
+      throws UnableToProxyException
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "generateAndLoadSubclass", new Object[] { aClass,
+        loader });
+
+    // set the newClassName
+    String newClassName = "$" + aClass.getSimpleName() + aClass.hashCode();
+    String packageName = aClass.getPackage().getName();
+    if (packageName.startsWith("java.") || packageName.startsWith("javax.")) {
+      packageName = "org.apache.aries.blueprint.proxy." + packageName;
+    }
+    String fullNewClassName = (packageName + "." + newClassName).replaceAll("\\.", "/");
+
+    LOGGER.debug("New class name: {}", newClassName);
+    LOGGER.debug("Full new class name: {}", fullNewClassName);
+
+    Class<?> clazz = null;
+    try {
+      ClassReader cReader = new ClassReader(loader.getResourceAsStream(aClass.getName().replaceAll(
+          "\\.", "/")
+          + ".class"));
+      ClassWriter cWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+      ClassVisitor dynamicSubclassAdapter = new ProxySubclassAdapter(cWriter, fullNewClassName,
+          loader);
+      byte[] byteClassData = processClass(cReader, cWriter, dynamicSubclassAdapter);
+      clazz = loadClassFromBytes(loader, getBinaryName(fullNewClassName), byteClassData, aClass
+          .getName());
+    } catch (IOException ioe) {
+      LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, ioe);
+      throw new ProxyClassBytecodeGenerationException(aClass.getName(), ioe);
+    } catch (TypeNotPresentException tnpe) {
+      LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, tnpe);
+      throw new ProxyClassBytecodeGenerationException(tnpe.typeName(), tnpe.getCause());
+    }
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "generateAndLoadSubclass", clazz);
+
+    return clazz;
+  }
+
+  private static byte[] processClass(ClassReader cReader, ClassWriter cWriter, ClassVisitor cVisitor)
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "processClass", new Object[] { cReader, cWriter,
+        cVisitor });
+
+    cReader.accept(cVisitor, ClassReader.SKIP_DEBUG);
+    byte[] byteClassData = cWriter.toByteArray();
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "processClass", byteClassData);
+
+    return byteClassData;
+  }
+
+  private static String getBinaryName(String name)
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "getBinaryName", name);
+
+    String binaryName = name.replaceAll("/", "\\.");
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "getBinaryName", binaryName);
+
+    return binaryName;
+  }
+
+  private static Class<?> loadClassFromBytes(ClassLoader loader, String name, byte[] classData,
+      String classToProxyName) throws UnableToProxyException
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "loadClassFromBytes", new Object[] { loader, name,
+        classData });
+
+    Class<?> clazz = null;
+    try {
+      Method defineClassMethod = Class.forName("java.lang.ClassLoader").getDeclaredMethod(
+          "defineClass", String.class, byte[].class, int.class, int.class, ProtectionDomain.class);
+      defineClassMethod.setAccessible(true);
+      // define the class in the same classloader where aClass is loaded,
+      // but use the protection domain of our code
+      clazz = (Class<?>) defineClassMethod.invoke(loader, name, classData, 0, classData.length,
+          ProxySubclassGenerator.class.getProtectionDomain());
+      defineClassMethod.setAccessible(false);
+    } catch (ClassNotFoundException cnfe) {
+      LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, cnfe);
+      throw new ProxyClassDefinitionException(classToProxyName, cnfe);
+    } catch (NoSuchMethodException nsme) {
+      LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, nsme);
+      throw new ProxyClassDefinitionException(classToProxyName, nsme);
+    } catch (InvocationTargetException ite) {
+      LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, ite);
+      throw new ProxyClassDefinitionException(classToProxyName, ite);
+    } catch (IllegalAccessException iae) {
+      LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, iae);
+      throw new ProxyClassDefinitionException(classToProxyName, iae);
+    }
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "loadClassFromBytes", clazz);
+
+    return clazz;
+  }
+
+  public static boolean isProxySubclass(Class<?> aClass)
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "isProxySubclass", new Object[] { aClass });
+
+    // We will always have a proxy map for the class loader of any proxy
+    // class, so if
+    // this is null we know to return false
+    Map<String, String> proxies = proxyClassesByClassLoader.get(aClass.getClassLoader());
+
+    boolean isProxySubclass = (proxies != null && proxies.containsValue(aClass.getName()));
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "isProxySubclass", isProxySubclass);
+
+    return isProxySubclass;
+  }
+
+  private static void scanForFinalModifiers(Class<?> clazz) throws FinalModifierException
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "scanForFinalModifiers", new Object[] { clazz });
+
+    if (isFinal(clazz.getModifiers())) {
+      throw new FinalModifierException(clazz);
+    }
+
+    List<String> finalMethods = new ArrayList<String>();
+
+    // we don't want to check for final methods on java.* or javax.* Class
+    // also, clazz can never be null here (we will always hit
+    // java.lang.Object first)
+    while (!clazz.getName().startsWith("java.") && !clazz.getName().startsWith("javax.")) {
+      for (Method m : clazz.getDeclaredMethods()) {
+        if (isFinal(m.getModifiers())) {
+          finalMethods.add(m.toGenericString());
+        }
+      }
+      clazz = clazz.getSuperclass();
+    }
+
+    if (!finalMethods.isEmpty()) {
+
+      String methodList = finalMethods.toString();
+      methodList = methodList.substring(1, methodList.length() - 1);
+      throw new FinalModifierException(clazz, methodList);
+    }
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "scanForFinalModifiers");
+
+  }
+
+  public static InvocationHandler getInvocationHandler(Object o)
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "getInvoationHandler", new Object[] { o });
+
+    InvocationHandler ih = null;
+    if (isProxySubclass(o.getClass())) {
+      // we have to catch exceptions here, but we just log them
+      // the reason for this is that it should be impossible to get these
+      // exceptions
+      // since the Object we are dealing with is a class we generated on
+      // the fly
+      try {
+        ih = (InvocationHandler) o.getClass().getDeclaredMethod("getInvocationHandler",
+            new Class[] {}).invoke(o, new Object[] {});
+      } catch (IllegalArgumentException e) {
+        LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, e);
+      } catch (SecurityException e) {
+        LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, e);
+      } catch (IllegalAccessException e) {
+        LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, e);
+      } catch (InvocationTargetException e) {
+        LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, e);
+      } catch (NoSuchMethodException e) {
+        LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, e);
+      }
+    }
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "getInvoationHandler", ih);
+    return ih;
+  }
+
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassHierarchyAdapter.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassHierarchyAdapter.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassHierarchyAdapter.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassHierarchyAdapter.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,124 @@
+/*
+ * 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 java.util.Collection;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/*
+ * Although we implement ClassVisitor we are only interested in the methods of
+ * the superclasses in the hierarchy.  For this reason although visitMethod is 
+ * implemented the other methods of ClassVisitor are currently no-op.
+ *
+ *
+ */
+public class ProxySubclassHierarchyAdapter implements ClassVisitor, Opcodes
+{
+
+  private ProxySubclassAdapter adapter = null;
+  private Collection<String> methodsToImplement = null;
+
+  private static Logger LOGGER = LoggerFactory.getLogger(ProxySubclassHierarchyAdapter.class);
+
+  ProxySubclassHierarchyAdapter(ProxySubclassAdapter adapter, Collection<String> methodsToImplement)
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "ProxySubclassHeirarchyAdapter", new Object[] {
+        this, adapter, methodsToImplement });
+
+    this.methodsToImplement = methodsToImplement;
+    this.adapter = adapter;
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "ProxySubclassHeirarchyAdapter", this);
+  }
+
+  public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+      String[] exceptions)
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "visitMethod", new Object[] { access, name, desc,
+        signature, exceptions });
+
+    // if the method we find in the superclass is one that is available on
+    // the class
+    // we are dynamically subclassing then we need to implement an
+    // invocation for it
+    String argDesc = ProxySubclassMethodHashSet.typeArrayToStringArgDescriptor(Type
+        .getArgumentTypes(desc));
+    if (methodsToImplement.contains(name + argDesc)) {
+      // create the method in bytecode
+      adapter.visitMethod(access, name, desc, signature, exceptions);
+    }
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "visitMethod");
+
+    // always return null because we don't want to copy any method code
+    return null;
+  }
+
+  public void visit(int arg0, int arg1, String arg2, String arg3, String arg4, String[] arg5)
+  {
+    // no-op
+  }
+
+  public AnnotationVisitor visitAnnotation(String arg0, boolean arg1)
+  {
+    // don't process any annotations at this stage
+    return null;
+  }
+
+  public void visitAttribute(Attribute arg0)
+  {
+    // no-op
+  }
+
+  public void visitEnd()
+  {
+    // no-op
+  }
+
+  public FieldVisitor visitField(int arg0, String arg1, String arg2, String arg3, Object arg4)
+  {
+    // don't process fields
+    return null;
+  }
+
+  public void visitInnerClass(String arg0, String arg1, String arg2, int arg3)
+  {
+    // no-op
+  }
+
+  public void visitOuterClass(String arg0, String arg1, String arg2)
+  {
+    // no-op
+  }
+
+  public void visitSource(String arg0, String arg1)
+  {
+    // no-op
+  }
+
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassMethodHashSet.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassMethodHashSet.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassMethodHashSet.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassMethodHashSet.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,69 @@
+/*
+ * 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 java.util.HashSet;
+
+import org.objectweb.asm.Type;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ProxySubclassMethodHashSet<E> extends HashSet<String>
+{
+  private static final long serialVersionUID = 7674408912532811084L;
+
+  private static Logger LOGGER = LoggerFactory.getLogger(ProxySubclassMethodHashSet.class);
+
+  public ProxySubclassMethodHashSet(int i)
+  {
+    super(i);
+  }
+
+  public void addMethodArray(java.lang.reflect.Method[] arrayOfEntries)
+  {
+    LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "addMethodArray", new Object[] { arrayOfEntries });
+
+    for (java.lang.reflect.Method entry : arrayOfEntries) {
+      String methodName = entry.getName();
+
+      LOGGER.debug("Method name: {}", methodName);
+
+      Type[] methodArgTypes = Type.getArgumentTypes(entry);
+      String argDescriptor = typeArrayToStringArgDescriptor(methodArgTypes);
+
+      LOGGER.debug("Descriptor: {}", argDescriptor);
+
+      boolean added = super.add(methodName + argDescriptor);
+
+      LOGGER.debug("Added: {}", added);
+    }
+
+    LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "addMethodArray");
+  }
+
+  static String typeArrayToStringArgDescriptor(Type[] argTypes)
+  {
+    StringBuilder descriptor = new StringBuilder();
+    for (Type t : argTypes) {
+      descriptor.append(t.toString());
+    }
+    return descriptor.toString();
+  }
+
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToLoadProxyException.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToLoadProxyException.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToLoadProxyException.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToLoadProxyException.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,33 @@
+/*
+ * 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 UnableToLoadProxyException extends UnableToProxyException
+{
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 506487573157016476L;
+
+  public UnableToLoadProxyException(String className, Exception e)
+  {
+    super(className, e);
+  }
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToProxyException.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToProxyException.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToProxyException.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToProxyException.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,51 @@
+/*
+ * 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 UnableToProxyException extends Exception
+{
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -17516969014644128L;
+  String className = null;
+
+  public UnableToProxyException(Class<?> clazz)
+  {
+    className = clazz.getName();
+  }
+
+  public UnableToProxyException(Class<?> clazz, Exception e)
+  {
+    this(clazz.getName(), e);
+  }
+
+  public UnableToProxyException(String className, Throwable e)
+  {
+    super(e);
+    this.className = className;
+  }
+
+  public String getClassName()
+  {
+    return className;
+  }
+
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/WrapperedObject.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/WrapperedObject.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/WrapperedObject.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/WrapperedObject.java Sun Feb 27 17:47:08 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;
+
+/**
+ * Interface added to wrapped objects, to enable retrieval of the original object.
+ */
+public interface WrapperedObject {
+    /**
+     * Obtain the object wrapped by this wrapper.
+     * @return unwrapped object.
+     */
+    public Object unwrapObject();
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/BeanArgumentImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/BeanArgumentImpl.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/BeanArgumentImpl.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/BeanArgumentImpl.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,83 @@
+/*
+ * 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.reflect;
+
+import org.apache.aries.blueprint.mutable.MutableBeanArgument;
+import org.osgi.service.blueprint.reflect.BeanArgument;
+import org.osgi.service.blueprint.reflect.Metadata;
+
+/**
+ * Implementation of BeanArgument
+ *
+ * @version $Rev: 896324 $, $Date: 2010-01-06 06:05:04 +0000 (Wed, 06 Jan 2010) $
+ */
+public class BeanArgumentImpl implements MutableBeanArgument {
+
+    private Metadata value;
+    private String valueType;
+    private int index = -1;
+
+    public BeanArgumentImpl() {
+    }
+
+    public BeanArgumentImpl(Metadata value, String valueType, int index) {
+        this.value = value;
+        this.valueType = valueType;
+        this.index = index;
+    }
+
+    public BeanArgumentImpl(BeanArgument source) {
+        value = MetadataUtil.cloneMetadata(source.getValue());
+        valueType = source.getValueType();
+        index = source.getIndex();
+    }
+
+    public Metadata getValue() {
+        return value;
+    }
+
+    public void setValue(Metadata value) {
+        this.value = value;
+    }
+
+    public String getValueType() {
+        return valueType;
+    }
+
+    public void setValueType(String valueType) {
+        this.valueType = valueType;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public void setIndex(int index) {
+        this.index = index;
+    }
+
+    @Override
+    public String toString() {
+        return "BeanArgument[" +
+                "value=" + value +
+                ", valueType='" + valueType + '\'' +
+                ", index=" + index +
+                ']';
+    }
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/BeanMetadataImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/BeanMetadataImpl.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/BeanMetadataImpl.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/BeanMetadataImpl.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,233 @@
+/*
+ * 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.reflect;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.aries.blueprint.ExtendedBeanMetadata;
+import org.apache.aries.blueprint.mutable.MutableBeanMetadata;
+import org.osgi.service.blueprint.reflect.BeanArgument;
+import org.osgi.service.blueprint.reflect.BeanMetadata;
+import org.osgi.service.blueprint.reflect.BeanProperty;
+import org.osgi.service.blueprint.reflect.Metadata;
+import org.osgi.service.blueprint.reflect.Target;
+
+/**
+ * Implementation of BeanMetadata
+ *
+ * @version $Rev: 910448 $, $Date: 2010-02-16 09:50:18 +0000 (Tue, 16 Feb 2010) $
+ */
+public class BeanMetadataImpl extends ComponentMetadataImpl implements MutableBeanMetadata {
+
+    private String className;
+    private String initMethod;
+    private String destroyMethod;
+    private List<BeanArgument> arguments;
+    private List<BeanProperty> properties;
+    private int initialization;
+    private String factoryMethod;
+    private Target factoryComponent;
+    private String scope;
+    private Class runtimeClass;
+    private boolean processor;
+    private boolean fieldInjection;
+    
+    public BeanMetadataImpl() {
+        this.fieldInjection = false;
+    }
+
+    public BeanMetadataImpl(BeanMetadata source) {
+        super(source);
+        this.className = source.getClassName();
+        this.initMethod = source.getInitMethod();
+        this.destroyMethod = source.getDestroyMethod();
+        for (BeanArgument argument : source.getArguments()) {
+            addArgument(new BeanArgumentImpl(argument));
+        }
+        for (BeanProperty property : source.getProperties()) {
+            addProperty(new BeanPropertyImpl(property));
+        }
+        this.initialization = source.getActivation();
+        this.factoryMethod = source.getFactoryMethod();
+        this.factoryComponent = MetadataUtil.cloneTarget(source.getFactoryComponent());
+        this.scope = source.getScope();
+        this.dependsOn = new ArrayList<String>(source.getDependsOn());
+        if (source instanceof ExtendedBeanMetadata) {
+            this.runtimeClass = ((ExtendedBeanMetadata) source).getRuntimeClass();
+            this.fieldInjection = ((ExtendedBeanMetadata) source).getFieldInjection();
+        } else {
+            this.fieldInjection = false;
+        }
+    }
+    
+    public String getClassName() {
+        return className;
+    }
+
+    public void setClassName(String className) {
+        this.className = className;
+    }
+
+    public String getInitMethod() {
+        return initMethod;
+    }
+
+    public void setInitMethod(String initMethodName) {
+        this.initMethod = initMethodName;
+    }
+
+    public String getDestroyMethod() {
+        return destroyMethod;
+    }
+
+    public void setDestroyMethod(String destroyMethodName) {
+        this.destroyMethod = destroyMethodName;
+    }
+
+    public List<BeanArgument> getArguments() {
+        if (this.arguments == null) {
+            return Collections.emptyList();
+        } else {
+            return Collections.unmodifiableList(this.arguments);
+        }
+    }
+
+    public void setArguments(List<BeanArgument> arguments) {
+        this.arguments = arguments != null ? new ArrayList<BeanArgument>(arguments) : null;
+    }
+
+    public void addArgument(BeanArgument argument) {
+        if (this.arguments == null) {
+            this.arguments = new ArrayList<BeanArgument>();
+        }
+        this.arguments.add(argument);
+    }
+
+    public BeanArgument addArgument(Metadata value, String valueType, int index) {
+        BeanArgument arg = new BeanArgumentImpl(value, valueType, index);
+        addArgument(arg);
+        return arg;
+    }
+
+    public void removeArgument(BeanArgument argument) {
+        if (this.arguments != null) {
+            this.arguments.remove(argument);
+        }
+    }
+
+    public List<BeanProperty> getProperties() {
+        if (this.properties == null) {
+            return Collections.emptyList();
+        } else {
+            return Collections.unmodifiableList(this.properties);
+        }
+    }
+
+    public void setProperties(List<BeanProperty> properties) {
+        this.properties = properties != null ? new ArrayList<BeanProperty>(properties) : null;
+    }
+
+    public void addProperty(BeanProperty property) {
+        if (this.properties == null) {
+            this.properties = new ArrayList<BeanProperty>();
+        }
+        this.properties.add(property);
+    }
+
+    public BeanProperty addProperty(String name, Metadata value) {
+        BeanProperty prop = new BeanPropertyImpl(name, value);
+        addProperty(prop);
+        return prop;
+    }
+
+    public void removeProperty(BeanProperty property) {
+        if (this.properties != null) {
+            this.properties.remove(property);
+        }
+    }
+
+    public String getFactoryMethod() {
+        return this.factoryMethod;
+    }
+
+    public void setFactoryMethod(String factoryMethodName) {
+        this.factoryMethod = factoryMethodName;
+    }
+
+    public Target getFactoryComponent() {
+        return this.factoryComponent;
+    }
+
+    public void setFactoryComponent(Target factoryComponent) {
+        this.factoryComponent = factoryComponent;
+    }
+
+    public String getScope() {
+        return this.scope;
+    }
+
+    public void setScope(String scope) {
+        this.scope = scope;
+    }
+
+    public Class getRuntimeClass() {
+        return this.runtimeClass;
+    }
+
+    public void setRuntimeClass(Class runtimeClass) {
+        this.runtimeClass = runtimeClass;
+    }
+
+    public boolean isProcessor() {
+        return processor;
+    }
+
+    public void setProcessor(boolean processor) {
+        this.processor = processor;
+    }
+
+    public boolean getFieldInjection() {
+        return fieldInjection;
+    }
+    
+    public void setFieldInjection(boolean fieldInjection) {
+        this.fieldInjection = fieldInjection;
+    }
+    
+    @Override
+    public String toString() {
+        return "BeanMetadata[" +
+                "id='" + id + '\'' +
+                ", initialization=" + initialization +
+                ", dependsOn=" + dependsOn +
+                ", className='" + className + '\'' +
+                ", initMethodName='" + initMethod + '\'' +
+                ", destroyMethodName='" + destroyMethod + '\'' +
+                ", arguments=" + arguments +
+                ", properties=" + properties +
+                ", factoryMethodName='" + factoryMethod + '\'' +
+                ", factoryComponent=" + factoryComponent +
+                ", scope='" + scope + '\'' +
+                ", runtimeClass=" + runtimeClass +
+                ", fieldInjection=" + fieldInjection + 
+                ']';
+    }
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/BeanPropertyImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/BeanPropertyImpl.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/BeanPropertyImpl.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/BeanPropertyImpl.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,71 @@
+/*
+ * 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.reflect;
+
+import org.apache.aries.blueprint.mutable.MutableBeanProperty;
+import org.osgi.service.blueprint.reflect.BeanProperty;
+import org.osgi.service.blueprint.reflect.Metadata;
+
+/**
+ * Implementation of BeanProperty
+ *
+ * @version $Rev: 896324 $, $Date: 2010-01-06 06:05:04 +0000 (Wed, 06 Jan 2010) $
+ */
+public class BeanPropertyImpl implements MutableBeanProperty {
+
+    private String name;
+    private Metadata value;
+
+    public BeanPropertyImpl() {
+    }
+
+    public BeanPropertyImpl(String name, Metadata value) {
+        this.name = name;
+        this.value = value;
+    }
+
+    public BeanPropertyImpl(BeanProperty source) {
+        this.name = source.getName();
+        this.value = MetadataUtil.cloneMetadata(source.getValue());
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Metadata getValue() {
+        return value;
+    }
+
+    public void setValue(Metadata value) {
+        this.value = value;
+    }
+
+    @Override
+    public String toString() {
+        return "BeanProperty[" +
+                "name='" + name + '\'' +
+                ", value=" + value +
+                ']';
+    }
+}
\ No newline at end of file

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/CollectionMetadataImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/CollectionMetadataImpl.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/CollectionMetadataImpl.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/CollectionMetadataImpl.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,106 @@
+/*
+ * 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.reflect;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.aries.blueprint.mutable.MutableCollectionMetadata;
+import org.osgi.service.blueprint.reflect.CollectionMetadata;
+import org.osgi.service.blueprint.reflect.Metadata;
+
+/**
+ * Implementation of CollectionMetadata
+ *
+ * @version $Rev: 896324 $, $Date: 2010-01-06 06:05:04 +0000 (Wed, 06 Jan 2010) $
+ */
+public class CollectionMetadataImpl implements MutableCollectionMetadata {
+
+    private Class collectionClass;
+    private String valueType;
+    private List<Metadata> values;
+
+    public CollectionMetadataImpl() {
+    }
+
+    public CollectionMetadataImpl(Class collectionClass, String valueType, List<Metadata> values) {
+        this.collectionClass = collectionClass;
+        this.valueType = valueType;
+        this.values = values;
+    }
+    
+    public CollectionMetadataImpl(CollectionMetadata source) {
+        this.collectionClass = source.getCollectionClass();
+        this.valueType = source.getValueType();
+        for (Metadata value : source.getValues()) {
+            addValue(MetadataUtil.cloneMetadata(value));
+        }
+    }
+
+    public Class getCollectionClass() {
+        return collectionClass;
+    }
+
+    public void setCollectionClass(Class collectionClass) {
+        this.collectionClass = collectionClass;
+    }
+
+    public String getValueType() {
+        return valueType;
+    }
+
+    public void setValueType(String valueType) {
+        this.valueType = valueType;
+    }
+
+    public List<Metadata> getValues() {
+        if (this.values == null) {
+            return Collections.emptyList();
+        } else {
+            return Collections.unmodifiableList(this.values);
+        }
+    }
+
+    public void setValues(List<Metadata> values) {
+        this.values = values != null ? new ArrayList<Metadata>(values) : null;
+    }
+
+    public void addValue(Metadata value) {
+        if (this.values == null) {
+            this.values = new ArrayList<Metadata>();
+        }
+        this.values.add(value);
+    }
+
+    public void removeValue(Metadata value) {
+        if (this.values != null) {
+            this.values.remove(value);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "CollectionMetadata[" +
+                "collectionClass=" + collectionClass +
+                ", valueType='" + valueType + '\'' +
+                ", values=" + values +
+                ']';
+    }
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/ComponentMetadataImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/ComponentMetadataImpl.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/ComponentMetadataImpl.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/ComponentMetadataImpl.java Sun Feb 27 17:47:08 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.blueprint.reflect;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.aries.blueprint.mutable.MutableComponentMetadata;
+import org.osgi.service.blueprint.reflect.ComponentMetadata;
+
+/**
+ * Implementation of ComponentMetadata
+ *
+ * @version $Rev: 896324 $, $Date: 2010-01-06 06:05:04 +0000 (Wed, 06 Jan 2010) $
+ */
+public class ComponentMetadataImpl implements MutableComponentMetadata {
+
+    protected String id;
+    protected int activation = ACTIVATION_EAGER;
+    protected List<String> dependsOn;
+
+    protected ComponentMetadataImpl() {
+    }
+    
+    protected ComponentMetadataImpl(ComponentMetadata source) {
+        id = source.getId();
+        activation = source.getActivation();
+        dependsOn = new ArrayList<String>(source.getDependsOn());
+    }
+    
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public int getActivation() {
+        return activation;
+    }
+
+    public void setActivation(int activation) {
+        this.activation = activation;
+    }
+
+    public List<String> getDependsOn() {
+        if (this.dependsOn == null) {
+            return Collections.emptyList();
+        } else {
+            return Collections.unmodifiableList(this.dependsOn);
+        }
+    }
+
+    public void setDependsOn(List<String> dependsOn) {
+        this.dependsOn = dependsOn != null ? new ArrayList<String>(dependsOn) : null;
+    }
+
+    public void addDependsOn(String explicitDependency) {
+        if (this.dependsOn == null) {
+            this.dependsOn = new ArrayList<String>();
+        }
+        this.dependsOn.add(explicitDependency);
+    }
+
+    public void removeDependsOn(String dependency) {
+        if (this.dependsOn != null) {
+            this.dependsOn.remove(dependency);
+        }
+    }
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/IdRefMetadataImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/IdRefMetadataImpl.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/IdRefMetadataImpl.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/IdRefMetadataImpl.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,58 @@
+/*
+ * 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.reflect;
+
+import org.apache.aries.blueprint.mutable.MutableIdRefMetadata;
+import org.osgi.service.blueprint.reflect.IdRefMetadata;
+
+/**
+ * Implementation of IdRefMetadata
+ *
+ * @version $Rev: 896324 $, $Date: 2010-01-06 06:05:04 +0000 (Wed, 06 Jan 2010) $
+ */
+public class IdRefMetadataImpl implements MutableIdRefMetadata {
+
+    protected String componentId;
+
+    public IdRefMetadataImpl() {
+    }
+
+    public IdRefMetadataImpl(String componentId) {
+        this.componentId = componentId;
+    }
+
+    public IdRefMetadataImpl(IdRefMetadata source) {
+        componentId = source.getComponentId();
+    }
+
+    public String getComponentId() {
+        return componentId;
+    }
+
+    public void setComponentId(String componentId) {
+        this.componentId = componentId;
+    }
+
+    @Override
+    public String toString() {
+        return "IdRefMetadata[" +
+                "componentId='" + componentId + '\'' +
+                ']';
+    }
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/MapEntryImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/MapEntryImpl.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/MapEntryImpl.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/MapEntryImpl.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,72 @@
+/*
+ * 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.reflect;
+
+import org.apache.aries.blueprint.mutable.MutableMapEntry;
+import org.osgi.service.blueprint.reflect.MapEntry;
+import org.osgi.service.blueprint.reflect.Metadata;
+import org.osgi.service.blueprint.reflect.NonNullMetadata;
+
+/**
+ * Implementation of MapEntry
+ *
+ * @version $Rev: 896324 $, $Date: 2010-01-06 06:05:04 +0000 (Wed, 06 Jan 2010) $
+ */
+public class MapEntryImpl implements MutableMapEntry {
+
+    private NonNullMetadata key;
+    private Metadata value;
+
+    public MapEntryImpl() {
+    }
+
+    public MapEntryImpl(NonNullMetadata key, Metadata value) {
+        this.key = key;
+        this.value = value;
+    }
+
+    public MapEntryImpl(MapEntry entry) {
+        this.key = (NonNullMetadata) MetadataUtil.cloneMetadata(entry.getKey());
+        this.value = MetadataUtil.cloneMetadata(entry.getValue());
+    }
+
+    public NonNullMetadata getKey() {
+        return key;
+    }
+
+    public void setKey(NonNullMetadata key) {
+        this.key = key;
+    }
+
+    public Metadata getValue() {
+        return value;
+    }
+
+    public void setValue(Metadata value) {
+        this.value = value;
+    }
+
+    @Override
+    public String toString() {
+        return "MapEntry[" +
+                "key=" + key +
+                ", value=" + value +
+                ']';
+    }
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/MapMetadataImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/MapMetadataImpl.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/MapMetadataImpl.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/MapMetadataImpl.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,114 @@
+/*
+ * 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.reflect;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.aries.blueprint.mutable.MutableMapMetadata;
+import org.osgi.service.blueprint.reflect.MapEntry;
+import org.osgi.service.blueprint.reflect.MapMetadata;
+import org.osgi.service.blueprint.reflect.Metadata;
+import org.osgi.service.blueprint.reflect.NonNullMetadata;
+
+/**
+ * Implementation of MapMetadata
+ *
+ * @version $Rev: 896324 $, $Date: 2010-01-06 06:05:04 +0000 (Wed, 06 Jan 2010) $
+ */
+public class MapMetadataImpl implements MutableMapMetadata {
+
+    private String keyType;
+    private String valueType;
+    private List<MapEntry> entries;
+
+    public MapMetadataImpl() {
+    }
+
+    public MapMetadataImpl(String keyType, String valueType, List<MapEntry> entries) {
+        this.keyType = keyType;
+        this.valueType = valueType;
+        this.entries = entries;
+    }
+
+    public MapMetadataImpl(MapMetadata source) {
+        this.valueType = source.getValueType();
+        this.keyType = source.getKeyType();
+        for (MapEntry entry : source.getEntries()) {
+            addEntry(new MapEntryImpl(entry));
+        }
+    }
+
+    public String getKeyType() {
+        return this.keyType;
+    }
+
+    public void setKeyType(String keyTypeName) {
+        this.keyType = keyTypeName;
+    }
+
+    public String getValueType() {
+        return this.valueType;
+    }
+
+    public void setValueType(String valueTypeName) {
+        this.valueType = valueTypeName;
+    }
+
+    public List<MapEntry> getEntries() {
+        if (this.entries == null) {
+            return Collections.emptyList();
+        } else {
+            return Collections.unmodifiableList(this.entries);
+        }
+    }
+
+    public void setEntries(List<MapEntry> entries) {
+        this.entries = entries != null ? new ArrayList<MapEntry>(entries) : null;
+    }
+
+    public void addEntry(MapEntry entry) {
+        if (this.entries == null) {
+            this.entries = new ArrayList<MapEntry>();
+        }
+        this.entries.add(entry);
+    }
+
+    public MapEntry addEntry(NonNullMetadata key, Metadata value) {
+        MapEntry entry = new MapEntryImpl(key, value);
+        addEntry(entry);
+        return entry;
+    }
+
+    public void removeEntry(MapEntry entry) {
+        if (this.entries != null) {
+            this.entries.remove(entry);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "MapMetadata[" +
+                "keyType='" + keyType + '\'' +
+                ", valueType='" + valueType + '\'' +
+                ", entries=" + entries +
+                ']';
+    }
+}