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) {


Reply via email to