blob: 84e60a474ca47addb1f893728d1ee5f75464a879 [file] [log] [blame]
/*
* Copyright 2003-2007 the original author or authors.
*
* Licensed 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 groovy.util;
import groovy.lang.GroovyObjectSupport;
import groovy.lang.GroovyRuntimeException;
import javax.management.*;
import java.io.IOException;
import java.util.*;
/**
* A GroovyObject facade for an underlying MBean which acts like a normal
* groovy object but which is actually implemented via
* an underlying JMX MBean.
* Properties and normal method invocations
* delegate to the MBeanServer to the actual MBean.
*
* @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
* @author Steve Button
* @author Paul King
* @version $Revision$
*/
public class GroovyMBean extends GroovyObjectSupport {
private final MBeanServerConnection server;
private final ObjectName name;
private MBeanInfo beanInfo;
private final boolean ignoreErrors;
private final Map operations = new HashMap();
public GroovyMBean(MBeanServerConnection server, String objectName) throws JMException, IOException {
this(server, objectName, false);
}
public GroovyMBean(MBeanServerConnection server, String objectName, boolean ignoreErrors) throws JMException, IOException {
this(server, new ObjectName(objectName), ignoreErrors);
}
public GroovyMBean(MBeanServerConnection server, ObjectName name) throws JMException, IOException {
this(server, name, false);
}
public GroovyMBean(MBeanServerConnection server, ObjectName name, boolean ignoreErrors) throws JMException, IOException {
this.server = server;
this.name = name;
this.ignoreErrors = ignoreErrors;
this.beanInfo = server.getMBeanInfo(name);
MBeanOperationInfo[] operationInfos = beanInfo.getOperations();
for (int i = 0; i < operationInfos.length; i++) {
MBeanOperationInfo info = operationInfos[i];
String signature[] = createSignature(info);
// Include a simple fix here to support overloaded operations on the MBean.
// Construct a simple key for an operation by adding the number of parameters it uses
String operationKey = createOperationKey(info.getName(), signature.length);
operations.put(operationKey, signature);
}
}
public MBeanServerConnection server() {
return server;
}
public ObjectName name() {
return name;
}
public MBeanInfo info() {
return beanInfo;
}
public Object getProperty(String property) {
try {
return server.getAttribute(name, property);
}
catch (MBeanException e) {
throwExceptionWithTarget("Could not access property: " + property + ". Reason: ", e);
}
catch (Exception e) {
if (!ignoreErrors)
throwException("Could not access property: " + property + ". Reason: ", e);
}
return null;
}
public void setProperty(String property, Object value) {
try {
server.setAttribute(name, new Attribute(property, value));
}
catch (MBeanException e) {
throwExceptionWithTarget("Could not set property: " + property + ". Reason: ", e);
}
catch (Exception e) {
throwException("Could not set property: " + property + ". Reason: ", e);
}
}
public Object invokeMethod(String method, Object arguments) {
// Moved this outside the try block so we can obtain the number of parameters
// specified in the arguments array, which is needed to find the correct method.
Object[] argArray = null;
if (arguments instanceof Object[]) {
argArray = (Object[]) arguments;
} else {
argArray = new Object[]{arguments};
}
// Locate the specific method based on the name and number of parameters
String operationKey = createOperationKey(method, argArray.length);
String[] signature = (String[]) operations.get(operationKey);
if (signature != null) {
try {
return server.invoke(name, method, argArray, signature);
}
catch (MBeanException e) {
throwExceptionWithTarget("Could not invoke method: " + method + ". Reason: ", e);
}
catch (Exception e) {
throwException("Could not invoke method: " + method + ". Reason: ", e);
}
return null;
} else {
return super.invokeMethod(method, arguments);
}
}
protected String[] createSignature(MBeanOperationInfo info) {
MBeanParameterInfo[] params = info.getSignature();
String[] answer = new String[params.length];
for (int i = 0; i < params.length; i++) {
answer[i] = params[i].getType();
}
return answer;
}
/**
* Construct a simple key based on the method name and the number of parameters
*
* @param operation - the mbean operation name
* @param params - the number of parameters the operation supports
* @return simple unique identifier for a method
*/
protected String createOperationKey(String operation, int params) {
// This could be changed to support some hash of the parameter types, etc.
return operation + "_" + params;
}
/**
* List of the names of each of the attributes on the MBean
*
* @return list of attribute names
*/
public Collection listAttributeNames() {
List list = new ArrayList();
try {
MBeanAttributeInfo[] attrs = beanInfo.getAttributes();
for (int i = 0; i < attrs.length; i++) {
MBeanAttributeInfo attr = attrs[i];
list.add(attr.getName());
}
} catch (Exception e) {
throwException("Could not list attribute names. Reason: ", e);
}
return list;
}
/**
* The values of each of the attributes on the MBean
*
* @return list of values of each attribute
*/
public List listAttributeValues() {
List list = new ArrayList();
Collection names = listAttributeNames();
for (Iterator iterator = names.iterator(); iterator.hasNext();) {
String name = (String) iterator.next();
try {
Object val = this.getProperty(name);
if (val != null) {
list.add(name + " : " + val.toString());
}
} catch (Exception e) {
throwException("Could not list attribute values. Reason: ", e);
}
}
return list;
}
/**
* List of string representations of all of the attributes on the MBean.
*
* @return list of descriptions of each attribute on the mbean
*/
public Collection listAttributeDescriptions() {
List list = new ArrayList();
try {
MBeanAttributeInfo[] attrs = beanInfo.getAttributes();
for (int i = 0; i < attrs.length; i++) {
MBeanAttributeInfo attr = attrs[i];
list.add(describeAttribute(attr));
}
} catch (Exception e) {
throwException("Could not list attribute descriptions. Reason: ", e);
}
return list;
}
/**
* Description of the specified attribute name.
*
* @param attr - the attribute
* @return String the description
*/
protected String describeAttribute(MBeanAttributeInfo attr) {
StringBuffer buf = new StringBuffer();
buf.append("(");
if (attr.isReadable()) {
buf.append("r");
}
if (attr.isWritable()) {
buf.append("w");
}
buf.append(") ")
.append(attr.getType())
.append(" ")
.append(attr.getName());
return buf.toString();
}
/**
* Description of the specified attribute name.
*
* @param attributeName - stringified name of the attribute
* @return the description
*/
public String describeAttribute(String attributeName) {
String ret = "Attribute not found";
try {
MBeanAttributeInfo[] attributes = beanInfo.getAttributes();
for (int i = 0; i < attributes.length; i++) {
MBeanAttributeInfo attribute = attributes[i];
if (attribute.getName().equals(attributeName)) {
return describeAttribute(attribute);
}
}
} catch (Exception e) {
throwException("Could not describe attribute '" + attributeName + "'. Reason: ", e);
}
return ret;
}
/**
* Names of all the operations available on the MBean.
*
* @return all the operations on the MBean
*/
public Collection listOperationNames() {
List list = new ArrayList();
try {
MBeanOperationInfo[] operations = beanInfo.getOperations();
for (int i = 0; i < operations.length; i++) {
MBeanOperationInfo operation = operations[i];
list.add(operation.getName());
}
} catch (Exception e) {
throwException("Could not list operation names. Reason: ", e);
}
return list;
}
/**
* Description of all of the operations available on the MBean.
*
* @return full description of each operation on the MBean
*/
public Collection listOperationDescriptions() {
List list = new ArrayList();
try {
MBeanOperationInfo[] operations = beanInfo.getOperations();
for (int i = 0; i < operations.length; i++) {
MBeanOperationInfo operation = operations[i];
list.add(describeOperation(operation));
}
} catch (Exception e) {
throwException("Could not list operation descriptions. Reason: ", e);
}
return list;
}
/**
* Get the description of the specified operation. This returns a Collection since
* operations can be overloaded and one operationName can have multiple forms.
*
* @param operationName the name of the operation to describe
* @return Collection of operation description
*/
public List describeOperation(String operationName) {
List list = new ArrayList();
try {
MBeanOperationInfo[] operations = beanInfo.getOperations();
for (int i = 0; i < operations.length; i++) {
MBeanOperationInfo operation = operations[i];
if (operation.getName().equals(operationName)) {
list.add(describeOperation(operation));
}
}
} catch (Exception e) {
throwException("Could not describe operations matching name '" + operationName + "'. Reason: ", e);
}
return list;
}
/**
* Description of the operation.
*
* @param operation the operation to describe
* @return pretty-printed description
*/
protected String describeOperation(MBeanOperationInfo operation) {
StringBuffer buf = new StringBuffer();
buf.append(operation.getReturnType())
.append(" ")
.append(operation.getName())
.append("(");
MBeanParameterInfo[] params = operation.getSignature();
for (int j = 0; j < params.length; j++) {
MBeanParameterInfo param = params[j];
if (j != 0) {
buf.append(", ");
}
buf.append(param.getType())
.append(" ")
.append(param.getName());
}
buf.append(")");
return buf.toString();
}
/**
* Return an end user readable representation of the underlying MBean
*
* @return the user readable description
*/
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("MBean Name:")
.append("\n ")
.append(name.getCanonicalName())
.append("\n ");
if (!listAttributeDescriptions().isEmpty()) {
buf.append("\nAttributes:");
for (Iterator iterator = listAttributeDescriptions().iterator(); iterator.hasNext();) {
buf.append("\n ")
.append((String) iterator.next());
}
}
if (!listOperationDescriptions().isEmpty()) {
buf.append("\nOperations:");
for (Iterator iterator = listOperationDescriptions().iterator(); iterator.hasNext();) {
buf.append("\n ")
.append((String) iterator.next());
}
}
return buf.toString();
}
private void throwException(String m, Exception e) {
if (!ignoreErrors) {
throw new GroovyRuntimeException(m + e, e);
}
}
private void throwExceptionWithTarget(String m, MBeanException e) {
if (!ignoreErrors) {
throw new GroovyRuntimeException(m + e, e.getTargetException());
}
}
}