Permalink
Browse files

ISPN-2885 Expose parameter names in MBean metadata

ISPN-2883 Use special naming to overcome JMX method overloading with RHQ
operation name uniqueness
  • Loading branch information...
tristantarrant authored and danberindei committed Mar 4, 2013
1 parent 0e55c2f commit cdfa3457786f6ce2dac37bf925cb8301ea324db1
@@ -20,9 +20,10 @@
package org.infinispan.factories.components;
import org.infinispan.jmx.annotations.ManagedOperation;
-import org.infinispan.util.ReflectionUtil;
+import org.infinispan.jmx.annotations.Parameter;
import java.io.Serializable;
+import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
@@ -33,18 +34,33 @@
* @since 5.1
*/
public class JmxOperationMetadata implements Serializable {
- private String methodName;
- private String[] methodParameters;
- private String description;
-
+ private final String methodName;
+ private final JmxOperationParameter[] methodParameters;
+ private final String description;
+ private final String returnType;
+
public JmxOperationMetadata(Method m) {
methodName = m.getName();
+ returnType = m.getReturnType().getName();
Class<?>[] params = m.getParameterTypes();
- methodParameters = ReflectionUtil.toStringArray(params);
- ManagedOperation mo = m.getAnnotation(ManagedOperation.class);
- if (mo != null) {
- description = mo.description();
+ Annotation[][] annots = m.getParameterAnnotations();
+ methodParameters = new JmxOperationParameter[params.length];
+ for (int i = 0; i < params.length; i++) {
+ Parameter annot = null;
+ for (int j = 0; j < annots[i].length; j++) {
+ if (annots[i][j] instanceof Parameter) {
+ annot = (Parameter) annots[i][j];
+ break;
+ }
+ }
+ if (annot == null) {
+ methodParameters[i] = new JmxOperationParameter("p" + i, params[i].getName(), null);
+ } else {
+ methodParameters[i] = new JmxOperationParameter(annot.name(), params[i].getName(), annot.description());
+ }
}
+ ManagedOperation mo = m.getAnnotation(ManagedOperation.class);
+ description = mo != null ? mo.description() : null;
}
public String getDescription() {
@@ -55,10 +71,15 @@ public String getMethodName() {
return methodName;
}
- public String[] getMethodParameters() {
+ public JmxOperationParameter[] getMethodParameters() {
return methodParameters;
}
+ public String getReturnType() {
+ return returnType;
+ }
+
+
@Override
public String toString() {
return "JmxOperationMetadata{" +
@@ -67,4 +88,5 @@ public String toString() {
", description='" + description + '\'' +
'}';
}
+
}
@@ -0,0 +1,60 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public License,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+package org.infinispan.factories.components;
+
+import java.io.Serializable;
+
+import javax.management.MBeanParameterInfo;
+
+/**
+ * JmxOperationParameter stores metadata information about MBean operation parameters which
+ * is then used at runtime to build the relevant {@link MBeanParameterInfo}
+ *
+ * @author Tristan Tarrant
+ * @since 5.2.3
+ */
+public class JmxOperationParameter implements Serializable {
+ final String name;
+ final String type;
+ final String description;
+
+ public JmxOperationParameter(String name, String type, String description) {
+ this.name = name;
+ this.type = type;
+ this.description = description;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ @Override
+ public String toString() {
+ return "JmxOperationParameter [name=" + name + ", type=" + type + ", description=" + description + "]";
+ }
+
+}
@@ -24,6 +24,7 @@
import org.infinispan.factories.components.JmxAttributeMetadata;
import org.infinispan.factories.components.JmxOperationMetadata;
+import org.infinispan.factories.components.JmxOperationParameter;
import org.infinispan.factories.components.ManageableComponentMetadata;
import org.infinispan.jmx.annotations.MBean;
import org.infinispan.jmx.annotations.ManagedOperation;
@@ -40,6 +41,7 @@
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
import javax.management.ReflectionException;
import javax.management.ServiceNotFoundException;
import java.lang.reflect.Field;
@@ -180,10 +182,12 @@ private InvokableMBeanAttributeInfo toJmxInfo(JmxAttributeMetadata attributeMeta
}
private MBeanOperationInfo toJmxInfo(JmxOperationMetadata operationMetadata) throws ClassNotFoundException {
- return new MBeanOperationInfo(operationMetadata.getDescription(),
- ReflectionUtil.findMethod(objectClass,
- operationMetadata.getMethodName(),
- getParameterArray(operationMetadata.getMethodParameters())));
+ JmxOperationParameter[] parameters = operationMetadata.getMethodParameters();
+ MBeanParameterInfo[] params = new MBeanParameterInfo[parameters.length];
+ for(int i=0; i< parameters.length; i++) {
+ params[i] = new MBeanParameterInfo(parameters[i].getName(), parameters[i].getType(), parameters[i].getDescription());
+ }
+ return new MBeanOperationInfo(operationMetadata.getMethodName(), operationMetadata.getDescription(), params, operationMetadata.getReturnType(), MBeanOperationInfo.UNKNOWN);
}
Object getObject() {
@@ -24,7 +24,7 @@
import java.lang.annotation.Target;
@Target(ElementType.PARAMETER)
-@Retention(RetentionPolicy.CLASS)
+@Retention(RetentionPolicy.RUNTIME)
public @interface Parameter {
String name() default "";
String description() default "";
@@ -885,7 +885,7 @@ public void startCache() {
getCache();
}
- @ManagedOperation(description = "Starts a named cache from this cache manager", name = "startCacheWithCacheName", displayName = "Starts a cache with the given name")
+ @ManagedOperation(description = "Starts a named cache from this cache manager", name = "startCache|cacheName", displayName = "Starts a cache with the given name")
public void startCache(@Parameter(name = "cacheName", description = "Name of cache to start") String cacheName) {
getCache(cacheName);
}
@@ -89,7 +89,7 @@ public String forceCommit(@Parameter(name = "internalId", description = "The int
return completeBasedOnInternalId(internalId, true);
}
- @ManagedOperation(description = "Forces the commit of an in-doubt transaction", displayName="Force commit by Xid", name="forceCommitByXid")
+ @ManagedOperation(description = "Forces the commit of an in-doubt transaction", displayName="Force commit by Xid", name="forceCommit|ByXid")
public String forceCommit(
@Parameter(name = "formatId", description = "The formatId of the transaction") int formatId,
@Parameter(name = "globalTxId", description = "The globalTxId of the transaction") byte[] globalTxId,
@@ -102,15 +102,15 @@ public String forceRollback(@Parameter(name = "internalId", description = "The i
return completeBasedOnInternalId(internalId, false);
}
- @ManagedOperation(description = "Forces the rollback of an in-doubt transaction", displayName="Force rollback by Xid", name="forceRollbackByXid")
+ @ManagedOperation(description = "Forces the rollback of an in-doubt transaction", displayName="Force rollback by Xid", name="forceRollback|ByXid")
public String forceRollback(
@Parameter(name = "formatId", description = "The formatId of the transaction") int formatId,
@Parameter(name = "globalTxId", description = "The globalTxId of the transaction") byte[] globalTxId,
@Parameter(name = "branchQualifier", description = "The branchQualifier of the transaction") byte[] branchQualifier) {
return completeBasedOnXid(formatId, globalTxId, branchQualifier, false);
}
- @ManagedOperation(description = "Removes recovery info for the given transaction.", displayName="Remove recovery info by Xid", name="forgetByXid")
+ @ManagedOperation(description = "Removes recovery info for the given transaction.", displayName="Remove recovery info by Xid", name="forget|ByXid")
public String forget(
@Parameter(name = "formatId", description = "The formatId of the transaction") int formatId,
@Parameter(name = "globalTxId", description = "The globalTxId of the transaction") byte[] globalTxId,
@@ -55,6 +55,7 @@
private CacheStore cacheStore;
private static final String JMX_DOMAIN = CacheLoaderAndCacheStoreInterceptorMBeanTest.class.getName();
+ @Override
protected EmbeddedCacheManager createCacheManager() throws Exception {
GlobalConfiguration globalConfiguration = GlobalConfiguration.getNonClusteredDefault();
globalConfiguration.setMBeanServerLookup(PerThreadMBeanServerLookup.class.getName());
@@ -87,6 +88,11 @@ public void resetStats() throws Exception {
threadMBeanServer.invoke(storeInterceptorObjName, "resetStatistics", new Object[0], new String[0]);
}
+ public void testJmxOperationMetadata() throws Exception {
+ checkMBeanOperationParameterNaming(loaderInterceptorObjName);
+ checkMBeanOperationParameterNaming(storeInterceptorObjName);
+ }
+
public void testPutKeyValue() throws Exception {
assertStoreAccess(0, 0, 0);
cache.put("key", "value");
@@ -25,6 +25,9 @@
import java.lang.reflect.Method;
import javax.management.InstanceNotFoundException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;
@@ -56,7 +59,12 @@ protected EmbeddedCacheManager createCacheManager() throws Exception {
server = PerThreadMBeanServerLookup.getThreadMBeanServer();
return cacheManager;
}
-
+
+ public void testJmxOperationMetadata() throws Exception {
+ ObjectName name = getCacheObjectName(JMX_DOMAIN);
+ checkMBeanOperationParameterNaming(name);
+ }
+
public void testStartStopManagedOperations() throws Exception {
ObjectName defaultOn = getCacheObjectName(JMX_DOMAIN);
ObjectName managerON = getCacheManagerObjectName(JMX_DOMAIN);
@@ -85,7 +93,7 @@ public void testStartStopManagedOperations() throws Exception {
assert server.getAttribute(managerON, "RunningCacheCount").equals("0");
assert ComponentStatus.TERMINATED.toString().equals(server.getAttribute(defaultOn, "CacheStatus"));
}
-
+
public void testManagerStopRemovesCacheMBean(Method m) throws Exception {
final String otherJmxDomain = getMethodSpecificJmxDomain(m, JMX_DOMAIN);
ObjectName defaultOn = getCacheObjectName(otherJmxDomain);
@@ -22,7 +22,9 @@
*/
package org.infinispan.jmx;
+import static org.testng.AssertJUnit.assertFalse;
import java.lang.reflect.Method;
+import java.util.regex.Pattern;
import org.infinispan.config.Configuration;
import org.infinispan.manager.CacheContainer;
@@ -34,6 +36,9 @@
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.ServiceNotFoundException;
@@ -53,6 +58,7 @@
private MBeanServer server;
private ObjectName name;
+ @Override
protected EmbeddedCacheManager createCacheManager() throws Exception {
cacheManager = TestCacheManagerFactory.createCacheManagerEnforceJmxDomain(JMX_DOMAIN, true, false);
name = getCacheManagerObjectName(JMX_DOMAIN);
@@ -90,17 +96,21 @@ public void testJmxOperations() throws Exception {
assert attribute.contains("b(");
assert attribute.contains("c(");
}
-
+
+ public void testJmxOperationMetadata() throws Exception {
+ checkMBeanOperationParameterNaming(name);
+ }
+
public void testInvokeJmxOperationNotExposed() throws Exception {
try {
server.invoke(name, "stop", new Object[]{}, new String[]{});
assert false : "Method not exposed, invocation should have failed";
} catch (MBeanException mbe) {
assert mbe.getCause() instanceof ServiceNotFoundException;
}
-
+
}
-
+
public void testJmxRegistrationAtStartupAndStop(Method m) throws Exception {
final String otherJmxDomain = getMethodSpecificJmxDomain(m, JMX_DOMAIN);
CacheContainer otherContainer = TestCacheManagerFactory.createCacheManagerEnforceJmxDomain(otherJmxDomain, true, false);
@@ -110,7 +120,7 @@ public void testJmxRegistrationAtStartupAndStop(Method m) throws Exception {
} finally {
otherContainer.stop();
}
-
+
try {
server.getAttribute(otherName, "CreatedCacheCount").equals("0");
assert false : "Failure expected, " + otherName + " shouldn't be registered in mbean server";
@@ -28,10 +28,15 @@
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.test.SingleCacheManagerTest;
import static org.infinispan.test.TestingUtil.*;
+import static org.testng.AssertJUnit.assertFalse;
+
import org.infinispan.test.fwk.TestCacheManagerFactory;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.util.HashMap;
@@ -46,10 +51,11 @@
@Test(groups = "functional", testName = "jmx.CacheMgmtInterceptorMBeanTest")
public class CacheMgmtInterceptorMBeanTest extends SingleCacheManagerTest {
private ObjectName mgmtInterceptor;
- private MBeanServer threadMBeanServer;
+ private MBeanServer server;
AdvancedCache advanced;
private static final String JMX_DOMAIN = CacheMgmtInterceptorMBeanTest.class.getSimpleName();
+ @Override
protected EmbeddedCacheManager createCacheManager() throws Exception {
GlobalConfiguration globalConfiguration = GlobalConfiguration.getNonClusteredDefault();
globalConfiguration.setExposeGlobalJmxStatistics(true);
@@ -64,13 +70,17 @@ protected EmbeddedCacheManager createCacheManager() throws Exception {
advanced = cache.getAdvancedCache();
mgmtInterceptor = getCacheObjectName(JMX_DOMAIN, "test(local)", "Statistics");
- threadMBeanServer = PerThreadMBeanServerLookup.getThreadMBeanServer();
+ server = PerThreadMBeanServerLookup.getThreadMBeanServer();
return cacheManager;
}
@AfterMethod(alwaysRun = true)
public void resetStats() throws Exception {
- threadMBeanServer.invoke(mgmtInterceptor, "resetStatistics", new Object[0], new String[0]);
+ server.invoke(mgmtInterceptor, "resetStatistics", new Object[0], new String[0]);
+ }
+
+ public void testJmxOperationMetadata() throws Exception {
+ checkMBeanOperationParameterNaming(mgmtInterceptor);
}
public void testEviction() throws Exception {
@@ -173,7 +183,7 @@ public void testRemoves() throws Exception {
}
private void assertAttributeValue(String attrName, float expectedValue) throws Exception {
- String receivedVal = threadMBeanServer.getAttribute(mgmtInterceptor, attrName).toString();
+ String receivedVal = server.getAttribute(mgmtInterceptor, attrName).toString();
assert Float.parseFloat(receivedVal) == expectedValue : "expecting " + expectedValue + " for " + attrName + ", but received " + receivedVal;
}
Oops, something went wrong.

0 comments on commit cdfa345

Please sign in to comment.