alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (NotificationInfoTest.java)

This example Java source code file (NotificationInfoTest.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

class, could, exception, failed, file, jar, jarinputstream, jmxserviceurl, management, mbeanserver, net, network, notificationbroadcaster, notificationbroadcasters, rmiconnectorserver, security, set, string, treeset, util

The NotificationInfoTest.java Java example source code

/*
 * Copyright (c) 2004, 2008, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/*
 * @test
 * @bug 5012634
 * @summary Test that JMX classes use fully-qualified class names
 * in MBeanNotificationInfo
 * @author Eamonn McManus
 * @run clean NotificationInfoTest
 * @run build NotificationInfoTest
 * @run main NotificationInfoTest
 */

import java.io.*;
import java.lang.management.*;
import java.lang.reflect.*;
import java.net.*;
import java.security.CodeSource;
import java.util.*;
import java.util.jar.*;
import javax.management.*;
import javax.management.relation.*;
import javax.management.remote.*;
import javax.management.remote.rmi.*;

/*
 * This test finds all classes in the same code-base as the JMX
 * classes that look like Standard MBeans, and checks that if they are
 * NotificationBroadcasters they declare existent notification types.
 * A class looks like a Standard MBean if both Thing and ThingMBean
 * classes exist.  So for example javax.management.timer.Timer looks
 * like a Standard MBean because javax.management.timer.TimerMBean
 * exists.  Timer is instanceof NotificationBroadcaster, so we expect
 * that ((NotificationBroadcaster) timer).getNotificationInfo() will
 * return an array of MBeanNotificationInfo where each entry has a
 * getName() that names an existent Java class that is a Notification.
 *
 * An MBean is "suspicious" if it is a NotificationBroadcaster but its
 * MBeanNotificationInfo[] is empty.  This is legal, but surprising.
 *
 * In order to call getNotificationInfo(), we need an instance of the
 * class.  We attempt to make one by calling a public no-arg
 * constructor.  But the "construct" method below can be extended to
 * construct specific MBean classes for which the no-arg constructor
 * doesn't exist.
 *
 * The test is obviously not exhaustive, but does catch the cases that
 * failed in 5012634.
 */
public class NotificationInfoTest {
    // class or object names where the test failed
    private static final Set<String> failed = new TreeSet();

    // class or object names where there were no MBeanNotificationInfo entries
    private static final Set<String> suspicious = new TreeSet();

    public static void main(String[] args) throws Exception {
        System.out.println("Checking that all known MBeans that are " +
                           "NotificationBroadcasters have sane " +
                           "MBeanInfo.getNotifications()");

        System.out.println("Checking platform MBeans...");
        checkPlatformMBeans();

        CodeSource cs =
            javax.management.MBeanServer.class.getProtectionDomain()
            .getCodeSource();
        URL codeBase;
        if (cs == null) {
            String javaHome = System.getProperty("java.home");
            String[] candidates = {"/lib/rt.jar", "/classes/"};
            codeBase = null;
            for (String candidate : candidates) {
                File file = new File(javaHome + candidate);
                if (file.exists()) {
                    codeBase = file.toURI().toURL();
                    break;
                }
            }
            if (codeBase == null) {
                throw new Exception(
                        "Could not determine codeBase for java.home=" + javaHome);
            }
        } else
            codeBase = cs.getLocation();

        System.out.println();
        System.out.println("Looking for standard MBeans...");
        String[] classes = findStandardMBeans(codeBase);

        System.out.println("Testing standard MBeans...");
        for (int i = 0; i < classes.length; i++) {
            String name = classes[i];
            Class<?> c;
            try {
                c = Class.forName(name);
            } catch (Throwable e) {
                System.out.println(name + ": cannot load (not public?): " + e);
                continue;
            }
            if (!NotificationBroadcaster.class.isAssignableFrom(c)) {
                System.out.println(name + ": not a NotificationBroadcaster");
                continue;
            }
            if (Modifier.isAbstract(c.getModifiers())) {
                System.out.println(name + ": abstract class");
                continue;
            }

            NotificationBroadcaster mbean;
            Constructor<?> constr;
            try {
                constr = c.getConstructor();
            } catch (Exception e) {
                System.out.println(name + ": no public no-arg constructor: "
                                   + e);
                continue;
            }
            try {
                mbean = (NotificationBroadcaster) constr.newInstance();
            } catch (Exception e) {
                System.out.println(name + ": no-arg constructor failed: " + e);
                continue;
            }

            check(mbean);
        }

        System.out.println();
        System.out.println("Testing some explicit cases...");

        check(new RelationService(false));
        /*
          We can't do this:
            check(new RequiredModelMBean());
          because the Model MBean spec more or less forces us to use the
          names GENERIC and ATTRIBUTE_CHANGE for its standard notifs.
        */
        checkRMIConnectorServer();

        System.out.println();
        if (!suspicious.isEmpty())
            System.out.println("SUSPICIOUS CLASSES: " + suspicious);

        if (failed.isEmpty())
            System.out.println("TEST PASSED");
        else {
            System.out.println("TEST FAILED: " + failed);
            System.exit(1);
        }
    }

    private static void check(NotificationBroadcaster mbean)
            throws Exception {
        System.out.print(mbean.getClass().getName() + ": ");

        check(mbean.getClass().getName(), mbean.getNotificationInfo());
    }

    private static void checkPlatformMBeans() throws Exception {
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        Set<ObjectName> mbeanNames = mbs.queryNames(null, null);
        for (ObjectName name : mbeanNames) {
            if (!mbs.isInstanceOf(name,
                                  NotificationBroadcaster.class.getName())) {
                System.out.println(name + ": not a NotificationBroadcaster");
            } else {
                MBeanInfo mbi = mbs.getMBeanInfo(name);
                check(name.toString(), mbi.getNotifications());
            }
        }
    }

    private static void checkRMIConnectorServer() throws Exception {
        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
        RMIConnectorServer connector = new RMIConnectorServer(url, null);
        check(connector);
    }

    private static void check(String what, MBeanNotificationInfo[] mbnis) {
        System.out.print(what + ": checking notification info: ");

        if (mbnis.length == 0) {
            System.out.println("NONE (suspicious)");
            suspicious.add(what);
            return;
        }

        // Each MBeanNotificationInfo.getName() should be an existent
        // Java class that is Notification or a subclass of it
        for (int j = 0; j < mbnis.length; j++) {
            String notifClassName = mbnis[j].getName();
                Class notifClass;
                try {
                    notifClass = Class.forName(notifClassName);
                } catch (Exception e) {
                    System.out.print("FAILED(" + notifClassName + ": " + e +
                                     ") ");
                    failed.add(what);
                    continue;
                }
                if (!Notification.class.isAssignableFrom(notifClass)) {
                    System.out.print("FAILED(" + notifClassName +
                                     ": not a Notification) ");
                    failed.add(what);
                    continue;
                }
                System.out.print("OK(" + notifClassName + ") ");
        }
        System.out.println();
    }

    private static String[] findStandardMBeans(URL codeBase)
            throws Exception {
        Set<String> names;
        if (codeBase.getProtocol().equalsIgnoreCase("file")
            && codeBase.toString().endsWith("/"))
            names = findStandardMBeansFromDir(codeBase);
        else
            names = findStandardMBeansFromJar(codeBase);

        Set<String> standardMBeanNames = new TreeSet();
        for (String name : names) {
            if (name.endsWith("MBean")) {
                String prefix = name.substring(0, name.length() - 5);
                if (names.contains(prefix))
                    standardMBeanNames.add(prefix);
            }
        }
        return standardMBeanNames.toArray(new String[0]);
    }

    private static Set<String> findStandardMBeansFromJar(URL codeBase)
            throws Exception {
        InputStream is = codeBase.openStream();
        JarInputStream jis = new JarInputStream(is);
        Set<String> names = new TreeSet();
        JarEntry entry;
        while ((entry = jis.getNextJarEntry()) != null) {
            String name = entry.getName();
            if (!name.endsWith(".class"))
                continue;
            name = name.substring(0, name.length() - 6);
            name = name.replace('/', '.');
            names.add(name);
        }
        return names;
    }

    private static Set<String> findStandardMBeansFromDir(URL codeBase)
            throws Exception {
        File dir = new File(new URI(codeBase.toString()));
        Set<String> names = new TreeSet();
        scanDir(dir, "", names);
        return names;
    }

    private static void scanDir(File dir, String prefix, Set<String> names)
            throws Exception {
        File[] files = dir.listFiles();
        if (files == null)
            return;
        for (int i = 0; i < files.length; i++) {
            File f = files[i];
            String name = f.getName();
            String p = (prefix.equals("")) ? name : prefix + "." + name;
            if (f.isDirectory())
                scanDir(f, p, names);
            else if (name.endsWith(".class")) {
                p = p.substring(0, p.length() - 6);
                names.add(p);
            }
        }
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java NotificationInfoTest.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.