Author: rmannibucau
Date: Wed Jul 31 15:52:31 2013
New Revision: 1508942

URL: http://svn.apache.org/r1508942
Log:
basic jmx invocations

Added:
    
commons/sandbox/monitoring/trunk/reporting/src/main/resources/resources/js/bootstrap-tab.js
Modified:
    
commons/sandbox/monitoring/trunk/core/src/main/java/org/apache/commons/monitoring/MonitoringException.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/java/org/apache/commons/monitoring/reporting/web/plugin/jmx/JMXNode.java
    
commons/sandbox/monitoring/trunk/reporting/src/main/resources/templates/jmx/main.vm
    
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/MonitoringException.java
URL: 
http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/core/src/main/java/org/apache/commons/monitoring/MonitoringException.java?rev=1508942&r1=1508941&r2=1508942&view=diff
==============================================================================
--- 
commons/sandbox/monitoring/trunk/core/src/main/java/org/apache/commons/monitoring/MonitoringException.java
 (original)
+++ 
commons/sandbox/monitoring/trunk/core/src/main/java/org/apache/commons/monitoring/MonitoringException.java
 Wed Jul 31 15:52:31 2013
@@ -20,4 +20,8 @@ public class MonitoringException extends
     public MonitoringException(final Exception e) {
         super(e);
     }
+
+    public MonitoringException(final String s) {
+        super(s);
+    }
 }

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=1508942&r1=1508941&r2=1508942&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
 Wed Jul 31 15:52:31 2013
@@ -22,9 +22,12 @@ import org.apache.commons.monitoring.rep
 import org.apache.commons.monitoring.reporting.web.handler.Renderer;
 import org.apache.commons.monitoring.reporting.web.template.MapBuilder;
 import org.apache.commons.monitoring.reporting.web.template.Templates;
+import org.apache.commons.monitoring.util.ClassLoaders;
 
 import javax.management.MBeanAttributeInfo;
 import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
 import javax.management.MBeanServer;
 import javax.management.MalformedObjectNameException;
 import javax.management.ObjectInstance;
@@ -34,7 +37,12 @@ import javax.management.openmbean.Tabula
 import java.io.PrintWriter;
 import java.lang.management.ManagementFactory;
 import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -43,14 +51,49 @@ import java.util.Set;
 public class JMXHandler extends HandlerRendererAdapter {
     private static final MBeanServer SERVER = 
ManagementFactory.getPlatformMBeanServer();
 
+    private static final Map<String, Class<?>> WRAPPERS = new HashMap<String, 
Class<?>>();
+
+    static {
+        for (final Class<?> c : Arrays.<Class<?>>asList(Byte.class, 
Short.class, Integer.class, Long.class, Float.class, Double.class, 
Character.class, Boolean.class )) {
+            try {
+                final Field f = c.getField("TYPE");
+                Class<?> p = (Class<?>) f.get(null);
+                WRAPPERS.put(p.getName(), c);
+            } catch (Exception e) {
+                throw new AssertionError(e);
+            }
+        }
+    }
+
+
     @Override
     protected Renderer rendererFor(final String path) {
         if ("/jmx".endsWith(path) || "/jmx/".equals(path)) {
             return this;
         }
 
+        String subPath = path.substring("/jmx/".length());
+        if (subPath.startsWith("operation/")) {
+            subPath = subPath.substring("operation/".length());
+            final String[] parts = subPath.split("/");
+
+            final Collection<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();
+            }
+
+            try {
+                return new InvokeRenderer(new ObjectName(new 
String(Base64.decodeBase64(parts[0]))), parts[1], params.toArray(new 
String[params.size()]));
+            } catch (final MalformedObjectNameException e) {
+                throw new MonitoringException(e);
+            }
+        }
+
         try {
-            return new MBeanRenderer(new ObjectName(new 
String(Base64.decodeBase64(path.substring("/jmx/".length())))));
+            return new MBeanRenderer(new ObjectName(new 
String(Base64.decodeBase64(subPath))));
         } catch (final MalformedObjectNameException e) {
             throw new MonitoringException(e);
         }
@@ -77,6 +120,117 @@ public class JMXHandler extends HandlerR
         return root;
     }
 
+    private static class InvokeRenderer implements Renderer {
+        private final ObjectName name;
+        private final String operation;
+        private final String[] params;
+
+        public InvokeRenderer(final ObjectName objectName, final String 
method, final String[] parameters) {
+            name = objectName;
+            operation = method;
+            params = parameters;
+        }
+
+        @Override
+        public void render(final PrintWriter writer, final Map<String, ?> 
ignored) {
+            try {
+                final MBeanInfo info = SERVER.getMBeanInfo(name);
+                for (final MBeanOperationInfo op : info.getOperations()) {
+                    if (op.getName().equals(operation)) {
+                        final MBeanParameterInfo[] signature = 
op.getSignature();
+                        final String[] sign = new String[signature.length];
+                        for (int i = 0; i < sign.length; i++) {
+                            sign[i] = signature[i].getType();
+                        }
+                        final Object result = SERVER.invoke(name, operation, 
convertParams(signature, params), sign);
+                        writer.write("<div>Method was invoked and 
returned:</div>" + value(result));
+                        return;
+                    }
+                }
+            } catch (final Exception e) {
+                writer.write("<div class=\"alert alert-error\">\n" +
+                    "\n" + e.getMessage() + "\n" +
+                    "</div>");
+                return;
+            }
+
+            writer.write("<div class=\"alert alert-error\">Operation" + 
operation + " not found.</div>");
+        }
+
+        private Object[] convertParams(final MBeanParameterInfo[] signature, 
final String[] params) {
+            if (params == null) {
+                return null;
+            }
+
+            final Object[] convertedParams = new Object[signature.length];
+            for (int i = 0; i < signature.length; i++) {
+                if (i < params.length) {
+                    convertedParams[i] = convert(signature[i].getType(), 
params[i]);
+                } else {
+                    convertedParams[i] = null;
+                }
+            }
+            return convertedParams;
+        }
+
+        public static Object convert(final String type, final String value) {
+            try {
+                if (WRAPPERS.containsKey(type)) {
+                    if (type.equals(Character.TYPE.getName())) {
+                        return value.charAt(0);
+                    } else {
+                        return tryStringConstructor(type, value);
+                    }
+                }
+
+                if (type.equals(Character.class.getName())) {
+                    return value.charAt(0);
+                }
+
+                if 
(Number.class.isAssignableFrom(ClassLoaders.current().loadClass(type))) {
+                    return toNumber(value);
+                }
+
+                if (value == null || value.equals("null")) {
+                    return null;
+                }
+
+                return tryStringConstructor(type, value);
+            } catch (final Exception e) {
+                throw new MonitoringException(e);
+            }
+        }
+
+        private static Number toNumber(final String value) throws 
NumberFormatException {
+            // first the user can force the conversion
+            final char lastChar = 
Character.toLowerCase(value.charAt(value.length() - 1));
+            if (lastChar == 'd') {
+                return Double.valueOf(value.substring(0, value.length() - 1));
+            }
+            if (lastChar == 'l') {
+                return Long.valueOf(value.substring(0, value.length() - 1));
+            }
+            if (lastChar == 'f') {
+                return Float.valueOf(value.substring(0, value.length() - 1));
+            }
+
+            // try all conversions in cascade until it works
+            for (final Class<?> clazz : new Class<?>[] { Integer.class, 
Long.class, Double.class }) {
+                try {
+                    return 
Number.class.cast(clazz.getMethod("valueOf").invoke(null, value));
+                } catch (final Exception e) {
+                    // no-op
+                }
+            }
+
+            throw new MonitoringException(value + " is not a number");
+        }
+
+        private static Object tryStringConstructor(String type, final String 
value) throws Exception {
+            return 
ClassLoaders.current().loadClass(type).getConstructor(String.class).newInstance(value);
+        }
+    }
+
     private static class MBeanRenderer implements Renderer {
         private final ObjectName name;
 
@@ -91,15 +245,29 @@ public class JMXHandler extends HandlerR
                 Templates.render(writer, "templates/jmx/mbean.vm",
                     new MapBuilder<String, Object>()
                         .set("objectname", name.toString())
+                        .set("objectnameHash", 
Base64.encodeBase64String(name.toString().getBytes()))
                         .set("classname", info.getClassName())
-                        .set("description", info.getDescription())
+                        .set("description", value(info.getDescription()))
                         .set("attributes", attributes(info))
+                        .set("operations", operations(info))
                         .build());
             } catch (final Exception e) {
                 throw new MonitoringException(e);
             }
         }
 
+        private Collection<MBeanOperation> operations(final MBeanInfo info) {
+            final Collection<MBeanOperation> operations = new 
LinkedList<MBeanOperation>();
+            for (final MBeanOperationInfo operationInfo : 
info.getOperations()) {
+                final MBeanOperation mBeanOperation = new 
MBeanOperation(operationInfo.getName(), operationInfo.getReturnType());
+                for (final MBeanParameterInfo param : 
operationInfo.getSignature()) {
+                    mBeanOperation.getParameters().add(new 
MBeanParameter(param.getName(), param.getType()));
+                }
+                operations.add(mBeanOperation);
+            }
+            return operations;
+        }
+
         private Collection<MBeanAttribute> attributes(final MBeanInfo info) {
             final Collection<MBeanAttribute> list = new 
LinkedList<MBeanAttribute>();
             for (final MBeanAttributeInfo attribute : info.getAttributes()) {
@@ -113,88 +281,88 @@ public class JMXHandler extends HandlerR
             }
             return list;
         }
+    }
 
-        private static String value(final Object value) {
-            try {
-                if (value == null) {
+    private static String value(final Object value) {
+        try {
+            if (value == null) {
+                return "";
+            }
+
+            if (value.getClass().isArray()) {
+                final int length = Array.getLength(value);
+                if (length == 0) {
                     return "";
                 }
 
-                if (value.getClass().isArray()) {
-                    final int length = Array.getLength(value);
-                    if (length == 0) {
-                        return "";
-                    }
-
-                    final StringBuilder builder = new 
StringBuilder().append("<ul>");
-                    for (int i = 0; i < length; i++) {
-                        builder.append("<li>").append(value(Array.get(value, 
i))).append("</li>");
-                    }
-                    builder.append("</ul>");
-                    return builder.toString();
+                final StringBuilder builder = new 
StringBuilder().append("<ul>");
+                for (int i = 0; i < length; i++) {
+                    builder.append("<li>").append(value(Array.get(value, 
i))).append("</li>");
                 }
+                builder.append("</ul>");
+                return builder.toString();
+            }
 
-                if (Collection.class.isInstance(value)) {
-                    final StringBuilder builder = new 
StringBuilder().append("<ul>");
-                    for (final Object o : Collection.class.cast(value)) {
-                        
builder.append("<li>").append(value(o)).append("</li>");
-                    }
-                    builder.append("</ul>");
-                    return builder.toString();
+            if (Collection.class.isInstance(value)) {
+                final StringBuilder builder = new 
StringBuilder().append("<ul>");
+                for (final Object o : Collection.class.cast(value)) {
+                    builder.append("<li>").append(value(o)).append("</li>");
                 }
+                builder.append("</ul>");
+                return builder.toString();
+            }
 
-                if (TabularData.class.isInstance(value)) {
-                    final TabularData td = TabularData.class.cast(value);
-                    final List<String> keys = 
td.getTabularType().getIndexNames();
-                    final int number = keys.size();
-
-                    final StringBuilder builder = new 
StringBuilder().append("<table class=\"table table-condensed\">");
-                    for (final Object type : td.keySet()) {
-                        final List<?> values = (List<?>) type;
-                        for (int i = 0; i < number; i++) {
-                            builder.append("<tr>")
-                                    
.append("<td>").append(value(keys.get(i))).append("</td>")
-                                    
.append("<td>").append(value(values.get(i))).append("</td>")
-                                .append("</tr>");
-                        }
-
+            if (TabularData.class.isInstance(value)) {
+                final TabularData td = TabularData.class.cast(value);
+                final List<String> keys = td.getTabularType().getIndexNames();
+                final int number = keys.size();
+
+                final StringBuilder builder = new 
StringBuilder().append("<table class=\"table table-condensed\">");
+                for (final Object type : td.keySet()) {
+                    final List<?> values = (List<?>) type;
+                    for (int i = 0; i < number; i++) {
+                        builder.append("<tr>")
+                            
.append("<td>").append(value(keys.get(i))).append("</td>")
+                            
.append("<td>").append(value(values.get(i))).append("</td>")
+                            .append("</tr>");
                     }
-                    builder.append("</table>");
 
-                    return builder.toString();
                 }
+                builder.append("</table>");
 
-                if (CompositeData.class.isInstance(value)) {
-                    final CompositeData cd = CompositeData.class.cast(value);
-                    final Set<String> keys = cd.getCompositeType().keySet();
-
-                    final StringBuilder builder = new 
StringBuilder().append("<table class=\"table table-condensed\">");
-                    for (final String type : keys) {
-                        
builder.append("<tr><td>").append(type).append("</td><td>").append(value(cd.get(type))).append("</td></tr>");
-                    }
-                    builder.append("</table>");
-
-                    return builder.toString();
+                return builder.toString();
+            }
 
+            if (CompositeData.class.isInstance(value)) {
+                final CompositeData cd = CompositeData.class.cast(value);
+                final Set<String> keys = cd.getCompositeType().keySet();
+
+                final StringBuilder builder = new 
StringBuilder().append("<table class=\"table table-condensed\">");
+                for (final String type : keys) {
+                    
builder.append("<tr><td>").append(type).append("</td><td>").append(value(cd.get(type))).append("</td></tr>");
                 }
+                builder.append("</table>");
 
-                if (Map.class.isInstance(value)) {
-                    final Map<?, ?> map = Map.class.cast(value);
+                return builder.toString();
 
-                    final StringBuilder builder = new 
StringBuilder().append("<table class=\"table table-condensed\">");
-                    for (final Map.Entry<?, ?> entry : map.entrySet()) {
-                        
builder.append("<tr><tr>").append(value(entry.getKey())).append("</td><td>").append(value(entry.getValue())).append("</td></tr>");
-                    }
-                    builder.append("</table>");
+            }
 
-                    return builder.toString();
+            if (Map.class.isInstance(value)) {
+                final Map<?, ?> map = Map.class.cast(value);
 
+                final StringBuilder builder = new 
StringBuilder().append("<table class=\"table table-condensed\">");
+                for (final Map.Entry<?, ?> entry : map.entrySet()) {
+                    
builder.append("<tr><tr>").append(value(entry.getKey())).append("</td><td>").append(value(entry.getValue())).append("</td></tr>");
                 }
+                builder.append("</table>");
+
+                return builder.toString();
 
-                return value.toString();
-            } catch (final Exception e) {
-                throw new MonitoringException(e);
             }
+
+            return value.toString();
+        } catch (final Exception e) {
+            throw new MonitoringException(e);
         }
     }
 
@@ -207,8 +375,12 @@ public class JMXHandler extends HandlerR
         public MBeanAttribute(final String name, final String type, final 
String description, final String value) {
             this.name = name;
             this.type = type;
-            this.description = description;
             this.value = value;
+            if (description != null) {
+                this.description = description;
+            } else {
+                this.description = "No description";
+            }
         }
 
         public String getName() {
@@ -227,4 +399,45 @@ public class JMXHandler extends HandlerR
             return value;
         }
     }
+
+    public static class MBeanOperation {
+        private final String name;
+        private final String returnType;
+        private final Collection<MBeanParameter> parameters = new 
LinkedList<MBeanParameter>();
+
+        public MBeanOperation(final String name, final String returnType) {
+            this.name = name;
+            this.returnType = returnType;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String getReturnType() {
+            return returnType;
+        }
+
+        public Collection<MBeanParameter> getParameters() {
+            return parameters;
+        }
+    }
+
+    public static class MBeanParameter {
+        private final String name;
+        private final String type;
+
+        public MBeanParameter(final String name, final String type) {
+            this.name = name;
+            this.type = type.replace("java.lang.", "");
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String getType() {
+            return type;
+        }
+    }
 }

Modified: 
commons/sandbox/monitoring/trunk/reporting/src/main/java/org/apache/commons/monitoring/reporting/web/plugin/jmx/JMXNode.java
URL: 
http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/reporting/src/main/java/org/apache/commons/monitoring/reporting/web/plugin/jmx/JMXNode.java?rev=1508942&r1=1508941&r2=1508942&view=diff
==============================================================================
--- 
commons/sandbox/monitoring/trunk/reporting/src/main/java/org/apache/commons/monitoring/reporting/web/plugin/jmx/JMXNode.java
 (original)
+++ 
commons/sandbox/monitoring/trunk/reporting/src/main/java/org/apache/commons/monitoring/reporting/web/plugin/jmx/JMXNode.java
 Wed Jul 31 15:52:31 2013
@@ -17,6 +17,7 @@
 package org.apache.commons.monitoring.reporting.web.plugin.jmx;
 
 import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang3.StringEscapeUtils;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -38,9 +39,9 @@ public class JMXNode {
         for (final String k : props.split(",")) {
             final String[] kv = k.split("=");
             if (kv.length < 2) {
-                properties.put(kv[0], "");
+                properties.put(StringEscapeUtils.escapeHtml4(kv[0]), "");
             } else {
-                properties.put(kv[0], kv[1]);
+                properties.put(StringEscapeUtils.escapeHtml4(kv[0]), 
StringEscapeUtils.escapeHtml4(kv[1]));
             }
         }
 

Added: 
commons/sandbox/monitoring/trunk/reporting/src/main/resources/resources/js/bootstrap-tab.js
URL: 
http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/reporting/src/main/resources/resources/js/bootstrap-tab.js?rev=1508942&view=auto
==============================================================================
--- 
commons/sandbox/monitoring/trunk/reporting/src/main/resources/resources/js/bootstrap-tab.js
 (added)
+++ 
commons/sandbox/monitoring/trunk/reporting/src/main/resources/resources/js/bootstrap-tab.js
 Wed Jul 31 15:52:31 2013
@@ -0,0 +1,144 @@
+/* ========================================================
+ * bootstrap-tab.js v2.3.2
+ * http://twbs.github.com/bootstrap/javascript.html#tabs
+ * ========================================================
+ * Copyright 2013 Twitter, Inc.
+ *
+ * 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.
+ * ======================================================== */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* TAB CLASS DEFINITION
+  * ==================== */
+
+  var Tab = function (element) {
+    this.element = $(element)
+  }
+
+  Tab.prototype = {
+
+    constructor: Tab
+
+  , show: function () {
+      var $this = this.element
+        , $ul = $this.closest('ul:not(.dropdown-menu)')
+        , selector = $this.attr('data-target')
+        , previous
+        , $target
+        , e
+
+      if (!selector) {
+        selector = $this.attr('href')
+        selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip 
for ie7
+      }
+
+      if ( $this.parent('li').hasClass('active') ) return
+
+      previous = $ul.find('.active:last a')[0]
+
+      e = $.Event('show', {
+        relatedTarget: previous
+      })
+
+      $this.trigger(e)
+
+      if (e.isDefaultPrevented()) return
+
+      $target = $(selector)
+
+      this.activate($this.parent('li'), $ul)
+      this.activate($target, $target.parent(), function () {
+        $this.trigger({
+          type: 'shown'
+        , relatedTarget: previous
+        })
+      })
+    }
+
+  , activate: function ( element, container, callback) {
+      var $active = container.find('> .active')
+        , transition = callback
+            && $.support.transition
+            && $active.hasClass('fade')
+
+      function next() {
+        $active
+          .removeClass('active')
+          .find('> .dropdown-menu > .active')
+          .removeClass('active')
+
+        element.addClass('active')
+
+        if (transition) {
+          element[0].offsetWidth // reflow for transition
+          element.addClass('in')
+        } else {
+          element.removeClass('fade')
+        }
+
+        if ( element.parent('.dropdown-menu') ) {
+          element.closest('li.dropdown').addClass('active')
+        }
+
+        callback && callback()
+      }
+
+      transition ?
+        $active.one($.support.transition.end, next) :
+        next()
+
+      $active.removeClass('in')
+    }
+  }
+
+
+ /* TAB PLUGIN DEFINITION
+  * ===================== */
+
+  var old = $.fn.tab
+
+  $.fn.tab = function ( option ) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('tab')
+      if (!data) $this.data('tab', (data = new Tab(this)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.tab.Constructor = Tab
+
+
+ /* TAB NO CONFLICT
+  * =============== */
+
+  $.fn.tab.noConflict = function () {
+    $.fn.tab = old
+    return this
+  }
+
+
+ /* TAB DATA-API
+  * ============ */
+
+  $(document).on('click.tab.data-api', '[data-toggle="tab"], 
[data-toggle="pill"]', function (e) {
+    e.preventDefault()
+    $(this).tab('show')
+  })
+
+}(window.jQuery);
\ No newline at end of file

Modified: 
commons/sandbox/monitoring/trunk/reporting/src/main/resources/templates/jmx/main.vm
URL: 
http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/reporting/src/main/resources/templates/jmx/main.vm?rev=1508942&r1=1508941&r2=1508942&view=diff
==============================================================================
--- 
commons/sandbox/monitoring/trunk/reporting/src/main/resources/templates/jmx/main.vm
 (original)
+++ 
commons/sandbox/monitoring/trunk/reporting/src/main/resources/templates/jmx/main.vm
 Wed Jul 31 15:52:31 2013
@@ -35,11 +35,12 @@
             #tree ( $jmxTree )
         </div>
         <div id="jmx-info" class="span10">
-            Click on the left tree to select a leaf top show the attributes of 
a MBean.
+            Click on the left tree to select a leaf to show the attributes of 
a MBean.
         </div>
     </div>
 </div>
 
+<script type="text/javascript" 
src="$mapping/resources/js/bootstrap-tab.js"></script>
 <script type="text/javascript">
     $(function() {
         $('li > ul').each(function (i) {

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=1508942&r1=1508941&r2=1508942&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
 Wed Jul 31 15:52:31 2013
@@ -15,63 +15,77 @@
   limitations under the License.
 *#
 <div class="page-header">
-    <h1><small>$objectname</small></h1>
+    <h1><small><div id="objectName">$objectname</div></small></h1>
     <h2><small>$classname</small></h2>
 </div>
 
-<div class="alert alert-info">
-    $description
-</div>
+<div id="invoke-result"></div>
 
-<table id="mbean-table" class="table table-bordered table-striped table-hover">
-    <thead>
-        <tr>
-            <th>Name</th>
-            <th>Description</th>
-            <th>Value</th>
-            <th>Type</th>
-        </tr>
-    </thead>
-    <tbody>
-        #foreach( $attribute in $attributes )
-            <tr>
-                <td>$attribute.name</td>
-                <td>$attribute.description</td>
-                <td>$attribute.value</td>
-                <td>$attribute.type</td>
-            </tr>
-        #end
-    </tbody>
-</table>
+<div class="tabbable">
+    <ul class="nav nav-tabs">
+        <li class="active"><a href="#attributes" 
data-toggle="tab">Attributes</a></li>
+        <li><a href="#operations" data-toggle="tab">Operations</a></li>
+    </ul>
+    <div class="tab-content">
+        <div class="tab-pane active" id="attributes">
+            <table id="mbean-table" class="table table-bordered table-striped 
table-hover">
+                <thead>
+                <tr>
+                    <th>Name</th>
+                    <th>Description</th>
+                    <th>Value</th>
+                    <th>Type</th>
+                </tr>
+                </thead>
+                <tbody>
+                    #foreach( $attribute in $attributes )
+                    <tr>
+                        <td>$attribute.name</td>
+                        <td>$attribute.description</td>
+                        <td>$attribute.value</td>
+                        <td>$attribute.type</td>
+                    </tr>
+                    #end
+                </tbody>
+            </table>
+        </div>
+        <div class="tab-pane" id="operations">
+            <ul>
+                #foreach( $operation in $operations )
+                    <li>
+                        <form class="form-inline invoker" 
id="operation-${objectnameHash}-$operation.name">
+                            $operation.name (
+                            #foreach( $param in $operation.parameters )
+                                <input type="text" class="input-small" 
placeholder="$param.name: $param.type#if( $foreach.hasNext ),#end">
+                            #end
+                            )
+                            <button type="submit" class="btn 
btn-primary">Invoke</button>
+                        </form>
+                    </li>
+                #end
+            </ul>
+        </div>
+    </div>
+</div>
 
-<script type="text/javascript" 
src="$mapping/resources/js/jquery.tablesorter.js"></script>
-<script type="text/javascript" 
src="$mapping/resources/js/jquery.tablesorter.widgets.js"></script>
 <script type="text/javascript">
     $(function() {
-        $("table#report-table").tablesorter({
-            widthFixed : false,
-            widgets: [ "filter" ],
-            widgetOptions : {
-                filter_childRows : false,
-                filter_columnFilters : true,
-                filter_cssFilter : 'tablesorter-filter',
-                filter_filteredRow   : 'filtered',
-                filter_formatter : null,
-                filter_functions : null,
-                filter_hideFilters : false,
-                filter_ignoreCase : true,
-                filter_liveSearch : true,
-                filter_reset : 'button.reset',
-                filter_searchDelay : 300,
-                filter_serversideFiltering: false,
-                filter_startsWith : false,
-                filter_useParsedData : false,
-                cssAsc: 'headerSortUp',
-                cssDesc: 'headerSortDown',
-                sortList: [[4, 1]] // sort by mean in descending order
-            }
-        });
+        $('.invoker').submit(function () {
+            var id = $(this).closest("form").attr('id');
+            var url = '$mapping/jmx/' + id.replace(/-/g, "/");
 
-        $("table#report-table tr th div").addClass("blue");
+            // 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();
+            });
+
+            $.get(url, function(data) {
+                var result = $('#invoke-result');
+                result.addClass('alert alert-success');
+                result.html(data);
+            });
+
+            return false;
+        });
     });
 </script>


Reply via email to