/* * 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; import org.apache.felix.ipojo.util.Logger; /** * 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 { /** * The instance manager. Used to store the InstanceManager instance. */ protected final InstanceManager m_instanceManager; /** * The JmxConfigDFieldMap. Stors the data extracted from metadata.xml. */ private JmxConfigFieldMap m_configMap; /** * The MBeanInfo. The class storing the MBean Informations. */ private MBeanInfo m_mBeanInfo; /** * The class name. Constant storing the name of the class. */ private String m_className = this.getClass().getName(); /** * The sequence number. Used to calculate unique id to notification. */ private int m_sequenceNumber; /** * Constructor. * * @param properties the data extracted from metadat.xml file * @param instanceManager the InstanceManager instance */ public DynamicMBeanImpl(JmxConfigFieldMap properties, InstanceManager instanceManager) { m_configMap = properties; m_instanceManager = instanceManager; this.buildMBeanInfo(); } /** * Gets the value of the required attribute. * * @param arg0 the name of required attribute * @throws AttributeNotFoundException if the attribute doesn't exist * @throws MBeanException if something bad occures * @throws ReflectionException if something bad occures * @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(); } } /** * Gets values of required attributes. * * @param attributeNames the 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; } /** * Returns the MBean Class builded. * * @return return MBeanInfo class constructed by buildMBeanInfo */ public MBeanInfo getMBeanInfo() { return m_mBeanInfo; } /** * Invokes the required method on the targeted POJO. * * @param operationName the name of the method called * @param params the parameters given to the method * @param signature the determine which method called * @return the object return by the method * @throws MBeanException if something bad occures * @throws ReflectionException if something bad occures */ 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) { throw new ReflectionException(e); } catch (IllegalAccessException e) { throw new ReflectionException(e); } catch (InvocationTargetException e) { throw new MBeanException(e); } } else { throw new ReflectionException(new NoSuchMethodException( operationName), "Cannot find the operation " + operationName + " in " + m_className); } } /** * Changes specified attribute value. * * @param attribute the attribute with new value to be changed * @throws AttributeNotFoundException if the required attribute was not found * @throws InvalidAttributeValueException if the value is inccorrect type * @throws MBeanException if something bad occures * @throws ReflectionException if something bad occures */ 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 set"); } if (value == null) { try { m_instanceManager.onSet(null, 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.onSet(null, propertyField.getField(), value); // } else { // throw new InvalidAttributeValueException( // "Cannot set attribute " + name + " to a " // + value.getClass().getName() // + " object, String expected"); // } } } /** * Changes all the attributes value. * * @param attributes the list of attribute value to be changed * @return the 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 // successful 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; } /** * Builds the MBean information on initialization. This * value doesn't change further. */ private void buildMBeanInfo() { // generate infos for attributes MBeanAttributeInfo[] dAttributes = null; if (m_configMap == null) { return; } String dDescription = m_configMap.getDecription(); 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 = iterator.next(); lAttributes.add(new MBeanAttributeInfo(propertyField.getName(), propertyField.getType(), propertyField.getDescription(), propertyField.isReadable(), propertyField.isWritable(), false)); } dAttributes = 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 = 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 = 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 = iterator .next(); lNotifications.add(notification.getNotificationInfo()); } dNotification = lNotifications .toArray(new MBeanNotificationInfo[lNotifications.size()]); } m_mBeanInfo = new MBeanInfo(this.m_className, dDescription, dAttributes, null, // No constructor dOperations, dNotification); } /** * Gets the notification informations (use by JMX). * * @return the 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 = iterator .next(); lNotifications.add(notification.getNotificationInfo()); } dNotification = lNotifications .toArray(new MBeanNotificationInfo[lNotifications.size()]); } return dNotification; } /** * Sends a notification to a subscriber. * * @param msg the msg to send * @param attributeName the name of the attribute * @param attributeType the type of the attribute * @param oldValue the old value of the attribute * @param newValue the new value of the attribute */ public void sendNotification(String msg, String attributeName, String attributeType, Object oldValue, Object newValue) { long timeStamp = System.currentTimeMillis(); if ((newValue == null && oldValue == null) || (newValue != null && newValue.equals(oldValue))) { return; } m_sequenceNumber++; Notification notification = new AttributeChangeNotification(this, m_sequenceNumber, timeStamp, msg, attributeName, attributeType, oldValue, newValue); sendNotification(notification); m_instanceManager.getFactory().getLogger().log(Logger.INFO, "Notification sent"); } }