blob: d2fe8f28dc97ad4011deb62fee06eaa48901d923 [file] [log] [blame]
/*
* 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");
}
}