Applied patch (FELIX-291) to cache component metadata during packaging.


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@539992 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/parser/FieldMetadata.java b/ipojo/src/main/java/org/apache/felix/ipojo/parser/FieldMetadata.java
new file mode 100644
index 0000000..46e0875
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/parser/FieldMetadata.java
@@ -0,0 +1,112 @@
+/* 
+ * 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.parser;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A Field Metadata represent a field of an implementation class.
+ * This class allow to avoid reflection to get the type and the name of a field.
+ * 
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class FieldMetadata {
+    
+    /**
+     * Name of the field.
+     */
+    private String m_name;
+    
+    /**
+     * Type of the field. 
+     */
+    private String m_type;
+    
+    /**
+     * Constructor.
+     * @param metadata : field manipulation element.
+     */
+    FieldMetadata(Element metadata) {
+        m_name = metadata.getAttribute("name");
+        m_type = metadata.getAttribute("type");
+    }
+    
+    public String getFieldName() { return m_name; }
+    
+    public String getFieldType() { return m_type; }
+    
+    /**
+     * Get the 'reflective' type of the field.
+     * The reflective type is the type used by the Java Reflection API.
+     * @return : the reflective type corresponding to this field.
+     */
+    public String getReflectionType() {
+        // Primitive Array 
+        if (m_type.endsWith("[]") && m_type.indexOf(".") == -1) {
+            String t = m_type.substring(0, m_type.length() - 2);
+            return "[" + getInternalPrimitiveType(t);
+        }
+        // Non-Primitive Array 
+        if (m_type.endsWith("[]") && m_type.indexOf(".") != -1) {
+            String t = m_type.substring(0, m_type.length() - 2);
+            return "[L" + t + ";";
+        }
+        // Simple type 
+        if (!m_type.endsWith("[]")) {
+            return m_type;
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Get the internal notation for primitive type.
+     * @param string : Stringform of the type
+     * @return the internal notation or null if not found
+     */
+    private String getInternalPrimitiveType(String string) {
+        if (string.equalsIgnoreCase("boolean")) {
+            return "Z";
+        }
+        if (string.equalsIgnoreCase("char")) {
+            return "C";
+        }
+        if (string.equalsIgnoreCase("byte")) {
+            return "B";
+        }
+        if (string.equalsIgnoreCase("short")) {
+            return "S";
+        }
+        if (string.equalsIgnoreCase("int")) {
+            return "I";
+        }
+        if (string.equalsIgnoreCase("float")) {
+            return "F";
+        }
+        if (string.equalsIgnoreCase("long")) {
+            return "J";
+        }
+        if (string.equalsIgnoreCase("double")) {
+            return "D";
+        }
+        System.err.println("No primitive type found for " + m_type);
+        return null;
+    }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/parser/ManipulationMetadata.java b/ipojo/src/main/java/org/apache/felix/ipojo/parser/ManipulationMetadata.java
new file mode 100644
index 0000000..62364cb
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/parser/ManipulationMetadata.java
@@ -0,0 +1,236 @@
+/* 
+ * 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.parser;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Manipulation Metadata allows getting information about the implementation class
+ * whithout doing reflection. 
+ * 
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ManipulationMetadata {
+    
+    /**
+     * List of implemented interfaces.
+     */
+    private String[] m_interfaces = new String[0];
+    
+    /**
+     * List of fields.
+     */
+    private FieldMetadata[] m_fields = new FieldMetadata[0];
+    
+    /**
+     * List of methods. 
+     */
+    private MethodMetadata[] m_methods = new MethodMetadata[0];
+    
+    
+    /**
+     * Constructor.
+     * Manipulation Metadata object are created from component type metadata by
+     * parsing manipulation metadata.
+     * @param metadata : component type metadata
+     */
+    public ManipulationMetadata(Element metadata) {
+        Element manip = metadata.getElements("manipulation", "")[0];
+        for (int i = 0; i < manip.getElements().length; i++) {
+            if (manip.getElements()[i].getName().equals("field")) {
+                FieldMetadata fm = new FieldMetadata(manip.getElements()[i]);
+                addField(fm);
+            } else if (manip.getElements()[i].getName().equals("method")) {
+                MethodMetadata fm = new MethodMetadata(manip.getElements()[i]);
+                addMethod(fm);
+            } else if (manip.getElements()[i].getName().equals("interface")) {
+                addInterface(manip.getElements()[i].getAttribute("name"));
+            }
+        }
+    }
+    
+    public MethodMetadata[] getMethods() { return m_methods; }
+    
+    public FieldMetadata[] getFields() { return m_fields; }
+    
+    public String[] getInterfaces() { return m_interfaces; }
+    
+    /**
+     * Get the field metadata for the given name. 
+     * @param name : name of the field
+     * @return the corresponding field metadata or null if not found
+     */
+    public FieldMetadata getField(String name) { 
+        for (int i = 0; i < m_fields.length; i++) {
+            if (m_fields[i].getFieldName().equalsIgnoreCase(name)) { return m_fields[i]; }
+        }
+        return null;
+    }
+    
+    /**
+     * Get the field metadata for the given name and type. 
+     * @param name : name of the field
+     * @param type : type of the field
+     * @return the corresponding field metadata or null if not found
+     */
+    public FieldMetadata getField(String name, String type) { 
+        for (int i = 0; i < m_fields.length; i++) {
+            if (m_fields[i].getFieldName().equalsIgnoreCase(name) && m_fields[i].getFieldType().equalsIgnoreCase(type)) { return m_fields[i]; }
+        }
+        return null;
+    }
+    
+    /**
+     * Check if the given interface name is implemented.
+     * @param itf : interface to check.
+     * @return true if the implementation class implement the given interface.
+     */
+    public boolean isInterfaceImplemented(String itf) {
+        for (int i = 0; i < m_interfaces.length; i++) {
+            if (m_interfaces[i].equals(itf)) { return true; }
+        }
+        return false;
+    }
+    
+    /**
+     * Get the MethodMetadata corresponding to the method
+     * (contained in the implementation class) to given name.
+     * If several method match, the first one is returned.
+     * @param name : name of the method to look for.
+     * @return the Method Metadate or null if not found
+     */
+    public MethodMetadata getMethod(String name) {
+        for (int i = 0; i < m_methods.length; i++) {
+            if (m_methods[i].getMethodName().equalsIgnoreCase(name)) { return m_methods[i]; }
+        }
+        return null;
+    }
+    
+    /**
+     * Get the MethodMetadata list corresponding to the method
+     * (contained in the implementation class) to given name.
+     * All methods contained in the implementation class matching 
+     * with the name are in the returned list.
+     * @param name : name of the method to look for.
+     * @return the Method Metadata array or an empty array if not found
+     */
+    public MethodMetadata[] getMethods(String name) {
+        MethodMetadata[] mms = new MethodMetadata[0];
+        for (int i = 0; i < m_methods.length; i++) {
+            if (m_methods[i].getMethodName().equalsIgnoreCase(name)) { 
+                if (mms.length > 0) {
+                    MethodMetadata[] newInstances = new MethodMetadata[mms.length + 1];
+                    System.arraycopy(mms, 0, newInstances, 0, mms.length);
+                    newInstances[mms.length] = m_methods[i];
+                    mms = newInstances;
+                } else {
+                    mms = new MethodMetadata[] { m_methods[i] };
+                }
+            }
+        }
+        return mms;
+    }
+    
+    /**
+     * Get the MethodMetadata corresponding to the method
+     * (contained in the implementation class) to given name 
+     * and argument types.
+     * @param name : name of the method to look for.
+     * @param types : array of the argument types of the method 
+     * @return the Method Metadate or null if not found
+     */
+    public MethodMetadata getMethod(String name, String[] types) {
+        for (int i = 0; i < m_methods.length; i++) {
+            if (m_methods[i].getMethodName().equalsIgnoreCase(name) && m_methods[i].getMethodArguments().length == types.length) {
+                boolean ok = true;
+                for (int j = 0; ok && j < types.length; j++) {
+                    if (! types[j].equals(m_methods[i].getMethodArguments()[j])) {
+                        ok = false;
+                    }
+                }
+                if (ok) { return m_methods[i]; }
+            }
+        }
+        return null;
+    }
+        
+     /**
+      * Add a method to the list.
+     * @param mm : Method Metadata to add.
+     */
+    private void addMethod(MethodMetadata mm) {
+        for (int i = 0; (m_methods != null) && (i < m_methods.length); i++) {
+            if (m_methods[i] == mm) {
+                return;
+            }
+        }
+
+        if (m_methods.length > 0) {
+            MethodMetadata[] newInstances = new MethodMetadata[m_methods.length + 1];
+            System.arraycopy(m_methods, 0, newInstances, 0, m_methods.length);
+            newInstances[m_methods.length] = mm;
+            m_methods = newInstances;
+        } else {
+            m_methods = new MethodMetadata[] { mm };
+        }
+    }
+        
+     /**
+      * Add a field to the list.
+     * @param mm : the Field Metadata to add.
+     */
+    private void addField(FieldMetadata mm) {
+        for (int i = 0; (m_fields != null) && (i < m_fields.length); i++) {
+            if (m_fields[i] == mm) {
+                return;
+            }
+        }
+
+        if (m_fields.length > 0) {
+            FieldMetadata[] newInstances = new FieldMetadata[m_fields.length + 1];
+            System.arraycopy(m_fields, 0, newInstances, 0, m_fields.length);
+            newInstances[m_fields.length] = mm;
+            m_fields = newInstances;
+        } else {
+            m_fields = new FieldMetadata[] { mm };
+        }
+    }
+        
+    /**
+     * Add the interface to the list.
+     * @param mm : the interface name to add.
+     */
+    private void addInterface(String mm) {
+        for (int i = 0; (m_interfaces != null) && (i < m_interfaces.length); i++) {
+            if (m_interfaces[i] == mm) {
+                return;
+            }
+        }
+
+        if (m_interfaces.length > 0) {
+            String[] newInstances = new String[m_interfaces.length + 1];
+            System.arraycopy(m_interfaces, 0, newInstances, 0, m_interfaces.length);
+            newInstances[m_interfaces.length] = mm;
+            m_interfaces = newInstances;
+        } else {
+            m_interfaces = new String[] { mm };
+        }
+    }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/parser/MethodMetadata.java b/ipojo/src/main/java/org/apache/felix/ipojo/parser/MethodMetadata.java
new file mode 100644
index 0000000..f0db3fb
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/parser/MethodMetadata.java
@@ -0,0 +1,66 @@
+/* 
+ * 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.parser;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A Method Metadata represent a method from the implementation class.
+ * This class allow to get information about a method : name, arguments, return type...
+ * 
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class MethodMetadata {
+    
+    /**
+     * Name of the method.
+     */
+    private String m_name;
+    
+    /**
+     * Argument type array. 
+     */
+    private String[] m_arguments = new String[0];
+    
+    /**
+     * Returned type. 
+     */
+    private String m_return = "void";
+    
+    /**
+     * Constructor.
+     * @param metadata : method manipulation element.
+     */
+    MethodMetadata(Element metadata) {
+        m_name = metadata.getAttribute("name");
+        if (metadata.containsAttribute("arguments")) {
+            m_arguments = ParseUtils.parseArrays(metadata.getAttribute("arguments"));
+        }
+        if (metadata.containsAttribute("return")) {
+            m_return = metadata.getAttribute("return");
+        }
+    }
+    
+    public String getMethodName() { return m_name; }
+    
+    public String[] getMethodArguments() { return m_arguments; }
+    
+    public String getMethodReturn() { return m_return; }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/util/Callback.java b/ipojo/src/main/java/org/apache/felix/ipojo/util/Callback.java
index 0ebcd62..de877fd 100644
--- a/ipojo/src/main/java/org/apache/felix/ipojo/util/Callback.java
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/util/Callback.java
@@ -22,6 +22,7 @@
 import java.lang.reflect.Method;
 
 import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.parser.MethodMetadata;
 
 /**
  * A callback allows calling a method on the component instances.
@@ -102,6 +103,36 @@
             m_args[i] = args[i].getName();
         }
     }
+    
+    /**
+     * Constructor.
+     * @param mm : Method Metadata obtain form manipulation metadata.
+     * @param im : instance manager.
+     */
+    public Callback(MethodMetadata mm, InstanceManager im) {
+        m_isStatic = false;
+        m_method = mm.getMethodName();
+        m_manager = im;
+        String[] args = mm.getMethodArguments();
+        m_args = new String[args.length];
+        for (int i = 0; i < args.length; i++) {
+            // Primitive Array 
+            if (args[i].endsWith("[]") && args[i].indexOf(".") == -1) {
+                String t = args[i].substring(0, args[i].length() - 2);
+                m_args[i] = "[" + getInternalPrimitiveType(t);
+            }
+            // Non-Primitive Array 
+            if (args[i].endsWith("[]") && args[i].indexOf(".") != -1) {
+                String t = args[i].substring(0, args[i].length() - 2);
+                m_args[i] = "[L" + t + ";";
+            }
+            // Simple type 
+            if (!args[i].endsWith("[]")) {
+                m_args[i] = args[i];
+            }
+            
+        }
+    }
 
     /**
      * Get the internal notation for primitive type.