Commit the JMX handler allowing to expose an JMX MBean to monitor & control an iPOJO instance remotely.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@586875 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/jmx.handler/pom.xml b/ipojo/jmx.handler/pom.xml
new file mode 100644
index 0000000..37111eb
--- /dev/null
+++ b/ipojo/jmx.handler/pom.xml
@@ -0,0 +1,58 @@
+<project>

+	<modelVersion>4.0.0</modelVersion>

+	<packaging>bundle</packaging>

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

+	<artifactId>org.apache.felix.ipojo.handler.jmx</artifactId>

+	<version>0.7.5-SNAPSHOT</version>

+	<name>iPOJO JMX Handler</name>

+

+	<dependencies>

+		<dependency>

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

+			<artifactId>org.osgi.core</artifactId>

+			<version>1.1.0-SNAPSHOT</version>

+		</dependency>

+		<dependency>

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

+			<artifactId>org.osgi.compendium</artifactId>

+			<version>0.9.0-SNAPSHOT</version>

+		</dependency>

+		<dependency>

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

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

+			<version>0.7.5-SNAPSHOT</version>

+		</dependency>

+		<dependency>

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

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

+			<version>0.7.5-SNAPSHOT</version>

+		</dependency>

+	</dependencies>

+

+	<build>

+		<plugins>

+			<plugin>

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

+				<artifactId>maven-bundle-plugin</artifactId>

+				<extensions>true</extensions>

+				<configuration>

+					<instructions>

+						<Private-Package>

+							org.apache.felix.ipojo.handlers.jmx

+						</Private-Package>

+						<Bundle-Name>${pom.name}</Bundle-Name>

+						<Bundle-SymbolicName>ipojo.jmx.handler</Bundle-SymbolicName>

+					</instructions>

+				</configuration>

+			</plugin>

+			<plugin>

+				<groupId>org.apache.maven.plugins</groupId>

+				<artifactId>maven-compiler-plugin</artifactId>

+				<configuration>

+					<source>1.5</source>

+					<target>1.5</target>

+				</configuration>

+			</plugin>

+		</plugins>

+	</build>

+</project>

diff --git a/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/DynamicMBeanImpl.java b/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/DynamicMBeanImpl.java
new file mode 100644
index 0000000..0c36ab0
--- /dev/null
+++ b/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/DynamicMBeanImpl.java
@@ -0,0 +1,389 @@
+/* 

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

+

+import java.lang.reflect.InvocationTargetException;

+import java.util.ArrayList;

+import java.util.Iterator;

+import java.util.List;

+

+import javax.management.Attribute;

+import javax.management.AttributeChangeNotification;

+import javax.management.AttributeList;

+import javax.management.AttributeNotFoundException;

+import javax.management.DynamicMBean;

+import javax.management.InvalidAttributeValueException;

+import javax.management.MBeanAttributeInfo;

+import javax.management.MBeanException;

+import javax.management.MBeanInfo;

+import javax.management.MBeanNotificationInfo;

+import javax.management.MBeanOperationInfo;

+import javax.management.Notification;

+import javax.management.NotificationBroadcasterSupport;

+import javax.management.ReflectionException;

+import javax.management.RuntimeOperationsException;

+

+import org.apache.felix.ipojo.InstanceManager;

+import org.apache.felix.ipojo.parser.MethodMetadata;

+import org.apache.felix.ipojo.util.Callback;

+

+/** 

+ * this class implements iPOJO DynamicMBean.

+ * it builds the dynamic MBean 

+ *  

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

+ */

+public class DynamicMBeanImpl extends NotificationBroadcasterSupport implements DynamicMBean {

+    /** 

+     * JmxConfigDFieldMap : store the data extracted from metadata.xml.

+     */

+    private JmxConfigFieldMap m_configMap;

+    /** 

+     * InstanceManager: use to store the InstanceManager instance.

+     */

+    private InstanceManager m_instanceManager;

+    /** 

+     * MBeanInfo : class wich store the MBean Informations.

+     */

+    private MBeanInfo m_mBeanInfo;

+    /**

+     * String : constant which store the name of the class.

+     */

+    private String m_className = this.getClass().getName();

+    

+    /** 

+     * sequenceNumber : use to calculate unique id to notification.

+     */

+    private int m_sequenceNumber = 0;

+    

+    /** 

+     * DynamicMBeanImpl : constructor.

+     * @param properties : data extracted from metadat.xml file

+     * @param instanceManager : InstanceManager instance

+     */

+    public DynamicMBeanImpl(JmxConfigFieldMap properties, InstanceManager instanceManager) {

+        m_configMap = properties;

+        m_instanceManager = instanceManager;

+        this.buildMBeanInfo();

+    }

+    

+    /** 

+     * getAttribute implements from JMX.

+     * get the value of the required attribute 

+     * @param arg0 name of required attribute

+     * @throws AttributeNotFoundException : if the attribute doesn't exist

+     * @throws MBeanException : 

+     * @throws ReflectionException : 

+     * @return  the object attribute

+     */

+    public Object getAttribute(String arg0) throws AttributeNotFoundException, MBeanException, ReflectionException {

+        PropertyField attribute = m_configMap.getPropertyFromName(arg0);

+        

+        if (attribute == null) {

+            throw new AttributeNotFoundException(arg0 + " not found");

+        } else {

+            return attribute.getValue();

+        }

+    }

+    /** 

+     * getAttributes : implement from JMX.

+     * get values of reuqired attributes 

+     * @param attributeNames : names of the required attributes

+     * @return return the list of the attribute

+     */

+    public AttributeList getAttributes(String[] attributeNames) {

+        

+        if (attributeNames == null) {

+            throw new IllegalArgumentException("attributeNames[] cannot be null");

+        }

+        

+        AttributeList resultList = new AttributeList();

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

+            PropertyField propertyField = (PropertyField) m_configMap.getPropertyFromField((String) attributeNames[i]);

+            

+            if (propertyField != null) {

+                resultList.add(new Attribute(attributeNames[i], propertyField.getValue()));

+            }

+        }

+        return resultList;

+    }

+    /** 

+     * getMBeanInfo : return the MBean Class builded.

+     * @return  return MBeanInfo class constructed by buildMBeanInfo

+     */

+    public MBeanInfo getMBeanInfo() {

+        return m_mBeanInfo;

+    }

+    /** 

+     * invoke : invoke the required method on the targeted POJO.

+     * @param operationName : name of the method called

+     * @param params : parameters given to the method

+     * @param signature : determine which method called

+     * @return Object : the object return by the method

+     * @throws MBeanException :

+     * @throws ReflectionException : 

+     */

+    public Object invoke(String operationName, Object[] params, String[] signature) throws MBeanException, ReflectionException {

+

+        MethodField method = m_configMap.getMethodFromName(operationName, signature);

+        if (method != null) {

+            MethodMetadata methodCall = method.getMethod();

+            Callback mc = new Callback(methodCall, m_instanceManager);

+            try {

+                return mc.call(params);

+            } catch (NoSuchMethodException e) {

+                System.err.println("No such method!: " + operationName);

+                e.printStackTrace();

+            } catch (IllegalAccessException e) {

+                System.err.println("Illegal Access Exception");

+                e.printStackTrace();

+            } catch (InvocationTargetException e) {

+                System.err.println("Invocation Target Exception");

+                e.printStackTrace();

+            }

+        } else {

+            throw new ReflectionException(new NoSuchMethodException(

+                    operationName), "Cannot find the operation "

+                    + operationName + " in " + m_className);

+        }

+        

+        return null;

+    }

+    /** 

+     * setAttribute : change specified attribute value.

+     * @param attribute : attribute with new value to be changed

+     * @throws AttributeNotFoundException : if the requiered attribute was not found

+     * @throws InvalidAttributeValueException : the value is inccorrect type

+     * @throws MBeanException :

+     * @throws ReflectionException :

+     */

+    public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {

+        

+        // Check attribute is not null to avoid NullPointerException later on

+        if (attribute == null) {

+            throw new RuntimeOperationsException(new IllegalArgumentException(

+                    "Attribute cannot be null"), "Cannot invoke a setter of "

+                    + m_className + " with null attribute");

+        }

+        String name = attribute.getName();

+        Object value = attribute.getValue();

+

+        if (name == null) {

+            throw new RuntimeOperationsException(new IllegalArgumentException(

+                    "Attribute name cannot be null"),

+                    "Cannot invoke the setter of " + m_className

+                            + " with null attribute name");

+        }

+        // Check for a recognized attribute name and call the corresponding

+        // setter

+        //

+        

+        PropertyField propertyField = (PropertyField) m_configMap.getPropertyFromName(name);

+        if (propertyField == null) {

+            // unrecognized attribute name:

+            throw new AttributeNotFoundException("Attribute " + name

+                    + " not found in " + m_className);

+        }

+        if (!propertyField.isWritable()) {

+            throw new InvalidAttributeValueException(

+                    "Attribute " + name + " can not be setted");

+        }

+        

+        if (value == null) {

+            try {

+                m_instanceManager.setterCallback(propertyField.getField(), null);

+            } catch (Exception e) {

+                throw new InvalidAttributeValueException(

+                        "Cannot set attribute " + name + " to null");

+            }

+        } else { // if non null value, make sure it is assignable to the attribute

+            if (true /* TODO type.class.isAssignableFrom(value.getClass())*/) {

+                //propertyField.setValue(value);

+                // setValue(attributeField.getField(),null);

+                m_instanceManager.setterCallback(propertyField.getField(), value);

+            } else {

+                throw new InvalidAttributeValueException(

+                        "Cannot set attribute " + name + " to a "

+                                + value.getClass().getName()

+                                + " object, String expected");

+            }

+        }

+

+        

+    }

+    /** 

+     * setAttributes : change all the attributes value.

+     * @param attributes : list of attribute value to be changed

+     * @return AttributeList : list of new attribute

+     */

+    public AttributeList setAttributes(AttributeList attributes) {

+        

+//       Check attributes is not null to avoid NullPointerException later on

+        if (attributes == null) {

+            throw new RuntimeOperationsException(new IllegalArgumentException(

+                    "AttributeList attributes cannot be null"),

+                    "Cannot invoke a setter of " + m_className);

+        }

+        AttributeList resultList = new AttributeList();

+

+        // if attributeNames is empty, nothing more to do

+        if (attributes.isEmpty()) {

+            return resultList;

+        }

+        

+        // for each attribute, try to set it and add to the result list if

+        // successfull

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

+            Attribute attr = (Attribute) i.next();

+            try {

+                setAttribute(attr);

+                String name = attr.getName();

+                Object value = getAttribute(name);

+                resultList.add(new Attribute(name, value));

+            } catch (Exception e) {

+                e.printStackTrace();

+            }

+        }

+        return resultList;

+    }

+    /** 

+     * buildMBeanInfo : buil the MBean information on initilisation.

+     * this value don't change after

+     */

+    private void buildMBeanInfo() {

+        String dDescription = m_configMap.getDecription();

+        

+        // generate infos for attributes

+        MBeanAttributeInfo[] dAttributes = null;

+        

+        if (m_configMap == null) {

+            return;

+        }

+        

+        if (m_configMap.getProperties() != null) {

+            List <MBeanAttributeInfo> lAttributes = null;            

+            lAttributes = new ArrayList <MBeanAttributeInfo> ();

+

+            Iterator <PropertyField> iterator = m_configMap.getProperties().iterator();

+            while (iterator.hasNext()) {

+                PropertyField propertyField = (PropertyField) iterator.next();

+                lAttributes.add(new MBeanAttributeInfo(

+                        propertyField.getName(),

+                        propertyField.getType(),

+                        propertyField.getDescription(),

+                        propertyField.isReadable(),

+                        propertyField.isWritable(),

+                        false));                

+            }

+            dAttributes = (MBeanAttributeInfo[]) lAttributes.toArray(new MBeanAttributeInfo[ lAttributes.size() ]);

+        }

+

+

+        

+        MBeanOperationInfo[] dOperations = null;

+        if (m_configMap.getMethods() != null) {

+            

+            List <MBeanOperationInfo> lOperations = new ArrayList <MBeanOperationInfo>();

+            

+            Iterator <MethodField[]> iterator = m_configMap.getMethods().iterator();

+            while (iterator.hasNext()) {

+                MethodField[] method = (MethodField[]) iterator.next();

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

+                    lOperations.add(

+                            new MBeanOperationInfo(

+                                    method[i].getName(),

+                                    method[i].getDescription(),

+                                    method[i].getParams(),

+                                    method[i].getReturnType(),

+                                    MBeanOperationInfo.UNKNOWN

+                        )

+                    );

+                }

+                dOperations = (MBeanOperationInfo[]) lOperations.toArray(new MBeanOperationInfo[lOperations.size()]);

+            }

+        }

+

+        MBeanNotificationInfo[] dNotification = new MBeanNotificationInfo[0];

+        if (m_configMap.getMethods() != null) {

+                

+            List <MBeanNotificationInfo> lNotifications = new ArrayList <MBeanNotificationInfo>();

+                

+            Iterator <NotificationField> iterator = m_configMap.getNotifications().iterator();

+            while (iterator.hasNext()) {

+                NotificationField notification = (NotificationField) iterator.next();

+                lNotifications.add(notification.getNotificationInfo());

+            }

+            dNotification = (MBeanNotificationInfo[]) lNotifications.toArray(new MBeanNotificationInfo[lNotifications.size()]);

+        }

+

+        m_mBeanInfo = new MBeanInfo(

+                this.m_className,

+                dDescription,

+                dAttributes,

+                null, // No constructor 

+                dOperations,

+                dNotification);

+    }

+

+    /** 

+     * getNotificationInfo : get the notification informations (use by JMX).

+     * @return MBeanNotificationInfo[] : structure which describe the notifications 

+     */

+    public MBeanNotificationInfo[] getNotificationInfo() {

+        MBeanNotificationInfo[] dNotification = new MBeanNotificationInfo[0];

+        if (m_configMap.getMethods() != null) {

+                

+            List < MBeanNotificationInfo> lNotifications = new ArrayList < MBeanNotificationInfo>();

+                

+            Iterator <NotificationField> iterator = m_configMap.getNotifications().iterator();

+            while (iterator.hasNext()) {

+                NotificationField notification = (NotificationField) iterator.next();

+                lNotifications.add(notification.getNotificationInfo());

+            }

+            dNotification = (MBeanNotificationInfo[]) lNotifications.toArray(new MBeanNotificationInfo[lNotifications.size()]);

+        }

+        return dNotification;

+    }

+ 

+    /** 

+     * sendNotification : send a notification to a subscriver.

+     * @param msg : msg to send

+     * @param attributeName : name of the attribute

+     * @param attributeType : type of the attribute

+     * @param oldValue : oldvalue of the attribute

+     * @param newValue : new value of the attribute

+     */

+    public void sendNotification(String msg, String attributeName,

+            String attributeType, Object oldValue, Object newValue) {

+

+        long timeStamp = System.currentTimeMillis();

+        

+               

+        if (newValue.equals(oldValue)) {

+            return;

+        }

+        m_sequenceNumber++;

+        Notification notification = new AttributeChangeNotification(

+                this, m_sequenceNumber, timeStamp,

+                msg, attributeName, attributeType, oldValue, newValue);

+        sendNotification(notification);

+        System.out.println("DEBUG: Notification sent");

+    }

+}

diff --git a/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/JmxConfigFieldMap.java b/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/JmxConfigFieldMap.java
new file mode 100644
index 0000000..64a72da
--- /dev/null
+++ b/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/JmxConfigFieldMap.java
@@ -0,0 +1,283 @@
+/* 

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

+

+import java.util.Collection;

+import java.util.HashMap;

+import java.util.Iterator;

+import java.util.Map;

+

+/** 

+ * JmxConfigFieldMap : use to store the informations needed to build the Dynamic MBean.

+ *  

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

+ */

+public class JmxConfigFieldMap {

+

+    /** 

+     * m_properties : use to store the attributes exposed.

+     */

+    private Map < String, PropertyField > m_properties = new HashMap < String, PropertyField >();

+    /** 

+     * m_methods : use to store the methods exposed.

+     */

+    private Map < String, MethodField[] > m_methods = new HashMap < String, MethodField[] >();

+    /** 

+     * m_notification : use to store the notification allowed.

+     */

+    private Map < String, NotificationField > m_notifications = new HashMap < String, NotificationField >();

+    /** 

+     * m_description : description of the Mbean.

+     */

+    private String m_description;

+    

+    

+    /** 

+     * JmxConfigFieldMap : constructor.

+     */

+    public JmxConfigFieldMap() {

+        

+    }

+    

+    /** 

+     * getDescription : get the descritpion of the MBean.

+     * @return String : Decription of the MBean

+     */

+    public String getDecription() {

+        return m_description;

+    }

+    

+    /** 

+     * setDescription : set the descritpion of the MBean.

+     * @param description : String which describe the Mbean

+     */

+    public void setDescription(String description) {

+        this.m_description = description;

+    }

+    

+    /** 

+     * addPropertyFromName : add a new attribute exposed in the Mbean.

+     * @param name : name of the new property

+     * @param propertyField : Field which describe the property

+     */

+    public void addPropertyFromName(String name, PropertyField propertyField) {

+        m_properties.put(name, propertyField);

+    }

+    

+    /** 

+     * getProperties : get all of the properties exposed.

+     * @return : collection of all properties

+     */

+    public Collection<PropertyField> getProperties() {

+        if (m_properties != null) {

+            return m_properties.values();

+        } else {

+            return null;

+        }     

+    }

+    

+    /** 

+     * getPropertyFromName : get the property by the name.

+     * @param name : name of the requiered property

+     * @return PropertyField : the field requiered or null if is not found

+     */

+    public PropertyField getPropertyFromName(String name) {

+        PropertyField prop = m_properties.get(name);

+        return prop;

+    }

+    

+    /** 

+     * getPropertyFromField : get the property by the field.

+     * @param field : the requiered field

+     * @return PropertyField : 

+     */

+    public PropertyField getPropertyFromField(String field) {

+        PropertyField property = null;

+        Iterator<PropertyField> it = m_properties.values().iterator();

+        while (it.hasNext()) {

+            PropertyField p = it.next();

+            if (p.getField().compareTo(field) == 0) {

+                if (property != null) {

+                    System.err.println("a field already exist");

+                } else {

+                    property = p;

+                }

+            }

+        }

+        return property;   

+    }

+    

+    

+    /** 

+     * addMethodFromName : add a new method descriptor from its name.

+     * @param name : name of the method

+     * @param methodField : descritpion of the method

+     */

+    public void addMethodFromName(String name, MethodField methodField) {

+        MethodField[] mf;

+        if (!m_methods.containsKey(name)) {

+            mf = new MethodField[1];

+            mf[0] = methodField;

+        } else {

+            MethodField[] temp = m_methods.get(name);

+            mf = new MethodField[temp.length + 1];

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

+                mf[i] = temp[i];

+            }

+            mf[temp.length] = methodField;

+        }

+        m_methods.put(name, mf);

+    }

+    

+    /** 

+     * addMethodFromName : add new methods descriptors from one name.

+     * (the method muste have the same name but different signature).

+     * @param name : name of the method

+     * @param methodsField : descritpion of the methods

+     */

+    public void addMethodFromName(String name, MethodField[] methodsField) {

+        MethodField[] mf;

+        if (!m_methods.containsKey(name)) {

+            mf = methodsField;

+        } else {

+            MethodField[] temp = m_methods.get(name);

+            mf = new MethodField[temp.length + methodsField.length];

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

+                mf[i] = temp[i];

+            }

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

+                mf[i + temp.length] = methodsField[i];

+            }

+        }

+        m_methods.put(name, mf);

+    }

+    

+    /** 

+     * DynamicMBeanImpl : add methods from name and erase the older if exist.

+     * @param name : name of the method

+     * @param methodField : method to be added

+     */

+    public void overrideMethodFromName(String name, MethodField methodField) {

+        MethodField[] mf = new MethodField[1];

+        mf[0] = methodField;

+        m_methods.put(name, mf);

+    }

+    

+    /** 

+     * DynamicMBeanImpl : add methods from name and erase the older if exist.

+     * @param name : name of the method

+     * @param methodsField : array of methods to be added

+     */

+    public void overrideMethodFromName(String name, MethodField[] methodsField) {

+        m_methods.put(name, methodsField);  

+    }

+    

+    /** 

+     * getMethodFromName : return the metod(s) which are similar.

+     * @param name : name of requiered method

+     * @return MethodField[] : list of returned methods

+     */

+    public MethodField[] getMethodFromName(String name) {

+        MethodField[] prop = m_methods.get(name);

+        return prop;

+    }

+    

+    /** 

+     * getMethodFromName : get the method which the good signature.

+     * @param operationName : name of the method requiered

+     * @param signature : signature requiered

+     * @return MethodField : the method which the same signature or null if not found

+     */

+    public MethodField getMethodFromName(String operationName, String[] signature) {

+        MethodField[] methods = m_methods.get(operationName);

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

+            if (isSameSignature(signature, methods[i].getSignature())) {

+                return methods[i];

+            }

+        }

+        return null;

+    }

+    

+    /** 

+     * isSameSignature : compare two method signature.

+     * @param sig1 : first signature

+     * @param sig2 : second signature

+     * @return boolean : return true if the signature are similar

+     *                   fale else

+     */

+    private boolean isSameSignature(String[] sig1, String[] sig2) {

+        if (sig1.length != sig2.length) {

+            return false;

+        } else {

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

+                //System.out.println(sig1[i] +" == "+ sig2[i]);

+                if (!sig1[i].equals(sig2[i])) {

+                    return false;

+                }

+            }

+            

+        }

+        return true;

+    }

+    

+    /** 

+     * getMethods : return all methods store.

+     * @return Collection : collection of methodField[]

+     */

+    public Collection<MethodField[]> getMethods() {

+        if (m_methods != null) {

+            return m_methods.values();

+        } else {

+            return null;

+        }

+    }   

+    

+    /** 

+     * addNotificationFromName : add a notification .

+     * @param name : 

+     * @param notificationField :

+     */

+    public void addNotificationFromName(String name, NotificationField notificationField) {

+        m_notifications.put(name, notificationField);

+    }

+    

+    /** 

+     * getNotificationFromName : return the notification with requiered name.

+     * @param name : name requiered

+     * @return NotificationField : return the notification if exist, null else

+     */

+    public NotificationField getNotificationFromName(String name) {

+        NotificationField prop = m_notifications.get(name);

+        return prop;

+    }

+    

+    /** 

+     * getNotification : get all notifications define.

+     * @return Collection : return collection of NotificationField

+     */

+    public Collection<NotificationField> getNotifications() {

+        if (m_notifications != null) {

+            return m_notifications.values();

+        } else {

+            return null;

+        }

+    }

+}

diff --git a/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MBeanHandler.java b/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MBeanHandler.java
new file mode 100644
index 0000000..9e04bb0
--- /dev/null
+++ b/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MBeanHandler.java
@@ -0,0 +1,257 @@
+/* 

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

+

+

+import java.util.Dictionary;

+import java.util.Properties;

+

+import org.apache.felix.ipojo.InstanceManager;

+import org.apache.felix.ipojo.PrimitiveHandler;

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

+import org.apache.felix.ipojo.parser.FieldMetadata;

+import org.apache.felix.ipojo.parser.ManipulationMetadata;

+import org.apache.felix.ipojo.parser.MethodMetadata;

+import org.osgi.framework.BundleContext;

+import org.osgi.framework.ServiceRegistration;

+

+/** this class implements iPOJO Handler.

+ * it builds the dynamic MBean from metadata.xml and expose it to the MBean Server.

+ *  

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

+ */

+public class MBeanHandler extends PrimitiveHandler {

+    /** 

+     * InstanceManager: use to store the InstanceManager instance.

+     */

+    private InstanceManager m_instanceManager;

+    /**

+     * ServiceRegistration : use to register and deregister the Dynamic MBean.

+     */

+    private ServiceRegistration m_serviceRegistration;

+    /**

+     * JmxConfigFieldMap : use to store data when parsing metadata.xml.

+     */

+    private JmxConfigFieldMap m_jmxConfigFieldMap;

+    /**

+     * DynamicMBeanImpl : store the Dynamic MBean.

+     */

+    private DynamicMBeanImpl m_MBean;

+    /**

+     * String : constant which store the name of the class.

+     */

+    private String m_NAMESPACE = this.getClass().getName();

+

+    /** 

+     * configure : construct the structure JmxConfigFieldMap.and the Dynamic Mbean.

+     * @param metadata Element

+     * @param dict Dictionnary

+     */

+    public void configure(Element metadata, Dictionary dict) {

+        

+        ManipulationMetadata manipulation = new ManipulationMetadata(metadata);

+        

+        m_instanceManager = getInstanceManager();

+

+

+        m_jmxConfigFieldMap = new JmxConfigFieldMap();

+

+        // Build the hashmap

+        Element[] mbeans = metadata.getElements("config", m_NAMESPACE);

+

+        if (mbeans.length != 1) { return; }

+        

+       

+        

+        // set property 

+        Element[] attributes = mbeans[0].getElements("property");

+        //String[] fields = new String[attributes.length];

+        FieldMetadata[] fields = new FieldMetadata[attributes.length];

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

+            boolean notif = false;

+            String rights;

+            String name;

+            String field = attributes[i].getAttribute("field");

+            

+            if (attributes[i].containsAttribute("name")) {

+                name = attributes[i].getAttribute("name");

+            } else {

+                name = field;

+            }

+            if (attributes[i].containsAttribute("rights")) {

+                rights = attributes[i].getAttribute("rights");

+            } else {

+                rights = "w";

+            }

+            

+            PropertyField property = new PropertyField(name, field, rights, getTypeFromAttributeField(field, manipulation));

+            

+            if (attributes[i].containsAttribute("notification")) {

+                notif = Boolean.parseBoolean(attributes[i].getAttribute("notification"));

+            }

+            

+            property.setNotifiable(notif);

+            

+            if (notif) {

+                //add the new notifiable property in structure

+                NotificationField notification = new NotificationField(name, this.getClass().getName() + "." + field, null);

+                m_jmxConfigFieldMap.addNotificationFromName(name, notification);

+            }

+            m_jmxConfigFieldMap.addPropertyFromName(name, property);

+            fields[i] = manipulation.getField(field);

+            System.out.println("DEBUG: property exposed:" + name + " " + field + ":" 

+                    + getTypeFromAttributeField(field, manipulation) + " " + rights 

+                    + ", Notif=" + notif);

+        }

+        

+        //set methods 

+        Element[] methods = mbeans[0].getElements("method");

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

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

+            String description = null;

+            if (methods[i].containsAttribute("description")) {

+                description = methods[i].getAttribute("description");

+            }

+            

+            MethodField[] method = getMethodsFromName(name, manipulation, description);

+            

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

+                m_jmxConfigFieldMap.addMethodFromName(name, method[j]);

+            

+                System.out.println("DEBUG: method exposed:" + method[j].getReturnType() + " " + name);

+            }

+        }

+

+        m_instanceManager.register(this, fields, null);

+        

+    }

+    /**

+     * start : register the Dynamic Mbean.

+     */

+    public void start() {

+        

+//      create the corresponding MBean

+        m_MBean = new DynamicMBeanImpl(m_jmxConfigFieldMap, m_instanceManager);

+        if (m_serviceRegistration != null) { m_serviceRegistration.unregister(); }

+

+        // Register the ManagedService

+        BundleContext bundleContext = m_instanceManager.getContext();

+        Properties properties = new Properties();

+        properties.put("jmxagent.objectName", "HandlerJMX:type=" 

+                + m_instanceManager.getClassName() 

+                + ",ServiceId=" 

+                + m_instanceManager.getInstanceName());

+

+        m_serviceRegistration = bundleContext.registerService(javax.management.DynamicMBean.class.getName(), m_MBean, properties);

+    }

+

+    /** 

+     * stop : deregister the Dynamic Mbean.

+     */

+    public void stop() {

+        if (m_serviceRegistration != null) { m_serviceRegistration.unregister(); }

+        

+        

+    }

+    

+    

+    /** 

+     * setterCallback : call when a POJO member is modified externally.

+     * @param fieldName : name of the modified field 

+     * @param value     : new value of the field

+     */

+    public void setterCallback(String fieldName, Object value) {

+        // Check if the field is a configurable property

+

+        PropertyField propertyField = (PropertyField) m_jmxConfigFieldMap.getPropertyFromField(fieldName);

+        if (propertyField != null) {

+            if (propertyField.isNotifiable()) {

+                                            

+                m_MBean.sendNotification(propertyField.getName() + " changed", propertyField.getName(),

+                                         propertyField.getType(), propertyField.getValue(), value);

+            }

+            propertyField.setValue(value);

+        }

+    }

+

+    /** 

+     * getterCallback : call when a POJO member is modified by the MBean.

+     * @param fieldName : name of the modified field 

+     * @param value     : old value of the field

+     * @return          : new value of the field

+     */

+    public Object getterCallback(String fieldName, Object value) {

+        

+        

+        // Check if the field is a configurable property

+        PropertyField propertyField = (PropertyField) m_jmxConfigFieldMap.getPropertyFromField(fieldName);

+        if (propertyField != null) { 

+            m_instanceManager.setterCallback(fieldName, propertyField.getValue());

+            return propertyField.getValue();

+        }

+        m_instanceManager.setterCallback(fieldName, value);

+        return value;

+    }

+    

+    /** 

+     * getTypeFromAttributeField : get the type from a field name.

+     * @param fieldRequire : name of the requiered field 

+     * @param manipulation : metadata extract from metadata.xml file

+     * @return          : type of the field or null if it wasn't found

+     */

+    private static String getTypeFromAttributeField(String fieldRequire, ManipulationMetadata manipulation) {

+        

+        FieldMetadata field = manipulation.getField(fieldRequire);

+        if (field == null) {

+            return null;

+        } else {

+            return field.getReflectionType();

+        }

+    }

+    

+    /** 

+     * getMethodsFromName : get all the methods available which get this name.

+     * @param methodName : name of the requiered methods

+     * @param manipulation : metadata extract from metadata.xml file

+     * @param description  : description which appears in jmx console

+     * @return          : array of methods with the right name

+     */

+    private MethodField[] getMethodsFromName(String methodName, ManipulationMetadata manipulation, String description) {

+        

+        MethodMetadata[] fields = manipulation.getMethods(methodName);

+        if (fields.length == 0) {

+            return null;

+        }

+        

+        MethodField[] ret = new MethodField[fields.length];

+        

+        if (fields.length == 1) {

+            ret[0] = new MethodField(fields[0], description);

+            return ret;

+        } else {

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

+                ret[i] = new MethodField(fields[i], description);

+            }

+            return ret;

+        }

+    }

+    

+

+}

diff --git a/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MethodField.java b/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MethodField.java
new file mode 100644
index 0000000..e4346d2
--- /dev/null
+++ b/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MethodField.java
@@ -0,0 +1,86 @@
+/* 

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

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

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

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

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

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

+ *

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

+ *

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

+ * software distributed under the License is distributed on an

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

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

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.felix.ipojo.handlers.jmx;

+

+import javax.management.MBeanParameterInfo;

+

+import org.apache.felix.ipojo.parser.MethodMetadata;

+

+/** 

+ * this class build a method JMX description.

+ *  

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

+ */

+public class MethodField {

+

+    /** 

+     * m_description : store the method descritpion.

+     */

+    private String m_description;

+    /** 

+     * m_method : store the method properties.

+     */

+    private MethodMetadata m_method;

+    

+    /** 

+     * MethodField : constructor.

+     * @param method : the metod properties

+     * @param description : thes method description

+     */

+    public MethodField(MethodMetadata method, String description) {

+        this.m_method = method;

+        this.m_description = description;

+    

+    }

+    

+

+    public MethodMetadata getMethod() {

+        return m_method;

+    }

+

+    public String getDescription() {

+        return m_description;

+    }

+

+    public String getName() {

+        return m_method.getMethodName();

+    }

+    

+    /** 

+     * getParams : get the parameter in JMX format.

+     * @return MBeanParameterInfo : return info on JMX format

+     */

+    public MBeanParameterInfo[] getParams() {

+        MBeanParameterInfo[] mbean = new MBeanParameterInfo[m_method.getMethodArguments().length];

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

+            mbean[i] = new MBeanParameterInfo("arg" + i, m_method.getMethodArguments()[i], null);

+        }

+        return mbean;

+    }

+

+    public String[] getSignature() {

+        return m_method.getMethodArguments();

+    }

+    

+    public String getReturnType() {

+        return m_method.getMethodReturn();

+    }

+

+}

diff --git a/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/NotificationField.java b/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/NotificationField.java
new file mode 100644
index 0000000..c6ff225
--- /dev/null
+++ b/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/NotificationField.java
@@ -0,0 +1,69 @@
+/* 

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

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

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

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

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

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

+ *

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

+ *

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

+ * software distributed under the License is distributed on an

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

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

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.felix.ipojo.handlers.jmx;

+

+import javax.management.MBeanNotificationInfo;

+

+/** 

+ * this calss build the notification descritpion structure.

+ *  

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

+ */

+public class NotificationField {

+    /** 

+     * m_name : name of the notification.

+     */

+    private String m_name;

+    /** 

+     * m_description : description of the notification.

+     */

+    private String m_description;

+    /** 

+     * m_description : field of the notification.

+     */

+    private String m_field;

+    

+    /** 

+     * NotificationField : constructor.

+     * @param name : name of the notification 

+     * @param field : field which send a notification when it is modified

+     * @param description : descritpion which appears in jmx console

+     */

+    

+    public NotificationField(String name, String field, String description) {

+        this.m_name = name;

+        this.m_field = field;

+        this.m_description = description;

+    }

+

+    /** 

+     * getNotificationInfo : return the MBeanNotificationInfo from this class.

+     * @return          : type of the field or null if it wasn't found

+     */

+    public MBeanNotificationInfo getNotificationInfo() {

+        String[] notificationTypes = new String[1];

+        notificationTypes[0] = m_field;

+        MBeanNotificationInfo mbni = new MBeanNotificationInfo(

+                    notificationTypes,

+                    m_name,

+                    m_description);

+        return mbni;

+    }

+}

diff --git a/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/PropertyField.java b/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/PropertyField.java
new file mode 100644
index 0000000..d692894
--- /dev/null
+++ b/ipojo/jmx.handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/PropertyField.java
@@ -0,0 +1,131 @@
+/* 

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

+

+/** 

+ * this calss build the notification descritpion structure.

+ *  

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

+ */

+public class PropertyField {

+

+    /** 

+     * m_name : name of the notification.

+     */

+    private String m_name;

+    /** 

+     * m_name : name of the notification.

+     */

+    private String m_field;

+    /** 

+     * m_name : name of the notification.

+     */

+    private String m_rights;

+    /** 

+     * m_name : name of the notification.

+     */

+    private String m_type;

+    /** 

+     * m_name : name of the notification.

+     */

+    private Object m_value;

+    /** 

+     * m_name : name of the notification.

+     */

+    private boolean m_notification = false;

+    

+    /** 

+     * PropertyField : constructor.

+     * @param name : name of the properety 

+     * @param field : field which send a notification when it is modified

+     * @param rights : the rights of the attribute (ie: 'r' or 'w')

+     * @param type : the type of the attribute

+     */

+    public PropertyField(String name, String field, String rights, String type) {

+        this.setName(name);

+        this.setField(field);

+        this.m_type = type;

+        if (isRightsValid(rights)) {

+            this.setRights(rights);

+        } else {

+            this.setField("r"); //default rights is read only

+        }

+    }

+    

+    public String getField() {

+        return m_field;

+    }

+    public void setField(String field) {

+        this.m_field = field;

+    }

+    public String getName() {

+        return m_name;

+    }

+    public void setName(String name) {

+        this.m_name = name;

+    }

+    public String getRights() {

+        return m_rights;

+    }

+    public void setRights(String rights) {

+        this.m_rights = rights;

+    }

+    public Object getValue() {

+        return m_value;

+    }

+    public void setValue(Object value) {

+        this.m_value = value;

+    }

+

+    public String getType() {

+        return this.m_type;

+    }

+

+    public String getDescription() {

+        // TODO Auto-generated method stub

+        return null;

+    }

+

+    public boolean isReadable() {

+        return this.getRights().equals("r") || this.getRights().equals("w");

+    }

+

+    public boolean isWritable() {

+        return  this.getRights().equals("w");

+    }

+    

+    public boolean isNotifiable() {

+        return this.m_notification;

+    }

+    

+    public void setNotifiable(boolean value) {

+        this.m_notification = value;

+    }

+    

+    /** 

+     * isRightsValid : return is the rights is valid or not (ie = 'r' || 'w').

+     * @param rights :  string represents the rights

+     * @return boolean : return true if rights = 'r' or 'w'

+     */

+    public static boolean isRightsValid(String rights) {

+        return rights != null && (rights.equals("r") || rights.equals("w"));

+    }

+    

+}

diff --git a/ipojo/jmx.handler/src/main/resources/metadata.xml b/ipojo/jmx.handler/src/main/resources/metadata.xml
new file mode 100644
index 0000000..65bdc15
--- /dev/null
+++ b/ipojo/jmx.handler/src/main/resources/metadata.xml
@@ -0,0 +1,5 @@
+<ipojo>

+<!-- Primitives handler -->

+<handler classname="org.apache.felix.ipojo.handlers.jmx.MBeanHandler" name="config" namespace="org.apache.felix.ipojo.handlers.jmx.MBeanHandler">

+</handler>	

+</ipojo>
\ No newline at end of file