From 373526f8caaa200a729eb3e57fff2b1e88b4eb0f Mon Sep 17 00:00:00 2001 From: Jesse McConnell Date: Thu, 2 Aug 2012 16:34:00 -0500 Subject: [PATCH] proxied and managed methods are working with annotations, converted impl and test to use the 3 annotations in place of @Managed --- .../org/eclipse/jetty/jmx/ObjectMBean.java | 140 +++++++++++------- jetty-jmx/src/test/java/com/acme/Derived.java | 12 +- .../test/java/com/acme/jmx/DerivedMBean.java | 23 ++- .../eclipse/jetty/jmx/ObjectMBeanTest.java | 28 ++-- .../handler/jmx/AbstractHandlerMBean.java | 1 + .../jetty/util/annotation/Managed.java | 1 + .../jetty/util/annotation/ManagedObject.java | 1 + .../util/annotation/ManagedOperation.java | 14 ++ .../util/component/AbstractLifeCycle.java | 17 ++- .../jetty/util/component/LifeCycle.java | 9 +- 10 files changed, 157 insertions(+), 89 deletions(-) diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java index e9c4389ece8..00cd6c9fca4 100644 --- a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java +++ b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java @@ -50,7 +50,9 @@ import javax.management.modelmbean.ModelMBean; import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.TypeUtil; -import org.eclipse.jetty.util.annotation.Managed; +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.annotation.ManagedOperation; import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -109,21 +111,23 @@ public class ObjectMBean implements DynamicMBean { try { - Class oClass = o.getClass(); + Class oClass = o.getClass(); Object mbean = null; while (mbean == null && oClass != null) { - String pName = oClass.getPackage().getName(); - String cName = oClass.getName().substring(pName.length() + 1); - String mName = pName + ".jmx." + cName + "MBean"; - + ManagedObject mo = oClass.getAnnotation(ManagedObject.class); + String mName = ""; + if ( mo != null ) + { + mName = mo.wrapper(); + } try { Class mClass = (Object.class.equals(oClass))?oClass=ObjectMBean.class:Loader.loadClass(oClass,mName,true); - if (LOG.isDebugEnabled()) - LOG.debug("mbeanFor " + o + " mClass=" + mClass); + + LOG.debug("ObjectMbean: mbeanFor {} mClass={}", o, mClass); try { @@ -140,8 +144,8 @@ public class ObjectMBean implements DynamicMBean } } - if (LOG.isDebugEnabled()) - LOG.debug("mbeanFor " + o + " is " + mbean); + LOG.debug("mbeanFor {} is {}", o, mbean); + return mbean; } catch (ClassNotFoundException e) @@ -234,7 +238,7 @@ public class ObjectMBean implements DynamicMBean LOG.debug("Influence Count: " + LazyList.size(influences) ); // Process Type Annotations - Managed primary = o_class.getAnnotation( Managed.class); + ManagedObject primary = o_class.getAnnotation( ManagedObject.class); desc = primary.value(); // For each influence @@ -242,7 +246,7 @@ public class ObjectMBean implements DynamicMBean { Class oClass = (Class)LazyList.get(influences, i); - Managed typeAnnotation = oClass.getAnnotation( Managed.class); + ManagedObject typeAnnotation = oClass.getAnnotation( ManagedObject.class); LOG.debug("Influenced by: " + oClass.getCanonicalName() ); if ( typeAnnotation == null ) @@ -257,7 +261,7 @@ public class ObjectMBean implements DynamicMBean for ( Field field : oClass.getDeclaredFields()) { LOG.debug("Checking: " + field.getName()); - Managed fieldAnnotation = field.getAnnotation(Managed.class); + ManagedAttribute fieldAnnotation = field.getAnnotation(ManagedAttribute.class); if ( fieldAnnotation != null ) { @@ -270,21 +274,21 @@ public class ObjectMBean implements DynamicMBean for ( Method method : oClass.getDeclaredMethods() ) { - Managed methodAnnotation = method.getAnnotation(Managed.class); + ManagedAttribute methodAttributeAnnotation = method.getAnnotation(ManagedAttribute.class); - if ( methodAnnotation != null ) + if ( methodAttributeAnnotation != null ) + { + // TODO sort out how a proper name could get here, its a method name as an attribute at this point. + LOG.debug("Attribute Annotation found for: " + method.getName() ); + attributes=LazyList.add(attributes,defineAttribute(method.getName(),methodAttributeAnnotation)); + } + + ManagedOperation methodOperationAnnotation = method.getAnnotation(ManagedOperation.class); + + if (methodOperationAnnotation != null) { - if ( methodAnnotation.attribute() ) - { - // TODO sort out how a proper name could get here, its a method name as an attribute at this point. - LOG.debug("Attribute Annotation found for: " + method.getName() ); - attributes=LazyList.add(attributes,defineAttribute(method.getName(),methodAnnotation)); - } - else - { - LOG.debug("Method Annotation found for: " + method.getName() ); - operations=LazyList.add(operations, defineOperation(method, methodAnnotation)); - } + LOG.debug("Method Annotation found for: " + method.getName()); + operations = LazyList.add(operations,defineOperation(method,methodOperationAnnotation)); } } @@ -317,7 +321,10 @@ public class ObjectMBean implements DynamicMBean { Method getter = (Method) _getters.get(name); if (getter == null) + { throw new AttributeNotFoundException(name); + } + try { Object o = _managed; @@ -326,7 +333,7 @@ public class ObjectMBean implements DynamicMBean // get the attribute Object r=getter.invoke(o, (java.lang.Object[]) null); - + // convert to ObjectName if need be. if (r!=null && _convert.contains(name)) { @@ -349,11 +356,13 @@ public class ObjectMBean implements DynamicMBean else { ObjectName mbean = _mbeanContainer.findMBean(r); + if (mbean==null) return null; r=mbean; } } + return r; } catch (IllegalAccessException e) @@ -462,8 +471,7 @@ public class ObjectMBean implements DynamicMBean /* ------------------------------------------------------------ */ public Object invoke(String name, Object[] params, String[] signature) throws MBeanException, ReflectionException { - if (LOG.isDebugEnabled()) - LOG.debug("invoke " + name); + LOG.debug("ObjectMBean:invoke " + name); String methodKey = name + "("; if (signature != null) @@ -480,8 +488,11 @@ public class ObjectMBean implements DynamicMBean throw new NoSuchMethodException(methodKey); Object o = _managed; + if (method.getDeclaringClass().isInstance(this)) + { o = this; + } return method.invoke(o, params); } catch (NoSuchMethodException e) @@ -505,35 +516,38 @@ public class ObjectMBean implements DynamicMBean } } - private static Object findInfluences(Object influences, Class aClass) + private static Object findInfluences(Object influences, Class aClass) { if (aClass!=null) { // This class is an influence influences=LazyList.add(influences,aClass); - /* enabled mbean influence - String pack = aClass.getPackage().getName(); - String clazz = aClass.getSimpleName(); + // check for mbean influence + ManagedObject mo = aClass.getAnnotation(ManagedObject.class); - try + if ( mo != null && !"".equals(mo.wrapper())) { - Class mbean = Class.forName(pack + ".jmx." + clazz + "MBean"); + String clazz = mo.wrapper(); - LOG.debug("MBean Influence found for " + aClass.getSimpleName() ); - influences = LazyList.add(influences, mbean); + try + { + Class mbean = Class.forName(clazz); + + LOG.debug("MBean Influence found for " + aClass.getSimpleName() ); + influences = LazyList.add(influences, mbean); + } + catch ( ClassNotFoundException cnfe ) + { + LOG.debug("No MBean Influence for " + aClass.getSimpleName() ); + } } - catch ( ClassNotFoundException cnfe ) - { - LOG.debug("No MBean Influence for " + aClass.getSimpleName() ); - } - */ // So are the super classes influences=findInfluences(influences,aClass.getSuperclass()); // So are the interfaces - Class[] ifs = aClass.getInterfaces(); + Class[] ifs = aClass.getInterfaces(); for (int i=0;ifs!=null && i * the access is either "RW" or "RO". */ - public MBeanAttributeInfo defineAttribute(String name, Managed fieldAnnotation) + public MBeanAttributeInfo defineAttribute(String name, ManagedAttribute attributeAnnotation) { //String name = field.getName(); - String description = fieldAnnotation.value(); - boolean writable = fieldAnnotation.readonly(); - boolean onMBean = fieldAnnotation.proxied(); - boolean convert = fieldAnnotation.managed(); + String description = attributeAnnotation.value(); + boolean writable = attributeAnnotation.readonly(); + boolean onMBean = attributeAnnotation.proxied(); + boolean convert = attributeAnnotation.managed(); String uName = name.substring(0, 1).toUpperCase() + name.substring(1); Class oClass = onMBean ? this.getClass() : _managed.getClass(); - if (LOG.isDebugEnabled()) - LOG.debug("defineAttribute "+name+" "+onMBean+":"+writable+":"+oClass+":"+description); + LOG.debug("defineAttribute {} {}:{}:{}:{}",name,onMBean,writable,oClass,description); Class type = null; Method getter = null; Method setter = null; - String declaredGetter = fieldAnnotation.getter(); - String declaredSetter = fieldAnnotation.setter(); + String declaredGetter = attributeAnnotation.getter(); + String declaredSetter = attributeAnnotation.setter(); + Method[] methods = oClass.getMethods(); for (int m = 0; m < methods.length; m++) @@ -585,6 +599,9 @@ public class ObjectMBean implements DynamicMBean if ((methods[m].getModifiers() & Modifier.PUBLIC) == 0) continue; + LOG.debug("Declared Getter: {} vs {}", declaredGetter, methods[m].getName()); + + // Check if it is a declared getter if (methods[m].getName().equals(declaredGetter) && methods[m].getParameterTypes().length == 0) { @@ -739,17 +756,17 @@ public class ObjectMBean implements DynamicMBean * the "Object","MBean", "MMBean" or "MObject" to indicate the method is on the object, the MBean or on the * object but converted to an MBean reference, and impact is either "ACTION","INFO","ACTION_INFO" or "UNKNOWN". */ - private MBeanOperationInfo defineOperation(Method method, Managed methodAnnotation) + private MBeanOperationInfo defineOperation(Method method, ManagedOperation methodAnnotation) { String description = methodAnnotation.value(); boolean onMBean = methodAnnotation.proxied(); boolean convert = methodAnnotation.managed(); String impactName = methodAnnotation.impact(); - String signature = method.getName(); LOG.debug("defineOperation "+method.getName()+" "+onMBean+":"+impactName+":"+description); + String signature = method.getName(); try { @@ -785,8 +802,21 @@ public class ObjectMBean implements DynamicMBean } } } - + + signature += "("; + for ( int i = 0 ; i < methodTypes.length ; ++i ) + { + signature += methodTypes[i].getName(); + + if ( i != methodTypes.length - 1 ) + { + signature += ","; + } + } + signature += ")"; + Class returnClass = method.getReturnType(); + LOG.debug("Method Cache: " + signature ); _methods.put(signature, method); if (convert) _convert.add(signature); diff --git a/jetty-jmx/src/test/java/com/acme/Derived.java b/jetty-jmx/src/test/java/com/acme/Derived.java index a1edea680ed..12afad11ca0 100644 --- a/jetty-jmx/src/test/java/com/acme/Derived.java +++ b/jetty-jmx/src/test/java/com/acme/Derived.java @@ -13,13 +13,15 @@ package com.acme; -import org.eclipse.jetty.util.annotation.Managed; +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.annotation.ManagedOperation; import org.eclipse.jetty.util.annotation.Name; -@Managed("Test the mbean stuff") +@ManagedObject(value="Test the mbean stuff", wrapper="com.acme.jmx.DerivedMBean") public class Derived extends Base implements Signature { - @Managed(value="The full name of something", getter="getFullName", setter="setFullName") + @ManagedAttribute(value="The full name of something", getter="getFullName", setter="setFullName") String fname="Full Name"; public String getFullName() @@ -32,13 +34,13 @@ public class Derived extends Base implements Signature fname=name; } - @Managed("publish something") + @ManagedOperation("publish something") public void publish() { System.err.println("publish"); } - @Managed("Doodle something") + @ManagedOperation("Doodle something") public void doodle(@Name(value="doodle", description="A description of the argument") String doodle) { System.err.println("doodle "+doodle); diff --git a/jetty-jmx/src/test/java/com/acme/jmx/DerivedMBean.java b/jetty-jmx/src/test/java/com/acme/jmx/DerivedMBean.java index 09586b26867..35b18b43735 100644 --- a/jetty-jmx/src/test/java/com/acme/jmx/DerivedMBean.java +++ b/jetty-jmx/src/test/java/com/acme/jmx/DerivedMBean.java @@ -1,27 +1,34 @@ package com.acme.jmx; -import org.eclipse.jetty.util.annotation.Managed; +import org.eclipse.jetty.jmx.ObjectMBean; +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.annotation.ManagedOperation; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import com.acme.Derived; -@Managed("Derived MBean") -public class DerivedMBean +@ManagedObject("Derived MBean Wrapper") +public class DerivedMBean extends ObjectMBean { private static final Logger LOG = Log.getLogger(DerivedMBean.class); - - Derived managedObject; public DerivedMBean(Object managedObject) { - this.managedObject = (Derived)managedObject; + super(managedObject); } - @Managed(value="test of proxy", attribute=true, managed=true, getter="good" ) + @ManagedOperation(value="test of proxy operations", managed=true) public String good() { - return "not " + managedObject.bad(); + return "not " + ((Derived)_managed).bad(); + } + + @ManagedAttribute(value="test of proxy attributes", getter="goop", proxied=true) + public String goop() + { + return "goop"; } } diff --git a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ObjectMBeanTest.java b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ObjectMBeanTest.java index bb61b779afa..ba14e220923 100644 --- a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ObjectMBeanTest.java +++ b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ObjectMBeanTest.java @@ -15,6 +15,8 @@ package org.eclipse.jetty.jmx; import static org.junit.Assert.assertTrue; +import java.lang.management.ManagementFactory; + import javax.management.AttributeNotFoundException; import javax.management.MBeanAttributeInfo; import javax.management.MBeanException; @@ -42,8 +44,15 @@ public class ObjectMBeanTest @Test public void testMbeanInfo() throws Exception { + MBeanContainer container = new MBeanContainer(ManagementFactory.getPlatformMBeanServer()); + + container.start(); + Derived derived = new Derived(); - ObjectMBean mbean = new ObjectMBean(derived); + //ObjectMBean mbean = new ObjectMBean(derived); + ObjectMBean mbean = (ObjectMBean)ObjectMBean.mbeanFor(derived); + mbean.setMBeanContainer(container); + assertTrue(mbean.getMBeanInfo()!=null); MBeanInfo info = mbean.getMBeanInfo(); @@ -57,13 +66,15 @@ public class ObjectMBeanTest } /* - * 6 attributes from lifecycle and 1 from Derived + * 6 attributes from lifecycle and 1 from Derived and 1 from MBean */ - Assert.assertEquals("attribute count does not match", 7, info.getAttributes().length); + Assert.assertEquals("attribute count does not match", 8, info.getAttributes().length); Assert.assertEquals("attribute values does not match", "Full Name", mbean.getAttribute("fname") ); - Assert.assertEquals("operation count does not match", 4, info.getOperations().length); + Assert.assertEquals("proxy attribute values do not match", "goop", mbean.getAttribute("goop") ); + + Assert.assertEquals("operation count does not match", 5, info.getOperations().length); MBeanOperationInfo[] opinfos = info.getOperations(); boolean publish = false; @@ -94,17 +105,16 @@ public class ObjectMBeanTest if ("good".equals(opinfo.getName())) { - doodle = true; - - Assert.assertEquals("description does not match", "test of proxy", opinfo.getDescription()); - Assert.assertEquals("execution contexts wrong", "not bad", mbean.invoke("good", new Object[] {}, new String[] {})); + good = true; + Assert.assertEquals("description does not match", "test of proxy operations", opinfo.getDescription()); + Assert.assertEquals("execution contexts wrong", "not bad", mbean.invoke("good", new Object[] {}, new String[] {})); } } Assert.assertTrue("publish operation was not not found", publish); Assert.assertTrue("doodle operation was not not found", doodle); - // Assert.assertTrue("good operation was not not found", good); not wired up yet + Assert.assertTrue("good operation was not not found", good); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/jmx/AbstractHandlerMBean.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/jmx/AbstractHandlerMBean.java index 1150ec0da22..e112f22b1f4 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/jmx/AbstractHandlerMBean.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/jmx/AbstractHandlerMBean.java @@ -23,6 +23,7 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.AbstractHandlerContainer; import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/Managed.java b/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/Managed.java index 96310747028..dee00935244 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/Managed.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/Managed.java @@ -18,6 +18,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +@Deprecated @Retention(RetentionPolicy.RUNTIME) @Documented @Target( { ElementType.TYPE, ElementType.METHOD, ElementType.FIELD } ) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedObject.java b/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedObject.java index 9420455d536..56cecadddba 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedObject.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedObject.java @@ -30,4 +30,5 @@ public @interface ManagedObject */ String value() default "Not Specified"; + String wrapper() default ""; } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedOperation.java b/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedOperation.java index b133a682e33..4c486c915b5 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedOperation.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedOperation.java @@ -42,4 +42,18 @@ public @interface ManagedOperation */ String impact() default "UNKNOWN"; + /** + * Is the managed field itself a Managed Object? + * + * @return true if the target is a Managed Object + */ + boolean managed() default false; + + /** + * Does the managed field exist on a proxy object? + * + * + * @return true if a proxy object is involved + */ + boolean proxied() default false; } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java index c46601527ee..ab00ce5b044 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java @@ -15,7 +15,8 @@ package org.eclipse.jetty.util.component; import java.util.concurrent.CopyOnWriteArrayList; -import org.eclipse.jetty.util.annotation.Managed; +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -24,22 +25,22 @@ import org.eclipse.jetty.util.log.Logger; * * */ -@Managed("Abstract Implementation of LifeCycle") +@ManagedObject("Abstract Implementation of LifeCycle") public abstract class AbstractLifeCycle implements LifeCycle { private static final Logger LOG = Log.getLogger(AbstractLifeCycle.class); - @Managed(value="instance is stopped", readonly=true, getter="isStopped") + @ManagedAttribute(value="instance is stopped", readonly=true, getter="isStopped") public static final String STOPPED="STOPPED"; - @Managed(value="instance is failed", readonly=true, getter="isFailed") + @ManagedAttribute(value="instance is failed", readonly=true, getter="isFailed") public static final String FAILED="FAILED"; - @Managed(value="instance is starting", readonly=true, getter="isStarting") + @ManagedAttribute(value="instance is starting", readonly=true, getter="isStarting") public static final String STARTING="STARTING"; - @Managed(value="instance is started", readonly=true, getter="isStarted") + @ManagedAttribute(value="instance is started", readonly=true, getter="isStarted") public static final String STARTED="STARTED"; - @Managed(value="instance is stopping", readonly=true, getter="isStopping") + @ManagedAttribute(value="instance is stopping", readonly=true, getter="isStopping") public static final String STOPPING="STOPPING"; - @Managed(value="instance is running", readonly=true, getter="isRunning") + @ManagedAttribute(value="instance is running", readonly=true, getter="isRunning") public static final String RUNNING="RUNNING"; private final CopyOnWriteArrayList _listeners=new CopyOnWriteArrayList(); diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/LifeCycle.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/LifeCycle.java index 30c2e85a615..701d60b35fd 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/LifeCycle.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/LifeCycle.java @@ -15,7 +15,8 @@ package org.eclipse.jetty.util.component; import java.util.EventListener; -import org.eclipse.jetty.util.annotation.Managed; +import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.annotation.ManagedOperation; /* ------------------------------------------------------------ */ /** @@ -26,7 +27,7 @@ import org.eclipse.jetty.util.annotation.Managed; * * */ -@Managed("Lifecycle Interface for startable components") +@ManagedObject("Lifecycle Interface for startable components") public interface LifeCycle { /* ------------------------------------------------------------ */ @@ -37,7 +38,7 @@ public interface LifeCycle * @see #stop() * @see #isFailed() */ - @Managed("Starts the instance") + @ManagedOperation("Starts the instance") public void start() throws Exception; @@ -51,7 +52,7 @@ public interface LifeCycle * @see #start() * @see #isFailed() */ - @Managed("Stops the instance") + @ManagedOperation("Stops the instance") public void stop() throws Exception;