Add the new manipulator project (Felix-311)

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@550247 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/manipulator/pom.xml b/ipojo/manipulator/pom.xml
new file mode 100644
index 0000000..c965f08
--- /dev/null
+++ b/ipojo/manipulator/pom.xml
@@ -0,0 +1,21 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.felix</groupId>

+  <artifactId>org.apache.felix.ipojo.manipulator</artifactId>

+  <packaging>jar</packaging>

+  <version>0.7.3-incubator-SNAPSHOT</version>

+  <name>Apache Felix iPOJO Manipulator</name>

+  <dependencies>

+    <dependency>

+      <groupId>asm</groupId>

+      <artifactId>asm</artifactId>

+      <version>3.0</version>

+    </dependency>

+    <dependency>

+      <groupId>${pom.groupId}</groupId>

+      <artifactId>org.apache.felix.ipojo.metadata</artifactId>

+      <version>0.7.3-incubator-SNAPSHOT</version>

+    </dependency>

+  </dependencies>

+</project>
\ No newline at end of file
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
new file mode 100644
index 0000000..0168055
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
@@ -0,0 +1,223 @@
+/* 

+ * 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.ArrayList;

+import java.util.HashMap;

+import java.util.List;

+

+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;

+

+/**

+ * Check thaht a POJO is already manipulated or not.

+ * Moreover it allows to get manipulation data about this class. 

+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>

+ */

+public class ClassChecker implements ClassVisitor, Opcodes {

+

+    /**

+     * True if the class is already manipulated.

+     */

+    private boolean m_isAlreadyManipulated = false;

+

+    /**

+     * Interfaces implemented by the component.

+     */

+    private String[] m_itfs = new String[0];

+

+    /**

+     * Field hashmap [field name, type] discovered in the component class.

+     */

+    private HashMap m_fields = new HashMap();

+

+    /**

+     * Method List of method descriptor discovered in the component class.

+     */

+    private List m_methods = new ArrayList()/* <MethodDesciptor> */;

+

+    /**

+     * Check if the _cm field already exists.

+     * Update the field list.

+     * @param access : access of the field

+     * @param name : name of the field

+     * @param desc : description of the field

+     * @param signature : signature of the field

+     * @param value : value of the field (for static field only)

+     * @return the field visitor

+     * @see org.objectweb.asm.ClassVisitor#visitField(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object)

+     */

+    public FieldVisitor visitField(int access, String name, String desc,

+            String signature, Object value) {

+

+        if (access == ACC_PRIVATE && name.equals("_cm")

+                && desc.equals("Lorg/apache/felix/ipojo/InstanceManager;")) {

+            m_isAlreadyManipulated = true;

+        }

+

+        Type type = Type.getType(desc);

+        if (type.getSort() == Type.ARRAY) {

+            if (type.getInternalName().startsWith("L")) {

+                String internalType = type.getInternalName().substring(1);

+                String nameType = internalType.replace('/', '.');

+                m_fields.put(name, nameType + "[]");

+            } else {

+                String nameType = type.getClassName().substring(0,

+                        type.getClassName().length() - 2);

+                m_fields.put(name, nameType + "[]");

+            }

+        } else {

+            m_fields.put(name, type.getClassName());

+        }

+

+        return null;

+    }

+

+    /**

+     * Check if the class was already manipulated.

+     * @return true if the class is already manipulated.

+     */

+    public boolean isalreadyManipulated() {

+        return m_isAlreadyManipulated;

+    }

+

+    /**

+     * Visit the class.

+     * Update the implemented insterface list.

+     * @param version : version of the class

+     * @param access : acess of the class

+     * @param name : name of the class

+     * @param signature : signature of the class

+     * @param superName : super class of the class

+     * @param interfaces : implemented interfaces.

+     * @see org.objectweb.asm.ClassVisitor#visit(int, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])

+     */

+    public void visit(int version, int access, String name, String signature,

+            String superName, String[] interfaces) {

+        // Store the interfaces :

+        m_itfs = interfaces;

+    }

+

+    /**

+     * Visit sources.

+     * Do nothing

+     * @param source : the name of the source file from which the class was compiled. May be null.

+       @param debug : additional debug information to compute the correspondance between source and compiled elements of the class. May be null.

+     * @see org.objectweb.asm.ClassVisitor#visitSource(java.lang.String, java.lang.String)

+     */

+    public void visitSource(String source, String debug) { }

+

+    /**

+     * Visit an outer class.

+     * @param owner - internal name of the enclosing class of the class.

+     * @param name - the name of the method that contains the class, or null if the class is not enclosed in a method of its enclosing class.

+     * @param desc - the descriptor of the method that contains the class, or null if the class is not enclosed in a method of its enclosing class.

+     * @see org.objectweb.asm.ClassVisitor#visitOuterClass(java.lang.String,

+     *      java.lang.String, java.lang.String)

+     */

+    public void visitOuterClass(String owner, String name, String desc) {

+    }

+

+    /**

+     * Visit an annotation.

+     * Do nothing.

+     * @param desc - the class descriptor of the annotation class.

+     * @param visible - true if the annotation is visible at runtime.

+     * @return null.

+     * @see org.objectweb.asm.ClassVisitor#visitAnnotation(java.lang.String, boolean)

+     */

+    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {

+        return null;

+    }

+

+    /**

+     * Visit a non standard attribute of the class.

+     * @param attr - an attribute.

+     * @see org.objectweb.asm.ClassVisitor#visitAttribute(org.objectweb.asm.Attribute)

+     */

+    public void visitAttribute(Attribute attr) {

+    }

+

+    /**

+     * Visit an inner class.

+     * @param name - the internal name of an inner class (see getInternalName).

+     * @param outerName - the internal name of the class to which the inner class belongs (see getInternalName). May be null for not member classes.

+     * @param innerName - the (simple) name of the inner class inside its enclosing class. May be null for anonymous inner classes.

+     * @param access - the access flags of the inner class as originally declared in the enclosing class.

+     * @see org.objectweb.asm.ClassVisitor#visitInnerClass(java.lang.String,

+     *      java.lang.String, java.lang.String, int)

+     */

+    public void visitInnerClass(String name, String outerName, String innerName, int access) { }

+

+    /**

+     * Visit a method.

+     * Update the method list (except if it init or clinit.

+     * @param  access - the method's access flags (see Opcodes). This parameter also indicates if the method is synthetic and/or deprecated.

+     * @param name - the method's name.

+     * @param desc - the method's descriptor (see Type).

+     * @param signature - the method's signature. May be null if the method parameters, return type and exceptions do not use generic types.

+     * @param exceptions - the internal names of the method's exception classes (see getInternalName). May be null.

+     * @return nothing.

+     * @see org.objectweb.asm.ClassVisitor#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) {

+        if (!name.equals("<init>") && !name.equals("<clinit>")) {

+            m_methods.add(new MethodDescriptor(name, desc));

+        }

+        return null;

+    }

+

+    /**

+     * End of the class visit.

+     * @see org.objectweb.asm.ClassVisitor#visitEnd()

+     */

+    public void visitEnd() { }

+

+    /**

+     * Get collected interfaces.

+     * @return the interfaces implemented by the component class.

+     */

+    public String[] getInterfaces() {

+        return m_itfs;

+    }

+

+    /**

+     * Get collected fields.

+     * @return the field hashmap [field_name, type].

+     */

+    public HashMap getFields() {

+        return m_fields;

+    }

+

+    /**

+     * Get collected methods.

+     * @return the method list of [method, signature].

+     */

+    public List getMethods() {

+        return m_methods;

+    }

+

+}

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
new file mode 100644
index 0000000..29ab001
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
@@ -0,0 +1,166 @@
+/* 

+ * 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 org.objectweb.asm.Label;

+import org.objectweb.asm.MethodVisitor;

+import org.objectweb.asm.Opcodes;

+import org.objectweb.asm.commons.GeneratorAdapter;

+

+/**

+ * Constructor Adapter : add a component manager argument inside a constructor.

+ * 

+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>

+ */

+public class ConstructorCodeAdapter extends GeneratorAdapter implements Opcodes {

+

+    /**

+     * The owner class of the field. 

+     * m_owner : String

+     */

+    private String m_owner;

+

+    /**

+     * Is the super call already detected ? 

+     */

+    private boolean m_superDetected;

+

+    /**

+     * ConstructorCodeAdapter constructor. 

+     * @param mv : method visitor.

+     * @param access : access level of the method.

+     * @param desc : descriptor of the constructor. 

+     * @param owner : onwer class

+     */

+    public ConstructorCodeAdapter(final MethodVisitor mv, int access,

+            String desc, final String owner) {

+        super(mv, access, "<init>", desc);

+        m_owner = owner;

+      //  m_superDetected = false;

+    }

+

+    /**

+     * Visit a method instruction.

+     * Inject the _setComponentManager invocation just of the super invocation.

+     * @param opcode : opcode

+     * @param owner : method owner class

+     * @param name : method name

+     * @param desc : method description

+     * @see org.objectweb.asm.commons.AdviceAdapter#visitMethodInsn(int, java.lang.String, java.lang.String, java.lang.String)

+     */

+    public void visitMethodInsn(int opcode, String owner, String name, String desc) {

+        // A method call is detected, check if it is the super call :

+        if (!m_superDetected) {

+            m_superDetected = true;

+            // The first invocation is the super call

+            // 1) Visit the super constructor :

+            mv.visitVarInsn(ALOAD, 0);

+            mv.visitMethodInsn(opcode, owner, name, desc); // Super constructor

+                                                            // invocation

+

+            // 2) Load the object and the component manager argument

+            mv.visitVarInsn(ALOAD, 0);

+            // mv.visitVarInsn(ALOAD,

+            // Type.getArgumentTypes(m_constructorDesc).length);

+            mv.visitVarInsn(ALOAD, 1); // CM is always the first argument

+            // 3) Initialize the field

+            mv.visitMethodInsn(INVOKESPECIAL, m_owner, "_setComponentManager",

+                    "(Lorg/apache/felix/ipojo/InstanceManager;)V");

+            // insertion finished

+        } else {

+            mv.visitMethodInsn(opcode, owner, name, desc);

+        }

+    }

+

+    /**

+     * Visit an instruction modifying a local variable.

+     * Increment the variable number if != 0.

+     * @param opcode : opcode of the instruction.

+     * @param var : variable number.

+     * @see org.objectweb.asm.commons.AdviceAdapter#visitVarInsn(int, int)

+     */

+    public void visitVarInsn(int opcode, int var) {

+        if (var == 0) {

+            mv.visitVarInsn(opcode, var); // ALOAD 0 (THIS)

+        } else {

+            mv.visitVarInsn(opcode, var + 1); // All other variable count

+        } 

+    }

+

+    /**

+     * Visit an increment instruction.

+     * Increment the variable number.

+     * @param var : incremented variable number.

+     * @param increment : increment.

+     * @see org.objectweb.asm.commons.LocalVariablesSorter#visitIincInsn(int, int)

+     */

+    public void visitIincInsn(int var, int increment) {

+        if (var != 0) {

+            mv.visitIincInsn(var + 1, increment);

+        } else {

+            mv.visitIincInsn(var, increment);

+        }

+    }

+

+    /**

+     * Visit local variable.

+     * @param name : name of the variable.

+     * @param desc : description of the variable.

+     * @param signature : signature of the variable.

+     * @param start : starting label.

+     * @param end : ending label.

+     * @param index : variable index.

+     * @see org.objectweb.asm.commons.LocalVariablesSorter#visitLocalVariable(java.lang.String, java.lang.String, java.lang.String, org.objectweb.asm.Label, org.objectweb.asm.Label, int)

+     */

+    public void visitLocalVariable(String name, String desc, String signature,

+            Label start, Label end, int index) {

+        if (index == 0) {

+            mv.visitLocalVariable(name, desc, signature, start, end, index);

+            mv.visitLocalVariable("_manager", "Lorg/apache/felix/ipojo/InstanceManager;", null, start, end, 1);

+        } else {

+            mv.visitLocalVariable(name, desc, signature, start, end, index + 1);   

+        }

+    }

+

+    /**

+     * Manage a field operation.

+     * Replace GETFIELD and PUTFILED by getter and setter invocation.

+     * 

+     * @param opcode : visited operation code

+     * @param owner : owner of the field

+     * @param name : name of the field

+     * @param desc : decriptor of the field

+     * @see org.objectweb.asm.commons.AdviceAdapter#visitFieldInsn(int, java.lang.String, java.lang.String, java.lang.String)

+     */

+    public void visitFieldInsn(final int opcode, final String owner,

+            final String name, final String desc) {

+        if (owner.equals(m_owner)) {

+            if (opcode == GETFIELD) {

+                String gDesc = "()" + desc;

+                visitMethodInsn(INVOKEVIRTUAL, owner, "_get" + name, gDesc);

+                return;

+            } else if (opcode == PUTFIELD) {

+                String sDesc = "(" + desc + ")V";

+                visitMethodInsn(INVOKESPECIAL, owner, "_set" + name, sDesc);

+                return;

+            }

+        }

+        super.visitFieldInsn(opcode, owner, name, desc);

+    }

+}

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/FieldAdapter.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/FieldAdapter.java
new file mode 100644
index 0000000..cd6e278
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/FieldAdapter.java
@@ -0,0 +1,656 @@
+/* 

+ * 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.logging.Level;

+

+import org.objectweb.asm.ClassAdapter;

+import org.objectweb.asm.ClassVisitor;

+import org.objectweb.asm.FieldVisitor;

+import org.objectweb.asm.Label;

+import org.objectweb.asm.MethodVisitor;

+import org.objectweb.asm.Opcodes;

+import org.objectweb.asm.Type;

+

+/**

+ * Create getter and setter for each fields .

+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>

+ */

+public class FieldAdapter extends ClassAdapter implements Opcodes {

+

+    /**

+     * The owner.

+     * m_owner : String

+     */

+    private String m_owner;

+

+    /**

+     * Constructor.

+     * @param cv : Class visitor

+     */

+    public FieldAdapter(final ClassVisitor cv) {

+        super(cv);

+    }

+

+    /**

+     * The visit method. - Insert the _cm field - Create the _initialize method - Create the _cm setter method

+     * 

+     * @see org.objectweb.asm.ClassVisitor#visit(int, int, String, String, String, String[])

+     * @param version : Version

+     * @param access : Access modifier

+     * @param name : name of the visited element

+     * @param signature : signature of the visited element

+     * @param superName : superclasses (extend clause)

+     * @param interfaces : implement clause

+     */

+    public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) {

+        m_owner = name;

+    }

+

+    /**

+     * Visit a Field.

+     * Inject the getter and the setter method for this field.

+     * @see org.objectweb.asm.ClassVisitor#visitField(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object)

+     * @param access : acces modifier

+     * @param name : name of the field

+     * @param desc : description of the field

+     * @param signature : signature of the field

+     * @param value : value of the field

+     * @return FieldVisitor : null

+     */

+    public FieldVisitor visitField(final int access, final String name, final String desc, final String signature, final Object value) {

+

+        if ((access & ACC_STATIC) == 0) {

+            ManipulationProperty.getLogger().log(Level.INFO, "Manipulate the field declaration of " + name);

+            Type type = Type.getType(desc);

+

+            if (type.getSort() == Type.ARRAY) {

+                String gDesc = "()" + desc;

+                createArrayGetter(name, gDesc, type);

+

+                // Generates setter method

+                String sDesc = "(" + desc + ")V";

+                createArraySetter(name, sDesc, type);

+

+            } else {

+                // Generate the getter method

+                String gDesc = "()" + desc;

+                createSimpleGetter(name, gDesc, type);

+

+                // Generates setter method

+                String sDesc = "(" + desc + ")V";

+                createSimpleSetter(name, sDesc, type);

+            }

+

+        }

+

+        return null;

+    }

+

+    /**

+     * Create a getter method for an array.

+     * @param name : field name

+     * @param desc : method description

+     * @param type : contained type (inside the array)

+     */

+    private void createArraySetter(String name, String desc, Type type) {

+        MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, "_set" + name, desc, null, null);

+

+        String internalType = desc.substring(1);

+        internalType = internalType.substring(0, internalType.length() - 2);

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitVarInsn(ALOAD, 1);

+        mv.visitFieldInsn(PUTFIELD, m_owner, name, internalType);

+

+        Label l1 = new Label();

+        mv.visitLabel(l1);

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, "_F" + name, "Z");

+        Label l2 = new Label();

+        mv.visitJumpInsn(IFNE, l2);

+        mv.visitInsn(RETURN);

+        mv.visitLabel(l2);

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");

+        mv.visitLdcInsn(name);

+        mv.visitVarInsn(ALOAD, 1);

+        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "setterCallback", "(Ljava/lang/String;Ljava/lang/Object;)V");

+

+        mv.visitInsn(RETURN);

+

+        // End

+        mv.visitMaxs(0, 0);

+        mv.visitEnd();

+    }

+

+    /**

+     * Create a setter method for an array.

+     * @param name : field name

+     * @param desc : method description

+     * @param type : contained type (inside the array)

+     */

+    private void createArrayGetter(String name, String desc, Type type) {

+

+        String methodName = "_get" + name;

+        MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, methodName, desc, null, null);

+

+        String internalType = desc.substring(2);

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, "_F" + name, "Z");

+        Label l1 = new Label();

+        mv.visitJumpInsn(IFNE, l1);

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, name, internalType);

+        mv.visitInsn(ARETURN);

+        mv.visitLabel(l1);

+

+        mv.visitVarInsn(ALOAD, 0);

+        // mv.visitFieldInsn(GETFIELD, m_owner, name, "["+type.getInternalName()+";");

+        mv.visitFieldInsn(GETFIELD, m_owner, name, internalType);

+        mv.visitVarInsn(ASTORE, 1);

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");

+        mv.visitLdcInsn(name);

+        mv.visitVarInsn(ALOAD, 1);

+        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getterCallback", "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;");

+        mv.visitVarInsn(ASTORE, 2);

+

+        mv.visitVarInsn(ALOAD, 2);

+        mv.visitTypeInsn(CHECKCAST, internalType);

+        mv.visitVarInsn(ASTORE, 3);

+

+        Label l3a = new Label();

+        mv.visitLabel(l3a);

+

+        mv.visitVarInsn(ALOAD, 1);

+        Label l4a = new Label();

+        mv.visitJumpInsn(IFNULL, l4a);

+        mv.visitVarInsn(ALOAD, 1);

+        mv.visitVarInsn(ALOAD, 3);

+        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z");

+

+        Label l5a = new Label();

+        mv.visitJumpInsn(IFNE, l5a);

+        mv.visitLabel(l4a);

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitVarInsn(ALOAD, 3);

+        mv.visitMethodInsn(INVOKEVIRTUAL, m_owner, "_set" + name, "(" + internalType + ")V");

+        mv.visitLabel(l5a);

+

+        mv.visitVarInsn(ALOAD, 3);

+        mv.visitInsn(ARETURN);

+

+        // End

+        mv.visitMaxs(0, 0);

+        mv.visitEnd();

+    }

+

+    /**

+     * Create the getter for a field.

+     * @param name : field of the dependency

+     * @param desc : description of the getter method

+     * @param type : type to return

+     */

+    private void createSimpleGetter(String name, String desc, Type type) {

+

+        String methodName = "_get" + name;

+        MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, methodName, desc, null, null);

+

+        switch (type.getSort()) {

+            case Type.BOOLEAN:

+            case Type.CHAR:

+            case Type.BYTE:

+            case Type.SHORT:

+            case Type.INT:

+

+                String internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];

+                String boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];

+                String unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];

+

+                Label l0 = new Label();

+                mv.visitLabel(l0);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, "_F" + name, "Z");

+                Label l1 = new Label();

+                mv.visitJumpInsn(IFNE, l1);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);

+                mv.visitInsn(IRETURN);

+

+                mv.visitLabel(l1);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);

+                mv.visitVarInsn(type.getOpcode(ISTORE), 1);

+

+                mv.visitTypeInsn(NEW, boxingType);

+                mv.visitInsn(DUP);

+                mv.visitVarInsn(type.getOpcode(ILOAD), 1);

+                mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V");

+                mv.visitVarInsn(ASTORE, 2);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");

+                mv.visitLdcInsn(name);

+                mv.visitVarInsn(ALOAD, 2);

+                mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getterCallback", "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;");

+                mv.visitVarInsn(ASTORE, 3);

+

+                mv.visitVarInsn(ALOAD, 3);

+                mv.visitTypeInsn(CHECKCAST, boxingType);

+                mv.visitVarInsn(ASTORE, 4);

+

+                mv.visitVarInsn(ALOAD, 4);

+                mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName);

+                mv.visitVarInsn(type.getOpcode(ISTORE), 5);

+

+                Label l5 = new Label();

+                mv.visitLabel(l5);

+

+                mv.visitVarInsn(type.getOpcode(ILOAD), 1);

+                mv.visitVarInsn(type.getOpcode(ILOAD), 5);

+                Label l6 = new Label();

+                mv.visitJumpInsn(type.getOpcode(IF_ICMPEQ), l6);

+

+                Label l7 = new Label();

+                mv.visitLabel(l7);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitVarInsn(type.getOpcode(ILOAD), 5);

+                mv.visitMethodInsn(INVOKEVIRTUAL, m_owner, "_set" + name, "(" + internalName + ")V");

+                mv.visitLabel(l6);

+

+                mv.visitVarInsn(type.getOpcode(ILOAD), 5);

+                mv.visitInsn(type.getOpcode(IRETURN));

+                break;

+

+            case Type.LONG:

+                internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];

+                boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];

+                unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];

+

+                Label l00 = new Label();

+                mv.visitLabel(l00);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, "_F" + name, "Z");

+                Label l10 = new Label();

+                mv.visitJumpInsn(IFNE, l10);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);

+                mv.visitInsn(LRETURN);

+                mv.visitLabel(l10);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);

+                mv.visitVarInsn(LSTORE, 1);

+

+                mv.visitTypeInsn(NEW, boxingType);

+                mv.visitInsn(DUP);

+                mv.visitVarInsn(LLOAD, 1);

+                mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V");

+                mv.visitVarInsn(ASTORE, 3); // Double Space

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");

+                mv.visitLdcInsn(name);

+                mv.visitVarInsn(ALOAD, 3);

+                mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getterCallback", "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;");

+                mv.visitVarInsn(ASTORE, 4);

+

+                mv.visitVarInsn(ALOAD, 4);

+                mv.visitTypeInsn(CHECKCAST, boxingType);

+                mv.visitVarInsn(ASTORE, 5);

+

+                mv.visitVarInsn(ALOAD, 5);

+                mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName);

+                mv.visitVarInsn(LSTORE, 6);

+

+                l5 = new Label();

+                mv.visitLabel(l5);

+

+                mv.visitVarInsn(LLOAD, 1);

+                mv.visitVarInsn(LLOAD, 6);

+                mv.visitInsn(LCMP);

+                l6 = new Label();

+                mv.visitJumpInsn(IFEQ, l6);

+

+                l7 = new Label();

+                mv.visitLabel(l7);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitVarInsn(LLOAD, 6);

+                mv.visitMethodInsn(INVOKEVIRTUAL, m_owner, "_set" + name, "(" + internalName + ")V");

+                mv.visitLabel(l6);

+

+                mv.visitVarInsn(LLOAD, 6);

+                mv.visitInsn(LRETURN);

+

+                break;

+

+            case Type.DOUBLE:

+                internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];

+                boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];

+                unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];

+

+                Label l01 = new Label();

+                mv.visitLabel(l01);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, "_F" + name, "Z");

+                Label l11 = new Label();

+                mv.visitJumpInsn(IFNE, l11);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);

+                mv.visitInsn(DRETURN);

+                mv.visitLabel(l11);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);

+                mv.visitVarInsn(DSTORE, 1);

+

+                mv.visitTypeInsn(NEW, boxingType);

+                mv.visitInsn(DUP);

+                mv.visitVarInsn(DLOAD, 1);

+                mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V");

+                mv.visitVarInsn(ASTORE, 3); // Double Space

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");

+                mv.visitLdcInsn(name);

+                mv.visitVarInsn(ALOAD, 3);

+                mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getterCallback", "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;");

+                mv.visitVarInsn(ASTORE, 4);

+

+                mv.visitVarInsn(ALOAD, 4);

+                mv.visitTypeInsn(CHECKCAST, boxingType);

+                mv.visitVarInsn(ASTORE, 5);

+

+                mv.visitVarInsn(ALOAD, 5);

+                mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName);

+                mv.visitVarInsn(DSTORE, 6);

+

+                l5 = new Label();

+                mv.visitLabel(l5);

+

+                mv.visitVarInsn(DLOAD, 1);

+                mv.visitVarInsn(DLOAD, 6);

+                mv.visitInsn(DCMPL);

+                l6 = new Label();

+                mv.visitJumpInsn(IFEQ, l6);

+

+                l7 = new Label();

+                mv.visitLabel(l7);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitVarInsn(DLOAD, 6);

+                mv.visitMethodInsn(INVOKEVIRTUAL, m_owner, "_set" + name, "(" + internalName + ")V");

+                mv.visitLabel(l6);

+

+                mv.visitVarInsn(DLOAD, 6);

+                mv.visitInsn(DRETURN);

+

+                break;

+

+            case Type.FLOAT:

+                internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];

+                boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];

+                unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];

+

+                Label l02 = new Label();

+                mv.visitLabel(l02);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, "_F" + name, "Z");

+                Label l12 = new Label();

+                mv.visitJumpInsn(IFNE, l12);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);

+                mv.visitInsn(FRETURN);

+                mv.visitLabel(l12);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);

+                mv.visitVarInsn(FSTORE, 1);

+

+                mv.visitTypeInsn(NEW, boxingType);

+                mv.visitInsn(DUP);

+                mv.visitVarInsn(FLOAD, 1);

+                mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V");

+                mv.visitVarInsn(ASTORE, 2); // One Space

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");

+                mv.visitLdcInsn(name);

+                mv.visitVarInsn(ALOAD, 2);

+                mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getterCallback", "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;");

+                mv.visitVarInsn(ASTORE, 3);

+

+                mv.visitVarInsn(ALOAD, 3);

+                mv.visitTypeInsn(CHECKCAST, boxingType);

+                mv.visitVarInsn(ASTORE, 4);

+

+                mv.visitVarInsn(ALOAD, 4);

+                mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName);

+                mv.visitVarInsn(FSTORE, 5);

+

+                l5 = new Label();

+                mv.visitLabel(l5);

+

+                mv.visitVarInsn(FLOAD, 1);

+                mv.visitVarInsn(FLOAD, 5);

+                mv.visitInsn(FCMPL);

+                l6 = new Label();

+                mv.visitJumpInsn(IFEQ, l6);

+

+                l7 = new Label();

+                mv.visitLabel(l7);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitVarInsn(FLOAD, 5);

+                mv.visitMethodInsn(INVOKEVIRTUAL, m_owner, "_set" + name, "(" + internalName + ")V");

+                mv.visitLabel(l6);

+

+                mv.visitVarInsn(FLOAD, 5);

+                mv.visitInsn(FRETURN);

+

+                break;

+

+            case Type.OBJECT:

+

+                Label l03 = new Label();

+                mv.visitLabel(l03);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, "_F" + name, "Z");

+                Label l13 = new Label();

+                mv.visitJumpInsn(IFNE, l13);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, name, "L" + type.getInternalName() + ";");

+                mv.visitInsn(ARETURN);

+                mv.visitLabel(l13);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, name, "L" + type.getInternalName() + ";");

+                mv.visitVarInsn(ASTORE, 1);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");

+                mv.visitLdcInsn(name);

+                mv.visitVarInsn(ALOAD, 1);

+                mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getterCallback", "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;");

+                mv.visitVarInsn(ASTORE, 2);

+

+                mv.visitVarInsn(ALOAD, 2);

+                mv.visitTypeInsn(CHECKCAST, type.getInternalName());

+                mv.visitVarInsn(ASTORE, 3);

+

+                Label l3b = new Label();

+                mv.visitLabel(l3b);

+

+                mv.visitVarInsn(ALOAD, 1);

+                Label l4b = new Label();

+                mv.visitJumpInsn(IFNULL, l4b);

+                mv.visitVarInsn(ALOAD, 1);

+                mv.visitVarInsn(ALOAD, 3);

+                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z");

+

+                Label l5b = new Label();

+                mv.visitJumpInsn(IFNE, l5b);

+                mv.visitLabel(l4b);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitVarInsn(ALOAD, 3);

+                mv.visitMethodInsn(INVOKEVIRTUAL, m_owner, "_set" + name, "(L" + type.getInternalName() + ";)V");

+                mv.visitLabel(l5b);

+

+                mv.visitVarInsn(ALOAD, 3);

+                mv.visitInsn(ARETURN);

+

+                break;

+

+            default:

+                ManipulationProperty.getLogger().log(Level.SEVERE, "Manipulation problem in " + m_owner + " : a type is not implemented : " + type);

+                break;

+        }

+

+        mv.visitMaxs(0, 0);

+        mv.visitEnd();

+    }

+

+    /**

+     * Create the setter method for one property. The name of the method is _set+name of the field

+     * 

+     * @param name :

+     *            name of the field representing a property

+     * @param desc :

+     *            description of the setter method

+     * @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);

+

+        switch (type.getSort()) {

+            case Type.BOOLEAN:

+            case Type.CHAR:

+            case Type.BYTE:

+            case Type.SHORT:

+            case Type.INT:

+            case Type.FLOAT:

+                String internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];

+                String boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitVarInsn(type.getOpcode(ILOAD), 1);

+                mv.visitFieldInsn(PUTFIELD, m_owner, name, internalName);

+                Label l1 = new Label();

+                mv.visitLabel(l1);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, "_F" + name, "Z");

+                Label l22 = new Label();

+                mv.visitJumpInsn(IFNE, l22);

+                mv.visitInsn(RETURN);

+                mv.visitLabel(l22);

+

+                mv.visitTypeInsn(NEW, boxingType);

+                mv.visitInsn(DUP);

+                mv.visitVarInsn(type.getOpcode(ILOAD), 1);

+                mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V");

+                mv.visitVarInsn(ASTORE, 2);

+

+                Label l2 = new Label();

+                mv.visitLabel(l2);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");

+                mv.visitLdcInsn(name);

+                mv.visitVarInsn(ALOAD, 2);

+                mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "setterCallback", "(Ljava/lang/String;Ljava/lang/Object;)V");

+

+                Label l3 = new Label();

+                mv.visitLabel(l3);

+                mv.visitInsn(RETURN);

+                break;

+

+            case Type.LONG:

+            case Type.DOUBLE:

+                internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];

+                boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitVarInsn(type.getOpcode(ILOAD), 1);

+                mv.visitFieldInsn(PUTFIELD, m_owner, name, internalName);

+                l1 = new Label();

+                mv.visitLabel(l1);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, "_F" + name, "Z");

+                Label l23 = new Label();

+                mv.visitJumpInsn(IFNE, l23);

+                mv.visitInsn(RETURN);

+                mv.visitLabel(l23);

+

+                mv.visitTypeInsn(NEW, boxingType);

+                mv.visitInsn(DUP);

+                mv.visitVarInsn(type.getOpcode(ILOAD), 1);

+                mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V");

+                mv.visitVarInsn(ASTORE, 3); // Double space

+

+                l2 = new Label();

+                mv.visitLabel(l2);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");

+                mv.visitLdcInsn(name);

+                mv.visitVarInsn(ALOAD, 3);

+                mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "setterCallback", "(Ljava/lang/String;Ljava/lang/Object;)V");

+

+                l3 = new Label();

+                mv.visitLabel(l3);

+                mv.visitInsn(RETURN);

+                break;

+

+            case Type.OBJECT:

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitVarInsn(ALOAD, 1);

+                mv.visitFieldInsn(PUTFIELD, m_owner, name, "L" + type.getInternalName() + ";");

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, "_F" + name, "Z");

+                Label l24 = new Label();

+                mv.visitJumpInsn(IFNE, l24);

+                mv.visitInsn(RETURN);

+                mv.visitLabel(l24);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");

+                mv.visitLdcInsn(name);

+                mv.visitVarInsn(ALOAD, 1);

+                mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "setterCallback", "(Ljava/lang/String;Ljava/lang/Object;)V");

+

+                mv.visitInsn(RETURN);

+                break;

+            default:

+                ManipulationProperty.getLogger().log(Level.SEVERE, "Manipulation Error : Cannot create the setter method for the field : " + name + " (" + type + ")");

+                break;

+        }

+

+        mv.visitMaxs(0, 0);

+        mv.visitEnd();

+    }

+}

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ManipulationProperty.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ManipulationProperty.java
new file mode 100644
index 0000000..5af9933
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ManipulationProperty.java
@@ -0,0 +1,84 @@
+/* 

+ * 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.logging.Level;

+import java.util.logging.Logger;

+

+/**

+ * Store properties for the manipulation process.

+ * 

+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>

+ * 

+ */

+public class ManipulationProperty {

+

+    /**

+     * Manipulator logger.

+     */

+    private static Logger m_logger;

+

+    /**

+     * Default logger level.

+     */

+    private static Level m_logLevel = Level.WARNING;

+

+    /**

+     * Get the manipulator logger.

+     * @return the logger used by the manipulator.

+     */

+    public static Logger getLogger() {

+        if (m_logger == null) {

+            String name = "org.apache.felix.ipojo.manipulator";

+            m_logger = Logger.getLogger(name);

+            m_logger.setLevel(m_logLevel);

+        }

+        return m_logger;

+    }

+

+    /**

+     * iPOJO Package name.

+     */

+    protected static final String IPOJO_PACKAGE_NAME = "org.apache.felix.ipojo";

+

+    /**

+     * Activator internal package name.

+     */

+    protected static final String IPOJO_INTERNAL_PACKAGE_NAME = "org/apache/felix/ipojo/";

+

+    /**

+     * Ipojo internal package name for internal descriptor.

+     */

+    protected static final String IPOJO_INTERNAL_DESCRIPTOR = "L" + IPOJO_INTERNAL_PACKAGE_NAME;

+

+    /**

+     * Helper array for bytecode manipulation of primitive type.

+     */

+    protected static final String[][] PRIMITIVE_BOXING_INFORMATION = new String[][] { { "V", "ILLEGAL", "ILLEGAL" }, // Void type [0]

+        { "Z", "java/lang/Boolean", "booleanValue" }, // boolean [1]

+        { "C", "java/lang/Character", "charValue" }, // char [2]

+        { "B", "java/lang/Byte", "byteValue" }, // byte [3]

+        { "S", "java/lang/Short", "shortValue" }, // short [4]

+        { "I", "java/lang/Integer", "intValue" }, // int [5]

+        { "F", "java/lang/Float", "floatValue" }, // float [6]

+        { "J", "java/lang/Long", "longValue" }, // long [7]

+        { "D", "java/lang/Double", "doubleValue" } // double [8]

+    };

+

+}

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
new file mode 100644
index 0000000..4063343
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
@@ -0,0 +1,241 @@
+/* 

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ *

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+package org.apache.felix.ipojo.manipulation;

+

+import java.io.ByteArrayInputStream;

+import java.io.File;

+import java.io.FileOutputStream;

+import java.io.IOException;

+import java.io.InputStream;

+import java.net.URL;

+import java.util.ArrayList;

+import java.util.HashMap;

+import java.util.Iterator;

+import java.util.List;

+import java.util.logging.Level;

+

+import org.apache.felix.ipojo.metadata.Attribute;

+import org.apache.felix.ipojo.metadata.Element;

+import org.objectweb.asm.ClassReader;

+import org.objectweb.asm.ClassWriter;

+

+/**

+ * iPOJO Bytecode Manipulator.

+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>

+ * 

+ */

+public class Manipulator {

+    /**

+     * Store the visited fields : [name fo the field, type of the field].

+     */

+    private HashMap m_fields = new HashMap();

+

+    /**

+     * Store the interface implemented by the class.

+     */

+    private String[] m_interfaces = new String[0];

+

+    /**

+     * Store the methods list.

+     */

+    private List m_methods = new ArrayList();

+

+    /**

+     * Manipulate the class.

+     * 

+     * @param name : The name of the class

+     * @param outputDirectory : output directory where the class if stored.

+     * @return true if the class is correctly manipulated.

+     * @throws Exception : throwed if the manipulation failed.

+     */

+    public boolean manipulate(String name, File outputDirectory) throws Exception {

+

+        // Init field, itfs and methods

+        m_fields = new HashMap();

+        m_interfaces = new String[0];

+        m_methods = new ArrayList();

+

+        // gets an input stream to read the bytecode of the class

+        String path = outputDirectory + "/" + name.replace('.', '/') + ".class";

+        File clazz = new File(path);

+

+        if (!clazz.exists()) {

+            return false;

+        }

+

+        URL url = clazz.toURI().toURL();

+

+        // if (url == null) { throw new ClassNotFoundException(name); }

+        ManipulationProperty.getLogger().log(Level.INFO, "Manipulate the class file : " + clazz.getAbsolutePath());

+

+        InputStream is1 = url.openStream();

+

+        // First check if the class is already manipulated :

+        ClassReader ckReader = new ClassReader(is1);

+        ClassChecker ck = new ClassChecker();

+        ckReader.accept(ck, ClassReader.SKIP_FRAMES);

+        is1.close();

+

+        m_fields = ck.getFields();

+

+        // Get interface and remove POJO interface is presents

+        String[] its = ck.getInterfaces();

+        ArrayList l = new ArrayList();

+        for (int i = 0; i < its.length; i++) {

+            l.add(its[i]);

+        }

+        l.remove("org/apache/felix/ipojo/Pojo");

+

+        m_interfaces = new String[l.size()];

+        for (int i = 0; i < m_interfaces.length; i++) {

+            m_interfaces[i] = ((String) l.get(i)).replace('/', '.');

+        }

+

+        // Get the method list

+        // Remove iPOJO methods

+        for (int i = 0; i < ck.getMethods().size(); i++) {

+            MethodDescriptor method = (MethodDescriptor) ck.getMethods().get(i);

+            if (!(method.getName().startsWith("_get") || // Avoid getter method

+                    method.getName().startsWith("_set") || // Avoid setter method

+                    method.getName().equals("_setComponentManager") || // Avoid the set method

+                    method.getName().equals("getComponentInstance"))) { // Avoid the getComponentInstance method

+                System.err.println(" Add the method : " + method);

+                m_methods.add(method);

+            }

+        }

+

+        if (!ck.isalreadyManipulated()) {

+

+            // Manipulation ->

+            // Add the _setComponentManager method

+            // Instrument all fields

+            InputStream is2 = url.openStream();

+            ClassReader cr0 = new ClassReader(is2);

+            ClassWriter cw0 = new ClassWriter(ClassWriter.COMPUTE_MAXS);

+            PojoAdapter preprocess = new PojoAdapter(cw0);

+            cr0.accept(preprocess, ClassReader.SKIP_FRAMES);

+            is2.close();

+

+            try {

+                FileOutputStream fos = new FileOutputStream(clazz);

+

+                fos.write(cw0.toByteArray());

+

+                fos.close();

+                ManipulationProperty.getLogger().log(Level.INFO, "Put the file " + clazz.getAbsolutePath() + " in the jar file");

+            } catch (Exception e) {

+                System.err.println("Problem to write the adapted class on the file system " + " [ " + clazz.getAbsolutePath() + " ] " + e.getMessage());

+            }

+        }

+        // The file is in the bundle

+        return true;

+    }

+

+    /**

+     * Manipulate the given byte array.

+     * 

+     * @param origin :

+     *            original class.

+     * @return the manipulated class.

+     * @throws IOException :

+     *             if an error occurs during the manipulation.

+     */

+    public byte[] manipulate(byte[] origin) throws IOException {

+        InputStream is1 = new ByteArrayInputStream(origin);

+

+        // First check if the class is already manipulated :

+        ClassReader ckReader = new ClassReader(is1);

+        ClassChecker ck = new ClassChecker();

+        ckReader.accept(ck, ClassReader.SKIP_FRAMES);

+        is1.close();

+

+        m_fields = ck.getFields();

+

+        // Get interface and remove POJO interface is presents

+        String[] its = ck.getInterfaces();

+        ArrayList l = new ArrayList();

+        for (int i = 0; i < its.length; i++) {

+            l.add(its[i]);

+        }

+        l.remove("org/apache/felix/ipojo/Pojo");

+

+        m_interfaces = new String[l.size()];

+        for (int i = 0; i < m_interfaces.length; i++) {

+            m_interfaces[i] = ((String) l.get(i)).replace('/', '.');

+        }

+

+        for (int i = 0; i < ck.getMethods().size(); i++) {

+            MethodDescriptor method = (MethodDescriptor) ck.getMethods().get(i);

+            if (!(method.getName().startsWith("_get") || // Avoid getter method

+                    method.getName().startsWith("_set") || // Avoid setter method

+                    method.getName().equals("_setComponentManager") || // Avoid the set method

+                    method.getName().equals("getComponentInstance"))) { // Avoid the getComponentInstance method

+                m_methods.add(method);

+            }

+        }

+

+        ClassWriter finalWriter = null;

+        if (!ck.isalreadyManipulated()) {

+            // Manipulation ->

+            // Add the _setComponentManager method

+            // Instrument all fields

+            InputStream is2 = new ByteArrayInputStream(origin);

+            ClassReader cr0 = new ClassReader(is2);

+            ClassWriter cw0 = new ClassWriter(ClassWriter.COMPUTE_MAXS);

+            PojoAdapter preprocess = new PojoAdapter(cw0);

+            cr0.accept(preprocess, ClassReader.SKIP_FRAMES);

+            is2.close();

+            finalWriter = cw0;

+        }

+        // The file is in the bundle

+        return finalWriter.toByteArray();

+    }

+

+    /**

+     * Compute component type manipulation metadata.

+     * @return the manipulation metadata of the class.

+     */

+    public Element getManipulationMetadata() {

+        Element elem = new Element("Manipulation", "");

+        for (int j = 0; j < m_interfaces.length; j++) {

+            Element itf = new Element("Interface", "");

+            Attribute att = new Attribute("name", m_interfaces[j]);

+            itf.addAttribute(att);

+            elem.addElement(itf);

+        }

+        for (Iterator it = m_fields.keySet().iterator(); it.hasNext();) {

+            Element field = new Element("Field", "");

+            String name = (String) it.next();

+            String type = (String) m_fields.get(name);

+            Attribute attName = new Attribute("name", name);

+            Attribute attType = new Attribute("type", type);

+            field.addAttribute(attName);

+            field.addAttribute(attType);

+            elem.addElement(field);

+        }

+

+        for (int j = 0; j < m_methods.size(); j++) {

+            MethodDescriptor method = (MethodDescriptor) m_methods.get(j);

+            elem.addElement(method.getElement());

+        }

+

+        return elem;

+    }

+

+}

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java
new file mode 100644
index 0000000..d240be6
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java
@@ -0,0 +1,174 @@
+/* 

+ * 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.logging.Level;

+

+import org.objectweb.asm.Label;

+import org.objectweb.asm.MethodVisitor;

+import org.objectweb.asm.Opcodes;

+import org.objectweb.asm.Type;

+import org.objectweb.asm.commons.AdviceAdapter;

+

+/**

+ * Insert code calling callbacks at the entry and before the exit of a method.

+ * Moreover it replaces all GETFIELD and SETFIELD by getter and setter invocation.

+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>

+ */

+public class MethodCodeAdapter extends AdviceAdapter implements Opcodes {

+

+    /**

+     * The owner class of the field. m_owner : String

+     */

+    private String m_owner;

+

+    /**

+     * Name of the method.

+     */

+    private String m_name;

+

+    /**

+     * MethodCodeAdapter constructor. 

+     * @param mv : MethodVisitor

+     * @param owner : Name of the class

+     * @param access : Method acess

+     * @param name : Method name

+     * @param desc : Method descriptor

+     */

+    public MethodCodeAdapter(final MethodVisitor mv, final String owner, int access, String name, String desc) {

+        super(mv, access, name, desc);

+        m_owner = owner;

+        m_name = name;

+    }

+

+    /**

+     * Visit an instruction modifying a method (GETFIELD/PUTFIELD).

+     * @see org.objectweb.asm.MethodVisitor#visitFieldInsn(int, String, String, String)

+     * @param opcode : visited operation code

+     * @param owner : owner of the field

+     * @param name : name of the field

+     * @param desc : decriptor of the field

+     */

+    public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) {

+        if (owner.equals(m_owner)) {

+            if (opcode == GETFIELD) {

+                ManipulationProperty.getLogger().log(Level.INFO, "Manipulate a GETFIELD on : " + name);

+                String gDesc = "()" + desc;

+                visitMethodInsn(INVOKEVIRTUAL, owner, "_get" + name, gDesc);

+                return;

+            } else if (opcode == PUTFIELD) {

+                ManipulationProperty.getLogger().log(Level.INFO, "Manipulate a PUTFIELD on : " + name);

+                String sDesc = "(" + desc + ")V";

+                visitMethodInsn(INVOKESPECIAL, owner, "_set" + name, sDesc);

+                return;

+            }

+        }

+        super.visitFieldInsn(opcode, owner, name, desc);

+    }

+

+    /**

+     * Method injecting call at the entry of each method.

+     * @see org.objectweb.asm.commons.AdviceAdapter#onMethodEnter()

+     */

+    protected void onMethodEnter() {

+        Type[] args = Type.getArgumentTypes(methodDesc);

+        String name = m_name;

+        

+        for (int i = 0; i < args.length; i++) {

+            String cn = args[i].getClassName();

+            if (cn.endsWith("[]")) {

+                cn = cn.replace("[]", "$");

+            }

+            cn = cn.replace(".", "_");

+            name += cn;

+        }

+

+        String flag = "_M" + name;

+

+        Label l0 = new Label();

+        mv.visitLabel(l0);

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, flag, "Z");

+        Label l1 = new Label();

+        mv.visitJumpInsn(IFEQ, l1);

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");

+        mv.visitLdcInsn(name);

+        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "entryCallback", "(Ljava/lang/String;)V");

+        mv.visitLabel(l1);

+    }

+

+    /**

+     * Method injecting call at the exit of each method.

+     * @param opcode : returned opcode (ARETURN, IRETURN, ATHROW ...)

+     * @see org.objectweb.asm.commons.AdviceAdapter#onMethodExit(int)

+     */

+    protected void onMethodExit(int opcode) {

+        Type[] args = Type.getArgumentTypes(methodDesc);

+        String name = m_name;

+       

+        for (int i = 0; i < args.length; i++) {

+            String cn = args[i].getClassName();

+            if (cn.endsWith("[]")) {

+                cn = cn.replace("[]", "$");

+            }

+            cn = cn.replace(".", "_");

+            name += cn;

+        }

+

+        String flag = "_M" + name;

+

+        int local = newLocal(Type.getType(Object.class));

+        if (opcode == RETURN) {

+            visitInsn(ACONST_NULL);

+        } else if (opcode != ARETURN && opcode != ATHROW) {

+            box(Type.getReturnType(this.methodDesc));

+        }

+        

+        mv.visitVarInsn(ASTORE, local);

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, flag, "Z");

+        Label l5 = new Label();

+        mv.visitJumpInsn(IFEQ, l5);

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");

+        mv.visitLdcInsn(name);

+        mv.visitVarInsn(ALOAD, local);

+        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "exitCallback", "(Ljava/lang/String;Ljava/lang/Object;)V");

+

+        mv.visitLabel(l5);

+        if (opcode == ARETURN || opcode == ATHROW) {

+            mv.visitVarInsn(ALOAD, local);

+        } else if (opcode != RETURN) {

+            mv.visitVarInsn(ALOAD, local);

+            unbox(Type.getReturnType(this.methodDesc));

+        }

+    }

+

+    /**

+     * Compute mx local and max stack size.

+     * @param maxStack : new stack size.

+     * @param maxLocals : max local (do not modified, super will update it automatically).

+     * @see org.objectweb.asm.commons.LocalVariablesSorter#visitMaxs(int, int)

+     */

+    public void visitMaxs(int maxStack, int maxLocals) {

+        super.visitMaxs(maxStack + 1, maxLocals);

+    }

+

+}

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java
new file mode 100644
index 0000000..184b2f2
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java
@@ -0,0 +1,129 @@
+/* 

+ * 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 org.apache.felix.ipojo.metadata.Attribute;

+import org.apache.felix.ipojo.metadata.Element;

+import org.objectweb.asm.Type;

+

+/**

+ * Method Descriptor describe a method.

+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>

+ */

+public class MethodDescriptor {

+

+    /**

+     * Method name.

+     */

+    private String m_name;

+

+    /**

+     * Returned type.

+     */

+    private String m_returnType;

+

+    /**

+     * Argument types.

+     */

+    private String[] m_arguments;

+

+    /**

+     * Constructor.

+     * @param name : name of the method.

+     * @param desc : descriptor of the method.

+     */

+    public MethodDescriptor(String name, String desc) {

+        m_name = name;

+        Type ret = Type.getReturnType(desc);

+        Type[] args = Type.getArgumentTypes(desc);

+

+        m_returnType = getType(ret);

+        m_arguments = new String[args.length];

+        for (int i = 0; i < args.length; i++) {

+            m_arguments[i] = getType(args[i]);

+        }

+    }

+

+    /**

+     * Compute method manipulation metadata.

+     * @return the element containing metadata about this method.

+     */

+    public Element getElement() {

+        Element method = new Element("method", "");

+        method.addAttribute(new Attribute("name", m_name));

+

+        // Add return

+        if (!m_returnType.equals("void")) {

+            method.addAttribute(new Attribute("return", m_returnType));

+        }

+

+        // Add arguments

+        if (m_arguments.length > 0) {

+            String args = "{";

+            args += m_arguments[0];

+            for (int i = 1; i < m_arguments.length; i++) {

+                args += "," + m_arguments[i];

+            }

+            args += "}";

+            method.addAttribute(new Attribute("arguments", args));

+        }

+

+        return method;

+    }

+

+    /**

+     * Get the iPOJO internal type for the given type.

+     * @param type : type.

+     * @return the iPOJO internal type.

+     */

+    private String getType(Type type) {

+        switch (type.getSort()) {

+            case Type.ARRAY:

+                Type elemType = type.getElementType();

+                return getType(elemType) + "[]";

+            case Type.BOOLEAN:

+                return "boolean";

+            case Type.BYTE:

+                return "byte";

+            case Type.CHAR:

+                return "char";

+            case Type.DOUBLE:

+                return "double";

+            case Type.FLOAT:

+                return "float";

+            case Type.INT:

+                return "int";

+            case Type.LONG:

+                return "long";

+            case Type.OBJECT:

+                return type.getClassName();

+            case Type.SHORT:

+                return "short";

+            case Type.VOID:

+                return "void";

+            default:

+                return "unknown";

+        }

+    }

+

+    public String getName() {

+        return m_name;

+    }

+

+}

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/PojoAdapter.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/PojoAdapter.java
new file mode 100644
index 0000000..ad427cd
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/PojoAdapter.java
@@ -0,0 +1,362 @@
+/* 

+ * 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.ArrayList;

+import java.util.List;

+

+import org.objectweb.asm.AnnotationVisitor;

+import org.objectweb.asm.Attribute;

+import org.objectweb.asm.ClassAdapter;

+import org.objectweb.asm.ClassVisitor;

+import org.objectweb.asm.FieldVisitor;

+import org.objectweb.asm.Label;

+import org.objectweb.asm.MethodVisitor;

+import org.objectweb.asm.Opcodes;

+import org.objectweb.asm.Type;

+

+/**

+ * Manipulate a POJO class.

+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>

+ */

+public class PojoAdapter extends ClassAdapter implements Opcodes {

+

+    /**

+     * POJO interface.

+     */

+    private final String m_pojo = "org/apache/felix/ipojo/Pojo";

+

+    /**

+     * The owner. m_owner : String

+     */

+    private String m_owner;

+

+    /**

+     * Field list.

+     */

+    private List m_fields = new ArrayList();

+

+    /**

+     * Method list.

+     */

+    private List m_methods = new ArrayList();

+

+    /**

+     * Getter/Setter methods creator.

+     */

+    FieldAdapter m_getterSetterCreator = new FieldAdapter(cv);

+

+    /**

+     * Constructor.

+     * @param arg0 : class adapter on which delegate.

+     */

+    public PojoAdapter(ClassVisitor arg0) {

+        super(arg0);

+    }

+

+    /**

+     * Start visiting a class.

+     * Initialize the getter/setter generator, add the _cm field, add the pojo interface.

+     * @param version : class version

+     * @param access : class access

+     * @param name : class name 

+     * @param signature : class signature

+     * @param superName : class super class

+     * @param interfaces : implemented interfaces

+     * @see org.objectweb.asm.ClassAdapter#visit(int, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])

+     */

+    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {

+        m_owner = name;

+        m_getterSetterCreator.visit(version, access, name, signature, superName, interfaces);

+        addCMField();

+        addPOJOInterface(version, access, name, signature, superName, interfaces);

+    }

+

+    /**

+     * Visit an annotation.

+     * @param desc : annotation descriptor.

+     * @param visible : is the annotation visible at runtime.

+     * @return the annotation visitor.

+     * @see org.objectweb.asm.ClassAdapter#visitAnnotation(java.lang.String, boolean)

+     */

+    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {

+        return super.visitAnnotation(desc, visible);

+    }

+

+    /**

+     * Visit an attribute.

+     * @param attr : visited attribute

+     * @see org.objectweb.asm.ClassAdapter#visitAttribute(org.objectweb.asm.Attribute)

+     */

+    public void visitAttribute(Attribute attr) {

+        super.visitAttribute(attr);

+    }

+

+    /**

+     * Visit end.

+     * Create helper methods.

+     * @see org.objectweb.asm.ClassAdapter#visitEnd()

+     */

+    public void visitEnd() {

+        // Create the _cmSetter(ComponentManager cm) method

+        createComponentManagerSetter();

+

+        // Add the getComponentInstance

+        createGetComponentInstanceMethod();

+

+        m_methods.clear();

+        m_fields.clear();

+

+        cv.visitEnd();

+    }

+

+    /**

+     * Visit a field.

+     * Call the adapter generating getter and setter methods.

+     * @param access : field acess.

+     * @param name : field name

+     * @param desc : field descriptor

+     * @param signature : field signature

+     * @param value : field value (static field only)

+     * @return the field visitor.

+     * @see org.objectweb.asm.ClassAdapter#visitField(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object)

+     */

+    public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {

+        // Add the field to the list.

+        if ((access & ACC_STATIC) == 0) {

+            m_fields.add(name);

+            addFlagField(name);

+            m_getterSetterCreator.visitField(access, name, desc, signature, value);

+        }

+

+        return super.visitField(access, name, desc, signature, value);

+    }

+

+    /**

+     * Visit an inner class.

+     * @param name : class name

+     * @param outerName : outer name

+     * @param innerName : inner name

+     * @param access : class access

+     * @see org.objectweb.asm.ClassAdapter#visitInnerClass(java.lang.String, java.lang.String, java.lang.String, int)

+     */

+    public void visitInnerClass(String name, String outerName, String innerName, int access) {

+        super.visitInnerClass(name, outerName, innerName, access);

+    }

+

+    /**

+     * Visit a method.

+     * Manipulate constructor and methods. Does nothing with clinit and class$

+     * @param access : method acess

+     * @param name : method name

+     * @param desc : method descriptor

+     * @param signature : method signature

+     * @param exceptions : method exceptions

+     * @return the Method Visitor.

+     * @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) {

+        if (name.equals("<clinit>") || name.equals("class$")) {

+            return super.visitMethod(access, name, desc, signature, exceptions);

+        }

+        if (name.equals("<init>")) {

+            // 1) change the constructor descriptor (add a component manager arg as first argument)

+            String newDesc = desc.substring(1);

+            newDesc = "(Lorg/apache/felix/ipojo/InstanceManager;" + newDesc;

+

+            // Insert the new constructor

+            MethodVisitor mv = super.visitMethod(ACC_PUBLIC, "<init>", newDesc, null, null);

+

+            if (mv == null) {

+                return null;

+            } else {

+                return new ConstructorCodeAdapter(mv, access, desc, m_owner);

+            }

+        } else {

+            Type[] args = Type.getArgumentTypes(desc);

+            String id = name;

+            for (int i = 0; i < args.length; i++) {

+                String cn = args[i].getClassName();

+                if (cn.endsWith("[]")) {

+                    cn = cn.replace("[]", "$");

+                }

+                cn = cn.replace(".", "_");

+                id += cn;

+            }

+

+            String flag = "_M" + id;

+            m_methods.add(id);

+

+            FieldVisitor flagField = cv.visitField(Opcodes.ACC_PRIVATE, flag, "Z", null, null);

+            if (flagField != null) {

+                flagField.visitEnd();

+            }

+

+            MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);

+            return new MethodCodeAdapter(mv, m_owner, access, name, desc);

+        }

+    }

+

+    /**

+     * Visit an outer class.

+     * @param owner : class owner

+     * @param name : class name

+     * @param desc : class descriptor.

+     * @see org.objectweb.asm.ClassAdapter#visitOuterClass(java.lang.String, java.lang.String, java.lang.String)

+     */

+    public void visitOuterClass(String owner, String name, String desc) {

+        super.visitOuterClass(owner, name, desc);

+    }

+

+    /**

+     * Visit source.

+     * @param source : source

+     * @param debug : debug

+     * @see org.objectweb.asm.ClassAdapter#visitSource(java.lang.String, java.lang.String)

+     */

+    public void visitSource(String source, String debug) {

+        super.visitSource(source, debug);

+    }

+

+    /**

+     * Add the instance manager field (_cm).

+     */

+    private void addCMField() {

+        // Insert _cm field

+        FieldVisitor fv = super.visitField(ACC_PRIVATE, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;", null, null);

+        fv.visitEnd();

+    }

+

+    /**

+     * Add the POJO interface to the visited class.

+     * @param version : class version

+     * @param access : class access

+     * @param name : class name

+     * @param signature : class signature

+     * @param superName : super class

+     * @param interfaces : implemented interfaces.

+     */

+    private void addPOJOInterface(int version, int access, String name, String signature, String superName, String[] interfaces) {

+

+        // Add the POJO interface to the interface list

+        // Check that the POJO interface isnot already in the list

+        boolean found = false;

+        for (int i = 0; i < interfaces.length; i++) {

+            if (interfaces[i].equals(m_pojo)) {

+                found = true;

+            }

+        }

+        String[] itfs;

+        if (!found) {

+            itfs = new String[interfaces.length + 1];

+            for (int i = 0; i < interfaces.length; i++) {

+                itfs[i] = interfaces[i];

+            }

+            itfs[interfaces.length] = m_pojo;

+        } else {

+            itfs = interfaces;

+        }

+

+        String str = "";

+        for (int i = 0; i < itfs.length; i++) {

+            str += itfs[i] + " ";

+        }

+

+        cv.visit(version, access, name, signature, superName, itfs);

+    }

+

+    /**

+     * Create the setter method for the _cm field.

+     */

+    private void createComponentManagerSetter() {

+        MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, "_setComponentManager", "(Lorg/apache/felix/ipojo/InstanceManager;)V", null, null);

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitVarInsn(ALOAD, 1);

+        mv.visitFieldInsn(PUTFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");

+        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getRegistredFields", "()Ljava/util/Set;");

+        mv.visitVarInsn(ASTORE, 2);

+

+        for (int i = 0; i < m_fields.size(); i++) {

+            String field = (String) m_fields.get(i);

+            mv.visitVarInsn(ALOAD, 2);

+            mv.visitLdcInsn(field);

+            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Set", "contains", "(Ljava/lang/Object;)Z");

+            Label l3 = new Label();

+            mv.visitJumpInsn(IFEQ, l3);

+            mv.visitVarInsn(ALOAD, 0);

+            mv.visitInsn(ICONST_1);

+            mv.visitFieldInsn(PUTFIELD, m_owner, "_F" + field, "Z");

+            mv.visitLabel(l3);

+        }

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");

+        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getRegistredMethods", "()Ljava/util/Set;");

+        mv.visitVarInsn(ASTORE, 2);

+

+        for (int i = 0; i < m_methods.size(); i++) {

+            String methodId = (String) m_methods.get(i);

+            mv.visitVarInsn(ALOAD, 2);

+            mv.visitLdcInsn(methodId);

+            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Set", "contains", "(Ljava/lang/Object;)Z");

+            Label l3 = new Label();

+            mv.visitJumpInsn(IFEQ, l3);

+            mv.visitVarInsn(ALOAD, 0);

+            mv.visitInsn(ICONST_1);

+            mv.visitFieldInsn(PUTFIELD, m_owner, "_M" + methodId, "Z");

+            mv.visitLabel(l3);

+        }

+

+        mv.visitInsn(RETURN);

+

+        mv.visitMaxs(0, 0);

+        mv.visitEnd();

+    }

+

+    /**

+     * Create the getComponentInstance method.

+     */

+    private void createGetComponentInstanceMethod() {

+        MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "getComponentInstance", "()Lorg/apache/felix/ipojo/ComponentInstance;", null, null);

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");

+        mv.visitInsn(ARETURN);

+

+        mv.visitMaxs(0, 0);

+        mv.visitEnd();

+    }

+

+    /**

+     * Add the flag field.

+     * @param name : name of the field

+     */

+    private void addFlagField(String name) {

+        // Add the flag field

+        FieldVisitor flag = cv.visitField(Opcodes.ACC_PRIVATE, "_F" + name, "Z", null, null);

+        if (flag != null) {

+            flag.visitEnd();

+        }

+    }

+

+}

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
new file mode 100644
index 0000000..0b34c5b
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
@@ -0,0 +1,610 @@
+/* 

+ * 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.manipulator;

+

+import java.io.File;

+import java.io.FileNotFoundException;

+import java.io.FileOutputStream;

+import java.io.IOException;

+import java.io.InputStream;

+import java.net.MalformedURLException;

+import java.net.URL;

+import java.util.ArrayList;

+import java.util.Enumeration;

+import java.util.HashMap;

+import java.util.Iterator;

+import java.util.LinkedHashMap;

+import java.util.List;

+import java.util.Map;

+import java.util.TreeMap;

+import java.util.jar.Attributes;

+import java.util.jar.JarEntry;

+import java.util.jar.JarFile;

+import java.util.jar.JarOutputStream;

+import java.util.jar.Manifest;

+

+import org.apache.felix.ipojo.manipulation.Manipulator;

+import org.apache.felix.ipojo.metadata.Element;

+import org.apache.felix.ipojo.xml.parser.ParseException;

+import org.apache.felix.ipojo.xml.parser.XMLMetadataParser;

+import org.xml.sax.InputSource;

+import org.xml.sax.SAXException;

+import org.xml.sax.XMLReader;

+import org.xml.sax.helpers.XMLReaderFactory;

+

+/**

+ * Pojoization allows creating an iPOJO bundle from a "normal" bundle.  

+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>

+ */

+public class Pojoization {

+

+    /**

+     * List of component types.

+     */

+    private List m_components;

+

+    /**

+     * Metadata (in internal format).

+     */

+    private Element[] m_metadata;

+

+    /**

+     * Errors occured during the manipulation.

+     */

+    private List m_errors = new ArrayList();

+

+    /**

+     * Warnings occured during the manipulation.

+     */

+    private List m_warnings = new ArrayList();

+

+    /**

+     * Class map (jar entry, byte[]).

+     */

+    private HashMap m_classes = new HashMap();

+

+    /**

+     * Referendec packages by the composite.

+     */

+    private List m_referredPackages;

+

+    /**

+     * Add an error in the error list.

+     * @param mes : error message.

+     */

+    private void error(String mes) {

+        System.out.println("An error occurs during the pojoization : " + mes);

+        m_errors.add(mes);

+    }

+

+    /**

+     * Add a warning in the warning list.

+     * @param mes : warning message

+     */

+    public void warn(String mes) {

+        System.out.println("An warning occurs during the pojoization : " + mes);

+        m_warnings.add(mes);

+    }

+

+    public List getErrors() {

+        return m_errors;

+    }

+

+    /**

+     * Manipulate a normal bundle.

+     * It will create an iPOJO bundle based on the given metadata file.

+     * The original and final bundle must be different.

+     * @param in : original bundle.

+     * @param out : final bundle.

+     * @param metadataFile : iPOJO metadata file (XML). 

+     */

+    public void pojoization(File in, File out, File metadataFile) {

+        // Get the metadata.xml location

+        String path = metadataFile.getAbsolutePath();

+        if (!path.startsWith("/")) {

+            path = "/" + path;

+        }

+        m_metadata = parseXMLMetadata(path);

+

+        // Get the list of declared component

+        m_components = getDeclaredComponents(m_metadata);

+

+        // Start the manipulation

+        manipulation(in, out);

+

+        // Check that all declared components are manipulated

+        for (int i = 0; i < m_components.size(); i++) {

+            ComponentInfo ci = (ComponentInfo) m_components.get(i);

+            if (!ci.m_isManipulated) {

+                error("The component " + ci.m_classname + " is declared but not in the bundle");

+            }

+        }

+    }

+

+    /**

+     * Manipulate the Bundle.

+     * @param in : original bundle

+     * @param out : final bundle

+     */

+    private void manipulation(File in, File out) {

+        // Get a jar file from the given file

+        JarFile inputJar = null;

+        try {

+            inputJar = new JarFile(in);

+        } catch (IOException e) {

+            error("Cannot the input file is not a JarFile : " + in.getAbsolutePath());

+            return;

+        }

+

+        manipulateComponents(inputJar); // Manipulate classes

+        Manifest mf = doManifest(inputJar); // Compute the manifest

+

+        // Create a new Jar file

+        FileOutputStream fos = null;

+        JarOutputStream jos = null;

+        try {

+            fos = new FileOutputStream(out);

+            jos = new JarOutputStream(fos, mf);

+        } catch (FileNotFoundException e1) {

+            error("Cannot manipulate the Jar file : the file " + out.getAbsolutePath() + " not found");

+            return;

+        } catch (IOException e) {

+            error("Cannot manipulate the Jar file : cannot access to " + out.getAbsolutePath());

+            return;

+        }

+

+        try {

+            // Copy classes and resources

+            Enumeration entries = inputJar.entries();

+            while (entries.hasMoreElements()) {

+                JarEntry curEntry = (JarEntry) entries.nextElement();

+                // Check if we need to manipulate the clazz

+                if (m_classes.containsKey(curEntry.getName())) {

+                    JarEntry je = new JarEntry(curEntry.getName());

+                    byte[] outClazz = (byte[]) m_classes.get(curEntry.getName());

+                    if (outClazz.length != 0) {

+                        jos.putNextEntry(je); // copy the entry header to jos

+                        jos.write(outClazz);

+                        jos.closeEntry();

+                    } else { // The class is already manipulated

+                        InputStream currIn = inputJar.getInputStream(curEntry);

+                        int c;

+                        int i = 0;

+                        while ((c = currIn.read()) >= 0) {

+                            jos.write(c);

+                            i++;

+                        }

+                        currIn.close();

+                        jos.closeEntry();

+                    }

+                } else {

+                    // Do not copy the manifest

+                    if (!curEntry.getName().equals("META-INF/MANIFEST.MF")) {

+                        // copy the entry header to jos

+                        jos.putNextEntry(curEntry);

+                        InputStream currIn = inputJar.getInputStream(curEntry);

+                        int c;

+                        int i = 0;

+                        while ((c = currIn.read()) >= 0) {

+                            jos.write(c);

+                            i++;

+                        }

+                        currIn.close();

+                        jos.closeEntry();

+                    }

+                }

+            }

+        } catch (IOException e) {

+            error("Cannot manipulate the Jar file : " + e.getMessage() + " - Cause : " + e.getCause());

+            return;

+        }

+

+        try {

+            inputJar.close();

+            jos.close();

+            fos.close();

+            jos = null;

+            fos = null;

+        } catch (IOException e) {

+            error("Cannot close the new Jar file : " + e.getMessage() + " - Cause : " + e.getCause());

+            return;

+        }

+    }

+

+    /**

+     * Manipulate classes of the input Jar.

+     * @param inputJar : input bundle.

+     */

+    private void manipulateComponents(JarFile inputJar) {

+        Enumeration entries = inputJar.entries();

+        while (entries.hasMoreElements()) {

+            JarEntry curEntry = (JarEntry) entries.nextElement();

+            // Check if we need to manipulate the clazz

+            for (int i = 0; i < m_components.size(); i++) {

+                ComponentInfo ci = (ComponentInfo) m_components.get(i);

+                if (ci.m_classname.equals(curEntry.getName())) {

+                    byte[] outClazz = manipulateComponent(inputJar, curEntry, ci);

+                    m_classes.put(curEntry.getName(), outClazz);

+                }

+            }

+        }

+    }

+

+    /**

+     * Create the manifest.

+     * Set the bundle activator, imports, iPOJO-components clauses

+     * @param initial : initial Jar file.

+     * @return the generated manifest.

+     */

+    private Manifest doManifest(JarFile initial) {

+        Manifest mf = null;

+        try {

+            mf = initial.getManifest(); // Get the initial manifest

+        } catch (IOException e) {

+            e.printStackTrace();

+        }

+        Attributes att = mf.getMainAttributes();

+        setBundleActivator(att); // Set the bundle activator

+        setImports(att); // Set the imports (add ipojo and handler namespaces

+        setPOJOMetadata(att); // Add iPOJO-Component

+        setCreatedBy(att); // Add iPOJO to the creators

+        return mf;

+    }

+

+    /**

+     * Manipulate a component class.

+     * @param inputJar : input bundle

+     * @param je : Jar entry of the classes

+     * @param ci : attached component info (containing metadata and manipulation metadata)

+     * @return the generated class (byte array)

+     */

+    private byte[] manipulateComponent(JarFile inputJar, JarEntry je, ComponentInfo ci) {

+        Manipulator man = new Manipulator();

+        try {

+            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;

+            }

+            currIn.close();

+            byte[] out = man.manipulate(in); // iPOJO manipulation

+            // Insert information to metadata

+            ci.m_componentMetadata.addElement(man.getManipulationMetadata());

+            ci.m_isManipulated = true;

+            return out;

+        } catch (IOException e) {

+            error("Cannot manipulate the class " + je.getName() + " : " + e.getMessage());

+            return null;

+        }

+    }

+

+    /**

+     * Return the list of "concrete" component.

+     * @param meta : metadata.

+     * @return the list of compionent info requiring a manipulation.

+     */

+    private List getDeclaredComponents(Element[] meta) {

+        List componentClazzes = new ArrayList();

+        for (int i = 0; i < meta.length; i++) {

+            if (meta[i].getName().equalsIgnoreCase("component") && meta[i].containsAttribute("className")) {

+                String name = meta[i].getAttribute("classname");

+                name = name.replace('.', '/');

+                name += ".class";

+                componentClazzes.add(new ComponentInfo(name, meta[i]));

+            }

+        }

+        return componentClazzes;

+    }

+

+    /**

+     * Component Info.

+     * Represent a component type to be manipulated or already manipulated.

+     * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>

+     */

+    private class ComponentInfo {

+        /**

+         * Component Type metadata.

+         */

+        Element m_componentMetadata;

+

+        /**

+         * Component Type implementation class.

+         */

+        String m_classname;

+

+        /**

+         * Is the class already manipulated. 

+         */

+        boolean m_isManipulated;

+

+        /**

+         * Constructor.

+         * @param cn : class name

+         * @param met : component type metadata

+         */

+        ComponentInfo(String cn, Element met) {

+            this.m_classname = cn;

+            this.m_componentMetadata = met;

+            m_isManipulated = false;

+        }

+    }

+

+    /**

+     * Set the bundle activator in the manifest.

+     * @param att : manifest attribute.

+     */

+    private void setBundleActivator(Attributes att) {

+        if (att.containsKey("Bundle-Activator")) {

+            warn("The bundle contains another Bundle-Activator : " + att.getValue("Bundle-Activator") + " - Replace the existing one");

+        }

+        att.putValue("Bundle-Activator", "org.apache.felix.ipojo.Activator");

+    }

+

+    /**

+     * Set the create-by in the manifest.

+     * @param att : manifest attribute.

+     */

+    private void setCreatedBy(Attributes att) {

+        String prev = att.getValue("Created-By");

+        att.putValue("Created-By", prev + " & iPOJO");

+    }

+

+    /**

+     * Add imports to the given manifest attribute list. This method add ipojo imports and handler imports (if needed).

+     * @param att : the manifest attribute list to modify.

+     */

+    private void setImports(Attributes att) {

+        Map imports = parseHeader(att.getValue("Import-Package"));

+        Map ver = new TreeMap();

+        ver.put("version", "0.7.3");

+        if (!imports.containsKey("org.apache.felix.ipojo")) {

+            imports.put("org.apache.felix.ipojo", ver);

+        }

+        if (!imports.containsKey("org.apache.felix.ipojo.architecture")) {

+            imports.put("org.apache.felix.ipojo.architecture", ver);

+        }

+        if (!imports.containsKey("org.osgi.service.cm")) {

+            Map verCM = new TreeMap();

+            verCM.put("version", "1.2");

+            imports.put("org.osgi.service.cm", verCM);

+        }

+        if (!imports.containsKey("org.osgi.service.log")) {

+            Map verCM = new TreeMap();

+            verCM.put("version", "1.3");

+            imports.put("org.osgi.service.cm", verCM);

+        }

+        

+

+        // Add handler namespace

+        String[][] namespaces = computeHandlerNamespace();

+        for (int j = 0; j < namespaces.length; j++) {

+            for (int k = 0; k < namespaces[j].length; k++) {

+                if (!namespaces[j][k].equals("")) {

+                    int lastIndex = namespaces[j][k].lastIndexOf('.');

+                    String ns = namespaces[j][k].substring(0, lastIndex);

+                    if (!imports.containsKey(ns)) {

+                        imports.put(ns, new TreeMap());

+                    }

+                }

+            }

+        }

+

+        // Add refered imports from the metadata

+        for (int i = 0; i < m_referredPackages.size(); i++) {

+            String pack = (String) m_referredPackages.get(i);

+            imports.put(pack, new TreeMap());

+        }

+

+        // Write imports

+        att.putValue("Import-Package", printClauses(imports, "resolution:"));

+    }

+

+    /**

+     * Add iPOJO-Components to the given manifest attribute list. This method add the iPOJO-Components header and its value (according to the metadata) to the manifest.

+     * @param att : the manifest attribute list to modify.

+     */

+    private void setPOJOMetadata(Attributes att) {

+        String meta = "";

+        for (int i = 0; i < m_metadata.length; i++) {

+            meta += buildManifestMetadata(m_metadata[i], "");

+        }

+        att.putValue("iPOJO-Components", meta);

+    }

+

+    /**

+     * Build the list of namespaces used in the metadata. (first-order only). 

+     * @return the list of namespaces [array of component [ array of namespace ] ].

+     */

+    private String[][] computeHandlerNamespace() {

+        String[][] ns = new String[m_metadata.length][];

+        for (int i = 0; i < m_metadata.length; i++) {

+            ns[i] = m_metadata[i].getNamespaces();

+        }

+        return ns;

+    }

+

+    /**

+     * Standard OSGi header parser. This parser can handle the format clauses ::= clause ( ',' clause ) + clause ::= name ( ';' name ) (';' key '=' value )

+     * This is mapped to a Map { name => Map { attr|directive => value } }

+     * 

+     * @param value : String to parse.

+     * @return parsed map.

+     */

+    public Map parseHeader(String value) {

+        if (value == null || value.trim().length() == 0) {

+            return new HashMap();

+        }

+

+        Map result = new LinkedHashMap();

+        QuotedTokenizer qt = new QuotedTokenizer(value, ";=,");

+        char del;

+        do {

+            boolean hadAttribute = false;

+            Map clause = new HashMap();

+            List aliases = new ArrayList();

+            aliases.add(qt.nextToken());

+            del = qt.getSeparator();

+            while (del == ';') {

+                String adname = qt.nextToken();

+                if ((del = qt.getSeparator()) != '=') {

+                    if (hadAttribute) {

+                        throw new IllegalArgumentException("Header contains name field after attribute or directive: " + adname + " from " + value);

+                    }

+                    aliases.add(adname);

+                } else {

+                    String advalue = qt.nextToken();

+                    clause.put(adname, advalue);

+                    del = qt.getSeparator();

+                    hadAttribute = true;

+                }

+            }

+            for (Iterator i = aliases.iterator(); i.hasNext();) {

+                result.put(i.next(), clause);

+            }

+        } while (del == ',');

+        return result;

+    }

+

+    /**

+     * Print a standard Map based OSGi header.

+     * 

+     * @param exports : map { name => Map { attribute|directive => value } }

+     * @param allowedDirectives : list of allowed directives.

+     * @return the clauses

+     */

+    public String printClauses(Map exports, String allowedDirectives) {

+        StringBuffer sb = new StringBuffer();

+        String del = "";

+        for (Iterator i = exports.keySet().iterator(); i.hasNext();) {

+            String name = (String) i.next();

+            Map map = (Map) exports.get(name);

+            sb.append(del);

+            sb.append(name);

+

+            for (Iterator j = map.keySet().iterator(); j.hasNext();) {

+                String key = (String) j.next();

+

+                // Skip directives we do not recognize

+                if (key.endsWith(":") && allowedDirectives.indexOf(key) < 0) {

+                    continue;

+                }

+

+                String value = (String) map.get(key);

+                sb.append(";");

+                sb.append(key);

+                sb.append("=");

+                boolean dirty = value.indexOf(',') >= 0 || value.indexOf(';') >= 0;

+                if (dirty) {

+                    sb.append("\"");

+                }

+                sb.append(value);

+                if (dirty) {

+                    sb.append("\"");

+                }

+            }

+            del = ", ";

+        }

+        return sb.toString();

+    }

+

+    /**

+     * Parse XML Metadata.

+     * @param path : path of the file to parse.

+     * @return the parsed element array.

+     */

+    private Element[] parseXMLMetadata(String path) {

+        File metadata = new File(path);

+        URL url;

+        Element[] meta = null;

+        try {

+            url = metadata.toURI().toURL();

+            if (url == null) {

+                error("Cannot find the metdata file : " + path);

+                return null;

+            }

+

+            InputStream stream = url.openStream();

+            XMLReader parser = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");

+            XMLMetadataParser handler = new XMLMetadataParser();

+            parser.setContentHandler(handler);

+            InputSource is = new InputSource(stream);

+            parser.parse(is);

+            meta = handler.getMetadata();

+            m_referredPackages = handler.getReferredPackages();

+            stream.close();

+

+        } catch (MalformedURLException e) {

+            error("Malformed Mtadata URL for " + path);

+            return null;

+        } catch (IOException e) {

+            error("Cannot open the file : " + path);

+            return null;

+        } catch (ParseException e) {

+            error("Parsing Error when parsing the XML file " + path + " : " + e.getMessage());

+            return null;

+        } catch (SAXException e) {

+            error("Parsing Error when parsing (Sax Error) the XML file " + path + " : " + e.getMessage());

+            return null;

+        }

+

+        if (meta == null || meta.length == 0) {

+            warn("Neither component, neither instance in " + path);

+        }

+

+        return meta;

+    }

+

+    /**

+     * Generate manipulation metadata.

+     * @param element : actual element. 

+     * @param actual : actual manipulation metadata.

+     * @return : given amnipulation metadata + manipulation metadata of the given element.

+     */

+    private String buildManifestMetadata(Element element, String actual) {

+        String result = "";

+        if (element.getNameSpace().equals("")) {

+            result = actual + element.getName() + " { ";

+        } else {

+            result = actual + element.getNameSpace() + ":" + element.getName() + " { ";

+        }

+

+        for (int i = 0; i < element.getAttributes().length; i++) {

+            if (element.getAttributes()[i].getNameSpace().equals("")) {

+                result = result + "$" + element.getAttributes()[i].getName() + "=\"" + element.getAttributes()[i].getValue() + "\" ";

+            } else {

+                result = result + "$" + element.getAttributes()[i].getNameSpace() + ":" + element.getAttributes()[i].getName() + "=\"" + element.getAttributes()[i].getValue() + "\" ";

+            }

+        }

+

+        for (int i = 0; i < element.getElements().length; i++) {

+            result = buildManifestMetadata(element.getElements()[i], result);

+        }

+

+        return result + "}";

+    }

+

+    public List getWarnings() {

+        return m_warnings;

+    }

+

+}

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/QuotedTokenizer.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/QuotedTokenizer.java
new file mode 100644
index 0000000..483f088
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/QuotedTokenizer.java
@@ -0,0 +1,204 @@
+/* 

+ * 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.manipulator;

+

+import java.util.ArrayList;

+import java.util.List;

+

+/**

+ * Parse on OSGi Manifest clause. 

+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>

+ */

+public class QuotedTokenizer {

+    /**

+     * String to parse.

+     */

+    String m_string;

+

+    /**

+     * Index.

+     */

+    int m_index = 0;

+

+    /**

+     * Default spearators to use.

+     */

+    String m_separators;

+

+    /**

+     * Does the tokenizer returns token.

+     */

+    boolean m_returnTokens;

+

+    /**

+     * Does the tokenizer should ignore white space.

+     */

+    boolean m_ignoreWhiteSpace = true;

+

+    /**

+     * Peek.

+     */

+    String m_peek;

+

+    /**

+     * Separator.

+     */

+    char m_separator;

+

+    /**

+     * Constructors.

+     * @param string : input String.

+     * @param separators : separators.

+     * @param returnTokens : should the tokenizer return tokens ?

+     */

+    public QuotedTokenizer(String string, String separators, boolean returnTokens) {

+        if (string == null) {

+            throw new IllegalArgumentException("string argument must be not null");

+        }

+        this.m_string = string;

+        this.m_separators = separators;

+        this.m_returnTokens = returnTokens;

+    }

+

+    /**

+     * Constructors.

+     * Fixe returnTokens to false.

+     * @param string : input String.

+     * @param separators : separators

+     */

+    public QuotedTokenizer(String string, String separators) {

+        this(string, separators, false);

+    }

+

+    /**

+     * Get the next token.

+     * @param separators : separators to used.

+     * @return : the next token.

+     */

+    public String nextToken(String separators) {

+        m_separator = 0;

+        if (m_peek != null) {

+            String tmp = m_peek;

+            m_peek = null;

+            return tmp;

+        }

+

+        if (m_index == m_string.length()) { return null; }

+

+        StringBuffer sb = new StringBuffer();

+

+        while (m_index < m_string.length()) {

+            char c = m_string.charAt(m_index++);

+

+            if (Character.isWhitespace(c)) {

+                if (m_index == m_string.length()) {

+                    break;

+                } else {

+                    continue;

+                }

+            }

+

+            if (separators.indexOf(c) >= 0) {

+                if (m_returnTokens) {

+                    m_peek = Character.toString(c);

+                } else {

+                    m_separator = c;

+                }

+                break;

+            }

+

+            switch (c) {

+                case '"':

+                case '\'':

+                    quotedString(sb, c);

+                    break;

+

+                default:

+                    sb.append(c);

+            }

+        }

+        String result = sb.toString().trim();

+        if (result.length() == 0 && m_index == m_string.length()) { return null; }

+        return result;

+    }

+

+    /**

+     * Get the next token.

+     * Used the defined separators.

+     * @return the next token.

+     */

+    public String nextToken() {

+        return nextToken(m_separators);

+    }

+

+    /**

+     * Append the next quote to the given String Buffer.

+     * @param sb : accumulator.

+     * @param c : quote.

+     */

+    private void quotedString(StringBuffer sb, char c) {

+        char quote = c;

+        while (m_index < m_string.length()) {

+            c = m_string.charAt(m_index++);

+            if (c == quote) { break; }

+            if (c == '\\' && m_index < m_string.length() && m_string.charAt(m_index + 1) == quote) {

+                c = m_string.charAt(m_index++);

+            }

+            sb.append(c);

+        }

+    }

+

+    public String[] getTokens() {

+        return getTokens(0);

+    }

+

+    /**

+     * Get the list of tokens.

+     * @param cnt : array length.

+     * @return : the array of token.

+     */

+    private String[] getTokens(int cnt) {

+        String token = nextToken();

+        if (token == null) {

+            return new String[cnt];

+        }

+

+        String[] result = getTokens(cnt + 1);

+        result[cnt] = token;

+        return result;

+    }

+

+    public char getSeparator() {

+        return m_separator;

+    }

+

+    /**

+     * Get token list.

+     * @return the list of token.

+     */

+    public List getTokenSet() {

+        List list = new ArrayList();

+        String token = nextToken();

+        while (token != null) {

+            list.add(token);

+            token = nextToken();

+        }

+        return list;

+    }

+}

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/ParseException.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/ParseException.java
new file mode 100644
index 0000000..cee043d
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/ParseException.java
@@ -0,0 +1,40 @@
+/* 

+ * 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.xml.parser;

+

+/**

+ * Exceptions thrown by parsers.

+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>

+ */

+public class ParseException extends Exception {

+

+    /**

+     * serialVersionUID.

+     */

+    private static final long serialVersionUID = 1L;

+

+    /**

+     * Parsing error.

+     * @param msg : the error emssage.

+     */

+    public ParseException(String msg) {

+        super(msg);

+    }

+

+}

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java
new file mode 100644
index 0000000..fa4fd1c
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java
@@ -0,0 +1,311 @@
+/* 

+ * 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.xml.parser;

+

+import java.util.ArrayList;

+import java.util.List;

+

+import org.apache.felix.ipojo.metadata.Attribute;

+import org.apache.felix.ipojo.metadata.Element;

+import org.xml.sax.Attributes;

+import org.xml.sax.ContentHandler;

+import org.xml.sax.Locator;

+import org.xml.sax.SAXException;

+

+/**

+ * XML Metadata parser.

+ * 

+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>

+ */

+public class XMLMetadataParser implements ContentHandler {

+

+    /**

+     * Element of the metadata.

+     */

+    private Element[] m_elements = new Element[0];

+

+    /**

+     * Get componenet type metadata. (both component and composite)

+     * 

+     * @return a components metadata

+     * @throws ParseException

+     *             when an error occurs in the xml parsing

+     */

+    public Element[] getComponentsMetadata() throws ParseException {

+        Element[] comp = m_elements[0].getElements("Component");

+        Element[] compo = m_elements[0].getElements("Composite");

+        Element[] metadata = new Element[comp.length + compo.length];

+        int l = 0;

+        for (int i = 0; i < comp.length; i++) {

+            metadata[l] = comp[i];

+            l++;

+        }

+        for (int i = 0; i < compo.length; i++) {

+            metadata[l] = compo[i];

+            l++;

+        }

+        return metadata;

+    }

+

+    /**

+     * Get packages referenced by composite.

+     * 

+     * @return the list of referenced packages.

+     */

+    public List getReferredPackages() {

+        List referred = new ArrayList();

+        Element[] compo = m_elements[0].getElements("Composite");

+        for (int i = 0; i < compo.length; i++) {

+            for (int j = 0; j < compo[i].getElements().length; j++) {

+                if (compo[i].getElements()[j].containsAttribute("specification")) {

+                    String p = compo[i].getElements()[j].getAttribute("specification");

+                    int last = p.lastIndexOf('.');

+                    if (last != -1) {

+                        referred.add(p.substring(0, last));

+                    }

+                }

+            }

+        }

+        return referred;

+    }

+

+    /**

+     * Get parsed metadata.

+     * The document must be parsed before calling this method. 

+     * @return : all the metadata.

+     * @throws ParseException : occurs if an error occurs during the parsing.

+     */

+    public Element[] getMetadata() throws ParseException {

+        Element[] comp = m_elements[0].getElements("Component");

+        Element[] compo = m_elements[0].getElements("Composite");

+        Element[] conf = m_elements[0].getElements("Instance");

+        Element[] metadata = new Element[comp.length + conf.length + compo.length];

+        int l = 0;

+        for (int i = 0; i < comp.length; i++) {

+            metadata[l] = comp[i];

+            l++;

+        }

+        for (int i = 0; i < compo.length; i++) {

+            metadata[l] = compo[i];

+            l++;

+        }

+        for (int i = 0; i < conf.length; i++) {

+            metadata[l] = conf[i];

+            l++;

+        }

+        return metadata;

+    }

+

+

+    /**

+     * Characters.

+     * @param ch : character

+     * @param start : start

+     * @param length : length

+     * @throws SAXException : can never occurs.

+     * @see org.xml.sax.ContentHandler#characters(char[], int, int)

+     */

+    public void characters(char[] ch, int start, int length) throws SAXException {

+        // NOTHING TO DO

+

+    }

+

+

+    /**

+     * End the document.

+     * @throws SAXException : can never occrus.

+     * @see org.xml.sax.ContentHandler#endDocument()

+     */

+    public void endDocument() throws SAXException {

+    }

+

+

+    /**

+     * End of an element.

+     * @param namespaceURI : element namespace

+     * @param localName : local name

+     * @param qName : qualified name

+     * @throws SAXException : occurs when the element is malformed

+     * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)

+     */

+    public void endElement(String namespaceURI, String localName, String qName) throws SAXException {

+        // Get the last element of the list

+        Element lastElement = removeLastElement();

+

+        // Check if the name is consitent with the name of this end tag

+        if (!lastElement.getName().equalsIgnoreCase(qName) && !lastElement.getNameSpace().equals(namespaceURI)) {

+            throw new SAXException("Parse error when ending an element : " + qName + " [" + namespaceURI + "]");

+        }

+

+        // The name is consitent

+        // Add this element last element with if it is not the root

+        if (m_elements.length != 0) {

+            Element newQueue = m_elements[m_elements.length - 1];

+            newQueue.addElement(lastElement);

+        } else {

+            // It is the last element

+            addElement(lastElement);

+        }

+

+    }

+

+    /**

+     * End prefix mapping.

+     * @param prefix : ended prefix

+     * @throws SAXException : can never occurs.

+     * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)

+     */

+    public void endPrefixMapping(String prefix) throws SAXException {

+        // NOTHING TO DO

+    }

+

+

+    /**

+     * Ignore whitespace.

+     * @param ch : character

+     * @param start : start

+     * @param length : length

+     * @throws SAXException : can never occurs. 

+     * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)

+     */

+    public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {

+        // NOTHING TO DO

+    }

+

+    /**

+     * Process an instruction.

+     * @param target : target

+     * @param data : data

+     * @throws SAXException : can never occurs.

+     * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)

+     */

+    public void processingInstruction(String target, String data) throws SAXException {

+        // DO NOTHING

+    }

+

+    /**

+     * Set Document locator.

+     * @param locator : new locator.

+     * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)

+     */

+    public void setDocumentLocator(Locator locator) {

+        // NOTHING TO DO

+

+    }

+

+    /**

+     * Skipped entity.

+     * @param name : name.

+     * @throws SAXException : can never occurs.

+     * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)

+     */

+    public void skippedEntity(String name) throws SAXException {

+        // NOTHING TO DO

+

+    }

+

+    /**

+     * Start a document.

+     * @throws SAXException : can never occurs.

+     * @see org.xml.sax.ContentHandler#startDocument()

+     */

+    public void startDocument() throws SAXException {

+    }

+

+

+    /**

+     * Start an element.

+     * @param namespaceURI : element namespace.

+     * @param localName : local element.

+     * @param qName : qualified name.

+     * @param atts : attribute

+     * @throws SAXException : occurs if the element cannot be parsed correctly.

+     * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)

+     */

+    public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {

+        Element elem = new Element(localName, namespaceURI);

+

+        for (int i = 0; i < atts.getLength(); i++) {

+            String name = (String) atts.getLocalName(i);

+            String ns = (String) atts.getURI(i);

+            String value = (String) atts.getValue(i);

+            Attribute att = new Attribute(name, ns, value);

+            elem.addAttribute(att);

+        }

+

+        addElement(elem);

+

+    }

+

+    /**

+     * Start a prefix mapping.

+     * @param prefix : prefix.

+     * @param uri : uri.

+     * @throws SAXException : can never occurs.

+     * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)

+     */

+    public void startPrefixMapping(String prefix, String uri) throws SAXException {

+        // NOTHING TO DO

+

+    }

+

+    /**

+     * Add an element.

+     * @param elem : the element to add

+     */

+    private void addElement(Element elem) {

+        for (int i = 0; (m_elements != null) && (i < m_elements.length); i++) {

+            if (m_elements[i] == elem) {

+                return;

+            }

+        }

+

+        if (m_elements != null) {

+            Element[] newElementsList = new Element[m_elements.length + 1];

+            System.arraycopy(m_elements, 0, newElementsList, 0, m_elements.length);

+            newElementsList[m_elements.length] = elem;

+            m_elements = newElementsList;

+        } else {

+            m_elements = new Element[] { elem };

+        }

+    }

+

+    /**

+     * Remove an element.

+     * @return : the removed element.

+     */

+    private Element removeLastElement() {

+        int idx = -1;

+        idx = m_elements.length - 1;

+        Element last = m_elements[idx];

+        if (idx >= 0) {

+            if ((m_elements.length - 1) == 0) {

+                // It is the last element of the list;

+                m_elements = new Element[0];

+            } else {

+                // Remove the last element of the list :

+                Element[] newElementsList = new Element[m_elements.length - 1];

+                System.arraycopy(m_elements, 0, newElementsList, 0, idx);

+                m_elements = newElementsList;

+            }

+        }

+        return last;

+    }

+

+}

diff --git a/ipojo/manipulator/src/main/java/org/objectweb/asm/commons/AdviceAdapter.java b/ipojo/manipulator/src/main/java/org/objectweb/asm/commons/AdviceAdapter.java
new file mode 100644
index 0000000..f4edfa4
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/objectweb/asm/commons/AdviceAdapter.java
@@ -0,0 +1,650 @@
+/***

+ * ASM: a very small and fast Java bytecode manipulation framework

+ * Copyright (c) 2000-2005 INRIA, France Telecom

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without

+ * modification, are permitted provided that the following conditions

+ * are met:

+ * 1. Redistributions of source code must retain the above copyright

+ *    notice, this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright

+ *    notice, this list of conditions and the following disclaimer in the

+ *    documentation and/or other materials provided with the distribution.

+ * 3. Neither the name of the copyright holders nor the names of its

+ *    contributors may be used to endorse or promote products derived from

+ *    this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"

+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE

+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR

+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF

+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF

+ * THE POSSIBILITY OF SUCH DAMAGE.

+ */

+package org.objectweb.asm.commons;

+

+import java.util.ArrayList;

+import java.util.HashMap;

+

+import org.objectweb.asm.Label;

+import org.objectweb.asm.MethodVisitor;

+import org.objectweb.asm.Opcodes;

+import org.objectweb.asm.Type;

+

+/**

+ * A {@link org.objectweb.asm.MethodAdapter} to insert before, after and around

+ * advices in methods and constructors. <p> The behavior for constructors is

+ * like this: <ol>

+ * 

+ * <li>as long as the INVOKESPECIAL for the object initialization has not been

+ * reached, every bytecode instruction is dispatched in the ctor code visitor</li>

+ * 

+ * <li>when this one is reached, it is only added in the ctor code visitor and

+ * a JP invoke is added</li>

+ * 

+ * <li>after that, only the other code visitor receives the instructions</li>

+ * 

+ * </ol>

+ * 

+ * @author Eugene Kuleshov

+ * @author Eric Bruneton

+ */

+public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes

+{

+    private static final Object THIS = new Object();

+    private static final Object OTHER = new Object();

+

+    protected int methodAccess;

+    protected String methodDesc;

+

+    private boolean constructor;

+    private boolean superInitialized;

+    private ArrayList stackFrame;

+    private HashMap branches;

+

+    /**

+     * Creates a new {@link AdviceAdapter}.

+     * 

+     * @param mv the method visitor to which this adapter delegates calls.

+     * @param access the method's access flags (see {@link Opcodes}).

+     * @param name the method's name.

+     * @param desc the method's descriptor (see {@link Type Type}).

+     */

+    public AdviceAdapter(

+        final MethodVisitor mv,

+        final int access,

+        final String name,

+        final String desc)

+    {

+        super(mv, access, name, desc);

+        methodAccess = access;

+        methodDesc = desc;

+

+        constructor = "<init>".equals(name);

+    }

+

+    public void visitCode() {

+        mv.visitCode();

+        if (!constructor) {

+            superInitialized = true;

+            onMethodEnter();

+        } else {

+            stackFrame = new ArrayList();

+            branches = new HashMap();

+        }

+    }

+

+    public void visitLabel(final Label label) {

+        mv.visitLabel(label);

+

+        if (constructor && branches != null) {

+            ArrayList frame = (ArrayList) branches.get(label);

+            if (frame != null) {

+                stackFrame = frame;

+                branches.remove(label);

+            }

+        }

+    }

+

+    public void visitInsn(final int opcode) {

+        if (constructor) {

+            switch (opcode) {

+                case RETURN: // empty stack

+                    onMethodExit(opcode);

+                    break;

+

+                case IRETURN: // 1 before n/a after

+                case FRETURN: // 1 before n/a after

+                case ARETURN: // 1 before n/a after

+                case ATHROW: // 1 before n/a after

+                    popValue();

+                    popValue();

+                    onMethodExit(opcode);

+                    break;

+

+                case LRETURN: // 2 before n/a after

+                case DRETURN: // 2 before n/a after

+                    popValue();

+                    popValue();

+                    onMethodExit(opcode);

+                    break;

+

+                case NOP:

+                case LALOAD: // remove 2 add 2

+                case DALOAD: // remove 2 add 2

+                case LNEG:

+                case DNEG:

+                case FNEG:

+                case INEG:

+                case L2D:

+                case D2L:

+                case F2I:

+                case I2B:

+                case I2C:

+                case I2S:

+                case I2F:

+                case Opcodes.ARRAYLENGTH:

+                    break;

+

+                case ACONST_NULL:

+                case ICONST_M1:

+                case ICONST_0:

+                case ICONST_1:

+                case ICONST_2:

+                case ICONST_3:

+                case ICONST_4:

+                case ICONST_5:

+                case FCONST_0:

+                case FCONST_1:

+                case FCONST_2:

+                case F2L: // 1 before 2 after

+                case F2D:

+                case I2L:

+                case I2D:

+                    pushValue(OTHER);

+                    break;

+

+                case LCONST_0:

+                case LCONST_1:

+                case DCONST_0:

+                case DCONST_1:

+                    pushValue(OTHER);

+                    pushValue(OTHER);

+                    break;

+

+                case IALOAD: // remove 2 add 1

+                case FALOAD: // remove 2 add 1

+                case AALOAD: // remove 2 add 1

+                case BALOAD: // remove 2 add 1

+                case CALOAD: // remove 2 add 1

+                case SALOAD: // remove 2 add 1

+                case POP:

+                case IADD:

+                case FADD:

+                case ISUB:

+                case LSHL: // 3 before 2 after

+                case LSHR: // 3 before 2 after

+                case LUSHR: // 3 before 2 after

+                case L2I: // 2 before 1 after

+                case L2F: // 2 before 1 after

+                case D2I: // 2 before 1 after

+                case D2F: // 2 before 1 after

+                case FSUB:

+                case FMUL:

+                case FDIV:

+                case FREM:

+                case FCMPL: // 2 before 1 after

+                case FCMPG: // 2 before 1 after

+                case IMUL:

+                case IDIV:

+                case IREM:

+                case ISHL:

+                case ISHR:

+                case IUSHR:

+                case IAND:

+                case IOR:

+                case IXOR:

+                case MONITORENTER:

+                case MONITOREXIT:

+                    popValue();

+                    break;

+

+                case POP2:

+                case LSUB:

+                case LMUL:

+                case LDIV:

+                case LREM:

+                case LADD:

+                case LAND:

+                case LOR:

+                case LXOR:

+                case DADD:

+                case DMUL:

+                case DSUB:

+                case DDIV:

+                case DREM:

+                    popValue();

+                    popValue();

+                    break;

+

+                case IASTORE:

+                case FASTORE:

+                case AASTORE:

+                case BASTORE:

+                case CASTORE:

+                case SASTORE:

+                case LCMP: // 4 before 1 after

+                case DCMPL:

+                case DCMPG:

+                    popValue();

+                    popValue();

+                    popValue();

+                    break;

+

+                case LASTORE:

+                case DASTORE:

+                    popValue();

+                    popValue();

+                    popValue();

+                    popValue();

+                    break;

+

+                case DUP:

+                    pushValue(peekValue());

+                    break;

+

+                case DUP_X1:

+                    // TODO optimize this

+                {

+                    Object o1 = popValue();

+                    Object o2 = popValue();

+                    pushValue(o1);

+                    pushValue(o2);

+                    pushValue(o1);

+                }

+                    break;

+

+                case DUP_X2:

+                    // TODO optimize this

+                {

+                    Object o1 = popValue();

+                    Object o2 = popValue();

+                    Object o3 = popValue();

+                    pushValue(o1);

+                    pushValue(o3);

+                    pushValue(o2);

+                    pushValue(o1);

+                }

+                    break;

+

+                case DUP2:

+                    // TODO optimize this

+                {

+                    Object o1 = popValue();

+                    Object o2 = popValue();

+                    pushValue(o2);

+                    pushValue(o1);

+                    pushValue(o2);

+                    pushValue(o1);

+                }

+                    break;

+

+                case DUP2_X1:

+                    // TODO optimize this

+                {

+                    Object o1 = popValue();

+                    Object o2 = popValue();

+                    Object o3 = popValue();

+                    pushValue(o2);

+                    pushValue(o1);

+                    pushValue(o3);

+                    pushValue(o2);

+                    pushValue(o1);

+                }

+                    break;

+

+                case DUP2_X2:

+                    // TODO optimize this

+                {

+                    Object o1 = popValue();

+                    Object o2 = popValue();

+                    Object o3 = popValue();

+                    Object o4 = popValue();

+                    pushValue(o2);

+                    pushValue(o1);

+                    pushValue(o4);

+                    pushValue(o3);

+                    pushValue(o2);

+                    pushValue(o1);

+                }

+                    break;

+

+                case SWAP: {

+                    Object o1 = popValue();

+                    Object o2 = popValue();

+                    pushValue(o1);

+                    pushValue(o2);

+                }

+                    break;

+            }

+        } else {

+            switch (opcode) {

+                case RETURN:

+                case IRETURN:

+                case FRETURN:

+                case ARETURN:

+                case LRETURN:

+                case DRETURN:

+                case ATHROW:

+                    onMethodExit(opcode);

+                    break;

+            }

+        }

+        mv.visitInsn(opcode);

+    }

+

+    public void visitVarInsn(final int opcode, final int var) {

+        super.visitVarInsn(opcode, var);

+

+        if (constructor) {

+            switch (opcode) {

+                case ILOAD:

+                case FLOAD:

+                    pushValue(OTHER);

+                    break;

+                case LLOAD:

+                case DLOAD:

+                    pushValue(OTHER);

+                    pushValue(OTHER);

+                    break;

+                case ALOAD:

+                    pushValue(var == 0 ? THIS : OTHER);

+                    break;

+                case ASTORE:

+                case ISTORE:

+                case FSTORE:

+                    popValue();

+                    break;

+                case LSTORE:

+                case DSTORE:

+                    popValue();

+                    popValue();

+                    break;

+            }

+        }

+    }

+

+    public void visitFieldInsn(

+        final int opcode,

+        final String owner,

+        final String name,

+        final String desc)

+    {

+        mv.visitFieldInsn(opcode, owner, name, desc);

+

+        if (constructor) {

+            char c = desc.charAt(0);

+            boolean longOrDouble = c == 'J' || c == 'D';

+            switch (opcode) {

+                case GETSTATIC:

+                    pushValue(OTHER);

+                    if (longOrDouble) {

+                        pushValue(OTHER);

+                    }

+                    break;

+                case PUTSTATIC:

+                    popValue();

+                    if (longOrDouble) {

+                        popValue();

+                    }

+                    break;

+                case PUTFIELD:

+                    popValue();

+                    if (longOrDouble) {

+                        popValue();

+                        popValue();

+                    }

+                    break;

+                // case GETFIELD:

+                default:

+                    if (longOrDouble) {

+                        pushValue(OTHER);

+                    }

+            }

+        }

+    }

+

+    public void visitIntInsn(final int opcode, final int operand) {

+        mv.visitIntInsn(opcode, operand);

+

+        if (constructor && opcode!=NEWARRAY) {

+            pushValue(OTHER);

+        }

+    }

+

+    public void visitLdcInsn(final Object cst) {

+        mv.visitLdcInsn(cst);

+

+        if (constructor) {

+            pushValue(OTHER);

+            if (cst instanceof Double || cst instanceof Long) {

+                pushValue(OTHER);

+            }

+        }

+    }

+

+    public void visitMultiANewArrayInsn(final String desc, final int dims) {

+        mv.visitMultiANewArrayInsn(desc, dims);

+

+        if (constructor) {

+            for (int i = 0; i < dims; i++) {

+                popValue();

+            }

+            pushValue(OTHER);

+        }

+    }

+

+    public void visitTypeInsn(final int opcode, final String name) {

+        mv.visitTypeInsn(opcode, name);

+

+        // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack

+        if (constructor && opcode == NEW) {

+            pushValue(OTHER);

+        }

+    }

+

+    public void visitMethodInsn(

+        final int opcode,

+        final String owner,

+        final String name,

+        final String desc)

+    {

+        mv.visitMethodInsn(opcode, owner, name, desc);

+

+        if (constructor) {

+            Type[] types = Type.getArgumentTypes(desc);

+            for (int i = 0; i < types.length; i++) {

+                popValue();

+                if (types[i].getSize() == 2) {

+                    popValue();

+                }

+            }

+            switch (opcode) {

+                // case INVOKESTATIC:

+                // break;

+

+                case INVOKEINTERFACE:

+                case INVOKEVIRTUAL:

+                    popValue(); // objectref

+                    break;

+

+                case INVOKESPECIAL:

+                    Object type = popValue(); // objectref

+                    if (type == THIS && !superInitialized) {

+                        onMethodEnter();

+                        superInitialized = true;

+                        // once super has been initialized it is no longer

+                        // necessary to keep track of stack state

+                        constructor = false;

+                    }

+                    break;

+            }

+

+            Type returnType = Type.getReturnType(desc);

+            if (returnType != Type.VOID_TYPE) {

+                pushValue(OTHER);

+                if (returnType.getSize() == 2) {

+                    pushValue(OTHER);

+                }

+            }

+        }

+    }

+

+    public void visitJumpInsn(final int opcode, final Label label) {

+        mv.visitJumpInsn(opcode, label);

+

+        if (constructor) {

+            switch (opcode) {

+                case IFEQ:

+                case IFNE:

+                case IFLT:

+                case IFGE:

+                case IFGT:

+                case IFLE:

+                case IFNULL:

+                case IFNONNULL:

+                    popValue();

+                    break;

+

+                case IF_ICMPEQ:

+                case IF_ICMPNE:

+                case IF_ICMPLT:

+                case IF_ICMPGE:

+                case IF_ICMPGT:

+                case IF_ICMPLE:

+                case IF_ACMPEQ:

+                case IF_ACMPNE:

+                    popValue();

+                    popValue();

+                    break;

+

+                case JSR:

+                    pushValue(OTHER);

+                    break;

+            }

+            addBranch(label);

+        }

+    }

+

+    public void visitLookupSwitchInsn(

+        final Label dflt,

+        final int[] keys,

+        final Label[] labels)

+    {

+        mv.visitLookupSwitchInsn(dflt, keys, labels);

+

+        if (constructor) {

+            popValue();

+            addBranches(dflt, labels);

+        }

+    }

+

+    public void visitTableSwitchInsn(

+        final int min,

+        final int max,

+        final Label dflt,

+        final Label[] labels)

+    {

+        mv.visitTableSwitchInsn(min, max, dflt, labels);

+

+        if (constructor) {

+            popValue();

+            addBranches(dflt, labels);

+        }

+    }

+

+    private void addBranches(final Label dflt, final Label[] labels) {

+        addBranch(dflt);

+        for (int i = 0; i < labels.length; i++) {

+            addBranch(labels[i]);

+        }

+    }

+

+    private void addBranch(final Label label) {

+        if (branches.containsKey(label)) {

+            return;

+        }

+        ArrayList frame = new ArrayList();

+        frame.addAll(stackFrame);

+        branches.put(label, frame);

+    }

+

+    private Object popValue() {

+        return stackFrame.remove(stackFrame.size() - 1);

+    }

+

+    private Object peekValue() {

+        return stackFrame.get(stackFrame.size() - 1);

+    }

+

+    private void pushValue(final Object o) {

+        stackFrame.add(o);

+    }

+

+    /**

+     * Called at the beginning of the method or after super class class call in

+     * the constructor. <br><br>

+     * 

+     * <i>Custom code can use or change all the local variables, but should not

+     * change state of the stack.</i>

+     */

+    protected abstract void onMethodEnter();

+

+    /**

+     * Called before explicit exit from the method using either return or throw.

+     * Top element on the stack contains the return value or exception instance.

+     * For example:

+     * 

+     * <pre>

+     *   public void onMethodExit(int opcode) {

+     *     if(opcode==RETURN) {

+     *         visitInsn(ACONST_NULL);

+     *     } else if(opcode==ARETURN || opcode==ATHROW) {

+     *         dup();

+     *     } else {

+     *         if(opcode==LRETURN || opcode==DRETURN) {

+     *             dup2();

+     *         } else {

+     *             dup();

+     *         }

+     *         box(Type.getReturnType(this.methodDesc));

+     *     }

+     *     visitIntInsn(SIPUSH, opcode);

+     *     visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");

+     *   }

+     *

+     *   // an actual call back method

+     *   public static void onExit(int opcode, Object param) {

+     *     ...

+     * </pre>

+     * 

+     * <br><br>

+     * 

+     * <i>Custom code can use or change all the local variables, but should not

+     * change state of the stack.</i>

+     * 

+     * @param opcode one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN,

+     *        DRETURN or ATHROW

+     * 

+     */

+    protected abstract void onMethodExit(int opcode);

+

+    // TODO onException, onMethodCall

+

+}

diff --git a/ipojo/manipulator/src/main/java/org/objectweb/asm/commons/GeneratorAdapter.java b/ipojo/manipulator/src/main/java/org/objectweb/asm/commons/GeneratorAdapter.java
new file mode 100644
index 0000000..972b2ff
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/objectweb/asm/commons/GeneratorAdapter.java
@@ -0,0 +1,1435 @@
+/***

+ * ASM: a very small and fast Java bytecode manipulation framework

+ * Copyright (c) 2000-2005 INRIA, France Telecom

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without

+ * modification, are permitted provided that the following conditions

+ * are met:

+ * 1. Redistributions of source code must retain the above copyright

+ *    notice, this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright

+ *    notice, this list of conditions and the following disclaimer in the

+ *    documentation and/or other materials provided with the distribution.

+ * 3. Neither the name of the copyright holders nor the names of its

+ *    contributors may be used to endorse or promote products derived from

+ *    this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"

+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE

+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR

+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF

+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF

+ * THE POSSIBILITY OF SUCH DAMAGE.

+ */

+package org.objectweb.asm.commons;

+

+import java.util.ArrayList;

+import java.util.Arrays;

+import java.util.List;

+

+import org.objectweb.asm.ClassVisitor;

+import org.objectweb.asm.Label;

+import org.objectweb.asm.MethodVisitor;

+import org.objectweb.asm.Opcodes;

+import org.objectweb.asm.Type;

+

+/**

+ * A {@link org.objectweb.asm.MethodAdapter} with convenient methods to generate

+ * code. For example, using this adapter, the class below

+ * 

+ * <pre>

+ * public class Example {

+ *     public static void main(String[] args) {

+ *         System.out.println(&quot;Hello world!&quot;);

+ *     }

+ * }

+ * </pre>

+ * 

+ * can be generated as follows:

+ * 

+ * <pre>

+ * ClassWriter cw = new ClassWriter(true);

+ * cw.visit(V1_1, ACC_PUBLIC, &quot;Example&quot;, null, &quot;java/lang/Object&quot;, null);

+ * 

+ * Method m = Method.getMethod(&quot;void &lt;init&gt; ()&quot;);

+ * GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);

+ * mg.loadThis();

+ * mg.invokeConstructor(Type.getType(Object.class), m);

+ * mg.returnValue();

+ * mg.endMethod();

+ * 

+ * m = Method.getMethod(&quot;void main (String[])&quot;);

+ * mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);

+ * mg.getStatic(Type.getType(System.class), &quot;out&quot;, Type.getType(PrintStream.class));

+ * mg.push(&quot;Hello world!&quot;);

+ * mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod(&quot;void println (String)&quot;));

+ * mg.returnValue();

+ * mg.endMethod();

+ * 

+ * cw.visitEnd();

+ * </pre>

+ * 

+ * @author Juozas Baliuka

+ * @author Chris Nokleberg

+ * @author Eric Bruneton

+ */

+public class GeneratorAdapter extends LocalVariablesSorter {

+

+    private final static Type BYTE_TYPE = Type.getObjectType("java/lang/Byte");

+

+    private final static Type BOOLEAN_TYPE = Type.getObjectType("java/lang/Boolean");

+

+    private final static Type SHORT_TYPE = Type.getObjectType("java/lang/Short");

+

+    private final static Type CHARACTER_TYPE = Type.getObjectType("java/lang/Character");

+

+    private final static Type INTEGER_TYPE = Type.getObjectType("java/lang/Integer");

+

+    private final static Type FLOAT_TYPE = Type.getObjectType("java/lang/Float");

+

+    private final static Type LONG_TYPE = Type.getObjectType("java/lang/Long");

+

+    private final static Type DOUBLE_TYPE = Type.getObjectType("java/lang/Double");

+

+    private final static Type NUMBER_TYPE = Type.getObjectType("java/lang/Number");

+

+    private final static Type OBJECT_TYPE = Type.getObjectType("java/lang/Object");

+

+    private final static Method BOOLEAN_VALUE = Method.getMethod("boolean booleanValue()");

+

+    private final static Method CHAR_VALUE = Method.getMethod("char charValue()");

+

+    private final static Method INT_VALUE = Method.getMethod("int intValue()");

+

+    private final static Method FLOAT_VALUE = Method.getMethod("float floatValue()");

+

+    private final static Method LONG_VALUE = Method.getMethod("long longValue()");

+

+    private final static Method DOUBLE_VALUE = Method.getMethod("double doubleValue()");

+

+    /**

+     * Constant for the {@link #math math} method.

+     */

+    public final static int ADD = Opcodes.IADD;

+

+    /**

+     * Constant for the {@link #math math} method.

+     */

+    public final static int SUB = Opcodes.ISUB;

+

+    /**

+     * Constant for the {@link #math math} method.

+     */

+    public final static int MUL = Opcodes.IMUL;

+

+    /**

+     * Constant for the {@link #math math} method.

+     */

+    public final static int DIV = Opcodes.IDIV;

+

+    /**

+     * Constant for the {@link #math math} method.

+     */

+    public final static int REM = Opcodes.IREM;

+

+    /**

+     * Constant for the {@link #math math} method.

+     */

+    public final static int NEG = Opcodes.INEG;

+

+    /**

+     * Constant for the {@link #math math} method.

+     */

+    public final static int SHL = Opcodes.ISHL;

+

+    /**

+     * Constant for the {@link #math math} method.

+     */

+    public final static int SHR = Opcodes.ISHR;

+

+    /**

+     * Constant for the {@link #math math} method.

+     */

+    public final static int USHR = Opcodes.IUSHR;

+

+    /**

+     * Constant for the {@link #math math} method.

+     */

+    public final static int AND = Opcodes.IAND;

+

+    /**

+     * Constant for the {@link #math math} method.

+     */

+    public final static int OR = Opcodes.IOR;

+

+    /**

+     * Constant for the {@link #math math} method.

+     */

+    public final static int XOR = Opcodes.IXOR;

+

+    /**

+     * Constant for the {@link #ifCmp ifCmp} method.

+     */

+    public final static int EQ = Opcodes.IFEQ;

+

+    /**

+     * Constant for the {@link #ifCmp ifCmp} method.

+     */

+    public final static int NE = Opcodes.IFNE;

+

+    /**

+     * Constant for the {@link #ifCmp ifCmp} method.

+     */

+    public final static int LT = Opcodes.IFLT;

+

+    /**

+     * Constant for the {@link #ifCmp ifCmp} method.

+     */

+    public final static int GE = Opcodes.IFGE;

+

+    /**

+     * Constant for the {@link #ifCmp ifCmp} method.

+     */

+    public final static int GT = Opcodes.IFGT;

+

+    /**

+     * Constant for the {@link #ifCmp ifCmp} method.

+     */

+    public final static int LE = Opcodes.IFLE;

+

+    /**

+     * Access flags of the method visited by this adapter.

+     */

+    private final int access;

+

+    /**

+     * Return type of the method visited by this adapter.

+     */

+    private final Type returnType;

+

+    /**

+     * Argument types of the method visited by this adapter.

+     */

+    private final Type[] argumentTypes;

+

+    /**

+     * Types of the local variables of the method visited by this adapter.

+     */

+    private final List localTypes = new ArrayList();

+

+    /**

+     * Creates a new {@link GeneratorAdapter}.

+     * 

+     * @param mv the method visitor to which this adapter delegates calls.

+     * @param access the method's access flags (see {@link Opcodes}).

+     * @param name the method's name.

+     * @param desc the method's descriptor (see {@link Type Type}).

+     */

+    public GeneratorAdapter(

+        final MethodVisitor mv,

+        final int access,

+        final String name,

+        final String desc)

+    {

+        super(access, desc, mv);

+        this.access = access;

+        this.returnType = Type.getReturnType(desc);

+        this.argumentTypes = Type.getArgumentTypes(desc);

+    }

+

+    /**

+     * Creates a new {@link GeneratorAdapter}.

+     * 

+     * @param access access flags of the adapted method.

+     * @param method the adapted method.

+     * @param mv the method visitor to which this adapter delegates calls.

+     */

+    public GeneratorAdapter(

+        final int access,

+        final Method method,

+        final MethodVisitor mv)

+    {

+        super(access, method.getDescriptor(), mv);

+        this.access = access;

+        this.returnType = method.getReturnType();

+        this.argumentTypes = method.getArgumentTypes();

+    }

+

+    /**

+     * Creates a new {@link GeneratorAdapter}.

+     * 

+     * @param access access flags of the adapted method.

+     * @param method the adapted method.

+     * @param signature the signature of the adapted method (may be

+     *        <tt>null</tt>).

+     * @param exceptions the exceptions thrown by the adapted method (may be

+     *        <tt>null</tt>).

+     * @param cv the class visitor to which this adapter delegates calls.

+     */

+    public GeneratorAdapter(

+        final int access,

+        final Method method,

+        final String signature,

+        final Type[] exceptions,

+        final ClassVisitor cv)

+    {

+        this(access, method, cv.visitMethod(access,

+                method.getName(),

+                method.getDescriptor(),

+                signature,

+                getInternalNames(exceptions)));

+    }

+

+    /**

+     * Returns the internal names of the given types.

+     * 

+     * @param types a set of types.

+     * @return the internal names of the given types.

+     */

+    private static String[] getInternalNames(final Type[] types) {

+        if (types == null) {

+            return null;

+        }

+        String[] names = new String[types.length];

+        for (int i = 0; i < names.length; ++i) {

+            names[i] = types[i].getInternalName();

+        }

+        return names;

+    }

+

+    // ------------------------------------------------------------------------

+    // Instructions to push constants on the stack

+    // ------------------------------------------------------------------------

+

+    /**

+     * Generates the instruction to push the given value on the stack.

+     * 

+     * @param value the value to be pushed on the stack.

+     */

+    public void push(final boolean value) {

+        push(value ? 1 : 0);

+    }

+

+    /**

+     * Generates the instruction to push the given value on the stack.

+     * 

+     * @param value the value to be pushed on the stack.

+     */

+    public void push(final int value) {

+        if (value >= -1 && value <= 5) {

+            mv.visitInsn(Opcodes.ICONST_0 + value);

+        } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {

+            mv.visitIntInsn(Opcodes.BIPUSH, value);

+        } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {

+            mv.visitIntInsn(Opcodes.SIPUSH, value);

+        } else {

+            mv.visitLdcInsn(new Integer(value));

+        }

+    }

+

+    /**

+     * Generates the instruction to push the given value on the stack.

+     * 

+     * @param value the value to be pushed on the stack.

+     */

+    public void push(final long value) {

+        if (value == 0L || value == 1L) {

+            mv.visitInsn(Opcodes.LCONST_0 + (int) value);

+        } else {

+            mv.visitLdcInsn(new Long(value));

+        }

+    }

+

+    /**

+     * Generates the instruction to push the given value on the stack.

+     * 

+     * @param value the value to be pushed on the stack.

+     */

+    public void push(final float value) {

+        int bits = Float.floatToIntBits(value);

+        if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2

+            mv.visitInsn(Opcodes.FCONST_0 + (int) value);

+        } else {

+            mv.visitLdcInsn(new Float(value));

+        }

+    }

+

+    /**

+     * Generates the instruction to push the given value on the stack.

+     * 

+     * @param value the value to be pushed on the stack.

+     */

+    public void push(final double value) {

+        long bits = Double.doubleToLongBits(value);

+        if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d

+            mv.visitInsn(Opcodes.DCONST_0 + (int) value);

+        } else {

+            mv.visitLdcInsn(new Double(value));

+        }

+    }

+

+    /**

+     * Generates the instruction to push the given value on the stack.

+     * 

+     * @param value the value to be pushed on the stack. May be <tt>null</tt>.

+     */

+    public void push(final String value) {

+        if (value == null) {

+            mv.visitInsn(Opcodes.ACONST_NULL);

+        } else {

+            mv.visitLdcInsn(value);

+        }

+    }

+

+    /**

+     * Generates the instruction to push the given value on the stack.

+     * 

+     * @param value the value to be pushed on the stack.

+     */

+    public void push(final Type value) {

+        if (value == null) {

+            mv.visitInsn(Opcodes.ACONST_NULL);

+        } else {

+            mv.visitLdcInsn(value);

+        }

+    }

+

+    // ------------------------------------------------------------------------

+    // Instructions to load and store method arguments

+    // ------------------------------------------------------------------------

+

+    /**

+     * Returns the index of the given method argument in the frame's local

+     * variables array.

+     * 

+     * @param arg the index of a method argument.

+     * @return the index of the given method argument in the frame's local

+     *         variables array.

+     */

+    private int getArgIndex(final int arg) {

+        int index = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0;

+        for (int i = 0; i < arg; i++) {

+            index += argumentTypes[i].getSize();

+        }

+        return index;

+    }

+

+    /**

+     * Generates the instruction to push a local variable on the stack.

+     * 

+     * @param type the type of the local variable to be loaded.

+     * @param index an index in the frame's local variables array.

+     */

+    private void loadInsn(final Type type, final int index) {

+        mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index);

+    }

+

+    /**

+     * Generates the instruction to store the top stack value in a local

+     * variable.

+     * 

+     * @param type the type of the local variable to be stored.

+     * @param index an index in the frame's local variables array.

+     */

+    private void storeInsn(final Type type, final int index) {

+        mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index);

+    }

+

+    /**

+     * Generates the instruction to load 'this' on the stack.

+     */

+    public void loadThis() {

+        if ((access & Opcodes.ACC_STATIC) != 0) {

+            throw new IllegalStateException("no 'this' pointer within static method");

+        }

+        mv.visitVarInsn(Opcodes.ALOAD, 0);

+    }

+

+    /**

+     * Generates the instruction to load the given method argument on the stack.

+     * 

+     * @param arg the index of a method argument.

+     */

+    public void loadArg(final int arg) {

+        loadInsn(argumentTypes[arg], getArgIndex(arg));

+    }

+

+    /**

+     * Generates the instructions to load the given method arguments on the

+     * stack.

+     * 

+     * @param arg the index of the first method argument to be loaded.

+     * @param count the number of method arguments to be loaded.

+     */

+    public void loadArgs(final int arg, final int count) {

+        int index = getArgIndex(arg);

+        for (int i = 0; i < count; ++i) {

+            Type t = argumentTypes[arg + i];

+            loadInsn(t, index);

+            index += t.getSize();

+        }

+    }

+

+    /**

+     * Generates the instructions to load all the method arguments on the stack.

+     */

+    public void loadArgs() {

+        loadArgs(0, argumentTypes.length);

+    }

+

+    /**

+     * Generates the instructions to load all the method arguments on the stack,

+     * as a single object array.

+     */

+    public void loadArgArray() {

+        push(argumentTypes.length);

+        newArray(OBJECT_TYPE);

+        for (int i = 0; i < argumentTypes.length; i++) {

+            dup();

+            push(i);

+            loadArg(i);

+            box(argumentTypes[i]);

+            arrayStore(OBJECT_TYPE);

+        }

+    }

+

+    /**

+     * Generates the instruction to store the top stack value in the given

+     * method argument.

+     * 

+     * @param arg the index of a method argument.

+     */

+    public void storeArg(final int arg) {

+        storeInsn(argumentTypes[arg], getArgIndex(arg));

+    }

+

+    // ------------------------------------------------------------------------

+    // Instructions to load and store local variables

+    // ------------------------------------------------------------------------

+

+    /**

+     * Returns the type of the given local variable.

+     * 

+     * @param local a local variable identifier, as returned by

+     *        {@link LocalVariablesSorter#newLocal(Type) newLocal()}.

+     * @return the type of the given local variable.

+     */

+    public Type getLocalType(final int local) {

+        return (Type) localTypes.get(local - firstLocal);

+    }

+

+    protected void setLocalType(final int local, final Type type) {

+        int index = local - firstLocal;

+        while (localTypes.size() < index + 1) {

+            localTypes.add(null);

+        }

+        localTypes.set(index, type);

+    }

+

+    /**

+     * Generates the instruction to load the given local variable on the stack.

+     * 

+     * @param local a local variable identifier, as returned by

+     *        {@link LocalVariablesSorter#newLocal(Type) newLocal()}.

+     */

+    public void loadLocal(final int local) {

+        loadInsn(getLocalType(local), local);

+    }

+

+    /**

+     * Generates the instruction to load the given local variable on the stack.

+     * 

+     * @param local a local variable identifier, as returned by

+     *        {@link LocalVariablesSorter#newLocal(Type) newLocal()}.

+     * @param type the type of this local variable.

+     */

+    public void loadLocal(final int local, final Type type) {

+        setLocalType(local, type);

+        loadInsn(type, local);

+    }

+

+    /**

+     * Generates the instruction to store the top stack value in the given local

+     * variable.

+     * 

+     * @param local a local variable identifier, as returned by

+     *        {@link LocalVariablesSorter#newLocal(Type) newLocal()}.

+     */

+    public void storeLocal(final int local) {

+        storeInsn(getLocalType(local), local);

+    }

+

+    /**

+     * Generates the instruction to store the top stack value in the given local

+     * variable.

+     * 

+     * @param local a local variable identifier, as returned by

+     *        {@link LocalVariablesSorter#newLocal(Type) newLocal()}.

+     * @param type the type of this local variable.

+     */

+    public void storeLocal(final int local, final Type type) {

+        setLocalType(local, type);

+        storeInsn(type, local);

+    }

+

+    /**

+     * Generates the instruction to load an element from an array.

+     * 

+     * @param type the type of the array element to be loaded.

+     */

+    public void arrayLoad(final Type type) {

+        mv.visitInsn(type.getOpcode(Opcodes.IALOAD));

+    }

+

+    /**

+     * Generates the instruction to store an element in an array.

+     * 

+     * @param type the type of the array element to be stored.

+     */

+    public void arrayStore(final Type type) {

+        mv.visitInsn(type.getOpcode(Opcodes.IASTORE));

+    }

+

+    // ------------------------------------------------------------------------

+    // Instructions to manage the stack

+    // ------------------------------------------------------------------------

+

+    /**

+     * Generates a POP instruction.

+     */

+    public void pop() {

+        mv.visitInsn(Opcodes.POP);

+    }

+

+    /**

+     * Generates a POP2 instruction.

+     */

+    public void pop2() {

+        mv.visitInsn(Opcodes.POP2);

+    }

+

+    /**

+     * Generates a DUP instruction.

+     */

+    public void dup() {

+        mv.visitInsn(Opcodes.DUP);

+    }

+

+    /**

+     * Generates a DUP2 instruction.

+     */

+    public void dup2() {

+        mv.visitInsn(Opcodes.DUP2);

+    }

+

+    /**

+     * Generates a DUP_X1 instruction.

+     */

+    public void dupX1() {

+        mv.visitInsn(Opcodes.DUP_X1);

+    }

+

+    /**

+     * Generates a DUP_X2 instruction.

+     */

+    public void dupX2() {

+        mv.visitInsn(Opcodes.DUP_X2);

+    }

+

+    /**

+     * Generates a DUP2_X1 instruction.

+     */

+    public void dup2X1() {

+        mv.visitInsn(Opcodes.DUP2_X1);

+    }

+

+    /**

+     * Generates a DUP2_X2 instruction.

+     */

+    public void dup2X2() {

+        mv.visitInsn(Opcodes.DUP2_X2);

+    }

+

+    /**

+     * Generates a SWAP instruction.

+     */

+    public void swap() {

+        mv.visitInsn(Opcodes.SWAP);

+    }

+

+    /**

+     * Generates the instructions to swap the top two stack values.

+     * 

+     * @param prev type of the top - 1 stack value.

+     * @param type type of the top stack value.

+     */

+    public void swap(final Type prev, final Type type) {

+        if (type.getSize() == 1) {

+            if (prev.getSize() == 1) {

+                swap(); // same as dupX1(), pop();

+            } else {

+                dupX2();

+                pop();

+            }

+        } else {

+            if (prev.getSize() == 1) {

+                dup2X1();

+                pop2();

+            } else {

+                dup2X2();

+                pop2();

+            }

+        }

+    }

+

+    // ------------------------------------------------------------------------

+    // Instructions to do mathematical and logical operations

+    // ------------------------------------------------------------------------

+

+    /**

+     * Generates the instruction to do the specified mathematical or logical

+     * operation.

+     * 

+     * @param op a mathematical or logical operation. Must be one of ADD, SUB,

+     *        MUL, DIV, REM, NEG, SHL, SHR, USHR, AND, OR, XOR.

+     * @param type the type of the operand(s) for this operation.

+     */

+    public void math(final int op, final Type type) {

+        mv.visitInsn(type.getOpcode(op));

+    }

+

+    /**

+     * Generates the instructions to compute the bitwise negation of the top

+     * stack value.

+     */

+    public void not() {

+        mv.visitInsn(Opcodes.ICONST_1);

+        mv.visitInsn(Opcodes.IXOR);

+    }

+

+    /**

+     * Generates the instruction to increment the given local variable.

+     * 

+     * @param local the local variable to be incremented.

+     * @param amount the amount by which the local variable must be incremented.

+     */

+    public void iinc(final int local, final int amount) {

+        mv.visitIincInsn(local, amount);

+    }

+

+    /**

+     * Generates the instructions to cast a numerical value from one type to

+     * another.

+     * 

+     * @param from the type of the top stack value

+     * @param to the type into which this value must be cast.

+     */

+    public void cast(final Type from, final Type to) {

+        if (from != to) {

+            if (from == Type.DOUBLE_TYPE) {

+                if (to == Type.FLOAT_TYPE) {

+                    mv.visitInsn(Opcodes.D2F);

+                } else if (to == Type.LONG_TYPE) {

+                    mv.visitInsn(Opcodes.D2L);

+                } else {

+                    mv.visitInsn(Opcodes.D2I);

+                    cast(Type.INT_TYPE, to);

+                }

+            } else if (from == Type.FLOAT_TYPE) {

+                if (to == Type.DOUBLE_TYPE) {

+                    mv.visitInsn(Opcodes.F2D);

+                } else if (to == Type.LONG_TYPE) {

+                    mv.visitInsn(Opcodes.F2L);

+                } else {

+                    mv.visitInsn(Opcodes.F2I);

+                    cast(Type.INT_TYPE, to);

+                }

+            } else if (from == Type.LONG_TYPE) {

+                if (to == Type.DOUBLE_TYPE) {

+                    mv.visitInsn(Opcodes.L2D);

+                } else if (to == Type.FLOAT_TYPE) {

+                    mv.visitInsn(Opcodes.L2F);

+                } else {

+                    mv.visitInsn(Opcodes.L2I);

+                    cast(Type.INT_TYPE, to);

+                }

+            } else {

+                if (to == Type.BYTE_TYPE) {

+                    mv.visitInsn(Opcodes.I2B);

+                } else if (to == Type.CHAR_TYPE) {

+                    mv.visitInsn(Opcodes.I2C);

+                } else if (to == Type.DOUBLE_TYPE) {

+                    mv.visitInsn(Opcodes.I2D);

+                } else if (to == Type.FLOAT_TYPE) {

+                    mv.visitInsn(Opcodes.I2F);

+                } else if (to == Type.LONG_TYPE) {

+                    mv.visitInsn(Opcodes.I2L);

+                } else if (to == Type.SHORT_TYPE) {

+                    mv.visitInsn(Opcodes.I2S);

+                }

+            }

+        }

+    }

+

+    // ------------------------------------------------------------------------

+    // Instructions to do boxing and unboxing operations

+    // ------------------------------------------------------------------------

+

+    /**

+     * Generates the instructions to box the top stack value. This value is

+     * replaced by its boxed equivalent on top of the stack.

+     * 

+     * @param type the type of the top stack value.

+     */

+    public void box(final Type type) {

+        if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {

+            return;

+        }

+        if (type == Type.VOID_TYPE) {

+            push((String) null);

+        } else {

+            Type boxed = type;

+            switch (type.getSort()) {

+                case Type.BYTE:

+                    boxed = BYTE_TYPE;

+                    break;

+                case Type.BOOLEAN:

+                    boxed = BOOLEAN_TYPE;

+                    break;

+                case Type.SHORT:

+                    boxed = SHORT_TYPE;

+                    break;

+                case Type.CHAR:

+                    boxed = CHARACTER_TYPE;

+                    break;

+                case Type.INT:

+                    boxed = INTEGER_TYPE;

+                    break;

+                case Type.FLOAT:

+                    boxed = FLOAT_TYPE;

+                    break;

+                case Type.LONG:

+                    boxed = LONG_TYPE;

+                    break;

+                case Type.DOUBLE:

+                    boxed = DOUBLE_TYPE;

+                    break;

+            }

+            newInstance(boxed);

+            if (type.getSize() == 2) {

+                // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o

+                dupX2();

+                dupX2();

+                pop();

+            } else {

+                // p -> po -> opo -> oop -> o

+                dupX1();

+                swap();

+            }

+            invokeConstructor(boxed, new Method("<init>",

+                    Type.VOID_TYPE,

+                    new Type[] { type }));

+        }

+    }

+

+    /**

+     * Generates the instructions to unbox the top stack value. This value is

+     * replaced by its unboxed equivalent on top of the stack.

+     * 

+     * @param type the type of the top stack value.

+     */

+    public void unbox(final Type type) {

+        Type t = NUMBER_TYPE;

+        Method sig = null;

+        switch (type.getSort()) {

+            case Type.VOID:

+                return;

+            case Type.CHAR:

+                t = CHARACTER_TYPE;

+                sig = CHAR_VALUE;

+                break;

+            case Type.BOOLEAN:

+                t = BOOLEAN_TYPE;

+                sig = BOOLEAN_VALUE;

+                break;

+            case Type.DOUBLE:

+                sig = DOUBLE_VALUE;

+                break;

+            case Type.FLOAT:

+                sig = FLOAT_VALUE;

+                break;

+            case Type.LONG:

+                sig = LONG_VALUE;

+                break;

+            case Type.INT:

+            case Type.SHORT:

+            case Type.BYTE:

+                sig = INT_VALUE;

+        }

+        if (sig == null) {

+            checkCast(type);

+        } else {

+            checkCast(t);

+            invokeVirtual(t, sig);

+        }

+    }

+

+    // ------------------------------------------------------------------------

+    // Instructions to jump to other instructions

+    // ------------------------------------------------------------------------

+

+    /**

+     * Creates a new {@link Label}.

+     * 

+     * @return a new {@link Label}.

+     */

+    public Label newLabel() {

+        return new Label();

+    }

+

+    /**

+     * Marks the current code position with the given label.

+     * 

+     * @param label a label.

+     */

+    public void mark(final Label label) {

+        mv.visitLabel(label);

+    }

+

+    /**

+     * Marks the current code position with a new label.

+     * 

+     * @return the label that was created to mark the current code position.

+     */

+    public Label mark() {

+        Label label = new Label();

+        mv.visitLabel(label);

+        return label;

+    }

+

+    /**

+     * Generates the instructions to jump to a label based on the comparison of

+     * the top two stack values.

+     * 

+     * @param type the type of the top two stack values.

+     * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,

+     *        LE.

+     * @param label where to jump if the comparison result is <tt>true</tt>.

+     */

+    public void ifCmp(final Type type, final int mode, final Label label) {

+        int intOp = -1;

+        switch (type.getSort()) {

+            case Type.LONG:

+                mv.visitInsn(Opcodes.LCMP);

+                break;

+            case Type.DOUBLE:

+                mv.visitInsn(Opcodes.DCMPG);

+                break;

+            case Type.FLOAT:

+                mv.visitInsn(Opcodes.FCMPG);

+                break;

+            case Type.ARRAY:

+            case Type.OBJECT:

+                switch (mode) {

+                    case EQ:

+                        mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);

+                        return;

+                    case NE:

+                        mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);

+                        return;

+                }

+                throw new IllegalArgumentException("Bad comparison for type "

+                        + type);

+            default:

+                switch (mode) {

+                    case EQ:

+                        intOp = Opcodes.IF_ICMPEQ;

+                        break;

+                    case NE:

+                        intOp = Opcodes.IF_ICMPNE;

+                        break;

+                    case GE:

+                        intOp = Opcodes.IF_ICMPGE;

+                        break;

+                    case LT:

+                        intOp = Opcodes.IF_ICMPLT;

+                        break;

+                    case LE:

+                        intOp = Opcodes.IF_ICMPLE;

+                        break;

+                    case GT:

+                        intOp = Opcodes.IF_ICMPGT;

+                        break;

+                }

+                mv.visitJumpInsn(intOp, label);

+                return;

+        }

+        int jumpMode = mode;

+        switch (mode) {

+            case GE:

+                jumpMode = LT;

+                break;

+            case LE:

+                jumpMode = GT;

+                break;

+        }

+        mv.visitJumpInsn(jumpMode, label);

+    }

+

+    /**

+     * Generates the instructions to jump to a label based on the comparison of

+     * the top two integer stack values.

+     * 

+     * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,

+     *        LE.

+     * @param label where to jump if the comparison result is <tt>true</tt>.

+     */

+    public void ifICmp(final int mode, final Label label) {

+        ifCmp(Type.INT_TYPE, mode, label);

+    }

+

+    /**

+     * Generates the instructions to jump to a label based on the comparison of

+     * the top integer stack value with zero.

+     * 

+     * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,

+     *        LE.

+     * @param label where to jump if the comparison result is <tt>true</tt>.

+     */

+    public void ifZCmp(final int mode, final Label label) {

+        mv.visitJumpInsn(mode, label);

+    }

+

+    /**

+     * Generates the instruction to jump to the given label if the top stack

+     * value is null.

+     * 

+     * @param label where to jump if the condition is <tt>true</tt>.

+     */

+    public void ifNull(final Label label) {

+        mv.visitJumpInsn(Opcodes.IFNULL, label);

+    }

+

+    /**

+     * Generates the instruction to jump to the given label if the top stack

+     * value is not null.

+     * 

+     * @param label where to jump if the condition is <tt>true</tt>.

+     */

+    public void ifNonNull(final Label label) {

+        mv.visitJumpInsn(Opcodes.IFNONNULL, label);

+    }

+

+    /**

+     * Generates the instruction to jump to the given label.

+     * 

+     * @param label where to jump if the condition is <tt>true</tt>.

+     */

+    public void goTo(final Label label) {

+        mv.visitJumpInsn(Opcodes.GOTO, label);

+    }

+

+    /**

+     * Generates a RET instruction.

+     * 

+     * @param local a local variable identifier, as returned by

+     *        {@link LocalVariablesSorter#newLocal(Type) newLocal()}.

+     */

+    public void ret(final int local) {

+        mv.visitVarInsn(Opcodes.RET, local);

+    }

+

+    /**

+     * Generates the instructions for a switch statement.

+     * 

+     * @param keys the switch case keys.

+     * @param generator a generator to generate the code for the switch cases.

+     */

+    public void tableSwitch(

+        final int[] keys,

+        final TableSwitchGenerator generator)

+    {

+        float density;

+        if (keys.length == 0) {

+            density = 0;

+        } else {

+            density = (float) keys.length

+                    / (keys[keys.length - 1] - keys[0] + 1);

+        }

+        tableSwitch(keys, generator, density >= 0.5f);

+    }

+

+    /**

+     * Generates the instructions for a switch statement.

+     * 

+     * @param keys the switch case keys.

+     * @param generator a generator to generate the code for the switch cases.

+     * @param useTable <tt>true</tt> to use a TABLESWITCH instruction, or

+     *        <tt>false</tt> to use a LOOKUPSWITCH instruction.

+     */

+    public void tableSwitch(

+        final int[] keys,

+        final TableSwitchGenerator generator,

+        final boolean useTable)

+    {

+        for (int i = 1; i < keys.length; ++i) {

+            if (keys[i] < keys[i - 1]) {

+                throw new IllegalArgumentException("keys must be sorted ascending");

+            }

+        }

+        Label def = newLabel();

+        Label end = newLabel();

+        if (keys.length > 0) {

+            int len = keys.length;

+            int min = keys[0];

+            int max = keys[len - 1];

+            int range = max - min + 1;

+            if (useTable) {

+                Label[] labels = new Label[range];

+                Arrays.fill(labels, def);

+                for (int i = 0; i < len; ++i) {

+                    labels[keys[i] - min] = newLabel();

+                }

+                mv.visitTableSwitchInsn(min, max, def, labels);

+                for (int i = 0; i < range; ++i) {

+                    Label label = labels[i];

+                    if (label != def) {

+                        mark(label);

+                        generator.generateCase(i + min, end);

+                    }

+                }

+            } else {

+                Label[] labels = new Label[len];

+                for (int i = 0; i < len; ++i) {

+                    labels[i] = newLabel();

+                }

+                mv.visitLookupSwitchInsn(def, keys, labels);

+                for (int i = 0; i < len; ++i) {

+                    mark(labels[i]);

+                    generator.generateCase(keys[i], end);

+                }

+            }

+        }

+        mark(def);

+        generator.generateDefault();

+        mark(end);

+    }

+

+    /**

+     * Generates the instruction to return the top stack value to the caller.

+     */

+    public void returnValue() {

+        mv.visitInsn(returnType.getOpcode(Opcodes.IRETURN));

+    }

+

+    // ------------------------------------------------------------------------

+    // Instructions to load and store fields

+    // ------------------------------------------------------------------------

+

+    /**

+     * Generates a get field or set field instruction.

+     * 

+     * @param opcode the instruction's opcode.

+     * @param ownerType the class in which the field is defined.

+     * @param name the name of the field.

+     * @param fieldType the type of the field.

+     */

+    private void fieldInsn(

+        final int opcode,

+        final Type ownerType,

+        final String name,

+        final Type fieldType)

+    {

+        mv.visitFieldInsn(opcode,

+                ownerType.getInternalName(),

+                name,

+                fieldType.getDescriptor());

+    }

+

+    /**

+     * Generates the instruction to push the value of a static field on the

+     * stack.

+     * 

+     * @param owner the class in which the field is defined.

+     * @param name the name of the field.

+     * @param type the type of the field.

+     */

+    public void getStatic(final Type owner, final String name, final Type type)

+    {

+        fieldInsn(Opcodes.GETSTATIC, owner, name, type);

+    }

+

+    /**

+     * Generates the instruction to store the top stack value in a static field.

+     * 

+     * @param owner the class in which the field is defined.

+     * @param name the name of the field.

+     * @param type the type of the field.

+     */

+    public void putStatic(final Type owner, final String name, final Type type)

+    {

+        fieldInsn(Opcodes.PUTSTATIC, owner, name, type);

+    }

+

+    /**

+     * Generates the instruction to push the value of a non static field on the

+     * stack.

+     * 

+     * @param owner the class in which the field is defined.

+     * @param name the name of the field.

+     * @param type the type of the field.

+     */

+    public void getField(final Type owner, final String name, final Type type) {

+        fieldInsn(Opcodes.GETFIELD, owner, name, type);

+    }

+

+    /**

+     * Generates the instruction to store the top stack value in a non static

+     * field.

+     * 

+     * @param owner the class in which the field is defined.

+     * @param name the name of the field.

+     * @param type the type of the field.

+     */

+    public void putField(final Type owner, final String name, final Type type) {

+        fieldInsn(Opcodes.PUTFIELD, owner, name, type);

+    }

+

+    // ------------------------------------------------------------------------

+    // Instructions to invoke methods

+    // ------------------------------------------------------------------------

+

+    /**

+     * Generates an invoke method instruction.

+     * 

+     * @param opcode the instruction's opcode.

+     * @param type the class in which the method is defined.

+     * @param method the method to be invoked.

+     */

+    private void invokeInsn(

+        final int opcode,

+        final Type type,

+        final Method method)

+    {

+        String owner = type.getSort() == Type.ARRAY

+                ? type.getDescriptor()

+                : type.getInternalName();

+        mv.visitMethodInsn(opcode,

+                owner,

+                method.getName(),

+                method.getDescriptor());

+    }

+

+    /**

+     * Generates the instruction to invoke a normal method.

+     * 

+     * @param owner the class in which the method is defined.

+     * @param method the method to be invoked.

+     */

+    public void invokeVirtual(final Type owner, final Method method) {

+        invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method);

+    }

+

+    /**

+     * Generates the instruction to invoke a constructor.

+     * 

+     * @param type the class in which the constructor is defined.

+     * @param method the constructor to be invoked.

+     */

+    public void invokeConstructor(final Type type, final Method method) {

+        invokeInsn(Opcodes.INVOKESPECIAL, type, method);

+    }

+

+    /**

+     * Generates the instruction to invoke a static method.

+     * 

+     * @param owner the class in which the method is defined.

+     * @param method the method to be invoked.

+     */

+    public void invokeStatic(final Type owner, final Method method) {

+        invokeInsn(Opcodes.INVOKESTATIC, owner, method);

+    }

+

+    /**

+     * Generates the instruction to invoke an interface method.

+     * 

+     * @param owner the class in which the method is defined.

+     * @param method the method to be invoked.

+     */

+    public void invokeInterface(final Type owner, final Method method) {

+        invokeInsn(Opcodes.INVOKEINTERFACE, owner, method);

+    }

+

+    // ------------------------------------------------------------------------

+    // Instructions to create objects and arrays

+    // ------------------------------------------------------------------------

+

+    /**

+     * Generates a type dependent instruction.

+     * 

+     * @param opcode the instruction's opcode.

+     * @param type the instruction's operand.

+     */

+    private void typeInsn(final int opcode, final Type type) {

+        String desc;

+        if (type.getSort() == Type.ARRAY) {

+            desc = type.getDescriptor();

+        } else {

+            desc = type.getInternalName();

+        }

+        mv.visitTypeInsn(opcode, desc);

+    }

+

+    /**

+     * Generates the instruction to create a new object.

+     * 

+     * @param type the class of the object to be created.

+     */

+    public void newInstance(final Type type) {

+        typeInsn(Opcodes.NEW, type);

+    }

+

+    /**

+     * Generates the instruction to create a new array.

+     * 

+     * @param type the type of the array elements.

+     */

+    public void newArray(final Type type) {

+        int typ;

+        switch (type.getSort()) {

+            case Type.BOOLEAN:

+                typ = Opcodes.T_BOOLEAN;

+                break;

+            case Type.CHAR:

+                typ = Opcodes.T_CHAR;

+                break;

+            case Type.BYTE:

+                typ = Opcodes.T_BYTE;

+                break;

+            case Type.SHORT:

+                typ = Opcodes.T_SHORT;

+                break;

+            case Type.INT:

+                typ = Opcodes.T_INT;

+                break;

+            case Type.FLOAT:

+                typ = Opcodes.T_FLOAT;

+                break;

+            case Type.LONG:

+                typ = Opcodes.T_LONG;

+                break;

+            case Type.DOUBLE:

+                typ = Opcodes.T_DOUBLE;

+                break;

+            default:

+                typeInsn(Opcodes.ANEWARRAY, type);

+                return;

+        }

+        mv.visitIntInsn(Opcodes.NEWARRAY, typ);

+    }

+

+    // ------------------------------------------------------------------------

+    // Miscelaneous instructions

+    // ------------------------------------------------------------------------

+

+    /**

+     * Generates the instruction to compute the length of an array.

+     */

+    public void arrayLength() {

+        mv.visitInsn(Opcodes.ARRAYLENGTH);

+    }

+

+    /**

+     * Generates the instruction to throw an exception.

+     */

+    public void throwException() {

+        mv.visitInsn(Opcodes.ATHROW);

+    }

+

+    /**

+     * Generates the instructions to create and throw an exception. The

+     * exception class must have a constructor with a single String argument.

+     * 

+     * @param type the class of the exception to be thrown.

+     * @param msg the detailed message of the exception.

+     */

+    public void throwException(final Type type, final String msg) {

+        newInstance(type);

+        dup();

+        push(msg);

+        invokeConstructor(type, Method.getMethod("void <init> (String)"));

+        throwException();

+    }

+

+    /**

+     * Generates the instruction to check that the top stack value is of the

+     * given type.

+     * 

+     * @param type a class or interface type.

+     */

+    public void checkCast(final Type type) {

+        if (!type.equals(OBJECT_TYPE)) {

+            typeInsn(Opcodes.CHECKCAST, type);

+        }

+    }

+

+    /**

+     * Generates the instruction to test if the top stack value is of the given

+     * type.

+     * 

+     * @param type a class or interface type.

+     */

+    public void instanceOf(final Type type) {

+        typeInsn(Opcodes.INSTANCEOF, type);

+    }

+

+    /**

+     * Generates the instruction to get the monitor of the top stack value.

+     */

+    public void monitorEnter() {

+        mv.visitInsn(Opcodes.MONITORENTER);

+    }

+

+    /**

+     * Generates the instruction to release the monitor of the top stack value.

+     */

+    public void monitorExit() {

+        mv.visitInsn(Opcodes.MONITOREXIT);

+    }

+

+    // ------------------------------------------------------------------------

+    // Non instructions

+    // ------------------------------------------------------------------------

+

+    /**

+     * Marks the end of the visited method.

+     */

+    public void endMethod() {

+        if ((access & Opcodes.ACC_ABSTRACT) == 0) {

+            mv.visitMaxs(0, 0);

+        }

+        mv.visitEnd();

+    }

+

+    /**

+     * Marks the start of an exception handler.

+     * 

+     * @param start beginning of the exception handler's scope (inclusive).

+     * @param end end of the exception handler's scope (exclusive).

+     * @param exception internal name of the type of exceptions handled by the

+     *        handler.

+     */

+    public void catchException(

+        final Label start,

+        final Label end,

+        final Type exception)

+    {

+        mv.visitTryCatchBlock(start, end, mark(), exception.getInternalName());

+    }

+}

diff --git a/ipojo/manipulator/src/main/java/org/objectweb/asm/commons/LocalVariablesSorter.java b/ipojo/manipulator/src/main/java/org/objectweb/asm/commons/LocalVariablesSorter.java
new file mode 100644
index 0000000..96c8283
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/objectweb/asm/commons/LocalVariablesSorter.java
@@ -0,0 +1,314 @@
+/***

+ * ASM: a very small and fast Java bytecode manipulation framework

+ * Copyright (c) 2000-2005 INRIA, France Telecom

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without

+ * modification, are permitted provided that the following conditions

+ * are met:

+ * 1. Redistributions of source code must retain the above copyright

+ *    notice, this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright

+ *    notice, this list of conditions and the following disclaimer in the

+ *    documentation and/or other materials provided with the distribution.

+ * 3. Neither the name of the copyright holders nor the names of its

+ *    contributors may be used to endorse or promote products derived from

+ *    this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"

+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE

+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR

+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF

+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF

+ * THE POSSIBILITY OF SUCH DAMAGE.

+ */

+package org.objectweb.asm.commons;

+

+import org.objectweb.asm.Label;

+import org.objectweb.asm.MethodAdapter;

+import org.objectweb.asm.MethodVisitor;

+import org.objectweb.asm.Opcodes;

+import org.objectweb.asm.Type;

+

+/**

+ * A {@link MethodAdapter} that renumbers local variables in their order of

+ * appearance. This adapter allows one to easily add new local variables to a

+ * method. It may be used by inheriting from this class, but the preferred way

+ * of using it is via delegation: the next visitor in the chain can indeed add

+ * new locals when needed by calling {@link #newLocal} on this adapter (this

+ * requires a reference back to this {@link LocalVariablesSorter}).

+ * 

+ * @author Chris Nokleberg

+ * @author Eugene Kuleshov

+ * @author Eric Bruneton

+ */

+public class LocalVariablesSorter extends MethodAdapter {

+

+    private final static Type OBJECT_TYPE = Type.getObjectType("java/lang/Object");

+

+    /**

+     * Mapping from old to new local variable indexes. A local variable at index

+     * i of size 1 is remapped to 'mapping[2*i]', while a local variable at

+     * index i of size 2 is remapped to 'mapping[2*i+1]'.

+     */

+    private int[] mapping = new int[40];

+

+    /**

+     * Array used to store stack map local variable types after remapping.

+     */

+    private Object[] newLocals = new Object[20];

+

+    /**

+     * Index of the first local variable, after formal parameters.

+     */

+    protected final int firstLocal;

+

+    /**

+     * Index of the next local variable to be created by {@link #newLocal}.

+     */

+    protected int nextLocal;

+

+    /**

+     * Indicates if at least one local variable has moved due to remapping.

+     */

+    private boolean changed;

+

+    /**

+     * Creates a new {@link LocalVariablesSorter}.

+     * 

+     * @param access access flags of the adapted method.

+     * @param desc the method's descriptor (see {@link Type Type}).

+     * @param mv the method visitor to which this adapter delegates calls.

+     */

+    public LocalVariablesSorter(

+        final int access,

+        final String desc,

+        final MethodVisitor mv)

+    {

+        super(mv);

+        Type[] args = Type.getArgumentTypes(desc);

+        nextLocal = (Opcodes.ACC_STATIC & access) != 0 ? 0 : 1;

+        for (int i = 0; i < args.length; i++) {

+            nextLocal += args[i].getSize();

+        }

+        firstLocal = nextLocal;

+    }

+

+    public void visitVarInsn(final int opcode, final int var) {

+        Type type;

+        switch (opcode) {

+            case Opcodes.LLOAD:

+            case Opcodes.LSTORE:

+                type = Type.LONG_TYPE;

+                break;

+

+            case Opcodes.DLOAD:

+            case Opcodes.DSTORE:

+                type = Type.DOUBLE_TYPE;

+                break;

+

+            case Opcodes.FLOAD:

+            case Opcodes.FSTORE:

+                type = Type.FLOAT_TYPE;

+                break;

+

+            case Opcodes.ILOAD:

+            case Opcodes.ISTORE:

+                type = Type.INT_TYPE;

+                break;

+

+            case Opcodes.ALOAD:

+            case Opcodes.ASTORE:

+                type = OBJECT_TYPE;

+                break;

+

+            // case RET:

+            default:

+                type = Type.VOID_TYPE;

+        }

+        mv.visitVarInsn(opcode, remap(var, type));

+    }

+

+    public void visitIincInsn(final int var, final int increment) {

+        mv.visitIincInsn(remap(var, Type.INT_TYPE), increment);

+    }

+

+    public void visitMaxs(final int maxStack, final int maxLocals) {

+        mv.visitMaxs(maxStack, nextLocal);

+    }

+

+    public void visitLocalVariable(

+        final String name,

+        final String desc,

+        final String signature,

+        final Label start,

+        final Label end,

+        final int index)

+    {

+        int size = "J".equals(desc) || "D".equals(desc) ? 2 : 1;

+        int newIndex = remap(index, size);

+        mv.visitLocalVariable(name, desc, signature, start, end, newIndex);

+    }

+

+    public void visitFrame(

+        final int type,

+        final int nLocal,

+        final Object[] local,

+        final int nStack,

+        final Object[] stack)

+    {

+        if (type != Opcodes.F_NEW) { // uncompressed frame

+            throw new IllegalStateException("ClassReader.accept() should be called with EXPAND_FRAMES flag");

+        }

+

+        if (!changed) { // optimization for the case where mapping = identity

+            mv.visitFrame(type, nLocal, local, nStack, stack);

+            return;

+        }

+

+        // creates a copy of newLocals

+        Object[] oldLocals = new Object[newLocals.length];

+        System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length);

+

+        // copies types from 'local' to 'newLocals'

+        // 'newLocals' already contains the variables added with 'newLocal'

+

+        int index = 0; // old local variable index

+        int number = 0; // old local variable number

+        for (; number < nLocal; ++number) {

+            Object t = local[number];

+            int size = t == Opcodes.LONG || t == Opcodes.DOUBLE ? 2 : 1;

+            if (t != Opcodes.TOP) {

+                setFrameLocal(remap(index, size), t);

+            }

+            index += size;

+        }

+

+        // removes TOP after long and double types as well as trailing TOPs

+

+        index = 0;

+        number = 0;

+        for (int i = 0; index < newLocals.length; ++i) {

+            Object t = newLocals[index++];

+            if (t != null && t != Opcodes.TOP) {

+                newLocals[i] = t;

+                number = i + 1;

+                if (t == Opcodes.LONG || t == Opcodes.DOUBLE) {

+                    index += 1;

+                }

+            } else {

+                newLocals[i] = Opcodes.TOP;

+            }

+        }

+

+        // visits remapped frame

+        mv.visitFrame(type, number, newLocals, nStack, stack);

+

+        // restores original value of 'newLocals'

+        newLocals = oldLocals;

+    }

+

+    // -------------

+

+    /**

+     * Creates a new local variable of the given type.

+     * 

+     * @param type the type of the local variable to be created.

+     * @return the identifier of the newly created local variable.

+     */

+    public int newLocal(final Type type) {

+        Object t;

+        switch (type.getSort()) {

+            case Type.BOOLEAN:

+            case Type.CHAR:

+            case Type.BYTE:

+            case Type.SHORT:

+            case Type.INT:

+                t = Opcodes.INTEGER;

+                break;

+            case Type.FLOAT:

+                t = Opcodes.FLOAT;

+                break;

+            case Type.LONG:

+                t = Opcodes.LONG;

+                break;

+            case Type.DOUBLE:

+                t = Opcodes.DOUBLE;

+                break;

+            case Type.ARRAY:

+                t = type.getDescriptor();

+                break;

+            // case Type.OBJECT:

+            default:

+                t = type.getInternalName();

+                break;

+        }

+        int local = nextLocal;

+        setLocalType(local, type);

+        setFrameLocal(local, t);

+        nextLocal += type.getSize();

+        return local;

+    }

+

+    /**

+     * Sets the current type of the given local variable. The default

+     * implementation of this method does nothing.

+     * 

+     * @param local a local variable identifier, as returned by {@link #newLocal

+     *        newLocal()}.

+     * @param type the type of the value being stored in the local variable

+     */

+    protected void setLocalType(final int local, final Type type) {

+    }

+

+    private void setFrameLocal(final int local, final Object type) {

+        int l = newLocals.length;

+        if (local >= l) {

+            Object[] a = new Object[Math.max(2 * l, local + 1)];

+            System.arraycopy(newLocals, 0, a, 0, l);

+            newLocals = a;

+        }

+        newLocals[local] = type;

+    }

+

+    private int remap(final int var, final Type type) {

+        if (var < firstLocal) {

+            return var;

+        }

+        int key = 2 * var + type.getSize() - 1;

+        int size = mapping.length;

+        if (key >= size) {

+            int[] newMapping = new int[Math.max(2 * size, key + 1)];

+            System.arraycopy(mapping, 0, newMapping, 0, size);

+            mapping = newMapping;

+        }

+        int value = mapping[key];

+        if (value == 0) {

+            value = nextLocal + 1;

+            mapping[key] = value;

+            setLocalType(nextLocal, type);

+            nextLocal += type.getSize();

+        }

+        if (value - 1 != var) {

+            changed = true;

+        }

+        return value - 1;

+    }

+

+    private int remap(final int var, final int size) {

+        if (var < firstLocal || !changed) {

+            return var;

+        }

+        int key = 2 * var + size - 1;

+        int value = key < mapping.length ? mapping[key] : 0;

+        if (value == 0) {

+            throw new IllegalStateException("Unknown local variable " + var);

+        }

+        return value - 1;

+    }

+}

diff --git a/ipojo/manipulator/src/main/java/org/objectweb/asm/commons/Method.java b/ipojo/manipulator/src/main/java/org/objectweb/asm/commons/Method.java
new file mode 100644
index 0000000..e177d90
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/objectweb/asm/commons/Method.java
@@ -0,0 +1,254 @@
+/***

+ * ASM: a very small and fast Java bytecode manipulation framework

+ * Copyright (c) 2000-2005 INRIA, France Telecom

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without

+ * modification, are permitted provided that the following conditions

+ * are met:

+ * 1. Redistributions of source code must retain the above copyright

+ *    notice, this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright

+ *    notice, this list of conditions and the following disclaimer in the

+ *    documentation and/or other materials provided with the distribution.

+ * 3. Neither the name of the copyright holders nor the names of its

+ *    contributors may be used to endorse or promote products derived from

+ *    this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"

+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE

+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR

+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF

+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF

+ * THE POSSIBILITY OF SUCH DAMAGE.

+ */

+package org.objectweb.asm.commons;

+

+import java.util.HashMap;

+import java.util.Map;

+

+import org.objectweb.asm.Type;

+

+/**

+ * A named method descriptor.

+ * 

+ * @author Juozas Baliuka

+ * @author Chris Nokleberg

+ * @author Eric Bruneton

+ */

+public class Method {

+

+    /**

+     * The method name.

+     */

+    private final String name;

+

+    /**

+     * The method descriptor.

+     */

+    private final String desc;

+

+    /**

+     * Maps primitive Java type names to their descriptors.

+     */

+    private final static Map DESCRIPTORS;

+

+    static {

+        DESCRIPTORS = new HashMap();

+        DESCRIPTORS.put("void", "V");

+        DESCRIPTORS.put("byte", "B");

+        DESCRIPTORS.put("char", "C");

+        DESCRIPTORS.put("double", "D");

+        DESCRIPTORS.put("float", "F");

+        DESCRIPTORS.put("int", "I");

+        DESCRIPTORS.put("long", "J");

+        DESCRIPTORS.put("short", "S");

+        DESCRIPTORS.put("boolean", "Z");

+    }

+

+    /**

+     * Creates a new {@link Method}.

+     * 

+     * @param name the method's name.

+     * @param desc the method's descriptor.

+     */

+    public Method(final String name, final String desc) {

+        this.name = name;

+        this.desc = desc;

+    }

+

+    /**

+     * Creates a new {@link Method}.

+     * 

+     * @param name the method's name.

+     * @param returnType the method's return type.

+     * @param argumentTypes the method's argument types.

+     */

+    public Method(

+        final String name,

+        final Type returnType,

+        final Type[] argumentTypes)

+    {

+        this(name, Type.getMethodDescriptor(returnType, argumentTypes));

+    }

+

+    /**

+     * Returns a {@link Method} corresponding to the given Java method

+     * declaration.

+     * 

+     * @param method a Java method declaration, without argument names, of the

+     *        form "returnType name (argumentType1, ... argumentTypeN)", where

+     *        the types are in plain Java (e.g. "int", "float",

+     *        "java.util.List", ...). Classes of the java.lang package can be

+     *        specified by their unqualified name; all other classes names must

+     *        be fully qualified.

+     * @return a {@link Method} corresponding to the given Java method

+     *         declaration.

+     * @throws IllegalArgumentException if <code>method</code> could not get

+     *         parsed.

+     */

+    public static Method getMethod(final String method)

+            throws IllegalArgumentException

+    {

+        return getMethod(method, false);

+    }

+

+    /**

+     * Returns a {@link Method} corresponding to the given Java method

+     * declaration.

+     * 

+     * @param method a Java method declaration, without argument names, of the

+     *        form "returnType name (argumentType1, ... argumentTypeN)", where

+     *        the types are in plain Java (e.g. "int", "float",

+     *        "java.util.List", ...). Classes of the java.lang package may be

+     *        specified by their unqualified name, depending on the

+     *        defaultPackage argument; all other classes names must be fully

+     *        qualified.

+     * @param defaultPackage true if unqualified class names belong to the

+     *        default package, or false if they correspond to java.lang classes.

+     *        For instance "Object" means "Object" if this option is true, or

+     *        "java.lang.Object" otherwise.

+     * @return a {@link Method} corresponding to the given Java method

+     *         declaration.

+     * @throws IllegalArgumentException if <code>method</code> could not get

+     *         parsed.

+     */

+    public static Method getMethod(

+        final String method,

+        final boolean defaultPackage) throws IllegalArgumentException

+    {

+        int space = method.indexOf(' ');

+        int start = method.indexOf('(', space) + 1;

+        int end = method.indexOf(')', start);

+        if (space == -1 || start == -1 || end == -1) {

+            throw new IllegalArgumentException();

+        }

+        // TODO: Check validity of returnType, methodName and arguments.

+        String returnType = method.substring(0, space);

+        String methodName = method.substring(space + 1, start - 1).trim();

+        StringBuffer sb = new StringBuffer();

+        sb.append('(');

+        int p;

+        do {

+            String s;

+            p = method.indexOf(',', start);

+            if (p == -1) {

+                s = map(method.substring(start, end).trim(), defaultPackage);

+            } else {

+                s = map(method.substring(start, p).trim(), defaultPackage);

+                start = p + 1;

+            }

+            sb.append(s);

+        } while (p != -1);

+        sb.append(')');

+        sb.append(map(returnType, defaultPackage));

+        return new Method(methodName, sb.toString());

+    }

+

+    private static String map(final String type, final boolean defaultPackage) {

+        if (type.equals("")) {

+            return type;

+        }

+

+        StringBuffer sb = new StringBuffer();

+        int index = 0;

+        while ((index = type.indexOf("[]", index) + 1) > 0) {

+            sb.append('[');

+        }

+

+        String t = type.substring(0, type.length() - sb.length() * 2);

+        String desc = (String) DESCRIPTORS.get(t);

+        if (desc != null) {

+            sb.append(desc);

+        } else {

+            sb.append('L');

+            if (t.indexOf('.') < 0) {

+                if (!defaultPackage) {

+                    sb.append("java/lang/");

+                }

+                sb.append(t);

+            } else {

+                sb.append(t.replace('.', '/'));

+            }

+            sb.append(';');

+        }

+        return sb.toString();

+    }

+

+    /**

+     * Returns the name of the method described by this object.

+     * 

+     * @return the name of the method described by this object.

+     */

+    public String getName() {

+        return name;

+    }

+

+    /**

+     * Returns the descriptor of the method described by this object.

+     * 

+     * @return the descriptor of the method described by this object.

+     */

+    public String getDescriptor() {

+        return desc;

+    }

+

+    /**

+     * Returns the return type of the method described by this object.

+     * 

+     * @return the return type of the method described by this object.

+     */

+    public Type getReturnType() {

+        return Type.getReturnType(desc);

+    }

+

+    /**

+     * Returns the argument types of the method described by this object.

+     * 

+     * @return the argument types of the method described by this object.

+     */

+    public Type[] getArgumentTypes() {

+        return Type.getArgumentTypes(desc);

+    }

+

+    public String toString() {

+        return name + desc;

+    }

+

+    public boolean equals(final Object o) {

+        if (!(o instanceof Method)) {

+            return false;

+        }

+        Method other = (Method) o;

+        return name.equals(other.name) && desc.equals(other.desc);

+    }

+

+    public int hashCode() {

+        return name.hashCode() ^ desc.hashCode();

+    }

+}
\ No newline at end of file
diff --git a/ipojo/manipulator/src/main/java/org/objectweb/asm/commons/TableSwitchGenerator.java b/ipojo/manipulator/src/main/java/org/objectweb/asm/commons/TableSwitchGenerator.java
new file mode 100644
index 0000000..54653c8
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/objectweb/asm/commons/TableSwitchGenerator.java
@@ -0,0 +1,55 @@
+/***

+ * ASM: a very small and fast Java bytecode manipulation framework

+ * Copyright (c) 2000-2005 INRIA, France Telecom

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without

+ * modification, are permitted provided that the following conditions

+ * are met:

+ * 1. Redistributions of source code must retain the above copyright

+ *    notice, this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright

+ *    notice, this list of conditions and the following disclaimer in the

+ *    documentation and/or other materials provided with the distribution.

+ * 3. Neither the name of the copyright holders nor the names of its

+ *    contributors may be used to endorse or promote products derived from

+ *    this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"

+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE

+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR

+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF

+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF

+ * THE POSSIBILITY OF SUCH DAMAGE.

+ */

+package org.objectweb.asm.commons;

+

+import org.objectweb.asm.Label;

+

+/**

+ * A code generator for switch statements.

+ * 

+ * @author Juozas Baliuka

+ * @author Chris Nokleberg

+ * @author Eric Bruneton

+ */

+public interface TableSwitchGenerator {

+

+    /**

+     * Generates the code for a switch case.

+     * 

+     * @param key the switch case key.

+     * @param end a label that corresponds to the end of the switch statement.

+     */

+    void generateCase(int key, Label end);

+

+    /**

+     * Generates the code for the default switch case.

+     */

+    void generateDefault();

+}