Author: rmannibucau
Date: Thu Aug 1 08:32:00 2013
New Revision: 1509112
URL: http://svn.apache.org/r1509112
Log:
escaping method parameter by parameter for jmx method invocation + fixing JMX
names of counters
Modified:
commons/sandbox/monitoring/trunk/core/src/main/java/org/apache/commons/monitoring/counter/factory/DefaultCounterFactory.java
commons/sandbox/monitoring/trunk/reporting/src/main/java/org/apache/commons/monitoring/reporting/web/plugin/jmx/JMXHandler.java
commons/sandbox/monitoring/trunk/reporting/src/main/resources/templates/jmx/mbean.vm
Modified:
commons/sandbox/monitoring/trunk/core/src/main/java/org/apache/commons/monitoring/counter/factory/DefaultCounterFactory.java
URL:
http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/core/src/main/java/org/apache/commons/monitoring/counter/factory/DefaultCounterFactory.java?rev=1509112&r1=1509111&r2=1509112&view=diff
==============================================================================
---
commons/sandbox/monitoring/trunk/core/src/main/java/org/apache/commons/monitoring/counter/factory/DefaultCounterFactory.java
(original)
+++
commons/sandbox/monitoring/trunk/core/src/main/java/org/apache/commons/monitoring/counter/factory/DefaultCounterFactory.java
Thu Aug 1 08:32:00 2013
@@ -21,19 +21,34 @@ import org.apache.commons.monitoring.Rol
import org.apache.commons.monitoring.configuration.Configuration;
import org.apache.commons.monitoring.counter.Counter;
import org.apache.commons.monitoring.counter.DefaultCounter;
-import org.apache.commons.monitoring.util.ClassLoaders;
+import org.apache.commons.monitoring.monitors.Monitor;
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.DynamicMBean;
+import javax.management.InvalidAttributeValueException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanConstructorInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanOperationInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;
+import javax.management.ReflectionException;
import java.io.Closeable;
import java.io.IOException;
import java.lang.management.ManagementFactory;
-import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
public class DefaultCounterFactory implements CounterFactory, Closeable {
private static final boolean JMX =
Configuration.isActivated(Configuration.Keys.JMX);
@@ -53,14 +68,16 @@ public class DefaultCounterFactory imple
}
try {
- final ObjectName name = new
ObjectName("org.apache.commons.monitoring:type=counter,name=" +
counter.getMonitor().getKey().getName());
-
SERVER.registerMBean(CounterMBean.class.cast(Proxy.newProxyInstance(ClassLoaders.current(),
new Class<?>[] { CounterMBean.class }, new InvocationHandler() {
- @Override
- public Object invoke(final Object proxy, final Method method,
final Object[] args) throws Throwable {
- return method.invoke(counter, args);
- }
- })), name);
- toUnregister.add(name);
+ final ObjectName name = new ObjectName(
+ "org.apache.commons.monitoring:" +
+ "type=counter," +
+ "monitorName=" +
counter.getMonitor().getKey().getName().replace(",", " ").replace("=", "
").replace(";", " ").replace("*", " ").replace("?", " ") + "," +
+ "monitorCategory=" +
counter.getMonitor().getKey().getCategory() + "," +
+ "role=" + counter.getRole().getName());
+ if (!SERVER.isRegistered(name)) {
+ SERVER.registerMBean(new CounterMBean(counter), name);
+ toUnregister.add(name);
+ }
} catch (final Exception e) {
throw new MonitoringException(e);
}
@@ -77,6 +94,114 @@ public class DefaultCounterFactory imple
}
}
- public static interface CounterMBean extends Counter {
+ public static class CounterMBean implements DynamicMBean {
+ private static final Map<String, Method> METHODS = new
ConcurrentHashMap<String, Method>();
+ private static final List<String> VIRTUAL_FIELDS = new
CopyOnWriteArrayList<String>() {{
+ add("Role");
+ add("Monitor");
+ add("Unit");
+ }};
+ private static final MBeanInfo INFO = computeCounterMBeanInfo();
+
+ private static MBeanInfo computeCounterMBeanInfo() {
+ final Collection<MBeanAttributeInfo> attributes = new
LinkedList<MBeanAttributeInfo>();
+ final Collection<MBeanOperationInfo> operations = new
LinkedList<MBeanOperationInfo>();
+
+ for (final Method m : Counter.class.getMethods()) {
+ final String name = m.getName();
+ if ("setMonitor".equals(name)) {
+ continue;
+ }
+
+ if (name.startsWith("get")) {
+ final String attributeName =
name.substring("get".length());
+ if (VIRTUAL_FIELDS.contains(attributeName)) {
+ attributes.add(new MBeanAttributeInfo(attributeName,
String.class.getName(), attributeName + " value", true, false, false));
+ } else {
+ attributes.add(new MBeanAttributeInfo(attributeName,
m.getReturnType().getName(), attributeName + " value", true, false, false));
+ }
+ } else {
+ METHODS.put(name, m);
+ operations.add(new MBeanOperationInfo(name + " method",
m));
+ }
+ }
+
+ return new MBeanInfo(
+ CounterMBean.class.getName(),
+ "Counter MBean",
+ attributes.toArray(new MBeanAttributeInfo[attributes.size()]),
+ new MBeanConstructorInfo[0],
+ operations.toArray(new MBeanOperationInfo[operations.size()]),
+ new MBeanNotificationInfo[0]);
+ }
+
+ private final Counter delegate;
+
+ public CounterMBean(final Counter counter) {
+ delegate = counter;
+ }
+
+ @Override
+ public Object getAttribute(final String attribute) throws
AttributeNotFoundException, MBeanException, ReflectionException {
+ if (VIRTUAL_FIELDS.contains(attribute)) {
+ if ("Role".equals(attribute)) {
+ final Role role = delegate.getRole();
+ return role.getName() + " (" + role.getUnit().getName() +
")";
+ }
+ if ("Unit".equals(attribute)) {
+ return delegate.getUnit().getName();
+ }
+ if ("Monitor".equals(attribute)) {
+ final Monitor.Key key = delegate.getMonitor().getKey();
+ return key.getName() + " (" + key.getCategory() + ")";
+ }
+ }
+ try {
+ return Counter.class.getMethod("get" +
attribute).invoke(delegate);
+ } catch (final Exception e) {
+ throw new AttributeNotFoundException(e.getMessage());
+ }
+ }
+
+ @Override
+ public void setAttribute(final Attribute attribute) throws
AttributeNotFoundException, InvalidAttributeValueException, MBeanException,
ReflectionException {
+ throw new UnsupportedOperationException("Read Only MBean");
+ }
+
+ @Override
+ public AttributeList getAttributes(final String[] attributes) {
+ final AttributeList list = new AttributeList();
+ for (final String attribute : attributes) {
+ try {
+ list.add(new Attribute(attribute,
getAttribute(attribute)));
+ } catch (final Exception e) {
+ // no-op
+ }
+ }
+ return list;
+ }
+
+ @Override
+ public AttributeList setAttributes(final AttributeList attributes) {
+ throw new UnsupportedOperationException("Read Only MBean");
+ }
+
+ @Override
+ public Object invoke(final String actionName, final Object[] params,
final String[] signature) throws MBeanException, ReflectionException {
+ final Method m = METHODS.get(actionName);
+ if (m == null) {
+ throw new MBeanException(new NullPointerException(), "method "
+ actionName + " doesn't exist");
+ }
+ try {
+ return m.invoke(delegate, params);
+ } catch (final Exception e) {
+ throw new MBeanException(e, e.getMessage());
+ }
+ }
+
+ @Override
+ public MBeanInfo getMBeanInfo() {
+ return INFO;
+ }
}
}
Modified:
commons/sandbox/monitoring/trunk/reporting/src/main/java/org/apache/commons/monitoring/reporting/web/plugin/jmx/JMXHandler.java
URL:
http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/reporting/src/main/java/org/apache/commons/monitoring/reporting/web/plugin/jmx/JMXHandler.java?rev=1509112&r1=1509111&r2=1509112&view=diff
==============================================================================
---
commons/sandbox/monitoring/trunk/reporting/src/main/java/org/apache/commons/monitoring/reporting/web/plugin/jmx/JMXHandler.java
(original)
+++
commons/sandbox/monitoring/trunk/reporting/src/main/java/org/apache/commons/monitoring/reporting/web/plugin/jmx/JMXHandler.java
Thu Aug 1 08:32:00 2013
@@ -18,6 +18,7 @@ package org.apache.commons.monitoring.re
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.monitoring.MonitoringException;
+import org.apache.commons.monitoring.configuration.Configuration;
import
org.apache.commons.monitoring.reporting.web.handler.HandlerRendererAdapter;
import org.apache.commons.monitoring.reporting.web.handler.Renderer;
import org.apache.commons.monitoring.reporting.web.template.MapBuilder;
@@ -35,9 +36,11 @@ import javax.management.ObjectName;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.TabularData;
import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
+import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -50,6 +53,7 @@ import java.util.Set;
public class JMXHandler extends HandlerRendererAdapter {
private static final MBeanServer SERVER =
ManagementFactory.getPlatformMBeanServer();
+ private static final boolean METHOD_INVOCATION_ALLOWED =
Configuration.is(Configuration.COMMONS_MONITORING_PREFIX +
"jmx.method.allowed", true);
private static final Map<String, Class<?>> WRAPPERS = new HashMap<String,
Class<?>>();
@@ -74,19 +78,31 @@ public class JMXHandler extends HandlerR
String subPath = path.substring("/jmx/".length());
if (subPath.startsWith("operation/")) {
+ if (!METHOD_INVOCATION_ALLOWED) {
+ throw new MonitoringException("Method invocation not allowed");
+ }
+
subPath = subPath.substring("operation/".length());
final String[] parts = subPath.split("/");
-
- final Collection<String> params = new
ArrayList<String>(parts.length - 2);
+ final List<String> params = new ArrayList<String>(parts.length -
2);
{ // remove object name and operation name to keep only parameters
params.addAll(Arrays.asList(parts));
final Iterator<String> it = params.iterator();
it.next(); it.remove();
it.next(); it.remove();
}
+ // decode params
+ final String[] decodedParams = new String[params.size()];
+ for (int i = 0; i < params.size(); i++) {
+ try {
+ decodedParams[i] = URLDecoder.decode(params.get(i),
"UTF-8");
+ } catch (final UnsupportedEncodingException e) {
+ decodedParams[i] = params.get(i);
+ }
+ }
try {
- return new InvokeRenderer(new ObjectName(new
String(Base64.decodeBase64(parts[0]))), parts[1], params.toArray(new
String[params.size()]));
+ return new InvokeRenderer(new ObjectName(new
String(Base64.decodeBase64(parts[0]))), parts[1], decodedParams);
} catch (final MalformedObjectNameException e) {
throw new MonitoringException(e);
}
Modified:
commons/sandbox/monitoring/trunk/reporting/src/main/resources/templates/jmx/mbean.vm
URL:
http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/reporting/src/main/resources/templates/jmx/mbean.vm?rev=1509112&r1=1509111&r2=1509112&view=diff
==============================================================================
---
commons/sandbox/monitoring/trunk/reporting/src/main/resources/templates/jmx/mbean.vm
(original)
+++
commons/sandbox/monitoring/trunk/reporting/src/main/resources/templates/jmx/mbean.vm
Thu Aug 1 08:32:00 2013
@@ -76,7 +76,7 @@
// we pass base64 as id so this is a workaround since = will
likely make #id fail
$('[id=\'' + id + '\']' + ' :input').each(function () {
- url = url + "/" + $(this).val();
+ url = url + "/" + encodeURIComponent($(this).val());
});
$.get(url, function(data) {