1 /*
   2  * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug     6320211
  27  * @summary Check that java.lang.management MXBeans have the same behavior
  28  *          as user MXBeans
  29  * @author  Eamonn McManus
  30  *
  31  * @modules jdk.management
  32  *
  33  * @run     main/othervm MXBeanBehavior
  34  */
  35 
  36 import java.lang.management.*;
  37 import java.lang.reflect.*;
  38 import java.util.*;
  39 import javax.management.*;
  40 
  41 public class MXBeanBehavior {
  42     // Exclude list: list of platform MBeans that are not MXBeans
  43     public static final HashSet<String> excludeList = new HashSet<>(
  44             Arrays.asList("com.sun.management:type=DiagnosticCommand"));
  45 
  46     public static void main(String[] args) throws Exception {
  47         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
  48 
  49         /* Test that all the MBeans in the java.* and com.sun.management*
  50            domains are MXBeans with the appropriate behavior.  */
  51         Set<ObjectName> names = mbs.queryNames(new ObjectName("java.*:*"),
  52                                                null);
  53         names.addAll(mbs.queryNames(new ObjectName("com.sun.management*:*"),
  54                                     null));
  55         for (ObjectName name : names)
  56             test(mbs, name);
  57 
  58         /* Now do some rudimentary testing of inter-MXBean references.
  59            It should be possible for a user MXBean to return e.g.  the
  60            CompilationMXBean from the platform from an attribute of
  61            type CompilationMXBean, and have the MXBean infrastructure
  62            map this into that MXBean's standard ObjectName.  It should
  63            also be possible for a proxy for this user MXBean to have
  64            this attribute's value mapped back into a CompilationMXBean
  65            instance, which however will be another proxy rather than
  66            the original object.  Finally, it should be possible to set
  67            the attribute in the user's MXBean through a proxy, giving
  68            the real CompilationMXBean as an argument, and have this be
  69            translated into that MXBean's standard ObjectName.  The
  70            user's MXBean will receive a proxy in this case, though we
  71            don't check that.  */
  72         ObjectName refName = new ObjectName("d:type=CompilationRef");
  73         mbs.registerMBean(new CompilationImpl(), refName);
  74         CompilationRefMXBean refProxy =
  75             JMX.newMXBeanProxy(mbs, refName, CompilationRefMXBean.class);
  76         refProxy.getCompilationMXBean();
  77         refProxy.setCompilationMXBean(ManagementFactory.getCompilationMXBean());
  78         ObjectName on =
  79             (ObjectName) mbs.getAttribute(refName, "CompilationMXBean");
  80         checkEqual(on, new ObjectName(ManagementFactory.COMPILATION_MXBEAN_NAME),
  81                    "Referenced object name");
  82         mbs.setAttribute(refName, new Attribute("CompilationMXBean", on));
  83 
  84         System.out.println("TEST PASSED");
  85     }
  86 
  87     /* Check the behavior of this MXBean to ensure that it conforms to
  88        what is expected of all MXBeans as detailed in
  89        javax.management.MXBean.  Its MBeanInfo should have a
  90        Descriptor with the fields mxbean and interfaceClassName, and
  91        furthermore we know that our implementation sets immutableInfo
  92        here.  Each attribute should have Descriptor with the fields
  93        openType and originalType that have appropriate values.  We
  94        don't currently check operations though the same considerations
  95        would apply there.  (If the MBeanInfo and MBeanAttributeInfo
  96        tests pass we can reasonably suppose that this MXBean will
  97        behave the same as all other MXBeans, so MBeanOperationInfo,
  98        MBeanNotificationInfo, and MBeanConstructorInfo will be covered
  99        by generic MXBean tests.
 100      */
 101     private static void test(MBeanServer mbs, ObjectName name) throws Exception {
 102         if(excludeList.contains(name.getCanonicalName())) {
 103             // Skipping not MXBean objects.
 104             return;
 105         }
 106         System.out.println("Testing: " + name);
 107 
 108         MBeanInfo mbi = mbs.getMBeanInfo(name);
 109         Descriptor mbid = mbi.getDescriptor();
 110         Object[] values = mbid.getFieldValues("immutableInfo",
 111                                               "interfaceClassName",
 112                                               "mxbean");
 113         checkEqual(values[0], "true", name + " immutableInfo field");
 114         checkEqual(values[2], "true", name + " mxbean field");
 115         String interfaceClassName = (String) values[1];
 116         if (!mbs.isInstanceOf(name, interfaceClassName)) {
 117             throw new RuntimeException(name + " not instance of " +
 118                                        interfaceClassName);
 119         }
 120         Class interfaceClass = Class.forName(interfaceClassName);
 121         for (MBeanAttributeInfo mbai : mbi.getAttributes()) {
 122             Descriptor mbaid = mbai.getDescriptor();
 123             Object[] avalues = mbaid.getFieldValues("openType",
 124                                                     "originalType");
 125             if (avalues[0] == null || avalues[1] == null) {
 126                 throw new RuntimeException("Null attribute descriptor fields: " +
 127                                            Arrays.toString(avalues));
 128             }
 129             if (mbai.isReadable()) {
 130                 String mname = (mbai.isIs() ? "is" : "get") + mbai.getName();
 131                 Method m = interfaceClass.getMethod(mname);
 132                 Type t = m.getGenericReturnType();
 133                 String ret =
 134                     (t instanceof Class) ? ((Class) t).getName() : t.toString();
 135                 if (!ret.equals(avalues[1])) {
 136                     final String msg =
 137                         name + " attribute " + mbai.getName() + " has wrong " +
 138                         "originalType: " + avalues[1] + " vs " + ret;
 139                     throw new RuntimeException(msg);
 140                 }
 141             }
 142         }
 143     }
 144 
 145     private static void checkEqual(Object x, Object y, String what) {
 146         final boolean eq;
 147         if (x == y)
 148             eq = true;
 149         else if (x == null)
 150             eq = false;
 151         else
 152             eq = x.equals(y);
 153         if (!eq)
 154             throw new RuntimeException(what + " should be " + y + ", is " + x);
 155     }
 156 
 157     public static interface CompilationRefMXBean {
 158         public CompilationMXBean getCompilationMXBean();
 159         public void setCompilationMXBean(CompilationMXBean mxb);
 160     }
 161 
 162     public static class CompilationImpl implements CompilationRefMXBean {
 163         public CompilationMXBean getCompilationMXBean() {
 164             return ManagementFactory.getCompilationMXBean();
 165         }
 166 
 167         public void setCompilationMXBean(CompilationMXBean mxb) {
 168             if (mxb == ManagementFactory.getCompilationMXBean())
 169                 return;
 170             MBeanServerInvocationHandler mbsih = (MBeanServerInvocationHandler)
 171                 Proxy.getInvocationHandler(mxb);
 172             ObjectName expectedName;
 173             try {
 174                 expectedName =
 175                     new ObjectName(ManagementFactory.COMPILATION_MXBEAN_NAME);
 176             } catch (MalformedObjectNameException e) {
 177                 throw new RuntimeException(e);
 178             }
 179             checkEqual(mbsih.getObjectName(), expectedName,
 180                        "Proxy name in setCompilationMXBean");
 181         }
 182     }
 183 }