changeset 752:f8c2f3b5c0ff

6675526: Define an Annotation to name registered MBeans Reviewed-by: emcmanus
author jfdenise
date Tue, 09 Dec 2008 15:57:09 +0100
parents 8d7117d71fc7
children ab4d12886aaf
files src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java src/share/classes/com/sun/jmx/mbeanserver/Introspector.java src/share/classes/javax/management/Descriptor.java src/share/classes/javax/management/JMX.java src/share/classes/javax/management/MBeanServer.java src/share/classes/javax/management/MBeanServerConnection.java src/share/classes/javax/management/ObjectNameTemplate.java test/javax/management/Introspector/ObjectNameTemplateTest.java
diffstat 8 files changed, 575 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java	Tue Dec 09 15:36:14 2008 +0100
+++ b/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java	Tue Dec 09 15:57:09 2008 +0100
@@ -919,6 +919,12 @@
 
         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);
     }
 
--- a/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java	Tue Dec 09 15:36:14 2008 +0100
+++ b/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java	Tue Dec 09 15:57:09 2008 +0100
@@ -65,8 +65,12 @@
 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 @@
  */
 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 @@
             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
--- a/src/share/classes/javax/management/Descriptor.java	Tue Dec 09 15:36:14 2008 +0100
+++ b/src/share/classes/javax/management/Descriptor.java	Tue Dec 09 15:57:09 2008 +0100
@@ -245,6 +245,13 @@
  * MXBean, if it was not the {@linkplain MXBeanMappingFactory#DEFAULT default}
  * one.</td>
  *
+ * <tr><td id="objectNameTemplate"><i>objectNameTemplate</i>
+ * </td><td>String</td>
+ * <td>MBeanInfo</td>
+ *
+ * <td>The template to use to name this MBean. Its value must be compliant with
+ * the specification of the {@link ObjectNameTemplate} annotation.</td>
+ *
  * <tr id="openType"><td><i>openType</i><td>{@link OpenType}</td>
  * <td>MBeanAttributeInfo<br>MBeanOperationInfo<br>MBeanParameterInfo</td>
  *
--- a/src/share/classes/javax/management/JMX.java	Tue Dec 09 15:36:14 2008 +0100
+++ b/src/share/classes/javax/management/JMX.java	Tue Dec 09 15:57:09 2008 +0100
@@ -150,6 +150,12 @@
     public static final String SET_EXCEPTIONS_FIELD = "setExceptions";
 
     /**
+     * The name of the <a href="Descriptor.html#objectNameTemplate">{@code
+     * objectNameTemplate}</a> field.
+     */
+    public static final String OBJECT_NAME_TEMPLATE = "objectNameTemplate";
+
+    /**
      * <p>Options to apply to an MBean proxy or to an instance of {@link
      * StandardMBean}.</p>
      *
--- a/src/share/classes/javax/management/MBeanServer.java	Tue Dec 09 15:36:14 2008 +0100
+++ b/src/share/classes/javax/management/MBeanServer.java	Tue Dec 09 15:57:09 2008 +0100
@@ -351,11 +351,14 @@
 
     /**
      * <p>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.</p>
+     * MBeanRegistration#preRegister preRegister} method; or by defining
+     * an {@code objectNameTemplate} field in its {@link Descriptor},
+     * typically using the {@link ObjectNameTemplate &#64;ObjectNameTemplate}
+     * annotation.</p>
      *
      * <p>If this method successfully registers an MBean, a notification
      * is sent as described <a href="#notif">above</a>.</p>
--- a/src/share/classes/javax/management/MBeanServerConnection.java	Tue Dec 09 15:36:14 2008 +0100
+++ b/src/share/classes/javax/management/MBeanServerConnection.java	Tue Dec 09 15:57:09 2008 +0100
@@ -46,11 +46,14 @@
      * 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.</p>
+     * MBeanRegistration#preRegister preRegister} method; or by defining
+     * an {@code objectNameTemplate} field in its {@link Descriptor},
+     * typically using the {@link ObjectNameTemplate &#64;ObjectNameTemplate}
+     * annotation.</p>
      *
      * <p>This method is equivalent to {@link
      * #createMBean(String,ObjectName,Object[],String[])
@@ -117,13 +120,16 @@
     /**
      * <p>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.</p>
+     * MBeanRegistration#preRegister preRegister} method; or by defining
+     * an {@code objectNameTemplate} field in its {@link Descriptor},
+     * typically using the {@link ObjectNameTemplate &#64;ObjectNameTemplate}
+     * annotation.</p>
      *
      * <p>This method is equivalent to {@link
      * #createMBean(String,ObjectName,ObjectName,Object[],String[])
@@ -198,11 +204,14 @@
      * 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 &#64;ObjectNameTemplate}
+     * annotation.</p>
      *
      * @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 @@
                    NotCompliantMBeanException, IOException;
 
     /**
-     * Instantiates and registers an MBean in the MBean server.  The
+     * <p>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 &#64;ObjectNameTemplate}
+     * annotation.</p>
      *
      * @param className The class name of the MBean to be instantiated.
      * @param name The object name of the MBean. May be null.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/javax/management/ObjectNameTemplate.java	Tue Dec 09 15:57:09 2008 +0100
@@ -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:
+ * <ul>
+ *   <li>MBean or MXBean Java interface.</li>
+ *   <li>Java class annotated with {@link javax.management.MBean &#64;MBean}</code>
+ * annotation.</li>
+ *   <li>Java class annotated with {@link javax.management.MXBean &#64;MXBean}</code>
+ * annotation.</li>
+ * </ul>
+ *
+ * <p>The value of this annotation is used to build the <code>ObjectName</code>
+ * when instances of the annotated type are registered in
+ * an <code>MBeanServer</code> and no explicit name is given to the
+ * {@code createMBean} or {@code registerMBean} method (the {@code ObjectName}
+ * is {@code null}).</p>
+ *
+ * <p>For Dynamic MBeans, which define their own {@code MBeanInfo}, you can
+ * produce the same effect as this annotation by including a field
+ * <a href="Descriptor.html#objectNameTemplate">{@code objectNameTemplate}</a>
+ * in the {@link Descriptor} for the {@code MBeanInfo} returned by
+ * {@link DynamicMBean#getMBeanInfo()}.</p>
+ *
+ * <p>For Standard MBeans and MXBeans, this annotation automatically produces
+ * an {@code objectNameTemplate} field in the {@code Descriptor}.</p>
+ *
+ * <p>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
+ * <code>{<em>attribute name</em>}</code>. For example, to make an MBean name
+ * depend on the <code>Name</code> attribute, use the variable
+ * <code>{Name}</code>. Attribute names are case sensitive.
+ * Naming attributes can be of any type. The <code>String</code> returned by
+ * <code>toString()</code> is included in the constructed name.</p>
+ *
+ * <p>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, <code>@ObjectNameTemplate("java.lang:type=MemoryPool,name=\"{Name}\"")</code>,
+ * quotes the <code>Name</code> attribute value. You can notice the "\"
+ * character needed to escape a quote within a <code>String</code>. A name
+ * produced by this template might look like
+ * {@code java.lang:type=MemoryPool,name="Code Cache"}.</p>
+ *
+ * <p>Variables can be used anywhere in the <code>String</code>.
+ * Be sure to make the template derived name comply with
+ * {@link ObjectName ObjectName} syntax.</p>
+ *
+ * <p>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 <code>preRegister</code> method.
+ * Similarly,
+ * if the MBean uses <a href="MBeanRegistration.html#injection">resource
+ * injection</a> to discover its name, it is the computed name that will
+ * be injected.</p>
+ * <p>All of the above can be used with the {@link StandardMBean} class and
+ * the annotation is effective in that case too.</p>
+ * <p>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
+ * <code>NotCompliantMBeanException</code>.</p>
+ * <p>Some ObjectName template examples:
+ * <ul><li>"com.example:type=Memory". Fixed ObjectName. Used to name a
+ * singleton MBean.</li>
+ * <li>"com.example:type=MemoryPool,name={Name}". Variable ObjectName.
+ * <code>Name</code> attribute is retrieved to compose the <code>name</code>
+ * key value.</li>
+ * <li>"com.example:type=SomeType,name={InstanceName},id={InstanceId}".
+ * Variable ObjectName.
+ * <code>InstanceName</code> and <code>InstanceId</code> attributes are
+ * retrieved to compose respectively
+ * the <code>name</code> and <code>id</code> key values.</li>
+ * <li>"com.example:type=OtherType,name=\"{ComplexName}\"". Variable ObjectName.
+ * <code>ComplexName</code> attribute is retrieved to compose the
+ * <code>name</code> key quoted value.</li> </li>
+ * <li>"com.example:{TypeKey}=SomeOtherType". Variable ObjectName.
+ * <code>TypeKey</code> attribute is retrieved to compose the
+ * first key name.</li>
+ * * <li>"{Domain}:type=YetAnotherType". Variable ObjectName.
+ * <code>Domain</code> attribute is retrieved to compose the
+ * management domain.</li>
+ * <li>"{Naming}". Variable ObjectName.
+ * <code>Naming</code> attribute is retrieved to compose the
+ * complete name.</li>
+ * </ul>
+ * </p>
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface ObjectNameTemplate {
+
+    /**
+     * The MBean name template.
+     * @return The MBean name template.
+     */
+    @DescriptorKey("objectNameTemplate")
+    public String value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/management/Introspector/ObjectNameTemplateTest.java	Tue Dec 09 15:57:09 2008 +0100
@@ -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 &#64;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<Class<?>> parameters = new ArrayList<Class<?>>();
+        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;
+        }
+    }
+}