提交 ca1683b0 编写于 作者: D dfuchs

6747983: jmx namespace: unspecified self-link detection logic

Reviewed-by: emcmanus
上级 672a5836
...@@ -25,22 +25,15 @@ ...@@ -25,22 +25,15 @@
package com.sun.jmx.namespace; package com.sun.jmx.namespace;
import com.sun.jmx.defaults.JmxProperties; import com.sun.jmx.defaults.JmxProperties;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.management.Attribute; import javax.management.Attribute;
import javax.management.AttributeList; import javax.management.AttributeList;
import javax.management.MBeanServer; import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException; import javax.management.MalformedObjectNameException;
import javax.management.ObjectName; import javax.management.ObjectName;
import javax.management.QueryExp;
import javax.management.namespace.JMXNamespaces;
import javax.management.namespace.JMXNamespace; import javax.management.namespace.JMXNamespace;
import javax.management.namespace.JMXNamespacePermission; import javax.management.namespace.JMXNamespacePermission;
...@@ -54,8 +47,6 @@ import javax.management.namespace.JMXNamespacePermission; ...@@ -54,8 +47,6 @@ import javax.management.namespace.JMXNamespacePermission;
*/ */
public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> { 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. // The target name space in which the NamepsaceHandler is mounted.
private final String targetNs; private final String targetNs;
...@@ -64,21 +55,6 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> { ...@@ -64,21 +55,6 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> {
private final ObjectNameRouter proc; 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 * Creates a new instance of NamespaceInterceptor
*/ */
...@@ -100,164 +76,6 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> { ...@@ -100,164 +76,6 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> {
", namespace="+this.targetNs+")"; ", 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. * This method will send a probe to detect self-linking name spaces.
* A self linking namespace is a namespace that links back directly * A self linking namespace is a namespace that links back directly
...@@ -277,29 +95,9 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> { ...@@ -277,29 +95,9 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> {
* (see JMXRemoteNamespace implementation). * (see JMXRemoteNamespace implementation).
*/ */
private MBeanServer connection() { private MBeanServer connection() {
try {
final MBeanServer c = super.source(); final MBeanServer c = super.source();
if (probe != null) // should not happen if (c != null) return c;
throw new RuntimeException("connection is being probed"); // should not come here
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;
}
throw new NullPointerException("getMBeanServerConnection"); throw new NullPointerException("getMBeanServerConnection");
} }
...@@ -315,24 +113,6 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> { ...@@ -315,24 +113,6 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> {
return super.source(); 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 @Override
protected ObjectName toSource(ObjectName targetName) protected ObjectName toSource(ObjectName targetName)
throws MalformedObjectNameException { throws MalformedObjectNameException {
......
...@@ -28,11 +28,9 @@ package javax.management.namespace; ...@@ -28,11 +28,9 @@ package javax.management.namespace;
import com.sun.jmx.defaults.JmxProperties; import com.sun.jmx.defaults.JmxProperties;
import com.sun.jmx.mbeanserver.Util; import com.sun.jmx.mbeanserver.Util;
import com.sun.jmx.namespace.JMXNamespaceUtils; import com.sun.jmx.namespace.JMXNamespaceUtils;
import com.sun.jmx.namespace.NamespaceInterceptor.DynamicProbe;
import com.sun.jmx.remote.util.EnvHelp; import com.sun.jmx.remote.util.EnvHelp;
import java.io.IOException; import java.io.IOException;
import java.security.AccessControlException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
...@@ -44,9 +42,7 @@ import javax.management.AttributeChangeNotification; ...@@ -44,9 +42,7 @@ import javax.management.AttributeChangeNotification;
import javax.management.InstanceNotFoundException; import javax.management.InstanceNotFoundException;
import javax.management.ListenerNotFoundException; import javax.management.ListenerNotFoundException;
import javax.management.MBeanNotificationInfo; import javax.management.MBeanNotificationInfo;
import javax.management.MBeanPermission;
import javax.management.MBeanServerConnection; import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.Notification; import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport; import javax.management.NotificationBroadcasterSupport;
import javax.management.NotificationEmitter; import javax.management.NotificationEmitter;
...@@ -118,9 +114,6 @@ public class JMXRemoteNamespace ...@@ -118,9 +114,6 @@ public class JMXRemoteNamespace
*/ */
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; 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 // This connection listener is used to listen for connection events from
// the underlying JMXConnector. It is used in particular to maintain the // the underlying JMXConnector. It is used in particular to maintain the
...@@ -153,8 +146,7 @@ public class JMXRemoteNamespace ...@@ -153,8 +146,7 @@ public class JMXRemoteNamespace
// because the one that is actually used is the one supplied by the // because the one that is actually used is the one supplied by the
// override of getMBeanServerConnection(). // override of getMBeanServerConnection().
private static class JMXRemoteNamespaceDelegate private static class JMXRemoteNamespaceDelegate
extends MBeanServerConnectionWrapper extends MBeanServerConnectionWrapper {
implements DynamicProbe {
private volatile JMXRemoteNamespace parent=null; private volatile JMXRemoteNamespace parent=null;
JMXRemoteNamespaceDelegate() { JMXRemoteNamespaceDelegate() {
...@@ -180,9 +172,6 @@ public class JMXRemoteNamespace ...@@ -180,9 +172,6 @@ public class JMXRemoteNamespace
} }
public boolean isProbeRequested() {
return this.parent.isProbeRequested();
}
} }
private static final MBeanNotificationInfo connectNotification = private static final MBeanNotificationInfo connectNotification =
...@@ -201,7 +190,6 @@ public class JMXRemoteNamespace ...@@ -201,7 +190,6 @@ public class JMXRemoteNamespace
private volatile MBeanServerConnection server = null; private volatile MBeanServerConnection server = null;
private volatile JMXConnector conn = null; private volatile JMXConnector conn = null;
private volatile ClassLoader defaultClassLoader = null; private volatile ClassLoader defaultClassLoader = null;
private volatile boolean probed;
/** /**
* Creates a new instance of {@code JMXRemoteNamespace}. * Creates a new instance of {@code JMXRemoteNamespace}.
...@@ -241,9 +229,6 @@ public class JMXRemoteNamespace ...@@ -241,9 +229,6 @@ public class JMXRemoteNamespace
// handles (dis)connection events // handles (dis)connection events
this.listener = new ConnectionListener(); this.listener = new ConnectionListener();
// XXX TODO: remove the probe, or simplify it.
this.probed = false;
} }
/** /**
...@@ -274,10 +259,6 @@ public class JMXRemoteNamespace ...@@ -274,10 +259,6 @@ public class JMXRemoteNamespace
return optionsMap; return optionsMap;
} }
boolean isProbeRequested() {
return probed==false;
}
public void addNotificationListener(NotificationListener listener, public void addNotificationListener(NotificationListener listener,
NotificationFilter filter, Object handback) { NotificationFilter filter, Object handback) {
broadcaster.addNotificationListener(listener, filter, handback); broadcaster.addNotificationListener(listener, filter, handback);
...@@ -603,26 +584,7 @@ public class JMXRemoteNamespace ...@@ -603,26 +584,7 @@ public class JMXRemoteNamespace
} }
public void connect() throws IOException { 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..."); LOG.fine("connecting...");
// TODO remove these traces
// System.err.println(getInitParameter()+" connecting");
final Map<String,Object> env = final Map<String,Object> env =
new HashMap<String,Object>(getEnvMap()); new HashMap<String,Object>(getEnvMap());
try { try {
...@@ -652,79 +614,9 @@ public class JMXRemoteNamespace ...@@ -652,79 +614,9 @@ public class JMXRemoteNamespace
throw x; 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); 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 LOG.fine("connected.");
// 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...
}
} }
public void close() throws IOException { public void close() throws IOException {
......
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
* NamespaceController.java NamespaceControllerMBean.java * NamespaceController.java NamespaceControllerMBean.java
* @run main/othervm JMXNamespaceTest * @run main/othervm JMXNamespaceTest
*/ */
import java.io.IOException;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean; import java.lang.management.MemoryMXBean;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
...@@ -52,10 +51,10 @@ import javax.management.InvalidAttributeValueException; ...@@ -52,10 +51,10 @@ import javax.management.InvalidAttributeValueException;
import javax.management.JMX; import javax.management.JMX;
import javax.management.MBeanServer; import javax.management.MBeanServer;
import javax.management.MBeanServerConnection; import javax.management.MBeanServerConnection;
import javax.management.MBeanServerFactory;
import javax.management.NotificationEmitter; import javax.management.NotificationEmitter;
import javax.management.ObjectInstance; import javax.management.ObjectInstance;
import javax.management.ObjectName; import javax.management.ObjectName;
import javax.management.RuntimeOperationsException;
import javax.management.StandardMBean; import javax.management.StandardMBean;
import javax.management.namespace.JMXNamespaces; import javax.management.namespace.JMXNamespaces;
import javax.management.namespace.JMXNamespace; import javax.management.namespace.JMXNamespace;
...@@ -155,7 +154,7 @@ public class JMXNamespaceTest { ...@@ -155,7 +154,7 @@ public class JMXNamespaceTest {
} }
} }
private static class SimpleTestConf { public static class SimpleTestConf {
public final Wombat wombat; public final Wombat wombat;
public final StandardMBean mbean; public final StandardMBean mbean;
public final String dirname; public final String dirname;
...@@ -457,259 +456,56 @@ public class JMXNamespaceTest { ...@@ -457,259 +456,56 @@ public class JMXNamespaceTest {
} }
} }
/** public static void verySimpleTest(String[] args) {
* Test cycle detection. System.err.println("verySimpleTest: starting");
* 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;
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 { try {
// ln -s kanga//kanga//roo//kanga roo final MBeanServer srv = MBeanServerFactory.createMBeanServer();
final JMXNamespace local = new JMXNamespace( srv.registerMBean(new JMXNamespace(
new MBeanServerConnectionWrapper(null, JMXNamespaces.narrowToNamespace(srv, "foo")),
JMXNamespaceTest.class.getClassLoader()){ JMXNamespaces.getNamespaceObjectName("foo"));
throw new Exception("Excpected IllegalArgumentException not raised.");
@Override } catch (IllegalArgumentException x) {
protected MBeanServerConnection getMBeanServerConnection() { System.err.println("verySimpleTest: got expected exception: "+x);
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");
} catch (Exception x) { } catch (Exception x) {
System.err.println("probeKangaRooTest FAILED: " +x); System.err.println("verySimpleTest FAILED: " +x);
x.printStackTrace(); x.printStackTrace();
throw new RuntimeException(x); 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 public static void verySimpleTest2(String[] args) {
final ObjectName dirName1 = System.err.println("verySimpleTest2: starting");
new ObjectName("roo//:type=JMXNamespace");
c.createMBean(JMXRemoteTargetNamespace.class.getName(),
dirName1, params,signature);
c.invoke(dirName1, "connect",null,null);
try { try {
final Map<String,Object> emptyMap = final MBeanServer srv = MBeanServerFactory.createMBeanServer();
Collections.emptyMap(); final JMXConnectorServer cs = JMXConnectorServerFactory.
final JMXNamespace local = new JMXNamespace( newJMXConnectorServer(new JMXServiceURL("rmi",null,0),
null, srv);
cs.start();
final JMXConnector cc = JMXConnectorFactory.connect(cs.getAddress());
srv.registerMBean(new JMXNamespace(
new MBeanServerConnectionWrapper( new MBeanServerConnectionWrapper(
JMXNamespaces.narrowToNamespace(c, JMXNamespaces.narrowToNamespace(
"roo//roo//"), cc.getMBeanServerConnection(),
JMXNamespaceTest.class.getClassLoader())) { "foo"))),
}; JMXNamespaces.getNamespaceObjectName("foo"));
// ln -s roo/roo kanga throw new Exception("Excpected IllegalArgumentException not raised.");
final ObjectName dirName2 = } catch (IllegalArgumentException x) {
new ObjectName("kanga//:type=JMXNamespace"); System.err.println("verySimpleTest2: got expected exception: "+x);
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");
} catch (Exception x) { } catch (Exception x) {
System.err.println("probeKangaRooCycleTest FAILED: " +x); System.err.println("verySimpleTest2 FAILED: " +x);
x.printStackTrace(); x.printStackTrace();
throw new RuntimeException(x); throw new RuntimeException(x);
} }
System.err.println("verySimpleTest2: PASSED");
} }
public static void main(String[] args) { public static void main(String[] args) {
simpleTest(args); simpleTest(args);
recursiveTest(args); recursiveTest(args);
probeKangaRooTest(args); verySimpleTest(args);
probeKangaRooCycleTest(args); verySimpleTest2(args);
} }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册