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>