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>