From b14fec697346025192512a64e1b3d5ffa8452335 Mon Sep 17 00:00:00 2001 From: Jean-Francois Denise Date: Tue, 9 Dec 2008 15:57:09 +0100 Subject: [PATCH] 6675526: Define an Annotation to name registered MBeans Reviewed-by: emcmanus --- .../DefaultMBeanServerInterceptor.java | 6 + .../com/sun/jmx/mbeanserver/Introspector.java | 48 ++- .../classes/javax/management/Descriptor.java | 7 + .../share/classes/javax/management/JMX.java | 6 + .../classes/javax/management/MBeanServer.java | 9 +- .../management/MBeanServerConnection.java | 46 ++- .../javax/management/ObjectNameTemplate.java | 131 +++++++ .../Introspector/ObjectNameTemplateTest.java | 343 ++++++++++++++++++ 8 files changed, 575 insertions(+), 21 deletions(-) create mode 100644 jdk/src/share/classes/javax/management/ObjectNameTemplate.java create mode 100644 jdk/test/javax/management/Introspector/ObjectNameTemplateTest.java diff --git a/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java b/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java index 6a261994bb4..faa39e7656f 100644 --- a/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java @@ -919,6 +919,12 @@ public class DefaultMBeanServerInterceptor DynamicMBean mbean = Introspector.makeDynamicMBean(object); + //Access the ObjectName template value only if the provided name is null + if(name == null) { + name = Introspector.templateToObjectName(mbean.getMBeanInfo(). + getDescriptor(), mbean); + } + return registerDynamicMBean(classname, mbean, name); } diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java index dbf45b9997a..ba27f6e8398 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java @@ -65,8 +65,12 @@ import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.util.LinkedHashSet; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.management.AttributeNotFoundException; import javax.management.JMX; +import javax.management.ObjectName; +import javax.management.ObjectNameTemplate; import javax.management.openmbean.CompositeData; import javax.management.openmbean.MXBeanMappingFactory; @@ -78,7 +82,13 @@ import javax.management.openmbean.MXBeanMappingFactory; */ public class Introspector { - + /** + * Pattern used to extract Attribute Names from ObjectNameTemplate Annotation + * For example, in the following example, the Name attribute value is + * retrieved : ":type=MyType, name={Name}" + */ + private static Pattern OBJECT_NAME_PATTERN_TEMPLATE = + Pattern.compile("(\\{[^\\}]+\\})|(=\"\\{[^\\}]+\\}\")"); /* * ------------------------------------------ * PRIVATE CONSTRUCTORS @@ -392,6 +402,42 @@ public class Introspector { return getStandardMBeanInterface(baseClass); } + public static ObjectName templateToObjectName(Descriptor descriptor, + DynamicMBean mbean) + throws NotCompliantMBeanException { + String template = (String) + descriptor.getFieldValue(JMX.OBJECT_NAME_TEMPLATE); + if(template == null) return null; + try { + Matcher m = OBJECT_NAME_PATTERN_TEMPLATE.matcher(template); + while (m.find()){ + String grp = m.group(); + System.out.println("GROUP " + grp); + String attributeName = null; + boolean quote = false; + if(grp.startsWith("=\"{")) { + attributeName = grp.substring(3, grp.length() - 2); + quote = true; + } else + attributeName = grp.substring(1, grp.length() - 1); + + Object attributeValue = mbean.getAttribute(attributeName); + String validValue = quote ? + "=" + ObjectName.quote(attributeValue.toString()) : + attributeValue.toString(); + template = template.replace(grp, validValue); + } + return new ObjectName(template); + }catch(Exception ex) { + NotCompliantMBeanException ncex = new + NotCompliantMBeanException(ObjectNameTemplate.class. + getSimpleName() + " annotation value [" + template + "] " + + "is invalid. " + ex); + ncex.initCause(ex); + throw ncex; + } + } + /* * ------------------------------------------ * PRIVATE METHODS diff --git a/jdk/src/share/classes/javax/management/Descriptor.java b/jdk/src/share/classes/javax/management/Descriptor.java index a9161903c64..30c6a5f5264 100644 --- a/jdk/src/share/classes/javax/management/Descriptor.java +++ b/jdk/src/share/classes/javax/management/Descriptor.java @@ -245,6 +245,13 @@ import javax.management.openmbean.OpenType; * MXBean, if it was not the {@linkplain MXBeanMappingFactory#DEFAULT default} * one. * + * objectNameTemplate + * String + * MBeanInfo + * + * The template to use to name this MBean. Its value must be compliant with + * the specification of the {@link ObjectNameTemplate} annotation. + * * openType{@link OpenType} * MBeanAttributeInfo
MBeanOperationInfo
MBeanParameterInfo * diff --git a/jdk/src/share/classes/javax/management/JMX.java b/jdk/src/share/classes/javax/management/JMX.java index 3e551f3902f..297b5a74cc4 100644 --- a/jdk/src/share/classes/javax/management/JMX.java +++ b/jdk/src/share/classes/javax/management/JMX.java @@ -149,6 +149,12 @@ public class JMX { */ public static final String SET_EXCEPTIONS_FIELD = "setExceptions"; + /** + * The name of the {@code + * objectNameTemplate} field. + */ + public static final String OBJECT_NAME_TEMPLATE = "objectNameTemplate"; + /** *

Options to apply to an MBean proxy or to an instance of {@link * StandardMBean}.

diff --git a/jdk/src/share/classes/javax/management/MBeanServer.java b/jdk/src/share/classes/javax/management/MBeanServer.java index e6d79e5bd94..e82650288bb 100644 --- a/jdk/src/share/classes/javax/management/MBeanServer.java +++ b/jdk/src/share/classes/javax/management/MBeanServer.java @@ -351,11 +351,14 @@ public interface MBeanServer extends MBeanServerConnection { /** *

Registers a pre-existing object as an MBean with the MBean - * server. If the object name given is null, the MBean must - * provide its own name by implementing the {@link + * server. If the object name given is null, the + * MBean must provide its own name in one or both of two ways: by implementing the {@link * javax.management.MBeanRegistration MBeanRegistration} interface * and returning the name from the {@link - * MBeanRegistration#preRegister preRegister} method.

+ * MBeanRegistration#preRegister preRegister} method; or by defining + * an {@code objectNameTemplate} field in its {@link Descriptor}, + * typically using the {@link ObjectNameTemplate @ObjectNameTemplate} + * annotation.

* *

If this method successfully registers an MBean, a notification * is sent as described above.

diff --git a/jdk/src/share/classes/javax/management/MBeanServerConnection.java b/jdk/src/share/classes/javax/management/MBeanServerConnection.java index fadebc10730..add96cfcb94 100644 --- a/jdk/src/share/classes/javax/management/MBeanServerConnection.java +++ b/jdk/src/share/classes/javax/management/MBeanServerConnection.java @@ -46,11 +46,14 @@ public interface MBeanServerConnection extends NotificationManager { * MBean server will use its {@link * javax.management.loading.ClassLoaderRepository Default Loader * Repository} to load the class of the MBean. An object name is - * associated to the MBean. If the object name given is null, the - * MBean must provide its own name by implementing the {@link + * associated with the MBean. If the object name given is null, the + * MBean must provide its own name in one or both of two ways: by implementing the {@link * javax.management.MBeanRegistration MBeanRegistration} interface * and returning the name from the {@link - * MBeanRegistration#preRegister preRegister} method.

+ * MBeanRegistration#preRegister preRegister} method; or by defining + * an {@code objectNameTemplate} field in its {@link Descriptor}, + * typically using the {@link ObjectNameTemplate @ObjectNameTemplate} + * annotation.

* *

This method is equivalent to {@link * #createMBean(String,ObjectName,Object[],String[]) @@ -117,13 +120,16 @@ public interface MBeanServerConnection extends NotificationManager { /** *

Instantiates and registers an MBean in the MBean server. The * class loader to be used is identified by its object name. An - * object name is associated to the MBean. If the object name of + * object name is associated with the MBean. If the object name of * the loader is null, the ClassLoader that loaded the MBean - * server will be used. If the MBean's object name given is null, - * the MBean must provide its own name by implementing the {@link + * server will be used. If the object name given is null, the + * MBean must provide its own name in one or both of two ways: by implementing the {@link * javax.management.MBeanRegistration MBeanRegistration} interface * and returning the name from the {@link - * MBeanRegistration#preRegister preRegister} method.

+ * MBeanRegistration#preRegister preRegister} method; or by defining + * an {@code objectNameTemplate} field in its {@link Descriptor}, + * typically using the {@link ObjectNameTemplate @ObjectNameTemplate} + * annotation.

* *

This method is equivalent to {@link * #createMBean(String,ObjectName,ObjectName,Object[],String[]) @@ -198,11 +204,14 @@ public interface MBeanServerConnection extends NotificationManager { * MBean server will use its {@link * javax.management.loading.ClassLoaderRepository Default Loader * Repository} to load the class of the MBean. An object name is - * associated to the MBean. If the object name given is null, the - * MBean must provide its own name by implementing the {@link + * associated with the MBean. If the object name given is null, the + * MBean must provide its own name in one or both of two ways: by implementing the {@link * javax.management.MBeanRegistration MBeanRegistration} interface * and returning the name from the {@link - * MBeanRegistration#preRegister preRegister} method. + * MBeanRegistration#preRegister preRegister} method; or by defining + * an {@code objectNameTemplate} field in its {@link Descriptor}, + * typically using the {@link ObjectNameTemplate @ObjectNameTemplate} + * annotation.

* * @param className The class name of the MBean to be instantiated. * @param name The object name of the MBean. May be null. @@ -267,15 +276,18 @@ public interface MBeanServerConnection extends NotificationManager { NotCompliantMBeanException, IOException; /** - * Instantiates and registers an MBean in the MBean server. The + *

Instantiates and registers an MBean in the MBean server. The * class loader to be used is identified by its object name. An - * object name is associated to the MBean. If the object name of + * object name is associated with the MBean. If the object name of * the loader is not specified, the ClassLoader that loaded the - * MBean server will be used. If the MBean object name given is - * null, the MBean must provide its own name by implementing the - * {@link javax.management.MBeanRegistration MBeanRegistration} - * interface and returning the name from the {@link - * MBeanRegistration#preRegister preRegister} method. + * MBean server will be used. If the object name given is null, the + * MBean must provide its own name in one or both of two ways: by implementing the {@link + * javax.management.MBeanRegistration MBeanRegistration} interface + * and returning the name from the {@link + * MBeanRegistration#preRegister preRegister} method; or by defining + * an {@code objectNameTemplate} field in its {@link Descriptor}, + * typically using the {@link ObjectNameTemplate @ObjectNameTemplate} + * annotation.

* * @param className The class name of the MBean to be instantiated. * @param name The object name of the MBean. May be null. diff --git a/jdk/src/share/classes/javax/management/ObjectNameTemplate.java b/jdk/src/share/classes/javax/management/ObjectNameTemplate.java new file mode 100644 index 00000000000..97e0c900fb3 --- /dev/null +++ b/jdk/src/share/classes/javax/management/ObjectNameTemplate.java @@ -0,0 +1,131 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package javax.management; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to allow an MBean to provide its name. + * This annotation can be used on the following types: + * + * + *

The value of this annotation is used to build the ObjectName + * when instances of the annotated type are registered in + * an MBeanServer and no explicit name is given to the + * {@code createMBean} or {@code registerMBean} method (the {@code ObjectName} + * is {@code null}).

+ * + *

For Dynamic MBeans, which define their own {@code MBeanInfo}, you can + * produce the same effect as this annotation by including a field + * {@code objectNameTemplate} + * in the {@link Descriptor} for the {@code MBeanInfo} returned by + * {@link DynamicMBean#getMBeanInfo()}.

+ * + *

For Standard MBeans and MXBeans, this annotation automatically produces + * an {@code objectNameTemplate} field in the {@code Descriptor}.

+ * + *

The template can contain variables so that the name of the MBean + * depends on the value of one or more of its attributes. + * A variable that identifies an MBean attribute is of the form + * {attribute name}. For example, to make an MBean name + * depend on the Name attribute, use the variable + * {Name}. Attribute names are case sensitive. + * Naming attributes can be of any type. The String returned by + * toString() is included in the constructed name.

+ * + *

If you need the attribute value to be quoted + * by a call to {@link ObjectName#quote(String) ObjectName.quote}, + * surround the variable with quotes. Quoting only applies to key values. + * For example, @ObjectNameTemplate("java.lang:type=MemoryPool,name=\"{Name}\""), + * quotes the Name attribute value. You can notice the "\" + * character needed to escape a quote within a String. A name + * produced by this template might look like + * {@code java.lang:type=MemoryPool,name="Code Cache"}.

+ * + *

Variables can be used anywhere in the String. + * Be sure to make the template derived name comply with + * {@link ObjectName ObjectName} syntax.

+ * + *

If an MBean is registered with a null name and it implements + * {@link javax.management.MBeanRegistration MBeanRegistration}, then + * the computed name is provided to the preRegister method. + * Similarly, + * if the MBean uses resource + * injection to discover its name, it is the computed name that will + * be injected.

+ *

All of the above can be used with the {@link StandardMBean} class and + * the annotation is effective in that case too.

+ *

If any exception occurs (such as unknown attribute, invalid syntax or + * exception + * thrown by the MBean) when the name is computed it is wrapped in a + * NotCompliantMBeanException.

+ *

Some ObjectName template examples: + *

+ *

+ */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface ObjectNameTemplate { + + /** + * The MBean name template. + * @return The MBean name template. + */ + @DescriptorKey("objectNameTemplate") + public String value(); +} diff --git a/jdk/test/javax/management/Introspector/ObjectNameTemplateTest.java b/jdk/test/javax/management/Introspector/ObjectNameTemplateTest.java new file mode 100644 index 00000000000..2abcaf08585 --- /dev/null +++ b/jdk/test/javax/management/Introspector/ObjectNameTemplateTest.java @@ -0,0 +1,343 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test %M% %I% + * @bug 6675526 + * @summary Test MBeans named with @ObjectNameTemplate + * @author Jean-Francois Denise + * @run main/othervm ObjectNameTemplateTest + */ +import java.lang.management.ManagementFactory; +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.List; +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.DynamicMBean; +import javax.management.ImmutableDescriptor; +import javax.management.InvalidAttributeValueException; +import javax.management.JMX; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanServer; +import javax.management.MXBean; +import javax.management.MBean; +import javax.management.ManagedAttribute; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; +import javax.management.ObjectNameTemplate; +import javax.management.ReflectionException; +import javax.management.StandardMBean; + +public class ObjectNameTemplateTest { + + private static MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + private static final String NAME_TEMPLATE_MULTI = + "com.example:type=MultiStdCache,name={Name}"; + private static final String NAME_TEMPLATE_MONO = + "com.example:{Type}={TypeValue}"; + private static final String NAME_TEMPLATE_QUOTED = + "com.example:type=Quotted,name=\"{Name}\""; + private static final String NAME_TEMPLATE_WRAPPED = + "com.example:type=MgtInterface,id={Id}"; + private static final String NAME_TEMPLATE_FULL = + "{Naming}"; + private static final String FULL_NAME = "com.example:type=NotAdvised"; + private static final String NAME1 = "toto1"; + private static final String NAME2 = "toto2"; + private static final String TYPE_KEY = "thisIsTheType"; + private static final String TYPE_VALUE = "aTypeValue"; + private static final String INVALID_NAME = "?,=*,\n, "; + private static final int ID = 999; + private static Object[] EMPTY_PARAMS = {}; + private static String[] EMPTY_SIGNATURE = {}; + private static final ObjectName OBJECTNAME_CACHE = + ObjectName.valueOf("com.example:type=Cache"); + private static final ObjectName OBJECTNAME_SUBCACHE = + ObjectName.valueOf("com.example:type=SubCache"); + private static final ObjectName OBJECTNAME_CACHEMX = + ObjectName.valueOf("com.example:type=CacheMX"); + private static final ObjectName OBJECTNAME_SUBCACHEMX = + ObjectName.valueOf("com.example:type=SubCacheMX"); + private static final ObjectName OBJECTNAME_DYNACACHE = + ObjectName.valueOf("com.example:type=DynaCache"); + private static final ObjectName OBJECTNAME_STDCACHE = + ObjectName.valueOf("com.example:type=StdCache"); + private static final ObjectName OBJECTNAME_STDCACHEMX = + ObjectName.valueOf("com.example:type=StdCacheMX"); + private static final ObjectName OBJECTNAME_MULTI_1 = + ObjectName.valueOf("com.example:" + + "type=MultiStdCache,name=" + NAME1); + private static final ObjectName OBJECTNAME_MULTI_2 = + ObjectName.valueOf("com.example:" + + "type=MultiStdCache,name=" + NAME2); + private static final ObjectName OBJECTNAME_MONO = + ObjectName.valueOf("com.example:" + TYPE_KEY + "=" + + TYPE_VALUE); + private static final ObjectName OBJECTNAME_QUOTED = + ObjectName.valueOf("com.example:type=Quotted," + + "name="+ObjectName.quote(INVALID_NAME)); + private static final ObjectName OBJECTNAME_WRAPPED_RESOURCE = + ObjectName.valueOf("com.example:type=MgtInterface,id=" + ID); + private static final ObjectName OBJECTNAME_FULL = + ObjectName.valueOf(FULL_NAME); + + private static void test(Class mbean, Object[] params, + String[] signature, ObjectName name, String template) + throws Exception { + mbs.createMBean(mbean.getName(), null, params, signature); + test(name, template); + List> parameters = new ArrayList>(); + for (String sig : signature) { + parameters.add(Class.forName(sig)); + } + Class classes[] = new Class[parameters.size()]; + Constructor ctr = mbean.getConstructor(parameters.toArray(classes)); + Object inst = ctr.newInstance(params); + test(inst, name, template); + } + + private static void test(Object obj, ObjectName name, String template) + throws Exception { + mbs.registerMBean(obj, null); + test(name, template); + } + + private static void test(ObjectName name, String template) + throws Exception { + if (!mbs.isRegistered(name)) { + throw new Exception("Wrong " + name + " name"); + } + if (template != null && !mbs.getMBeanInfo(name).getDescriptor(). + getFieldValue("objectNameTemplate").equals(template)) { + throw new Exception("Invalid Derscriptor"); + } + mbs.unregisterMBean(name); + } + + public static void main(String[] args) throws Exception { + test(Cache.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_CACHE, + OBJECTNAME_CACHE.toString()); + + test(CacheMX.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_CACHEMX, + OBJECTNAME_CACHEMX.toString()); + + test(SubCache.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_SUBCACHE, + OBJECTNAME_SUBCACHE.toString()); + + test(SubCacheMX.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_SUBCACHEMX, + OBJECTNAME_SUBCACHEMX.toString()); + + test(DynaCache.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_DYNACACHE, + null); + + test(StdCacheMX.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_STDCACHEMX, + OBJECTNAME_STDCACHEMX.toString()); + + test(StdCache.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_STDCACHE, + OBJECTNAME_STDCACHE.toString()); + String[] sig = {String.class.getName()}; + Object[] params = {NAME1}; + test(MultiStdCache.class, params, sig, OBJECTNAME_MULTI_1, + NAME_TEMPLATE_MULTI); + Object[] params2 = {NAME2}; + test(MultiStdCache.class, params2, sig, OBJECTNAME_MULTI_2, + NAME_TEMPLATE_MULTI); + + test(MonoStdCache.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_MONO, + NAME_TEMPLATE_MONO); + + test(Quoted.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_QUOTED, + NAME_TEMPLATE_QUOTED); + + test(new StandardMBean(new WrappedResource(), MgtInterface.class), + OBJECTNAME_WRAPPED_RESOURCE, NAME_TEMPLATE_WRAPPED); + + test(FullName.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_FULL, + NAME_TEMPLATE_FULL); + try { + test(Wrong.class, EMPTY_PARAMS, EMPTY_SIGNATURE, null, null); + throw new Exception("No treceived expected Exception"); + } catch (NotCompliantMBeanException ncex) { + if (!(ncex.getCause() instanceof AttributeNotFoundException)) { + throw new Exception("Invalid initCause"); + } + } + } + + @MBean + @ObjectNameTemplate("{Naming}") + public static class FullName { + + @ManagedAttribute + public String getNaming() { + return FULL_NAME; + } + } + + @ObjectNameTemplate("com.example:type=MgtInterface,id={Id}") + public interface MgtInterface { + + public int getId(); + } + + public static class WrappedResource implements MgtInterface { + + public int getId() { + return ID; + } + } + + @MBean + @ObjectNameTemplate("com.example:type=Cache") + public static class Cache { + } + + @ObjectNameTemplate("com.example:type=SubCache") + public static class SubCache extends Cache { + } + + @MXBean + @ObjectNameTemplate("com.example:type=CacheMX") + public static class CacheMX { + } + + @ObjectNameTemplate("com.example:type=SubCacheMX") + public static class SubCacheMX extends CacheMX { + } + + @ObjectNameTemplate("com.example:type=StdCache") + public interface StdCacheMBean { + } + + public static class StdCache implements StdCacheMBean { + } + + @ObjectNameTemplate("com.example:type=StdCacheMX") + public interface StdCacheMXBean { + } + + public static class StdCacheMX implements StdCacheMXBean { + } + + public static class DynaCache implements DynamicMBean { + + public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public AttributeList getAttributes(String[] attributes) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public AttributeList setAttributes(AttributeList attributes) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public MBeanInfo getMBeanInfo() { + ImmutableDescriptor d = new ImmutableDescriptor(JMX.OBJECT_NAME_TEMPLATE + "=com.example:type=DynaCache"); + + return new MBeanInfo("DynaCache", "Description", null, null, null, null, d); + } + } + + @ObjectNameTemplate("com.example:type=MultiStdCache,name={Name}") + public interface MultiStdCacheMXBean { + + public String getName(); + } + + public static class MultiStdCache implements MultiStdCacheMXBean { + + private String name; + + public MultiStdCache(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } + + @ObjectNameTemplate("com.example:{Type}={TypeValue}") + public interface MonoStdCacheMXBean { + + public String getTypeValue(); + + public String getType(); + } + + public static class MonoStdCache implements MonoStdCacheMXBean { + + public String getTypeValue() { + return TYPE_VALUE; + } + + public String getType() { + return TYPE_KEY; + } + } + + @ObjectNameTemplate("com.example:type=Quotted,name=\"{Name}\"") + public interface QuottedMXBean { + + public String getName(); + } + + public static class Quoted implements QuottedMXBean { + + public String getName() { + return INVALID_NAME; + } + } + + @ObjectNameTemplate("com.example:{Type}={TypeValue}, name={Name}") + public interface WrongMXBean { + + public String getTypeValue(); + + public String getType(); + } + + public static class Wrong implements WrongMXBean { + + public String getTypeValue() { + return TYPE_VALUE; + } + + public String getType() { + return TYPE_KEY; + } + } +}