Return-Path: X-Original-To: apmail-commons-commits-archive@minotaur.apache.org Delivered-To: apmail-commons-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 7ADA0102C0 for ; Wed, 31 Jul 2013 15:53:03 +0000 (UTC) Received: (qmail 66932 invoked by uid 500); 31 Jul 2013 15:53:02 -0000 Delivered-To: apmail-commons-commits-archive@commons.apache.org Received: (qmail 66636 invoked by uid 500); 31 Jul 2013 15:53:00 -0000 Mailing-List: contact commits-help@commons.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@commons.apache.org Delivered-To: mailing list commits@commons.apache.org Received: (qmail 66629 invoked by uid 99); 31 Jul 2013 15:53:00 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 31 Jul 2013 15:53:00 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 31 Jul 2013 15:52:54 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 882EF2388980; Wed, 31 Jul 2013 15:52:32 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1508942 - in /commons/sandbox/monitoring/trunk: core/src/main/java/org/apache/commons/monitoring/ reporting/src/main/java/org/apache/commons/monitoring/reporting/web/plugin/jmx/ reporting/src/main/resources/resources/js/ reporting/src/main... Date: Wed, 31 Jul 2013 15:52:32 -0000 To: commits@commons.apache.org From: rmannibucau@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20130731155232.882EF2388980@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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> WRAPPERS = new HashMap>(); + + static { + for (final Class c : Arrays.>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 params = new ArrayList(parts.length - 2); + { // remove object name and operation name to keep only parameters + params.addAll(Arrays.asList(parts)); + final Iterator 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 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("
Method was invoked and returned:
" + value(result)); + return; + } + } + } catch (final Exception e) { + writer.write("
\n" + + "\n" + e.getMessage() + "\n" + + "
"); + return; + } + + writer.write("
Operation" + operation + " not found.
"); + } + + 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() .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 operations(final MBeanInfo info) { + final Collection operations = new LinkedList(); + 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 attributes(final MBeanInfo info) { final Collection list = new LinkedList(); 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("
    "); - for (int i = 0; i < length; i++) { - builder.append("
  • ").append(value(Array.get(value, i))).append("
  • "); - } - builder.append("
"); - return builder.toString(); + final StringBuilder builder = new StringBuilder().append("
    "); + for (int i = 0; i < length; i++) { + builder.append("
  • ").append(value(Array.get(value, i))).append("
  • "); } + builder.append("
"); + return builder.toString(); + } - if (Collection.class.isInstance(value)) { - final StringBuilder builder = new StringBuilder().append("
    "); - for (final Object o : Collection.class.cast(value)) { - builder.append("
  • ").append(value(o)).append("
  • "); - } - builder.append("
"); - return builder.toString(); + if (Collection.class.isInstance(value)) { + final StringBuilder builder = new StringBuilder().append("
    "); + for (final Object o : Collection.class.cast(value)) { + builder.append("
  • ").append(value(o)).append("
  • "); } + builder.append("
"); + return builder.toString(); + } - if (TabularData.class.isInstance(value)) { - final TabularData td = TabularData.class.cast(value); - final List keys = td.getTabularType().getIndexNames(); - final int number = keys.size(); - - final StringBuilder builder = new StringBuilder().append(""); - for (final Object type : td.keySet()) { - final List values = (List) type; - for (int i = 0; i < number; i++) { - builder.append("") - .append("") - .append("") - .append(""); - } - + if (TabularData.class.isInstance(value)) { + final TabularData td = TabularData.class.cast(value); + final List keys = td.getTabularType().getIndexNames(); + final int number = keys.size(); + + final StringBuilder builder = new StringBuilder().append("
").append(value(keys.get(i))).append("").append(value(values.get(i))).append("
"); + for (final Object type : td.keySet()) { + final List values = (List) type; + for (int i = 0; i < number; i++) { + builder.append("") + .append("") + .append("") + .append(""); } - builder.append("
").append(value(keys.get(i))).append("").append(value(values.get(i))).append("
"); - return builder.toString(); } + builder.append(""); - if (CompositeData.class.isInstance(value)) { - final CompositeData cd = CompositeData.class.cast(value); - final Set keys = cd.getCompositeType().keySet(); - - final StringBuilder builder = new StringBuilder().append(""); - for (final String type : keys) { - builder.append(""); - } - builder.append("
").append(type).append("").append(value(cd.get(type))).append("
"); - - return builder.toString(); + return builder.toString(); + } + if (CompositeData.class.isInstance(value)) { + final CompositeData cd = CompositeData.class.cast(value); + final Set keys = cd.getCompositeType().keySet(); + + final StringBuilder builder = new StringBuilder().append(""); + for (final String type : keys) { + builder.append(""); } + builder.append("
").append(type).append("").append(value(cd.get(type))).append("
"); - if (Map.class.isInstance(value)) { - final Map map = Map.class.cast(value); + return builder.toString(); - final StringBuilder builder = new StringBuilder().append(""); - for (final Map.Entry entry : map.entrySet()) { - builder.append("").append(value(entry.getKey())).append(""); - } - builder.append("
").append(value(entry.getValue())).append("
"); + } - return builder.toString(); + if (Map.class.isInstance(value)) { + final Map map = Map.class.cast(value); + final StringBuilder builder = new StringBuilder().append(""); + for (final Map.Entry entry : map.entrySet()) { + builder.append("").append(value(entry.getKey())).append(""); } + builder.append("
").append(value(entry.getValue())).append("
"); + + 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 parameters = new LinkedList(); + + 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 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 )
- 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.
+ -