jdk/test/javax/management/MBeanInfo/NotificationInfoTest.java
changeset 2 90ce3da70b43
child 1155 a9a142fcf1b5
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2004 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    20  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    21  * have any questions.
       
    22  */
       
    23 
       
    24 /*
       
    25  * @test
       
    26  * @bug 5012634
       
    27  * @summary Test that JMX classes use fully-qualified class names
       
    28  * in MBeanNotificationInfo
       
    29  * @author Eamonn McManus
       
    30  * @run clean NotificationInfoTest
       
    31  * @run build NotificationInfoTest
       
    32  * @run main NotificationInfoTest
       
    33  */
       
    34 
       
    35 import java.io.*;
       
    36 import java.lang.reflect.*;
       
    37 import java.net.*;
       
    38 import java.security.CodeSource;
       
    39 import java.util.*;
       
    40 import java.util.jar.*;
       
    41 import javax.management.*;
       
    42 import javax.management.modelmbean.*;
       
    43 import javax.management.relation.*;
       
    44 
       
    45 /*
       
    46  * This test finds all classes in the same code-base as the JMX
       
    47  * classes that look like Standard MBeans, and checks that if they are
       
    48  * NotificationBroadcasters they declare existent notification types.
       
    49  * A class looks like a Standard MBean if both Thing and ThingMBean
       
    50  * classes exist.  So for example javax.management.timer.Timer looks
       
    51  * like a Standard MBean because javax.management.timer.TimerMBean
       
    52  * exists.  Timer is instanceof NotificationBroadcaster, so we expect
       
    53  * that ((NotificationBroadcaster) timer).getNotificationInfo() will
       
    54  * return an array of MBeanNotificationInfo where each entry has a
       
    55  * getName() that names an existent Java class that is a Notification.
       
    56  *
       
    57  * An MBean is "suspicious" if it is a NotificationBroadcaster but its
       
    58  * MBeanNotificationInfo[] is empty.  This is legal, but surprising.
       
    59  *
       
    60  * In order to call getNotificationInfo(), we need an instance of the
       
    61  * class.  We attempt to make one by calling a public no-arg
       
    62  * constructor.  But the "construct" method below can be extended to
       
    63  * construct specific MBean classes for which the no-arg constructor
       
    64  * doesn't exist.
       
    65  *
       
    66  * The test is obviously not exhaustive, but does catch the cases that
       
    67  * failed in 5012634.
       
    68  */
       
    69 public class NotificationInfoTest {
       
    70     // class or object names where the test failed
       
    71     private static final Set/*<String>*/ failed = new TreeSet();
       
    72 
       
    73     // class or object names where there were no MBeanNotificationInfo entries
       
    74     private static final Set/*<String>*/ suspicious = new TreeSet();
       
    75 
       
    76     public static void main(String[] args) throws Exception {
       
    77         System.out.println("Checking that all known MBeans that are " +
       
    78                            "NotificationBroadcasters have sane " +
       
    79                            "MBeanInfo.getNotifications()");
       
    80 
       
    81         System.out.println("Checking platform MBeans...");
       
    82         checkPlatformMBeans();
       
    83 
       
    84         CodeSource cs =
       
    85             javax.management.MBeanServer.class.getProtectionDomain()
       
    86             .getCodeSource();
       
    87         URL codeBase;
       
    88         if (cs == null) {
       
    89             codeBase = new URL("file:" + System.getProperty("java.home") +
       
    90                                "/lib/rt.jar");
       
    91         } else
       
    92             codeBase = cs.getLocation();
       
    93 
       
    94         System.out.println();
       
    95         System.out.println("Looking for standard MBeans...");
       
    96         String[] classes = findStandardMBeans(codeBase);
       
    97 
       
    98         System.out.println("Testing standard MBeans...");
       
    99         for (int i = 0; i < classes.length; i++) {
       
   100             String name = classes[i];
       
   101             Class c;
       
   102             try {
       
   103                 c = Class.forName(name);
       
   104             } catch (Throwable e) {
       
   105                 System.out.println(name + ": cannot load (not public?): " + e);
       
   106                 continue;
       
   107             }
       
   108             if (!NotificationBroadcaster.class.isAssignableFrom(c)) {
       
   109                 System.out.println(name + ": not a NotificationBroadcaster");
       
   110                 continue;
       
   111             }
       
   112 
       
   113             NotificationBroadcaster mbean;
       
   114             Constructor constr;
       
   115             try {
       
   116                 constr = c.getConstructor(null);
       
   117             } catch (Exception e) {
       
   118                 System.out.println(name + ": no public no-arg constructor: "
       
   119                                    + e);
       
   120                 continue;
       
   121             }
       
   122             try {
       
   123                 mbean = (NotificationBroadcaster) constr.newInstance(null);
       
   124             } catch (Exception e) {
       
   125                 System.out.println(name + ": no-arg constructor failed: " + e);
       
   126                 continue;
       
   127             }
       
   128 
       
   129             check(mbean);
       
   130         }
       
   131 
       
   132         System.out.println();
       
   133         System.out.println("Testing some explicit cases...");
       
   134 
       
   135         check(new RelationService(false));
       
   136         /*
       
   137           We can't do this:
       
   138             check(new RequiredModelMBean());
       
   139           because the Model MBean spec more or less forces us to use the
       
   140           names GENERIC and ATTRIBUTE_CHANGE for its standard notifs.
       
   141         */
       
   142         checkRMIConnectorServer();
       
   143 
       
   144         System.out.println();
       
   145         if (!suspicious.isEmpty())
       
   146             System.out.println("SUSPICIOUS CLASSES: " + suspicious);
       
   147 
       
   148         if (failed.isEmpty())
       
   149             System.out.println("TEST PASSED");
       
   150         else {
       
   151             System.out.println("TEST FAILED: " + failed);
       
   152             System.exit(1);
       
   153         }
       
   154     }
       
   155 
       
   156     private static void check(NotificationBroadcaster mbean)
       
   157             throws Exception {
       
   158         System.out.print(mbean.getClass().getName() + ": ");
       
   159 
       
   160         check(mbean.getClass().getName(), mbean.getNotificationInfo());
       
   161     }
       
   162 
       
   163     private static void checkPlatformMBeans() throws Exception {
       
   164         Class managementFactory;
       
   165         try {
       
   166             managementFactory =
       
   167                 Class.forName("java.lang.management.ManagementFactory");
       
   168         } catch (Exception e) {
       
   169             System.out.println("...no ManagementFactory, assuming pre-Tiger: "
       
   170                                + e);
       
   171             return;
       
   172         }
       
   173         Method getPlatformMBeanServer =
       
   174             managementFactory.getMethod("getPlatformMBeanServer", null);
       
   175         MBeanServer mbs = (MBeanServer)
       
   176             getPlatformMBeanServer.invoke(null, null);
       
   177         Set mbeanNames = mbs.queryNames(null, null);
       
   178         for (Iterator it = mbeanNames.iterator(); it.hasNext(); ) {
       
   179             ObjectName name = (ObjectName) it.next();
       
   180             if (!mbs.isInstanceOf(name,
       
   181                                   NotificationBroadcaster.class.getName())) {
       
   182                 System.out.println(name + ": not a NotificationBroadcaster");
       
   183             } else {
       
   184                 MBeanInfo mbi = mbs.getMBeanInfo(name);
       
   185                 check(name.toString(), mbi.getNotifications());
       
   186             }
       
   187         }
       
   188     }
       
   189 
       
   190     private static void checkRMIConnectorServer() throws Exception {
       
   191         Class rmiConnectorServer;
       
   192         try {
       
   193             rmiConnectorServer =
       
   194                 Class.forName("javax.management.remote.rmi.RMIConnectorServer");
       
   195         } catch (Exception e) {
       
   196             System.out.println("No RMIConnectorServer class, skipping: " + e);
       
   197             return;
       
   198         }
       
   199         Class jmxServiceURL =
       
   200             Class.forName("javax.management.remote.JMXServiceURL");
       
   201         Constructor jmxServiceURLConstructor =
       
   202             jmxServiceURL.getConstructor(new Class[] {String.class});
       
   203         Object url =
       
   204             jmxServiceURLConstructor.newInstance(new Object[] {
       
   205                 "service:jmx:rmi://"
       
   206             });
       
   207         Constructor rmiConnectorServerConstructor =
       
   208             rmiConnectorServer.getConstructor(new Class[] {
       
   209                 jmxServiceURL, Map.class
       
   210             });
       
   211         Object connector =
       
   212             rmiConnectorServerConstructor.newInstance(new Object[] {
       
   213                 url, null
       
   214             });
       
   215         check((NotificationBroadcaster) connector);
       
   216     }
       
   217 
       
   218     private static void check(String what, MBeanNotificationInfo[] mbnis) {
       
   219         System.out.print(what + ": checking notification info: ");
       
   220 
       
   221         if (mbnis.length == 0) {
       
   222             System.out.println("NONE (suspicious)");
       
   223             suspicious.add(what);
       
   224             return;
       
   225         }
       
   226 
       
   227         // Each MBeanNotificationInfo.getName() should be an existent
       
   228         // Java class that is Notification or a subclass of it
       
   229         for (int j = 0; j < mbnis.length; j++) {
       
   230             String notifClassName = mbnis[j].getName();
       
   231                 Class notifClass;
       
   232                 try {
       
   233                     notifClass = Class.forName(notifClassName);
       
   234                 } catch (Exception e) {
       
   235                     System.out.print("FAILED(" + notifClassName + ": " + e +
       
   236                                      ") ");
       
   237                     failed.add(what);
       
   238                     continue;
       
   239                 }
       
   240                 if (!Notification.class.isAssignableFrom(notifClass)) {
       
   241                     System.out.print("FAILED(" + notifClassName +
       
   242                                      ": not a Notification) ");
       
   243                     failed.add(what);
       
   244                     continue;
       
   245                 }
       
   246                 System.out.print("OK(" + notifClassName + ") ");
       
   247         }
       
   248         System.out.println();
       
   249     }
       
   250 
       
   251     private static String[] findStandardMBeans(URL codeBase)
       
   252             throws Exception {
       
   253         Set names;
       
   254         if (codeBase.getProtocol().equalsIgnoreCase("file")
       
   255             && codeBase.toString().endsWith("/"))
       
   256             names = findStandardMBeansFromDir(codeBase);
       
   257         else
       
   258             names = findStandardMBeansFromJar(codeBase);
       
   259 
       
   260         Set standardMBeanNames = new TreeSet();
       
   261         for (Iterator it = names.iterator(); it.hasNext(); ) {
       
   262             String name = (String) it.next();
       
   263             if (name.endsWith("MBean")) {
       
   264                 String prefix = name.substring(0, name.length() - 5);
       
   265                 if (names.contains(prefix))
       
   266                     standardMBeanNames.add(prefix);
       
   267             }
       
   268         }
       
   269         return (String[]) standardMBeanNames.toArray(new String[0]);
       
   270     }
       
   271 
       
   272     private static Set findStandardMBeansFromJar(URL codeBase)
       
   273             throws Exception {
       
   274         InputStream is = codeBase.openStream();
       
   275         JarInputStream jis = new JarInputStream(is);
       
   276         Set names = new TreeSet();
       
   277         JarEntry entry;
       
   278         while ((entry = jis.getNextJarEntry()) != null) {
       
   279             String name = entry.getName();
       
   280             if (!name.endsWith(".class"))
       
   281                 continue;
       
   282             name = name.substring(0, name.length() - 6);
       
   283             name = name.replace('/', '.');
       
   284             names.add(name);
       
   285         }
       
   286         return names;
       
   287     }
       
   288 
       
   289     private static Set findStandardMBeansFromDir(URL codeBase)
       
   290             throws Exception {
       
   291         File dir = new File(new URI(codeBase.toString()));
       
   292         Set names = new TreeSet();
       
   293         scanDir(dir, "", names);
       
   294         return names;
       
   295     }
       
   296 
       
   297     private static void scanDir(File dir, String prefix, Set names)
       
   298             throws Exception {
       
   299         File[] files = dir.listFiles();
       
   300         if (files == null)
       
   301             return;
       
   302         for (int i = 0; i < files.length; i++) {
       
   303             File f = files[i];
       
   304             String name = f.getName();
       
   305             String p = (prefix.equals("")) ? name : prefix + "." + name;
       
   306             if (f.isDirectory())
       
   307                 scanDir(f, p, names);
       
   308             else if (name.endsWith(".class")) {
       
   309                 p = p.substring(0, p.length() - 6);
       
   310                 names.add(p);
       
   311             }
       
   312         }
       
   313     }
       
   314 }