Repository: deltaspike
Updated Branches:
  refs/heads/master 135c59f05 -> a82f6ad27


merging with master


Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/a82f6ad2
Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/a82f6ad2
Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/a82f6ad2

Branch: refs/heads/master
Commit: a82f6ad27486756cc6d80d3a2db1695b779e36be
Parents: 135c59f
Author: rmannibucau <rmannibu...@apache.org>
Authored: Tue Apr 25 22:47:28 2017 +0200
Committer: rmannibucau <rmannibu...@apache.org>
Committed: Tue Apr 25 22:47:28 2017 +0200

----------------------------------------------------------------------
 .../deltaspike/core/api/jmx/JmxManaged.java     |  6 +-
 .../apache/deltaspike/core/api/jmx/Table.java   | 89 ++++++++++++++++++++
 .../core/impl/jmx/AttributeAccessor.java        |  9 +-
 .../core/impl/jmx/DynamicMBeanWrapper.java      | 49 +++++++----
 .../deltaspike/core/impl/jmx/Operation.java     | 46 ++++++++++
 .../deltaspike/test/core/impl/jmx/MyMBean.java  |  9 ++
 .../core/impl/jmx/SimpleRegistrationTest.java   | 42 +++++++--
 7 files changed, 222 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/deltaspike/blob/a82f6ad2/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/jmx/JmxManaged.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/jmx/JmxManaged.java
 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/jmx/JmxManaged.java
index 441df8c..5237e00 100644
--- 
a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/jmx/JmxManaged.java
+++ 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/jmx/JmxManaged.java
@@ -47,8 +47,8 @@ public @interface JmxManaged
     String description() default "";
 
     /**
-     * @return if {@code true} a Map will be converted to a TabularData with a 
CompositeData entry,
-     *         if {@code false} the map will be returned directly.
+     * @return if {@code true} a Map or Table will be converted to a 
TabularData with a CompositeData entry,
+     *         if {@code false} the Map or Table will be returned directly.
      */
-    boolean convertMapToTabularData() default true;
+    boolean convertToTabularData() default true;
 }

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/a82f6ad2/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/jmx/Table.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/jmx/Table.java
 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/jmx/Table.java
new file mode 100644
index 0000000..897e6ad
--- /dev/null
+++ 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/jmx/Table.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.deltaspike.core.api.jmx;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import static java.util.Arrays.asList;
+
+/**
+ * Allows to expose in JMX a STRING TabularData without having to built it in 
the MBean.
+ *
+ * Ensure to register columns before the lines.
+ *
+ * You just have to type the operation or attribute with this type to expose 
it as a TabularData.
+ */
+public class Table
+{
+    private Collection<String> columns = new ArrayList<String>();
+    private Collection<Collection<String>> values = new 
ArrayList<Collection<String>>();
+
+    public Table withColumns(final Collection<String> names)
+    {
+        columns.addAll(names);
+        return this;
+    }
+
+    public Table withColumns(final String... names)
+    {
+        columns.addAll(asList(names));
+        return this;
+    }
+
+    public Table withLines(final Collection<Collection<String>> lines)
+    {
+        for (final Collection<String> line : lines)
+        {
+            withLine(line);
+        }
+        return this;
+    }
+
+    public Table withLine(final Collection<String> line)
+    {
+        if (line.size() != columns.size())
+        {
+            throw new IllegalArgumentException("Please set columns before 
lines");
+        }
+        values.add(line);
+        return this;
+    }
+
+    public Table withLine(final String... line)
+    {
+        if (line.length != columns.size())
+        {
+            throw new IllegalArgumentException("Please set columns before 
lines");
+        }
+        values.add(asList(line));
+        return this;
+    }
+
+    public Collection<String> getColumnNames()
+    {
+        return Collections.unmodifiableCollection(columns);
+    }
+
+    public Collection<Collection<String>> getLines()
+    {
+        return Collections.unmodifiableCollection(values);
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/a82f6ad2/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/jmx/AttributeAccessor.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/jmx/AttributeAccessor.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/jmx/AttributeAccessor.java
index 0b4d3ba..79d97d6 100644
--- 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/jmx/AttributeAccessor.java
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/jmx/AttributeAccessor.java
@@ -30,11 +30,18 @@ public class AttributeAccessor
 {
     private final Method getter;
     private final Method setter;
+    private final boolean presentAsTabularIfPossible;
 
-    public AttributeAccessor(final Method get, final Method set)
+    public AttributeAccessor(final Method get, final Method set, final boolean 
presentAsTabularIfPossible)
     {
         this.setter = set;
         this.getter = get;
+        this.presentAsTabularIfPossible = presentAsTabularIfPossible;
+    }
+
+    public boolean isPresentAsTabularIfPossible()
+    {
+        return presentAsTabularIfPossible;
     }
 
     public Object get(final Object instance) throws InvocationTargetException, 
IllegalAccessException

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/a82f6ad2/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/jmx/DynamicMBeanWrapper.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/jmx/DynamicMBeanWrapper.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/jmx/DynamicMBeanWrapper.java
index 3146a21..c37585c 100644
--- 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/jmx/DynamicMBeanWrapper.java
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/jmx/DynamicMBeanWrapper.java
@@ -24,6 +24,7 @@ import org.apache.deltaspike.core.api.jmx.JmxManaged;
 import org.apache.deltaspike.core.api.jmx.JmxParameter;
 import org.apache.deltaspike.core.api.jmx.MBean;
 import org.apache.deltaspike.core.api.jmx.NotificationInfo;
+import org.apache.deltaspike.core.api.jmx.Table;
 import org.apache.deltaspike.core.api.provider.BeanManagerProvider;
 import org.apache.deltaspike.core.api.provider.BeanProvider;
 import org.apache.deltaspike.core.util.ParameterUtil;
@@ -61,6 +62,7 @@ import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -78,7 +80,7 @@ public class DynamicMBeanWrapper extends 
NotificationBroadcasterSupport implemen
 
     private final MBeanInfo info;
     private final Map<String, AttributeAccessor> fields = new HashMap<String, 
AttributeAccessor>();
-    private final Map<String, Method> operations = new HashMap<String, 
Method>();
+    private final Map<String, Operation> operations = new HashMap<String, 
Operation>();
     private final ClassLoader classloader;
     private final Class<?> clazz;
     private final boolean normalScope;
@@ -141,7 +143,7 @@ public class DynamicMBeanWrapper extends 
NotificationBroadcasterSupport implemen
                 continue;
             }
 
-            operations.put(method.getName(), method);
+            operations.put(method.getName(), new Operation(method, 
annotation.convertToTabularData()));
 
             String operationDescr = getDescription(annotation.description(), 
method.getName());
             
@@ -240,7 +242,7 @@ public class DynamicMBeanWrapper extends 
NotificationBroadcasterSupport implemen
                         fieldName, toMBeanType(type).getName(), 
fieldDescription,
                             getter != null, setter != null, false));
 
-                    fields.put(fieldName, new AttributeAccessor(getter, 
setter));
+                    fields.put(fieldName, new AttributeAccessor(getter, 
setter, annotation.convertToTabularData()));
                 }
             }
             clazz = clazz.getSuperclass();
@@ -256,7 +258,7 @@ public class DynamicMBeanWrapper extends 
NotificationBroadcasterSupport implemen
 
     private Class<?> toMBeanType(final Class<?> type)
     {
-        if (Map.class == type)
+        if (Map.class.isAssignableFrom(type) || 
Table.class.isAssignableFrom(type))
         {
             return TabularData.class;
         }
@@ -305,12 +307,9 @@ public class DynamicMBeanWrapper extends 
NotificationBroadcasterSupport implemen
             Thread.currentThread().setContextClassLoader(classloader);
             try
             {
-                final Object o = fields.get(attribute).get(instance());
-                if (Map.class.isInstance(o))
-                {
-                    return toTabularData(attribute, attribute, 
Map.class.cast(o));
-                }
-                return o;
+                final AttributeAccessor attributeAccessor = 
fields.get(attribute);
+                final Object value = attributeAccessor.get(instance());
+                return attributeAccessor.isPresentAsTabularIfPossible() ? 
toResult(attribute, value) : value;
             }
             catch (IllegalArgumentException e)
             {
@@ -332,9 +331,24 @@ public class DynamicMBeanWrapper extends 
NotificationBroadcasterSupport implemen
         throw new AttributeNotFoundException();
     }
 
-    private TabularData toTabularData(final String typeName, final String 
description, final Map map)
+    private Object toResult(final String attribute, final Object value)
+        throws InvocationTargetException, IllegalAccessException
     {
-        final OpenType<?>[] types = new OpenType<?>[map.size()];
+        if (Map.class.isInstance(value))
+        {
+            Map map = Map.class.cast(value);
+            return toTabularData(attribute, attribute, new 
Table().withColumns(map.keySet()).withLine(map.values()));
+        }
+        if (Table.class.isInstance(value))
+        {
+            return toTabularData(attribute, attribute, 
Table.class.cast(value));
+        }
+        return value;
+    }
+
+    private TabularData toTabularData(final String typeName, final String 
description, final Table table)
+    {
+        final OpenType<?>[] types = new 
OpenType<?>[table.getColumnNames().size()];
         for (int i = 0; i < types.length; i++)
         {
             types[i] = SimpleType.STRING;
@@ -342,12 +356,15 @@ public class DynamicMBeanWrapper extends 
NotificationBroadcasterSupport implemen
 
         try
         {
-            final String[] keys = String[].class.cast(map.keySet().toArray(new 
String[map.size()]));
+            final String[] keys = table.getColumnNames().toArray(new 
String[table.getColumnNames().size()]);
             final CompositeType ct = new CompositeType(
                     typeName, description, keys, keys, types);
             final TabularType type = new TabularType(typeName, description, 
ct, keys);
             final TabularDataSupport data = new TabularDataSupport(type);
-            data.put(new CompositeDataSupport(ct, map));
+            for (final Collection<String> line : table.getLines())
+            {
+                data.put(new CompositeDataSupport(ct, keys, line.toArray(new 
Object[line.size()])));
+            }
             return data;
         }
         catch (final OpenDataException e)
@@ -439,7 +456,9 @@ public class DynamicMBeanWrapper extends 
NotificationBroadcasterSupport implemen
             Thread.currentThread().setContextClassLoader(classloader);
             try
             {
-                return operations.get(actionName).invoke(instance(), params);
+                final Operation operation = operations.get(actionName);
+                final Object result = 
operation.getOperation().invoke(instance(), params);
+                return operation.isPresentAsTabularIfPossible() ? 
toResult(actionName, result) : result;
             }
             catch (InvocationTargetException e)
             {

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/a82f6ad2/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/jmx/Operation.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/jmx/Operation.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/jmx/Operation.java
new file mode 100644
index 0000000..40920bc
--- /dev/null
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/jmx/Operation.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.deltaspike.core.impl.jmx;
+
+import java.lang.reflect.Method;
+
+/**
+ * Just a helper class mapping a JMX operation.
+ */
+class Operation
+{
+    private final Method operation;
+    private final boolean presentAsTabularIfPossible;
+
+    public Operation(final Method operation, final boolean 
presentAsTabularIfPossible)
+    {
+        this.operation = operation;
+        this.presentAsTabularIfPossible = presentAsTabularIfPossible;
+    }
+
+    public boolean isPresentAsTabularIfPossible()
+    {
+        return presentAsTabularIfPossible;
+    }
+
+    public Method getOperation()
+    {
+        return operation;
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/a82f6ad2/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/jmx/MyMBean.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/jmx/MyMBean.java
 
b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/jmx/MyMBean.java
index 16e8cbd..3cf6370 100644
--- 
a/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/jmx/MyMBean.java
+++ 
b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/jmx/MyMBean.java
@@ -22,6 +22,7 @@ import org.apache.deltaspike.core.api.jmx.JmxBroadcaster;
 import org.apache.deltaspike.core.api.jmx.JmxManaged;
 import org.apache.deltaspike.core.api.jmx.JmxParameter;
 import org.apache.deltaspike.core.api.jmx.MBean;
+import org.apache.deltaspike.core.api.jmx.Table;
 
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
@@ -42,6 +43,9 @@ public class MyMBean
     @JmxManaged
     private Map<String, String> table;
 
+    @JmxManaged // just a marker to expose it as an attribute, will call the 
getter
+    private Table table2;
+
     public Map<String, String> getTable() {
         return table != null ? table : (table = new HashMap<String, String>() 
{{
             put("key1", "value1");
@@ -49,6 +53,11 @@ public class MyMBean
         }});
     }
 
+    @JmxManaged
+    public Table getTable2() {
+        return new Table().withColumns("a", "b", "c").withLine("1", "2", 
"3").withLine("alpha", "beta", "gamma");
+    }
+
     public int getCounter()
     {
         return counter;

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/a82f6ad2/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/jmx/SimpleRegistrationTest.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/jmx/SimpleRegistrationTest.java
 
b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/jmx/SimpleRegistrationTest.java
index 5409fac..512d24c 100644
--- 
a/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/jmx/SimpleRegistrationTest.java
+++ 
b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/jmx/SimpleRegistrationTest.java
@@ -32,6 +32,7 @@ import javax.management.openmbean.TabularData;
 import java.lang.management.ManagementFactory;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Iterator;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -75,14 +76,37 @@ public abstract class SimpleRegistrationTest {
         assertEquals("multiplier", parameterInfo.getName());
         assertEquals("the multiplier", parameterInfo.getDescription());
 
-        // table support
-        Object table = server.getAttribute(on, "table");
-        assertTrue(TabularData.class.isInstance(table));
-        final TabularData data = TabularData.class.cast(table);
-        assertEquals(1, data.size());
-        final CompositeData compositeData = 
CompositeData.class.cast(data.values().iterator().next());
-        assertEquals(2, compositeData.values().size());
-        assertEquals("value1", compositeData.get("key1"));
-        assertEquals("value2", compositeData.get("key2"));
+        { // table support - through map
+            Object table = server.getAttribute(on, "table");
+            assertTrue(TabularData.class.isInstance(table));
+            final TabularData data = TabularData.class.cast(table);
+            assertEquals(1, data.size());
+            final CompositeData compositeData = 
CompositeData.class.cast(data.values().iterator().next());
+            assertEquals(2, compositeData.values().size());
+            assertEquals("value1", compositeData.get("key1"));
+            assertEquals("value2", compositeData.get("key2"));
+        }
+
+        { // table support - through Table
+            Object table = server.getAttribute(on, "table2");
+            assertTrue(TabularData.class.isInstance(table));
+            final TabularData data = TabularData.class.cast(table);
+            assertEquals(2, data.size());
+            final Iterator<?> iterator = data.values().iterator();
+            {
+                final CompositeData compositeData = 
CompositeData.class.cast(iterator.next());
+                assertEquals(3, compositeData.values().size());
+                assertEquals("1", compositeData.get("a"));
+                assertEquals("2", compositeData.get("b"));
+                assertEquals("3", compositeData.get("c"));
+            }
+            {
+                final CompositeData compositeData = 
CompositeData.class.cast(iterator.next());
+                assertEquals(3, compositeData.values().size());
+                assertEquals("alpha", compositeData.get("a"));
+                assertEquals("beta", compositeData.get("b"));
+                assertEquals("gamma", compositeData.get("c"));
+            }
+        }
     }
 }

Reply via email to