| /* |
| * 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"); |
| } |
| } |