in geode-core/src/main/java/org/apache/geode/admin/jmx/internal/MX4JModelMBean.java [698:858]
public Object invoke(String method, Object[] arguments, String[] params)
throws MBeanException, ReflectionException {
if (method == null) {
throw new RuntimeOperationsException(new IllegalArgumentException(
"Method name cannot be null."));
}
if (arguments == null) {
arguments = new Object[0];
}
if (params == null) {
params = new String[0];
}
Logger logger = getLogger();
// Find operation descriptor
ModelMBeanInfo info = getModelMBeanInfo();
if (info == null) {
throw new MBeanException(new ServiceNotFoundException(
"ModelMBeanInfo is null"));
}
if (logger.isEnabledFor(Logger.DEBUG)) {
logger.debug("ModelMBeanInfo is: " + info);
}
// This is a clone, we use it read only
ModelMBeanOperationInfo operInfo = info.getOperation(method);
if (operInfo == null) {
throw new MBeanException(new ServiceNotFoundException(
String.format("Cannot find ModelMBeanOperationInfo for operation %s",
method)));
}
if (logger.isEnabledFor(Logger.DEBUG)) {
logger.debug("Operation info is: " + operInfo);
}
// This descriptor is a clone
Descriptor operationDescriptor = operInfo.getDescriptor();
if (operationDescriptor == null) {
throw new MBeanException(new ServiceNotFoundException(
String.format("Operation descriptor for operation %s cannot be null",
method)));
}
String role = (String) operationDescriptor.getFieldValue("role");
if (role == null || !role.equals("operation")) {
throw new MBeanException(new ServiceNotFoundException(
String.format("Operation descriptor field 'role' must be 'operation', not %s",
role)));
}
if (logger.isEnabledFor(Logger.DEBUG)) {
logger.debug("Operation descriptor is: " + operationDescriptor);
}
// This returns a clone of the mbean descriptor, we use it read only
Descriptor mbeanDescriptor = info.getMBeanDescriptor();
if (mbeanDescriptor == null) {
throw new MBeanException(new ServiceNotFoundException(
"MBean descriptor cannot be null"));
}
if (logger.isEnabledFor(Logger.DEBUG)) {
logger.debug("MBean descriptor is: " + mbeanDescriptor);
}
Object returnValue = null;
String lastUpdateField = "lastReturnedTimeStamp";
// Check if the method should be invoked given the cache settings
int staleness = getStaleness(operationDescriptor, mbeanDescriptor, lastUpdateField);
if (staleness == ALWAYS_STALE || staleness == STALE) {
if (logger.isEnabledFor(Logger.TRACE)) {
logger.trace("Value is stale");
}
// Find parameters classes
Class[] parameters = null;
try {
parameters = Utils.loadClasses(Thread.currentThread().getContextClassLoader(), params);
} catch (ClassNotFoundException x) {
logger.error("Cannot find operation's parameter classes", x);
throw new ReflectionException(x);
}
if (logger.isEnabledFor(Logger.TRACE)) {
logger.trace("Invoking operation...");
}
// Find target object
Object target = resolveTargetObject(operationDescriptor);
returnValue = invokeMethod(target, method, parameters, arguments);
if (logger.isEnabledFor(Logger.DEBUG)) {
logger.debug("Returned value is: " + returnValue);
}
if (returnValue != null) {
Class parameter = returnValue.getClass();
Class declared = loadClassWithContextClassLoader(operInfo.getReturnType());
checkAssignability(parameter, declared);
}
// Cache the new value only if caching is needed
if (staleness != ALWAYS_STALE) {
operationDescriptor.setField("lastReturnedValue", returnValue);
operationDescriptor.setField(lastUpdateField, System.currentTimeMillis());
if (logger.isEnabledFor(Logger.TRACE)) {
logger.trace("Returned value has been cached");
}
// And now replace the descriptor with the updated clone
info.setDescriptor(operationDescriptor, "operation");
}
if (logger.isEnabledFor(Logger.DEBUG)) {
logger.debug("invoke for operation " + method + " returns invoked value: " + returnValue);
}
} else {
// Return cached value
returnValue = operationDescriptor.getFieldValue("lastReturnedValue");
if (returnValue != null) {
Class parameter = returnValue.getClass();
Class declared = loadClassWithContextClassLoader(operInfo.getReturnType());
checkAssignability(parameter, declared);
}
if (logger.isEnabledFor(Logger.DEBUG)) {
logger.debug("invoke for operation " + method + " returns cached value: " + returnValue);
}
}
// As an extension, persist this model mbean also after operation invocation, but using only
// settings provided in the operation descriptor, without falling back to defaults set in
// the MBean descriptor
boolean persistNow = shouldPersistNow(operationDescriptor, null, lastUpdateField);
int impact = operInfo.getImpact();
if (persistNow && impact != MBeanOperationInfo.INFO) {
if (logger.isEnabledFor(Logger.TRACE)) {
logger.trace("Persisting this ModelMBean...");
}
try {
store();
if (logger.isEnabledFor(Logger.TRACE)) {
logger.trace("ModelMBean persisted successfully");
}
} catch (Exception x) {
logger.error(
"Cannot store ModelMBean after operation invocation", x);
if (x instanceof MBeanException) {
throw (MBeanException) x;
} else {
throw new MBeanException(x);
}
}
}
return returnValue;
}