mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-11 05:59:52 +00:00
6747983: jmx namespace: unspecified self-link detection logic
Reviewed-by: emcmanus
This commit is contained in:
parent
38e8cbedc6
commit
c3552d0201
@ -25,22 +25,15 @@
|
||||
package com.sun.jmx.namespace;
|
||||
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.namespace.JMXNamespaces;
|
||||
import javax.management.namespace.JMXNamespace;
|
||||
import javax.management.namespace.JMXNamespacePermission;
|
||||
|
||||
@ -54,8 +47,6 @@ import javax.management.namespace.JMXNamespacePermission;
|
||||
*/
|
||||
public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> {
|
||||
|
||||
private static final Logger PROBE_LOG = Logger.getLogger(
|
||||
JmxProperties.NAMESPACE_LOGGER+".probe");
|
||||
|
||||
// The target name space in which the NamepsaceHandler is mounted.
|
||||
private final String targetNs;
|
||||
@ -64,21 +55,6 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> {
|
||||
|
||||
private final ObjectNameRouter proc;
|
||||
|
||||
/**
|
||||
* Internal hack. The JMXRemoteNamespace can be closed and reconnected.
|
||||
* Each time the JMXRemoteNamespace connects, a probe should be sent
|
||||
* to detect cycle. The MBeanServer exposed by JMXRemoteNamespace thus
|
||||
* implements the DynamicProbe interface, which makes it possible for
|
||||
* this handler to know that it should send a new probe.
|
||||
*
|
||||
* XXX: TODO this probe thing is way too complex and fragile.
|
||||
* This *must* go away or be replaced by something simpler.
|
||||
* ideas are welcomed.
|
||||
**/
|
||||
public static interface DynamicProbe {
|
||||
public boolean isProbeRequested();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of NamespaceInterceptor
|
||||
*/
|
||||
@ -100,164 +76,6 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> {
|
||||
", namespace="+this.targetNs+")";
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: TODO this probe thing is way too complex and fragile.
|
||||
* This *must* go away or be replaced by something simpler.
|
||||
* ideas are welcomed.
|
||||
*/
|
||||
private volatile boolean probed = false;
|
||||
private volatile ObjectName probe;
|
||||
|
||||
// Query Pattern that we will send through the source server in order
|
||||
// to detect self-linking namespaces.
|
||||
//
|
||||
// XXX: TODO this probe thing is way too complex and fragile.
|
||||
// This *must* go away or be replaced by something simpler.
|
||||
// ideas are welcomed.
|
||||
final ObjectName makeProbePattern(ObjectName probe)
|
||||
throws MalformedObjectNameException {
|
||||
|
||||
// we could probably link the probe pattern with the probe - e.g.
|
||||
// using the UUID as key in the pattern - but is it worth it? it
|
||||
// also has some side effects on the context namespace - because
|
||||
// such a probe may get rejected by the jmx.context// namespace.
|
||||
//
|
||||
// The trick here is to devise a pattern that is not likely to
|
||||
// be blocked by intermediate levels. Querying for all namespace
|
||||
// handlers in the source (or source namespace) is more likely to
|
||||
// achieve this goal.
|
||||
//
|
||||
return ObjectName.getInstance("*" +
|
||||
JMXNamespaces.NAMESPACE_SEPARATOR + ":" +
|
||||
JMXNamespace.TYPE_ASSIGNMENT);
|
||||
}
|
||||
|
||||
// tell whether the name pattern corresponds to what might have been
|
||||
// sent as a probe.
|
||||
// XXX: TODO this probe thing is way too complex and fragile.
|
||||
// This *must* go away or be replaced by something simpler.
|
||||
// ideas are welcomed.
|
||||
final boolean isProbePattern(ObjectName name) {
|
||||
final ObjectName p = probe;
|
||||
if (p == null) return false;
|
||||
try {
|
||||
return String.valueOf(name).endsWith(targetNs+
|
||||
JMXNamespaces.NAMESPACE_SEPARATOR + "*" +
|
||||
JMXNamespaces.NAMESPACE_SEPARATOR + ":" +
|
||||
JMXNamespace.TYPE_ASSIGNMENT);
|
||||
} catch (RuntimeException x) {
|
||||
// should not happen.
|
||||
PROBE_LOG.finest("Ignoring unexpected exception in self link detection: "+
|
||||
x);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The first time a request reaches this NamespaceInterceptor, the
|
||||
// interceptor will send a probe to detect whether the underlying
|
||||
// JMXNamespace links to itslef.
|
||||
//
|
||||
// One way to create such self-linking namespace would be for instance
|
||||
// to create a JMXNamespace whose getSourceServer() method would return:
|
||||
// JMXNamespaces.narrowToNamespace(getMBeanServer(),
|
||||
// getObjectName().getDomain())
|
||||
//
|
||||
// If such an MBeanServer is returned, then any call to that MBeanServer
|
||||
// will trigger an infinite loop.
|
||||
// There can be even trickier configurations if remote connections are
|
||||
// involved.
|
||||
//
|
||||
// In order to prevent this from happening, the NamespaceInterceptor will
|
||||
// send a probe, in an attempt to detect whether it will receive it at
|
||||
// the other end. If the probe is received, an exception will be thrown
|
||||
// in order to break the recursion. The probe is only sent once - when
|
||||
// the first request to the namespace occurs. The DynamicProbe interface
|
||||
// can also be used by a Sun JMXNamespace implementation to request the
|
||||
// emission of a probe at any time (see JMXRemoteNamespace
|
||||
// implementation).
|
||||
//
|
||||
// Probes work this way: the NamespaceInterceptor sets a flag and sends
|
||||
// a queryNames() request. If a queryNames() request comes in when the flag
|
||||
// is on, then it deduces that there is a self-linking loop - and instead
|
||||
// of calling queryNames() on the source MBeanServer of the JMXNamespace
|
||||
// handler (which would cause the loop to go on) it breaks the recursion
|
||||
// by returning the probe ObjectName.
|
||||
// If the NamespaceInterceptor receives the probe ObjectName as result of
|
||||
// its original sendProbe() request it knows that it has been looping
|
||||
// back on itslef and throws an IOException...
|
||||
//
|
||||
//
|
||||
// XXX: TODO this probe thing is way too complex and fragile.
|
||||
// This *must* go away or be replaced by something simpler.
|
||||
// ideas are welcomed.
|
||||
//
|
||||
final void sendProbe(MBeanServerConnection msc)
|
||||
throws IOException {
|
||||
try {
|
||||
PROBE_LOG.fine("Sending probe");
|
||||
|
||||
// This is just to prevent any other thread to modify
|
||||
// the probe while the detection cycle is in progress.
|
||||
//
|
||||
final ObjectName probePattern;
|
||||
// we don't want to synchronize on this - we use targetNs
|
||||
// because it's non null and final.
|
||||
synchronized (targetNs) {
|
||||
probed = false;
|
||||
if (probe != null) {
|
||||
throw new IOException("concurent connection in progress");
|
||||
}
|
||||
final String uuid = UUID.randomUUID().toString();
|
||||
final String endprobe =
|
||||
JMXNamespaces.NAMESPACE_SEPARATOR + uuid +
|
||||
":type=Probe,key="+uuid;
|
||||
final ObjectName newprobe =
|
||||
ObjectName.getInstance(endprobe);
|
||||
probePattern = makeProbePattern(newprobe);
|
||||
probe = newprobe;
|
||||
}
|
||||
|
||||
try {
|
||||
PROBE_LOG.finer("Probe query: "+probePattern+" expecting: "+probe);
|
||||
final Set<ObjectName> res = msc.queryNames(probePattern, null);
|
||||
final ObjectName expected = probe;
|
||||
PROBE_LOG.finer("Probe res: "+res);
|
||||
if (res.contains(expected)) {
|
||||
throw new IOException("namespace " +
|
||||
targetNs + " is linking to itself: " +
|
||||
"cycle detected by probe");
|
||||
}
|
||||
} catch (SecurityException x) {
|
||||
PROBE_LOG.finer("Can't check for cycles: " + x);
|
||||
// can't do anything....
|
||||
} catch (RuntimeException x) {
|
||||
PROBE_LOG.finer("Exception raised by queryNames: " + x);
|
||||
throw x;
|
||||
} finally {
|
||||
probe = null;
|
||||
}
|
||||
} catch (MalformedObjectNameException x) {
|
||||
final IOException io =
|
||||
new IOException("invalid name space: probe failed");
|
||||
io.initCause(x);
|
||||
throw io;
|
||||
}
|
||||
PROBE_LOG.fine("Probe returned - no cycles");
|
||||
probed = true;
|
||||
}
|
||||
|
||||
// allows a Sun implementation JMX Namespace, such as the
|
||||
// JMXRemoteNamespace, to control when a probe should be sent.
|
||||
//
|
||||
// XXX: TODO this probe thing is way too complex and fragile.
|
||||
// This *must* go away or be replaced by something simpler.
|
||||
// ideas are welcomed.
|
||||
private boolean isProbeRequested(Object o) {
|
||||
if (o instanceof DynamicProbe)
|
||||
return ((DynamicProbe)o).isProbeRequested();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will send a probe to detect self-linking name spaces.
|
||||
* A self linking namespace is a namespace that links back directly
|
||||
@ -277,29 +95,9 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> {
|
||||
* (see JMXRemoteNamespace implementation).
|
||||
*/
|
||||
private MBeanServer connection() {
|
||||
try {
|
||||
final MBeanServer c = super.source();
|
||||
if (probe != null) // should not happen
|
||||
throw new RuntimeException("connection is being probed");
|
||||
|
||||
if (probed == false || isProbeRequested(c)) {
|
||||
try {
|
||||
// Should not happen if class well behaved.
|
||||
// Never probed. Force it.
|
||||
//System.err.println("sending probe for " +
|
||||
// "target="+targetNs+", source="+srcNs);
|
||||
sendProbe(c);
|
||||
} catch (IOException io) {
|
||||
throw new RuntimeException(io.getMessage(), io);
|
||||
}
|
||||
}
|
||||
|
||||
if (c != null) {
|
||||
return c;
|
||||
}
|
||||
} catch (RuntimeException x) {
|
||||
throw x;
|
||||
}
|
||||
final MBeanServer c = super.source();
|
||||
if (c != null) return c;
|
||||
// should not come here
|
||||
throw new NullPointerException("getMBeanServerConnection");
|
||||
}
|
||||
|
||||
@ -315,24 +113,6 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> {
|
||||
return super.source();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link MBeanServerConnection#queryNames queryNames}
|
||||
* on the underlying
|
||||
* {@link #getMBeanServerConnection MBeanServerConnection}.
|
||||
**/
|
||||
@Override
|
||||
public final Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
|
||||
// XXX: TODO this probe thing is way too complex and fragile.
|
||||
// This *must* go away or be replaced by something simpler.
|
||||
// ideas are welcomed.
|
||||
PROBE_LOG.finer("probe is: "+probe+" pattern is: "+name);
|
||||
if (probe != null && isProbePattern(name)) {
|
||||
PROBE_LOG.finer("Return probe: "+probe);
|
||||
return Collections.singleton(probe);
|
||||
}
|
||||
return super.queryNames(name, query);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObjectName toSource(ObjectName targetName)
|
||||
throws MalformedObjectNameException {
|
||||
|
||||
@ -28,11 +28,9 @@ package javax.management.namespace;
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import com.sun.jmx.namespace.JMXNamespaceUtils;
|
||||
import com.sun.jmx.namespace.NamespaceInterceptor.DynamicProbe;
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.AccessControlException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
@ -44,9 +42,7 @@ import javax.management.AttributeChangeNotification;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanPermission;
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.Notification;
|
||||
import javax.management.NotificationBroadcasterSupport;
|
||||
import javax.management.NotificationEmitter;
|
||||
@ -118,9 +114,6 @@ public class JMXRemoteNamespace
|
||||
*/
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
private static final Logger PROBE_LOG = Logger.getLogger(
|
||||
JmxProperties.NAMESPACE_LOGGER_NAME+".probe");
|
||||
|
||||
|
||||
// This connection listener is used to listen for connection events from
|
||||
// the underlying JMXConnector. It is used in particular to maintain the
|
||||
@ -153,8 +146,7 @@ public class JMXRemoteNamespace
|
||||
// because the one that is actually used is the one supplied by the
|
||||
// override of getMBeanServerConnection().
|
||||
private static class JMXRemoteNamespaceDelegate
|
||||
extends MBeanServerConnectionWrapper
|
||||
implements DynamicProbe {
|
||||
extends MBeanServerConnectionWrapper {
|
||||
private volatile JMXRemoteNamespace parent=null;
|
||||
|
||||
JMXRemoteNamespaceDelegate() {
|
||||
@ -180,9 +172,6 @@ public class JMXRemoteNamespace
|
||||
|
||||
}
|
||||
|
||||
public boolean isProbeRequested() {
|
||||
return this.parent.isProbeRequested();
|
||||
}
|
||||
}
|
||||
|
||||
private static final MBeanNotificationInfo connectNotification =
|
||||
@ -201,7 +190,6 @@ public class JMXRemoteNamespace
|
||||
private volatile MBeanServerConnection server = null;
|
||||
private volatile JMXConnector conn = null;
|
||||
private volatile ClassLoader defaultClassLoader = null;
|
||||
private volatile boolean probed;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@code JMXRemoteNamespace}.
|
||||
@ -241,9 +229,6 @@ public class JMXRemoteNamespace
|
||||
|
||||
// handles (dis)connection events
|
||||
this.listener = new ConnectionListener();
|
||||
|
||||
// XXX TODO: remove the probe, or simplify it.
|
||||
this.probed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -274,10 +259,6 @@ public class JMXRemoteNamespace
|
||||
return optionsMap;
|
||||
}
|
||||
|
||||
boolean isProbeRequested() {
|
||||
return probed==false;
|
||||
}
|
||||
|
||||
public void addNotificationListener(NotificationListener listener,
|
||||
NotificationFilter filter, Object handback) {
|
||||
broadcaster.addNotificationListener(listener, filter, handback);
|
||||
@ -603,26 +584,7 @@ public class JMXRemoteNamespace
|
||||
}
|
||||
|
||||
public void connect() throws IOException {
|
||||
if (conn != null) {
|
||||
try {
|
||||
// This is much too fragile. It must go away!
|
||||
PROBE_LOG.finest("Probing again...");
|
||||
triggerProbe(getMBeanServerConnection());
|
||||
} catch(Exception x) {
|
||||
close();
|
||||
Throwable cause = x;
|
||||
// if the cause is a security exception - rethrows it...
|
||||
while (cause != null) {
|
||||
if (cause instanceof SecurityException)
|
||||
throw (SecurityException) cause;
|
||||
cause = cause.getCause();
|
||||
}
|
||||
throw new IOException("connection failed: cycle?",x);
|
||||
}
|
||||
}
|
||||
LOG.fine("connecting...");
|
||||
// TODO remove these traces
|
||||
// System.err.println(getInitParameter()+" connecting");
|
||||
final Map<String,Object> env =
|
||||
new HashMap<String,Object>(getEnvMap());
|
||||
try {
|
||||
@ -652,79 +614,9 @@ public class JMXRemoteNamespace
|
||||
throw x;
|
||||
}
|
||||
|
||||
|
||||
// XXX Revisit here
|
||||
// Note from the author: This business of switching connection is
|
||||
// incredibly complex. Isn't there any means to simplify it?
|
||||
//
|
||||
switchConnection(conn,aconn,msc);
|
||||
try {
|
||||
triggerProbe(msc);
|
||||
} catch(Exception x) {
|
||||
close();
|
||||
Throwable cause = x;
|
||||
// if the cause is a security exception - rethrows it...
|
||||
while (cause != null) {
|
||||
if (cause instanceof SecurityException)
|
||||
throw (SecurityException) cause;
|
||||
cause = cause.getCause();
|
||||
}
|
||||
throw new IOException("connection failed: cycle?",x);
|
||||
}
|
||||
LOG.fine("connected.");
|
||||
}
|
||||
|
||||
// If this is a self-linking namespace, this method should trigger
|
||||
// the emission of a probe in the wrapping NamespaceInterceptor.
|
||||
// The first call to source() in the wrapping NamespaceInterceptor
|
||||
// causes the emission of the probe.
|
||||
//
|
||||
// Note: the MBeanServer returned by getSourceServer
|
||||
// (our private JMXRemoteNamespaceDelegate inner class)
|
||||
// implements a sun private interface (DynamicProbe) which is
|
||||
// used by the NamespaceInterceptor to determine whether it should
|
||||
// send a probe or not.
|
||||
// We needed this interface here because the NamespaceInterceptor
|
||||
// has otherwise no means to knows that this object has just
|
||||
// connected, and that a new probe should be sent.
|
||||
//
|
||||
// Probes work this way: the NamespaceInterceptor sets a flag and sends
|
||||
// a queryNames() request. If a queryNames() request comes in when the flag
|
||||
// is on, then it deduces that there is a self-linking loop - and instead
|
||||
// of calling queryNames() on the JMXNamespace (which would cause the
|
||||
// loop to go on) it breaks the recursion by returning the probe ObjectName.
|
||||
// If the NamespaceInterceptor receives the probe ObjectName as result of
|
||||
// its original queryNames() it knows that it has been looping back on
|
||||
// itslef and throws an Exception - which will be raised through this
|
||||
// method, thus preventing the connection to be established...
|
||||
//
|
||||
// More info in the com.sun.jmx.namespace.NamespaceInterceptor class
|
||||
//
|
||||
// XXX: TODO this probe thing is way too complex and fragile.
|
||||
// This *must* go away or be replaced by something simpler.
|
||||
// ideas are welcomed.
|
||||
//
|
||||
private void triggerProbe(final MBeanServerConnection msc)
|
||||
throws MalformedObjectNameException, IOException {
|
||||
// Query Pattern that we will send through the source server in order
|
||||
// to detect self-linking namespaces.
|
||||
//
|
||||
//
|
||||
final ObjectName pattern;
|
||||
pattern = ObjectName.getInstance("*" +
|
||||
JMXNamespaces.NAMESPACE_SEPARATOR + ":" +
|
||||
JMXNamespace.TYPE_ASSIGNMENT);
|
||||
probed = false;
|
||||
try {
|
||||
msc.queryNames(pattern, null);
|
||||
probed = true;
|
||||
} catch (AccessControlException x) {
|
||||
// if we have an MBeanPermission missing then do nothing...
|
||||
if (!(x.getPermission() instanceof MBeanPermission))
|
||||
throw x;
|
||||
PROBE_LOG.finer("Can't check for cycles: " + x);
|
||||
probed = false; // no need to do it again...
|
||||
}
|
||||
LOG.fine("connected.");
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
|
||||
@ -35,7 +35,6 @@
|
||||
* NamespaceController.java NamespaceControllerMBean.java
|
||||
* @run main/othervm JMXNamespaceTest
|
||||
*/
|
||||
import java.io.IOException;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MemoryMXBean;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@ -52,10 +51,10 @@ import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.JMX;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.MBeanServerFactory;
|
||||
import javax.management.NotificationEmitter;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.RuntimeOperationsException;
|
||||
import javax.management.StandardMBean;
|
||||
import javax.management.namespace.JMXNamespaces;
|
||||
import javax.management.namespace.JMXNamespace;
|
||||
@ -155,7 +154,7 @@ public class JMXNamespaceTest {
|
||||
}
|
||||
}
|
||||
|
||||
private static class SimpleTestConf {
|
||||
public static class SimpleTestConf {
|
||||
public final Wombat wombat;
|
||||
public final StandardMBean mbean;
|
||||
public final String dirname;
|
||||
@ -457,259 +456,56 @@ public class JMXNamespaceTest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cycle detection.
|
||||
* mkdir test ; cd test ; ln -s . kanga ; ln -s kanga/kanga/roo/kanga roo
|
||||
* touch kanga/roo/wombat
|
||||
**/
|
||||
public static void probeKangaRooTest(String[] args) {
|
||||
final SimpleTestConf conf;
|
||||
public static void verySimpleTest(String[] args) {
|
||||
System.err.println("verySimpleTest: starting");
|
||||
try {
|
||||
conf = new SimpleTestConf(args);
|
||||
try {
|
||||
final JMXServiceURL url =
|
||||
new JMXServiceURL("rmi","localHost",0);
|
||||
final Map<String,Object> empty = Collections.emptyMap();
|
||||
final JMXConnectorServer server =
|
||||
JMXConnectorServerFactory.newJMXConnectorServer(url,
|
||||
empty,conf.server);
|
||||
server.start();
|
||||
final JMXServiceURL address = server.getAddress();
|
||||
final JMXConnector client =
|
||||
JMXConnectorFactory.connect(address,
|
||||
empty);
|
||||
final String[] signature = {
|
||||
JMXServiceURL.class.getName(),
|
||||
Map.class.getName(),
|
||||
};
|
||||
|
||||
final Object[] params = {
|
||||
address,
|
||||
null,
|
||||
};
|
||||
final MBeanServerConnection c =
|
||||
client.getMBeanServerConnection();
|
||||
|
||||
// ln -s . kanga
|
||||
final ObjectName dirName1 =
|
||||
new ObjectName("kanga//:type=JMXNamespace");
|
||||
c.createMBean(JMXRemoteTargetNamespace.class.getName(),
|
||||
dirName1, params,signature);
|
||||
c.invoke(dirName1, "connect", null, null);
|
||||
try {
|
||||
// ln -s kanga//kanga//roo//kanga roo
|
||||
final JMXNamespace local = new JMXNamespace(
|
||||
new MBeanServerConnectionWrapper(null,
|
||||
JMXNamespaceTest.class.getClassLoader()){
|
||||
|
||||
@Override
|
||||
protected MBeanServerConnection getMBeanServerConnection() {
|
||||
return JMXNamespaces.narrowToNamespace(c,
|
||||
"kanga//kanga//roo//kanga"
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
final ObjectName dirName2 =
|
||||
new ObjectName("roo//:type=JMXNamespace");
|
||||
conf.server.registerMBean(local,dirName2);
|
||||
System.out.println(dirName2 + " created!");
|
||||
try {
|
||||
// touch kanga/roo/wombat
|
||||
final ObjectName wombatName1 =
|
||||
new ObjectName("kanga//roo//"+conf.wombatName);
|
||||
final WombatMBean wombat1 =
|
||||
JMX.newMBeanProxy(c,wombatName1,WombatMBean.class);
|
||||
final String newCaption="I am still the same old wombat";
|
||||
Exception x = null;
|
||||
try {
|
||||
wombat1.setCaption(newCaption);
|
||||
} catch (RuntimeOperationsException r) {
|
||||
x=r.getTargetException();
|
||||
System.out.println("Got expected exception: " + x);
|
||||
// r.printStackTrace();
|
||||
}
|
||||
if (x == null)
|
||||
throw new RuntimeException("cycle not detected!");
|
||||
} finally {
|
||||
c.unregisterMBean(dirName2);
|
||||
}
|
||||
} finally {
|
||||
c.unregisterMBean(dirName1);
|
||||
client.close();
|
||||
server.stop();
|
||||
}
|
||||
} finally {
|
||||
conf.close();
|
||||
}
|
||||
System.err.println("probeKangaRooTest PASSED");
|
||||
final MBeanServer srv = MBeanServerFactory.createMBeanServer();
|
||||
srv.registerMBean(new JMXNamespace(
|
||||
JMXNamespaces.narrowToNamespace(srv, "foo")),
|
||||
JMXNamespaces.getNamespaceObjectName("foo"));
|
||||
throw new Exception("Excpected IllegalArgumentException not raised.");
|
||||
} catch (IllegalArgumentException x) {
|
||||
System.err.println("verySimpleTest: got expected exception: "+x);
|
||||
} catch (Exception x) {
|
||||
System.err.println("probeKangaRooTest FAILED: " +x);
|
||||
System.err.println("verySimpleTest FAILED: " +x);
|
||||
x.printStackTrace();
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
System.err.println("verySimpleTest: PASSED");
|
||||
}
|
||||
/**
|
||||
* Test cycle detection 2.
|
||||
* mkdir test ; cd test ; ln -s . roo ; ln -s roo/roo kanga
|
||||
* touch kanga/roo/wombat ; rm roo ; ln -s kanga roo ;
|
||||
* touch kanga/roo/wombat
|
||||
*
|
||||
**/
|
||||
public static void probeKangaRooCycleTest(String[] args) {
|
||||
final SimpleTestConf conf;
|
||||
try {
|
||||
conf = new SimpleTestConf(args);
|
||||
Exception failed = null;
|
||||
try {
|
||||
final JMXServiceURL url =
|
||||
new JMXServiceURL("rmi","localHost",0);
|
||||
final Map<String,Object> empty = Collections.emptyMap();
|
||||
final JMXConnectorServer server =
|
||||
JMXConnectorServerFactory.newJMXConnectorServer(url,
|
||||
empty,conf.server);
|
||||
server.start();
|
||||
final JMXServiceURL address = server.getAddress();
|
||||
final JMXConnector client =
|
||||
JMXConnectorFactory.connect(address,
|
||||
empty);
|
||||
final String[] signature = {
|
||||
JMXServiceURL.class.getName(),
|
||||
Map.class.getName(),
|
||||
};
|
||||
final String[] signature2 = {
|
||||
JMXServiceURL.class.getName(),
|
||||
Map.class.getName(),
|
||||
String.class.getName()
|
||||
};
|
||||
final Object[] params = {
|
||||
address,
|
||||
Collections.emptyMap(),
|
||||
};
|
||||
final Object[] params2 = {
|
||||
address,
|
||||
null,
|
||||
"kanga",
|
||||
};
|
||||
final MBeanServerConnection c =
|
||||
client.getMBeanServerConnection();
|
||||
|
||||
// ln -s . roo
|
||||
final ObjectName dirName1 =
|
||||
new ObjectName("roo//:type=JMXNamespace");
|
||||
c.createMBean(JMXRemoteTargetNamespace.class.getName(),
|
||||
dirName1, params,signature);
|
||||
c.invoke(dirName1, "connect",null,null);
|
||||
try {
|
||||
final Map<String,Object> emptyMap =
|
||||
Collections.emptyMap();
|
||||
final JMXNamespace local = new JMXNamespace(
|
||||
new MBeanServerConnectionWrapper(
|
||||
JMXNamespaces.narrowToNamespace(c,
|
||||
"roo//roo//"),
|
||||
JMXNamespaceTest.class.getClassLoader())) {
|
||||
};
|
||||
// ln -s roo/roo kanga
|
||||
final ObjectName dirName2 =
|
||||
new ObjectName("kanga//:type=JMXNamespace");
|
||||
conf.server.registerMBean(local,dirName2);
|
||||
System.out.println(dirName2 + " created!");
|
||||
try {
|
||||
// touch kanga/roo/wombat
|
||||
final ObjectName wombatName1 =
|
||||
new ObjectName("kanga//roo//"+conf.wombatName);
|
||||
final WombatMBean wombat1 =
|
||||
JMX.newMBeanProxy(c,wombatName1,WombatMBean.class);
|
||||
final String newCaption="I am still the same old wombat";
|
||||
wombat1.setCaption(newCaption);
|
||||
// rm roo
|
||||
c.unregisterMBean(dirName1);
|
||||
// ln -s kanga roo
|
||||
System.err.println("**** Creating " + dirName1 +
|
||||
" ****");
|
||||
c.createMBean(JMXRemoteTargetNamespace.class.getName(),
|
||||
dirName1, params2,signature2);
|
||||
System.err.println("**** Created " + dirName1 +
|
||||
" ****");
|
||||
Exception x = null;
|
||||
try {
|
||||
// touch kanga/roo/wombat
|
||||
wombat1.setCaption(newCaption+" I hope");
|
||||
} catch (RuntimeOperationsException r) {
|
||||
x=(Exception)r.getCause();
|
||||
System.out.println("Got expected exception: " + x);
|
||||
//r.printStackTrace();
|
||||
}
|
||||
if (x == null)
|
||||
throw new RuntimeException("should have failed!");
|
||||
x = null;
|
||||
try {
|
||||
// ls kanga/roo/wombat
|
||||
System.err.println("**** Connecting " + dirName1 +
|
||||
" ****");
|
||||
JMX.newMBeanProxy(c,dirName1,
|
||||
JMXRemoteNamespaceMBean.class).connect();
|
||||
System.err.println("**** Connected " + dirName1 +
|
||||
" ****");
|
||||
} catch (IOException r) {
|
||||
x=r;
|
||||
System.out.println("Got expected exception: " + x);
|
||||
//r.printStackTrace();
|
||||
}
|
||||
System.err.println("**** Expected Exception Not Raised ****");
|
||||
if (x == null) {
|
||||
System.out.println(dirName1+" contains: "+
|
||||
c.queryNames(new ObjectName(
|
||||
dirName1.getDomain()+"*:*"),null));
|
||||
throw new RuntimeException("cycle not detected!");
|
||||
}
|
||||
} catch (Exception t) {
|
||||
if (failed == null) failed = t;
|
||||
} finally {
|
||||
c.unregisterMBean(dirName2);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
c.unregisterMBean(dirName1);
|
||||
} catch (Exception t) {
|
||||
if (failed == null) failed = t;
|
||||
System.err.println("Failed to unregister "+dirName1+
|
||||
": "+t);
|
||||
}
|
||||
try {
|
||||
client.close();
|
||||
} catch (Exception t) {
|
||||
if (failed == null) failed = t;
|
||||
System.err.println("Failed to close client: "+t);
|
||||
}
|
||||
try {
|
||||
server.stop();
|
||||
} catch (Exception t) {
|
||||
if (failed == null) failed = t;
|
||||
System.err.println("Failed to stop server: "+t);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
conf.close();
|
||||
} catch (Exception t) {
|
||||
if (failed == null) failed = t;
|
||||
System.err.println("Failed to stop server: "+t);
|
||||
}
|
||||
}
|
||||
if (failed != null) throw failed;
|
||||
System.err.println("probeKangaRooCycleTest PASSED");
|
||||
public static void verySimpleTest2(String[] args) {
|
||||
System.err.println("verySimpleTest2: starting");
|
||||
try {
|
||||
final MBeanServer srv = MBeanServerFactory.createMBeanServer();
|
||||
final JMXConnectorServer cs = JMXConnectorServerFactory.
|
||||
newJMXConnectorServer(new JMXServiceURL("rmi",null,0),
|
||||
null, srv);
|
||||
cs.start();
|
||||
final JMXConnector cc = JMXConnectorFactory.connect(cs.getAddress());
|
||||
|
||||
srv.registerMBean(new JMXNamespace(
|
||||
new MBeanServerConnectionWrapper(
|
||||
JMXNamespaces.narrowToNamespace(
|
||||
cc.getMBeanServerConnection(),
|
||||
"foo"))),
|
||||
JMXNamespaces.getNamespaceObjectName("foo"));
|
||||
throw new Exception("Excpected IllegalArgumentException not raised.");
|
||||
} catch (IllegalArgumentException x) {
|
||||
System.err.println("verySimpleTest2: got expected exception: "+x);
|
||||
} catch (Exception x) {
|
||||
System.err.println("probeKangaRooCycleTest FAILED: " +x);
|
||||
System.err.println("verySimpleTest2 FAILED: " +x);
|
||||
x.printStackTrace();
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
System.err.println("verySimpleTest2: PASSED");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
simpleTest(args);
|
||||
recursiveTest(args);
|
||||
probeKangaRooTest(args);
|
||||
probeKangaRooCycleTest(args);
|
||||
verySimpleTest(args);
|
||||
verySimpleTest2(args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user