b2e851f920
6669137: RFE: InstanceNotFoundException should have a constructor that takes an ObjectName 6746796: jmx namespaces: Several tests are missing an @bug or @run keyword Note on 6669137: first implementation of 6669137 was actually pushed with 5072476 - here we only have a small update and a test case. Also re-fixes 6737133: Compilation failure of test/javax/management/eventService/LeaseManagerDeadlockTest.java which had failed. Reviewed-by: emcmanus, yjoan
791 lines
30 KiB
Java
791 lines
30 KiB
Java
/*
|
|
* 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 LazyDomainTest.java
|
|
* @bug 5072476
|
|
* @summary Basic test for Lazy Domains.
|
|
* @author Daniel Fuchs
|
|
* @run clean LazyDomainTest Wombat WombatMBean
|
|
* @run build LazyDomainTest Wombat WombatMBean
|
|
* @run main LazyDomainTest
|
|
*/
|
|
|
|
|
|
import java.lang.management.ClassLoadingMXBean;
|
|
import java.lang.management.ManagementFactory;
|
|
import java.lang.reflect.InvocationHandler;
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.lang.reflect.Method;
|
|
import java.lang.reflect.Proxy;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.concurrent.ArrayBlockingQueue;
|
|
import java.util.concurrent.BlockingQueue;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import javax.management.JMX;
|
|
import javax.management.ListenerNotFoundException;
|
|
import javax.management.MBeanServer;
|
|
import javax.management.MBeanServerBuilder;
|
|
import javax.management.MBeanServerDelegate;
|
|
import javax.management.MBeanServerFactory;
|
|
import javax.management.MBeanServerNotification;
|
|
import javax.management.Notification;
|
|
import javax.management.NotificationFilter;
|
|
import javax.management.NotificationListener;
|
|
import javax.management.ObjectName;
|
|
import javax.management.namespace.JMXDomain;
|
|
import javax.management.remote.MBeanServerForwarder;
|
|
|
|
/**
|
|
* Test simple creation/registration of namespace.
|
|
*
|
|
*/
|
|
public class LazyDomainTest {
|
|
private static Map<String,Object> emptyEnvMap() {
|
|
return Collections.emptyMap();
|
|
}
|
|
|
|
|
|
public static interface MBeanServerLoader {
|
|
public MBeanServer loadMBeanServer();
|
|
}
|
|
|
|
|
|
public static class MBeanServerProxy implements InvocationHandler {
|
|
|
|
private final static Map<Method,Method> localMap;
|
|
static {
|
|
localMap = new HashMap<Method, Method>();
|
|
for (Method m : MBeanServerForwarder.class.getDeclaredMethods()) {
|
|
try {
|
|
final Method loc = MBeanServerProxy.class.
|
|
getMethod(m.getName(), m.getParameterTypes());
|
|
localMap.put(m, loc);
|
|
} catch (Exception x) {
|
|
// not defined...
|
|
}
|
|
}
|
|
try {
|
|
localMap.put(MBeanServer.class.
|
|
getMethod("getMBeanCount", (Class[]) null),
|
|
MBeanServerProxy.class.
|
|
getMethod("getMBeanCount", (Class[]) null));
|
|
} catch (NoSuchMethodException x) {
|
|
// OK.
|
|
}
|
|
}
|
|
|
|
private final MBeanServerLoader loader;
|
|
private MBeanServer server;
|
|
private final Set<LazyDomain> domains;
|
|
|
|
public MBeanServerProxy(MBeanServerLoader loader) {
|
|
if (loader == null)
|
|
throw new IllegalArgumentException("null loader");
|
|
this.loader = loader;
|
|
this.server = null;
|
|
domains = new HashSet<LazyDomain>();
|
|
}
|
|
|
|
|
|
public Object invoke(Object proxy, Method method, Object[] args)
|
|
throws Throwable {
|
|
if (method.getDeclaringClass().equals(Object.class)) {
|
|
return invokeMethod(this,method,args);
|
|
}
|
|
final Method local = localMap.get(method);
|
|
if (local != null) {
|
|
return invokeMethod(this,local,args);
|
|
}
|
|
if (method.getDeclaringClass().equals(MBeanServer.class)) {
|
|
return invokeMethod(getMBeanServer(),method,args);
|
|
}
|
|
throw new NoSuchMethodException(method.getName());
|
|
}
|
|
|
|
private Object invokeMethod(Object on, Method method, Object[] args)
|
|
throws Throwable {
|
|
try {
|
|
return method.invoke(on, args);
|
|
} catch (InvocationTargetException ex) {
|
|
throw ex.getTargetException();
|
|
}
|
|
}
|
|
|
|
public synchronized MBeanServer getMBeanServer() {
|
|
if (server == null) setMBeanServer(loader.loadMBeanServer());
|
|
return server;
|
|
}
|
|
|
|
public synchronized void setMBeanServer(MBeanServer mbs) {
|
|
this.server = mbs;
|
|
if (mbs != null) {
|
|
for (LazyDomain dom : domains) dom.loaded();
|
|
domains.clear();
|
|
}
|
|
}
|
|
|
|
public synchronized boolean isLoaded() {
|
|
return server != null;
|
|
}
|
|
|
|
public synchronized void add(LazyDomain dom) {
|
|
if (isLoaded()) dom.loaded();
|
|
else domains.add(dom);
|
|
}
|
|
|
|
public synchronized boolean remove(LazyDomain dom) {
|
|
return domains.remove(dom);
|
|
}
|
|
|
|
public Integer getMBeanCount() {
|
|
if (isLoaded()) return server.getMBeanCount();
|
|
else return Integer.valueOf(0);
|
|
}
|
|
}
|
|
|
|
public static class LazyDomain extends JMXDomain {
|
|
public static MBeanServer makeProxyFor(MBeanServerProxy proxy) {
|
|
return (MBeanServer)
|
|
Proxy.newProxyInstance(LazyDomain.class.getClassLoader(),
|
|
new Class[] {MBeanServer.class, MBeanServerForwarder.class},
|
|
proxy);
|
|
}
|
|
|
|
private final MBeanServerProxy proxy;
|
|
private volatile NotificationListener listener;
|
|
private volatile NotificationFilter filter;
|
|
|
|
public LazyDomain(MBeanServerProxy proxy) {
|
|
super(makeProxyFor(proxy));
|
|
this.proxy = proxy;
|
|
}
|
|
|
|
@Override
|
|
public Integer getMBeanCount() {
|
|
if (proxy.isLoaded())
|
|
return super.getMBeanCount();
|
|
return 0;
|
|
}
|
|
|
|
|
|
@Override
|
|
public synchronized void addMBeanServerNotificationListener(
|
|
NotificationListener listener,
|
|
NotificationFilter filter) {
|
|
if (proxy.isLoaded()) {
|
|
super.addMBeanServerNotificationListener(listener, filter);
|
|
} else {
|
|
this.listener = listener;
|
|
this.filter = filter;
|
|
proxy.add(this);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public synchronized void removeMBeanServerNotificationListener(
|
|
NotificationListener listener)
|
|
throws ListenerNotFoundException {
|
|
if (this.listener != listener)
|
|
throw new ListenerNotFoundException();
|
|
this.listener = null;
|
|
this.filter = null;
|
|
if (proxy.isLoaded())
|
|
super.removeMBeanServerNotificationListener(listener);
|
|
proxy.remove(this);
|
|
}
|
|
|
|
public synchronized void loaded() {
|
|
if (listener != null)
|
|
addMBeanServerNotificationListener(listener, filter);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* This is a use case for e.g GlassFish: the LazyStarterDomain MBean
|
|
* is a place holder that will unregister itself and autoload a set
|
|
* of MBeans in place of its own domain when that domain is
|
|
* accessed.
|
|
* This is an abstract class, where the only abstract method
|
|
* is loadMBeans(MBeanServer).
|
|
* Subclasses should implement that method to register whatever MBeans
|
|
* in the domain previously held by that LazyStarterDomain object.
|
|
* In other words: the LazyStarterDomain MBean is 'replaced' by the
|
|
* MBeans loaded by loadMBeans();
|
|
*/
|
|
public static abstract class LazyStarterDomain extends LazyDomain {
|
|
|
|
/**
|
|
* This is a loader that will unregister the JMXDomain that
|
|
* created it, and register a bunch of MBeans in its place
|
|
* by calling LazyStarterDomain.loadMBeans
|
|
*
|
|
* That one gave me "la migraine".
|
|
*/
|
|
private static class HalfGrainLoader implements MBeanServerLoader {
|
|
private volatile LazyStarterDomain domain;
|
|
public MBeanServer loadMBeanServer() {
|
|
if (domain == null)
|
|
throw new IllegalStateException(
|
|
"JMXDomain MBean not registered!");
|
|
final MBeanServer server = domain.getMBeanServer();
|
|
final ObjectName domainName = domain.getObjectName();
|
|
try {
|
|
server.unregisterMBean(domainName);
|
|
} catch (Exception x) {
|
|
throw new IllegalStateException("Can't unregister " +
|
|
"JMXDomain: "+x,x);
|
|
}
|
|
domain.loadMBeans(server,domainName.getDomain());
|
|
return server;
|
|
}
|
|
public void setDomain(LazyStarterDomain domain) {
|
|
this.domain = domain;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This is an MBeanServerProxy which create a loader for the
|
|
* LazyStarterDomain MBean.
|
|
*/
|
|
private static class DomainStarter extends MBeanServerProxy {
|
|
|
|
public DomainStarter() {
|
|
this(new HalfGrainLoader());
|
|
}
|
|
|
|
private final HalfGrainLoader loader;
|
|
private DomainStarter(HalfGrainLoader loader) {
|
|
super(loader);
|
|
this.loader = loader;
|
|
}
|
|
|
|
public void setDomain(LazyStarterDomain domain) {
|
|
loader.setDomain(domain);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A new LazyStarterDomain. When the domain monitored by this
|
|
* MBean is accessed, this MBean will unregister itself and call
|
|
* the abstract loadMBeans(MBeanServer) method.
|
|
* Subclasses need only to implement loadMBeans().
|
|
*/
|
|
public LazyStarterDomain() {
|
|
this(new DomainStarter());
|
|
}
|
|
|
|
private LazyStarterDomain(DomainStarter starter) {
|
|
super(starter);
|
|
starter.setDomain(this);
|
|
}
|
|
|
|
// Contrarily to its LazyDomain superclass, this LazyDomain
|
|
// doesn't wrapp another MBeanServer: it simply registers a bunch
|
|
// of MBeans in its own MBeanServer.
|
|
// Thus, there's no notifications to forward.
|
|
//
|
|
@Override
|
|
public void addMBeanServerNotificationListener(
|
|
NotificationListener listener, NotificationFilter filter) {
|
|
// nothing to do.
|
|
}
|
|
|
|
// Contrarily to its LazyDomain superclass, this LazyDomain
|
|
// doesn't wrapp another MBeanServer: it simply registers a bunch
|
|
// of MBeans in its own MBeanServer.
|
|
// Thus, there's no notifications to forward.
|
|
//
|
|
@Override
|
|
public void removeMBeanServerNotificationListener(
|
|
NotificationListener listener) throws ListenerNotFoundException {
|
|
// nothing to do
|
|
}
|
|
|
|
// If this domain is registered, it contains no MBean.
|
|
// If it is not registered, then it no longer contain any MBean.
|
|
// The MBeanCount is thus always 0.
|
|
@Override
|
|
public Integer getMBeanCount() {
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Called when the domain is first accessed.
|
|
* {@code server} is the server in which this MBean was registered.
|
|
* A subclass must override this method in order to register
|
|
* the MBeans that should be contained in domain.
|
|
*
|
|
* @param server the server in which to load the MBeans.
|
|
* @param domain the domain in which the MBeans should be registered.
|
|
*/
|
|
protected abstract void loadMBeans(MBeanServer server, String domain);
|
|
|
|
|
|
}
|
|
|
|
private static MBeanServerNotification pop(
|
|
BlockingQueue<Notification> queue,
|
|
String type,
|
|
ObjectName mbean,
|
|
String test)
|
|
throws InterruptedException {
|
|
final Notification n = queue.poll(1, TimeUnit.SECONDS);
|
|
if (!(n instanceof MBeanServerNotification))
|
|
fail(test+"expected MBeanServerNotification, got "+n);
|
|
final MBeanServerNotification msn = (MBeanServerNotification)n;
|
|
if (!type.equals(msn.getType()))
|
|
fail(test+"expected "+type+", got "+msn.getType());
|
|
if (!mbean.apply(msn.getMBeanName()))
|
|
fail(test+"expected "+mbean+", got "+msn.getMBeanName());
|
|
System.out.println(test+" got: "+msn);
|
|
return msn;
|
|
}
|
|
private static MBeanServerNotification popADD(
|
|
BlockingQueue<Notification> queue,
|
|
ObjectName mbean,
|
|
String test)
|
|
throws InterruptedException {
|
|
return pop(queue, MBeanServerNotification.REGISTRATION_NOTIFICATION,
|
|
mbean, test);
|
|
}
|
|
|
|
private static MBeanServerNotification popREM(
|
|
BlockingQueue<Notification> queue,
|
|
ObjectName mbean,
|
|
String test)
|
|
throws InterruptedException {
|
|
return pop(queue, MBeanServerNotification.UNREGISTRATION_NOTIFICATION,
|
|
mbean, test);
|
|
}
|
|
|
|
|
|
private static void fail(String msg) {
|
|
raise(new RuntimeException(msg));
|
|
}
|
|
|
|
private static void fail(String msg, Throwable cause) {
|
|
raise(new RuntimeException(msg,cause));
|
|
}
|
|
|
|
private static void raise(RuntimeException x) {
|
|
lastException = x;
|
|
exceptionCount++;
|
|
throw x;
|
|
}
|
|
|
|
private static volatile Exception lastException = null;
|
|
private static volatile int exceptionCount = 0;
|
|
|
|
// ZZZ need to add a test case with several LazyDomains, and
|
|
// need to test that nothing is loaded until the lazy domains
|
|
// are accessed...
|
|
//
|
|
|
|
private static void registerWombats(MBeanServer server, String domain,
|
|
int count) {
|
|
try {
|
|
for (int i=0;i<count;i++) {
|
|
final ObjectName name =
|
|
new ObjectName(domain+":type=Wombat,name=wombat#"+i);
|
|
server.createMBean("Wombat", name);
|
|
}
|
|
} catch (RuntimeException x) {
|
|
throw x;
|
|
} catch(Exception x) {
|
|
throw new RuntimeException(x.toString(),x);
|
|
}
|
|
}
|
|
|
|
public static void checkSize(String test, MBeanServer server, int size) {
|
|
System.out.println("We have now "+server.getMBeanCount()+
|
|
" MBeans in "+Arrays.toString(server.getDomains()));
|
|
if (server.getMBeanCount() != size)
|
|
fail(test+"Expected "+size+
|
|
" MBeans, found " + server.getMBeanCount());
|
|
}
|
|
|
|
private static MBeanServer newMBeanServer() {
|
|
return MBeanServerFactory.newMBeanServer();
|
|
}
|
|
|
|
public static void lazyTest() throws Exception {
|
|
final String test = "lazyTest: ";
|
|
System.out.println("" +
|
|
"\nThis test checks that it is possible to perform lazy loading" +
|
|
"\nof MBeans in a given domain by using a JMXDomain subclass" +
|
|
"\nfor that domain.");
|
|
|
|
System.out.println(test + " START");
|
|
|
|
// The "global" MBeanServer...
|
|
final MBeanServer server = newMBeanServer();
|
|
|
|
// An MBeanServer proxy which makes it possible to `lazy load'
|
|
// the platform MBeanServer domains inside the global MBeanServer.
|
|
//
|
|
final MBeanServerProxy platform =
|
|
new MBeanServerProxy(new MBeanServerLoader() {
|
|
|
|
public MBeanServer loadMBeanServer() {
|
|
return ManagementFactory.getPlatformMBeanServer();
|
|
}
|
|
});
|
|
|
|
|
|
// The list of domain from the platform MBeanServer that will be
|
|
// lazily loaded in the global MBeanServer
|
|
//
|
|
final String[] platformDomains = {
|
|
"java.lang", "com.sun.management",
|
|
"java.util.logging", "java.nio"
|
|
};
|
|
|
|
// We create a second MBeanServer, in which we will store some
|
|
// custom MBeans. We will use this server to perform lazy loading
|
|
// of two domains: custom.awomb and custom.bwomb.
|
|
//
|
|
// We use an MBeanServerBuilder here so that the MBeans registered
|
|
// in our custom domain see all the MBeans in the global MBeanServer.
|
|
// We do this by saying that the 'outer' MBeanServer is our global
|
|
// servers. This means that the MBeans registered in the global
|
|
// MBeanServer will see the MBeans from custom.awomb and custom.bwomb,
|
|
// and the MBeans from custom.awomb and custom.bwomb will also see
|
|
// the MBeans from the global MBeanServer, including those from
|
|
// the platform domains.
|
|
//
|
|
final MBeanServerBuilder builder = new MBeanServerBuilder();
|
|
final MBeanServerDelegate delegate = builder.newMBeanServerDelegate();
|
|
final MBeanServer custom = builder.newMBeanServer("custom",
|
|
server, delegate);
|
|
|
|
// Number of MBean that we will put in each of the custom domain.
|
|
//
|
|
final int customCount = 10;
|
|
|
|
// We use one MBeanServer proxy for each of the custom domains.
|
|
// This makes it possible to load custom.awomb independently of
|
|
// custom.bwomb.
|
|
//
|
|
// Here, the logic of the loader is to register MBeans in the loaded
|
|
// domain as soon as the domain is loaded.
|
|
//
|
|
final MBeanServerProxy customa =
|
|
new MBeanServerProxy(new MBeanServerLoader() {
|
|
// A loader to register awomb MBeans in the custom MBeanServer.
|
|
public MBeanServer loadMBeanServer() {
|
|
registerWombats(custom, "custom.awomb", customCount);
|
|
return custom;
|
|
}
|
|
});
|
|
final MBeanServerProxy customb =
|
|
new MBeanServerProxy(new MBeanServerLoader() {
|
|
// A loader to register bwomb MBeans in the custom MBeanServer.
|
|
public MBeanServer loadMBeanServer() {
|
|
registerWombats(custom, "custom.bwomb", customCount);
|
|
return custom;
|
|
}
|
|
});
|
|
|
|
// A notification queue.
|
|
final BlockingQueue<Notification> queue =
|
|
new ArrayBlockingQueue<Notification>(100);
|
|
|
|
// A listener that puts notifs in the queue.
|
|
final NotificationListener l = new NotificationListener() {
|
|
|
|
public void handleNotification(Notification notification,
|
|
Object handback) {
|
|
try {
|
|
if (!queue.offer(notification, 5, TimeUnit.SECONDS)) {
|
|
throw new RuntimeException("timeout exceeded");
|
|
}
|
|
} catch (Exception x) {
|
|
fail(test + "failed to handle notif", x);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Create a LazyDomain for each of the platform domain.
|
|
// All platform domain share the same MBeanServer proxy, which means
|
|
// that loading one domain will also load all the others.
|
|
//
|
|
Map<String,LazyDomain> domainsMap = new HashMap<String,LazyDomain>();
|
|
for (String dom : platformDomains) {
|
|
domainsMap.put(dom, new LazyDomain(platform));
|
|
}
|
|
domainsMap.put("custom.awomb", new LazyDomain(customa));
|
|
domainsMap.put("custom.bwomb", new LazyDomain(customb));
|
|
|
|
for (Map.Entry<String,LazyDomain> e : domainsMap.entrySet()) {
|
|
server.registerMBean(e.getValue(),
|
|
JMXDomain.getDomainObjectName(e.getKey()));
|
|
}
|
|
|
|
// check that lazy MBeans are not there...
|
|
checkSize(test,server,domainsMap.size()+1);
|
|
|
|
System.out.println(test+" registering listener with delegate.");
|
|
server.addNotificationListener(MBeanServerDelegate.DELEGATE_NAME, l,
|
|
null, null);
|
|
|
|
// check that lazy MBeans are not there...
|
|
checkSize(test,server,domainsMap.size()+1);
|
|
|
|
// force loading of custom.awomb.
|
|
final ObjectName awombat = new ObjectName(
|
|
"custom.awomb:type=Wombat,name=wombat#"+customCount/2);
|
|
if (!server.isRegistered(awombat))
|
|
fail(test+"Expected "+awombat+" to be reggistered!");
|
|
|
|
final int oldCount = domainsMap.size()+1+customCount;
|
|
checkSize(test,server,oldCount);
|
|
|
|
if (queue.peek() != null)
|
|
fail(test+"Received unexpected notifications: "+queue);
|
|
|
|
|
|
System.out.println(test+"creating a proxy for ClassLoadingMXBean.");
|
|
final ClassLoadingMXBean cl =
|
|
JMX.newMXBeanProxy(server,
|
|
new ObjectName(ManagementFactory.CLASS_LOADING_MXBEAN_NAME),
|
|
ClassLoadingMXBean.class);
|
|
|
|
checkSize(test,server,oldCount);
|
|
|
|
System.out.println(test+"Loaded classes: "+cl.getLoadedClassCount());
|
|
|
|
final int newCount = server.getMBeanCount();
|
|
if (newCount < oldCount+6)
|
|
fail(test+"Expected at least "+(oldCount+6)+
|
|
" MBeans. Found "+newCount);
|
|
|
|
final ObjectName jwombat = new ObjectName("java.lang:type=Wombat");
|
|
server.createMBean("Wombat", jwombat);
|
|
System.out.println(test+"Created "+jwombat);
|
|
checkSize(test,server,newCount+1);
|
|
|
|
popADD(queue, jwombat, test);
|
|
if (queue.peek() != null)
|
|
fail(test+"Received unexpected notifications: "+queue);
|
|
|
|
|
|
int platcount = 0;
|
|
for (String dom : platformDomains) {
|
|
final Set<ObjectName> found =
|
|
server.queryNames(new ObjectName(dom+":*"),null);
|
|
final int jcount = found.size();
|
|
System.out.println(test+"Found "+jcount+" MBeans in "+dom+
|
|
": "+found);
|
|
checkSize(test,server,newCount+1);
|
|
platcount += (jcount-1);
|
|
}
|
|
checkSize(test,server,oldCount+platcount);
|
|
|
|
final ObjectName owombat = new ObjectName("custom:type=Wombat");
|
|
server.createMBean("Wombat", owombat);
|
|
System.out.println(test+"Created "+owombat);
|
|
checkSize(test,server,newCount+2);
|
|
popADD(queue, owombat, test);
|
|
if (queue.peek() != null)
|
|
fail(test+"Received unexpected notifications: "+queue);
|
|
|
|
final Set<ObjectName> jwombatView = (Set<ObjectName>)
|
|
server.invoke(jwombat, "listMatching", new Object[] {null},
|
|
new String[] {ObjectName.class.getName()});
|
|
System.out.println(test+jwombat+" sees: "+jwombatView);
|
|
checkSize(test, server, newCount+2);
|
|
if (jwombatView.size() != (platcount+1))
|
|
fail(test+jwombat+" sees "+jwombatView.size()+" MBeans - should" +
|
|
" have seen "+(platcount+1));
|
|
|
|
final Set<ObjectName> platformMBeans =
|
|
ManagementFactory.getPlatformMBeanServer().
|
|
queryNames(null, null);
|
|
if (!platformMBeans.equals(jwombatView))
|
|
fail(test+jwombat+" should have seen "+platformMBeans);
|
|
|
|
// check that awombat triggers loading of bwombats
|
|
final Set<ObjectName> awombatView = (Set<ObjectName>)
|
|
server.invoke(awombat, "listMatching", new Object[] {null},
|
|
new String[] {ObjectName.class.getName()});
|
|
System.out.println(test+awombat+" sees: "+awombatView);
|
|
final int totalCount = newCount+2+customCount;
|
|
checkSize(test, server, totalCount);
|
|
if (awombatView.size() != totalCount)
|
|
fail(test+jwombat+" sees "+jwombatView.size()+" MBeans - should" +
|
|
" have seen "+totalCount);
|
|
|
|
final Set<ObjectName> allMBeans = server.
|
|
queryNames(null, null);
|
|
if (!allMBeans.equals(awombatView))
|
|
fail(test+awombat+" should have seen "+allMBeans);
|
|
|
|
System.out.println(test + " PASSED");
|
|
|
|
}
|
|
|
|
|
|
public static void lazyStarterTest() throws Exception {
|
|
final String test = "lazyStarterTest: ";
|
|
System.out.println("" +
|
|
"\nThis test checks that it is possible to perform lazy loading" +
|
|
"\nof MBeans in a given domain by using a transient JMXDomain" +
|
|
"\nsubclass for that domain. ");
|
|
|
|
System.out.println(test + " START");
|
|
|
|
// The "global" MBeanServer...
|
|
final MBeanServer platform =
|
|
ManagementFactory.getPlatformMBeanServer();
|
|
|
|
// A notification queue.
|
|
final BlockingQueue<Notification> queue =
|
|
new ArrayBlockingQueue<Notification>(100);
|
|
|
|
// A listener that puts notifs in the queue.
|
|
final NotificationListener l = new NotificationListener() {
|
|
|
|
public void handleNotification(Notification notification,
|
|
Object handback) {
|
|
try {
|
|
if (!queue.offer(notification, 5, TimeUnit.SECONDS)) {
|
|
throw new RuntimeException("timeout exceeded");
|
|
}
|
|
} catch (Exception x) {
|
|
fail(test + "failed to handle notif", x);
|
|
}
|
|
}
|
|
};
|
|
|
|
System.out.println(test+" registering listener with delegate.");
|
|
platform.addNotificationListener(MBeanServerDelegate.DELEGATE_NAME, l,
|
|
null, null);
|
|
|
|
final String ld1 = "lazy1";
|
|
final String ld2 = "lazy2";
|
|
final int wCount = 5;
|
|
final LazyStarterDomain lazy1 = new LazyStarterDomain() {
|
|
@Override
|
|
protected void loadMBeans(MBeanServer server, String domain) {
|
|
registerWombats(server, ld1, wCount);
|
|
}
|
|
};
|
|
final LazyStarterDomain lazy2 = new LazyStarterDomain() {
|
|
@Override
|
|
protected void loadMBeans(MBeanServer server, String domain) {
|
|
registerWombats(server, ld2, wCount);
|
|
}
|
|
};
|
|
final ObjectName lo1 = JMXDomain.getDomainObjectName(ld1);
|
|
final ObjectName lo2 = JMXDomain.getDomainObjectName(ld2);
|
|
|
|
final int initial = platform.getMBeanCount();
|
|
|
|
platform.registerMBean(lazy1, lo1);
|
|
System.out.println(test+"registered "+lo1);
|
|
checkSize(test, platform, initial+1);
|
|
popADD(queue, lo1, test);
|
|
|
|
platform.registerMBean(lazy2, lo2);
|
|
System.out.println(test+"registered "+lo2);
|
|
checkSize(test, platform, initial+2);
|
|
popADD(queue, lo2, test);
|
|
|
|
|
|
final ObjectName awombat = new ObjectName(
|
|
ld1+":type=Wombat,name=wombat#"+wCount/2);
|
|
if (!platform.isRegistered(awombat))
|
|
fail(test+"Expected "+awombat+" to be reggistered!");
|
|
checkSize(test,platform,initial+wCount+1);
|
|
popREM(queue, lo1, test);
|
|
final ObjectName pat1 =
|
|
new ObjectName(ld1+":type=Wombat,name=wombat#*");
|
|
for (int i=0;i<wCount;i++) {
|
|
popADD(queue,pat1,test);
|
|
}
|
|
System.out.println(test+"Found: "+
|
|
platform.queryNames(pat1,null));
|
|
checkSize(test,platform,initial+wCount+1);
|
|
|
|
final Set<ObjectName> all = platform.queryNames(null, null);
|
|
popREM(queue, lo2, test);
|
|
System.out.println(test+"Now found: "+all);
|
|
checkSize(test,platform,initial+wCount+wCount);
|
|
final ObjectName pat2 =
|
|
new ObjectName(ld2+":type=Wombat,name=wombat#*");
|
|
for (int i=0;i<wCount;i++) {
|
|
popADD(queue,pat2,test);
|
|
}
|
|
|
|
System.out.println(test+"check concurrent modification " +
|
|
"of the DomainDispatcher.");
|
|
System.out.println(test+"This will fail if the DomainDispatcher" +
|
|
" doesn't allow concurrent modifications.");
|
|
final HashMap<String,LazyStarterDomain> testConcurrent =
|
|
new HashMap<String,LazyStarterDomain>();
|
|
for (int i=0;i<(100/wCount);i++) {
|
|
final String ld = "concurrent.lazy"+i;
|
|
final LazyStarterDomain lazy = new LazyStarterDomain() {
|
|
@Override
|
|
protected void loadMBeans(MBeanServer server, String domain) {
|
|
registerWombats(server, ld, wCount-1);
|
|
}
|
|
};
|
|
testConcurrent.put(ld, lazy);
|
|
final ObjectName lo = JMXDomain.getDomainObjectName(ld);
|
|
platform.registerMBean(lazy, lo);
|
|
popADD(queue, lo, test);
|
|
}
|
|
|
|
System.out.println(test+"Big autoload: "+
|
|
platform.queryNames(null,null));
|
|
System.out.println(test+"Big after load: "+
|
|
platform.queryNames(null,null));
|
|
if (!platform.queryNames(JMXDomain.getDomainObjectName("*"), null).
|
|
isEmpty()) {
|
|
fail(test+" some domains are still here: "+
|
|
platform.queryNames(
|
|
JMXDomain.getDomainObjectName("*"), null));
|
|
}
|
|
queue.clear();
|
|
System.out.println(test+"PASSED: The DomainDispatcher appears to be " +
|
|
"resilient to concurrent modifications.");
|
|
}
|
|
|
|
public static void main(String... args) throws Exception {
|
|
|
|
lazyTest();
|
|
lazyStarterTest();
|
|
|
|
if (lastException != null)
|
|
throw lastException;
|
|
}
|
|
}
|