Author: clement
Date: Wed Aug 20 06:17:35 2008
New Revision: 687319

URL: http://svn.apache.org/viewvc?rev=687319&view=rev
Log:
Add the inner class support (Felix-687).
This new manipulator manipulate both the component implementation class and 
inner classes in order to allow accessing managed fields from the inner class.

Added:
    
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassAdapter.java
    
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassManipulator.java
Modified:
    
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
    
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
    
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
    
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java
    
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java
    
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java

Modified: 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java?rev=687319&r1=687318&r2=687319&view=diff
==============================================================================
--- 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
 (original)
+++ 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
 Wed Aug 20 06:17:35 2008
@@ -31,7 +31,7 @@
 import org.objectweb.asm.commons.EmptyVisitor;
 
 /**
- * Check that a POJO is already manipulated or not.
+ * Checks that a POJO is already manipulated or not.
  * Moreover it allows to get manipulation data about this class. 
  * @author <a href="mailto:[EMAIL PROTECTED]">Felix Project Team</a>
  */
@@ -61,6 +61,16 @@
      * Super class if not java.lang.Object.
      */
     private String m_superClass;
+    
+    /**
+     * Class name.
+     */
+    private String m_className;
+    
+    /**
+     * List of visited inner class owned by the implementation class.
+     */
+    private List m_inners = new ArrayList();
 
     /**
      * Check if the _cm field already exists.
@@ -102,6 +112,22 @@
 
         return null;
     }
+    
+    /**
+     * Add the inner class to the list of inner class to manipulate.
+     * The method checks that the inner class is really owned by the 
implementation class.
+     * @param name inner class qualified name
+     * @param outerName outer class name (may be null for anonymous class)
+     * @param innerName inner class simple (i.e. short) name
+     * @param access inner class visibility
+     * @see 
org.objectweb.asm.commons.EmptyVisitor#visitInnerClass(java.lang.String, 
java.lang.String, java.lang.String, int)
+     */
+    public void visitInnerClass(String name, String outerName, String 
innerName, int access) {
+        if (m_className.equals(outerName)  || outerName == null) { // 
Anonymous classes does not have an outer class.
+            m_inners.add(name);
+        }
+    }
+
 
     /**
      * Check if the class was already manipulated.
@@ -134,6 +160,8 @@
                 m_itfs.add(interfaces[i].replace('/', '.'));
             }
         }
+        
+        m_className = name;
     }
 
     /**
@@ -194,5 +222,9 @@
     public String getSuperClass() {
         return m_superClass;
     }
+    
+    public List getInnerClasses() {
+        return m_inners;
+    }
 
 }

Modified: 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java?rev=687319&r1=687318&r2=687319&view=diff
==============================================================================
--- 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
 (original)
+++ 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
 Wed Aug 20 06:17:35 2008
@@ -83,12 +83,12 @@
         if (m_fields.contains(name) && m_owner.equals(owner)) {
             if (opcode == GETFIELD) {
                 String gDesc = "()" + desc;
-                mv.visitMethodInsn(INVOKESPECIAL, owner, "__get" + name, 
gDesc);
+                mv.visitMethodInsn(INVOKEVIRTUAL, owner, "__get" + name, 
gDesc);
                 return;
             } else
                 if (opcode == PUTFIELD) {
                     String sDesc = "(" + desc + ")V";
-                    mv.visitMethodInsn(INVOKESPECIAL, owner, "__set" + name, 
sDesc);
+                    mv.visitMethodInsn(INVOKEVIRTUAL, owner, "__set" + name, 
sDesc);
                     return;
                 }
         }

Added: 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassAdapter.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassAdapter.java?rev=687319&view=auto
==============================================================================
--- 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassAdapter.java
 (added)
+++ 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassAdapter.java
 Wed Aug 20 06:17:35 2008
@@ -0,0 +1,74 @@
+/* 
+ * 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.felix.ipojo.manipulation;
+
+import java.util.Set;
+
+import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Adapts a inner class in order to allow accessing outer class fields.
+ * A manipulated inner class has access to the managed field of the outer 
class.
+ * @author <a href="mailto:[EMAIL PROTECTED]">Felix Project Team</a>
+ */
+public class InnerClassAdapter extends ClassAdapter implements Opcodes {
+    
+    /**
+     * Implementation class name.
+     */
+    private String m_outer;
+    
+    /**
+     * List of fields of the implementation class. 
+     */
+    private Set m_fields;
+
+    /**
+     * Creates the inner class adapter.
+     * @param arg0 parent class visitor
+     * @param outerClass outer class (implementation class)
+     * @param fields fields of the implementation class
+     */
+    public InnerClassAdapter(ClassVisitor arg0, String outerClass, Set fields) 
{
+        super(arg0);
+        m_outer = outerClass;
+        m_fields = fields;
+    }
+    
+    /**
+     * Visits a method.
+     * This methods create a code visitor manipulating outer class field 
accesses.
+     * @param access method visibility
+     * @param name method name
+     * @param desc method descriptor
+     * @param signature method signature
+     * @param exceptions list of exceptions thrown by the method
+     * @return a code adapter manipulating field accesses
+     * @see org.objectweb.asm.ClassAdapter#visitMethod(int, java.lang.String, 
java.lang.String, java.lang.String, java.lang.String[])
+     */
+    public MethodVisitor visitMethod(int access, String name, String desc, 
String signature, String[] exceptions) {
+        MethodVisitor mv = super.visitMethod(access, name, desc, signature, 
exceptions);
+        return new MethodCodeAdapter(mv, m_outer, access, name, desc, 
m_fields);
+    }    
+    
+
+}

Added: 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassManipulator.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassManipulator.java?rev=687319&view=auto
==============================================================================
--- 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassManipulator.java
 (added)
+++ 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassManipulator.java
 Wed Aug 20 06:17:35 2008
@@ -0,0 +1,74 @@
+/* 
+ * 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.felix.ipojo.manipulation;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Set;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+
+/**
+ * Manipulates inner class allowing outer class access. The manipulated class
+ * has access to managed field of the outer class.
+ * @author <a href="mailto:[EMAIL PROTECTED]">Felix Project Team</a>
+ */
+public class InnerClassManipulator {
+
+    /**
+     * Component implementation class name.
+     */
+    private String m_outer;
+    
+    /**
+     * Component class fields.
+     */
+    private Set m_fields;
+
+    /**
+     * Creates an inner class manipulator.
+     * @param classname : class name
+     * @param fields : fields
+     */
+    public InnerClassManipulator(String classname, Set fields) {
+        m_outer = classname;
+        m_fields = fields;
+    }
+
+    /**
+     * Manipulate the inner class.
+     * @param in input (i.e. original) class
+     * @return manipulated class
+     * @throws IOException the class cannot be read correctly
+     */
+    public byte[] manipulate(byte[] in) throws IOException {
+        InputStream is1 = new ByteArrayInputStream(in);
+
+        ClassReader cr = new ClassReader(is1);
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+        InnerClassAdapter adapter = new InnerClassAdapter(cw, m_outer, 
m_fields);
+        cr.accept(adapter, ClassReader.SKIP_FRAMES);
+        is1.close();
+
+        return cw.toByteArray();
+    }
+
+}

Modified: 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java?rev=687319&r1=687318&r2=687319&view=diff
==============================================================================
--- 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
 (original)
+++ 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
 Wed Aug 20 06:17:35 2008
@@ -55,6 +55,11 @@
      * Pojo super class.
      */
     private String m_superClass;
+    
+    /**
+     * List of owned inner classed.
+     */
+    private List m_inners;
 
     /**
      * Manipulate the given byte array.
@@ -79,6 +84,8 @@
 
         // Get the methods list
         m_methods = ck.getMethods();
+        
+        m_inners = ck.getInnerClasses();
 
         ClassWriter finalWriter = null;
         if (!ck.isalreadyManipulated()) {
@@ -142,5 +149,9 @@
     public Map getFields() {
         return m_fields;
     }
+    
+    public List getInnerClasses() {
+        return m_inners;
+    }
 
 }

Modified: 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java?rev=687319&r1=687318&r2=687319&view=diff
==============================================================================
--- 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java
 (original)
+++ 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java
 Wed Aug 20 06:17:35 2008
@@ -68,11 +68,11 @@
         if (owner.equals(m_owner) && m_fields.contains(name)) {
             if (opcode == GETFIELD) {
                 String gDesc = "()" + desc;
-                visitMethodInsn(INVOKESPECIAL, owner, "__get" + name, gDesc);
+                visitMethodInsn(INVOKEVIRTUAL, owner, "__get" + name, gDesc);
                 return;
             } else if (opcode == PUTFIELD) {
                 String sDesc = "(" + desc + ")V";
-                visitMethodInsn(INVOKESPECIAL, owner, "__set" + name, sDesc);
+                visitMethodInsn(INVOKEVIRTUAL, owner, "__set" + name, sDesc);
                 return;
             }
         }

Modified: 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java?rev=687319&r1=687318&r2=687319&view=diff
==============================================================================
--- 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java
 (original)
+++ 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java
 Wed Aug 20 06:17:35 2008
@@ -147,7 +147,7 @@
      * @param desc : method descriptor
      * @param signature : signature
      * @param exceptions : declared exceptions.
-     * @return the MethodVisitor wichi will visit the method code.
+     * @return the MethodVisitor wich will visit the method code.
      * @see org.objectweb.asm.ClassAdapter#visitMethod(int, java.lang.String, 
java.lang.String, java.lang.String, java.lang.String[])
      */
     public MethodVisitor visitMethod(int access, String name, String desc, 
String signature, String[] exceptions) {
@@ -176,6 +176,11 @@
             MethodVisitor mv = super.visitMethod(ACC_PRIVATE, "<init>", 
newDesc, signature, exceptions);
             return new ConstructorCodeAdapter(mv, m_owner, m_fields, 
ACC_PRIVATE, name, newDesc);
         }
+        
+        if ((access & ACC_SYNTHETIC) == ACC_SYNTHETIC && 
name.startsWith("access$")) { 
+            MethodVisitor mv = super.visitMethod(access, name, desc, 
signature, exceptions);
+            return new MethodCodeAdapter(mv, m_owner, access, name, desc, 
m_fields); 
+        }
 
         if ((access & ACC_STATIC) == ACC_STATIC) { return 
super.visitMethod(access, name, desc, signature, exceptions); }
 
@@ -186,7 +191,7 @@
         MethodVisitor mv = super.visitMethod(ACC_PRIVATE, PREFIX + name, desc, 
signature, exceptions);
         return new MethodCodeAdapter(mv, m_owner, ACC_PRIVATE, PREFIX + name, 
desc, m_fields);
     }
-
+    
     /**
      * Visit a Field.
      * This field access is replaced by an invocation to the getter method or 
to the setter method.
@@ -606,7 +611,7 @@
      */
     private void createArrayGetter(String name, String desc, Type type) {
         String methodName = "__get" + name;
-        MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, methodName, desc, null, 
null);
+        MethodVisitor mv = cv.visitMethod(0, methodName, desc, null, null);
         mv.visitCode();
 
         String internalType = desc.substring(2);
@@ -641,7 +646,7 @@
      */
     private void createSimpleGetter(String name, String desc, Type type) {
         String methodName = "__get" + name;
-        MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, methodName, desc, null, 
null);
+        MethodVisitor mv = cv.visitMethod(0, methodName, desc, null, null);
         mv.visitCode();
 
         switch (type.getSort()) {
@@ -821,7 +826,7 @@
      * @param type : type of the property
      */
     private void createSimpleSetter(String name, String desc, Type type) {
-        MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, "__set" + name, desc, 
null, null);
+        MethodVisitor mv = cv.visitMethod(0, "__set" + name, desc, null, null);
         mv.visitCode();
 
         switch (type.getSort()) {

Modified: 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java?rev=687319&r1=687318&r2=687319&view=diff
==============================================================================
--- 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
 (original)
+++ 
felix/trunk/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
 Wed Aug 20 06:17:35 2008
@@ -31,6 +31,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.TreeMap;
 import java.util.jar.Attributes;
 import java.util.jar.JarEntry;
@@ -38,6 +39,7 @@
 import java.util.jar.JarOutputStream;
 import java.util.jar.Manifest;
 
+import org.apache.felix.ipojo.manipulation.InnerClassManipulator;
 import org.apache.felix.ipojo.manipulation.Manipulator;
 import org.apache.felix.ipojo.manipulation.annotations.MetadataCollector;
 import org.apache.felix.ipojo.metadata.Attribute;
@@ -307,6 +309,14 @@
                         if (ci.m_classname.equals(curEntry.getName())) {
                             byte[] outClazz = manipulateComponent(in, 
curEntry, ci);
                             m_classes.put(curEntry.getName(), outClazz);
+                            
+                            // Manipulate inner classes ?
+                            if (!ci.m_inners.isEmpty()) {
+                                for (int k = 0; k < ci.m_inners.size(); k++) {
+                                    JarEntry inner = 
inputJar.getJarEntry((String) ci.m_inners.get(k) + ".class");
+                                    manipulateInnerClass(inputJar, inner, 
(String) ci.m_inners.get(k), ci);
+                                }
+                            }
                         }
                     }
                 } catch (IOException e) {
@@ -316,6 +326,32 @@
             }
         }
     }
+    
+    /**
+     * Manipulates an inner class.
+     * @param inputJar input jar
+     * @param je inner class jar entry
+     * @param innerClassName inner class name
+     * @param ci component info of the component owning the inner class
+     * @throws IOException the inner class cannot be read
+     */
+    private void manipulateInnerClass(JarFile inputJar, JarEntry je, String 
innerClassName, ComponentInfo ci) throws IOException {
+        InputStream currIn = inputJar.getInputStream(je);
+        byte[] in = new byte[0];
+        int c;
+        while ((c = currIn.read()) >= 0) {
+            byte[] in2 = new byte[in.length + 1];
+            System.arraycopy(in, 0, in2, 0, in.length);
+            in2[in.length] = (byte) c;
+            in = in2;
+        }
+        
+        InnerClassManipulator man = new 
InnerClassManipulator(ci.m_classname.substring(0, ci.m_classname.length() - 6), 
ci.m_fields);
+        byte[] out = man.manipulate(in);
+        
+        m_classes.put(je.getName(), out);
+        
+    }
 
     /**
      * Create the manifest.
@@ -352,6 +388,8 @@
             // Insert information to metadata
             ci.m_componentMetadata.addElement(man.getManipulationMetadata());
             ci.m_isManipulated = true;
+            ci.m_inners = man.getInnerClasses();
+            ci.m_fields = man.getFields().keySet();
             return out;
         } catch (IOException e) {
             error("Cannot manipulate the class " + je.getName() + " : " + 
e.getMessage());
@@ -397,6 +435,16 @@
          * Is the class already manipulated. 
          */
         boolean m_isManipulated;
+        
+        /**
+         * List of inner classes of the implementation class.
+         */
+        List m_inners;
+        
+        /**
+         * Set of fields of the implementation class.
+         */
+        Set m_fields;
 
         /**
          * Constructor.


Reply via email to