This makes the JMX server more thread-safe by switching
to ConcurrentHashMaps and ensuring atomic updates and
initialisation.
ChangeLog:
2008-08-26 Andrew John Hughes <[EMAIL PROTECTED]>
PR classpath/35487:
* gnu/javax/management/Server.java:
(beans): Change to ConcurrentHashMap.
(defaultDomain): Make final.
(outer): Likewise.
(LazyListenersHolder): Added to wrap
listeners, also now a ConcurrentHashMap,
providing lazy initialisation safely.
(sequenceNumber): Documented.
(getBean(ObjectName)): Remove redundant cast.
(addNotificationListener(ObjectName,NotificationListener,
NotificationFilter,Object)): Remove map initialisation
and use holder.
(getObjectInstance(ObjectName)): Remove redundant cast.
(registerMBean(Object,ObjectName)): Add bean atomically.
(removeNotificationListener(ObjectName,NotificationListener)):
Simplified.
(removeNotificationListener(ObjectName,NotificationListener,
NotificationFilter,Object)): Likewise.
(notify(ObjectName,String)): Documented.
--
Andrew :)
Support Free Java!
Contribute to GNU Classpath and the OpenJDK
http://www.gnu.org/software/classpath
http://openjdk.java.net
PGP Key: 94EFD9D8 (http://subkeys.pgp.net)
Fingerprint = F8EF F1EA 401E 2E60 15FA 7927 142C 2591 94EF D9D8
Index: gnu/javax/management/Server.java
===================================================================
RCS file: /sources/classpath/classpath/gnu/javax/management/Server.java,v
retrieving revision 1.8
diff -u -u -r1.8 Server.java
--- gnu/javax/management/Server.java 27 Aug 2008 18:50:35 -0000 1.8
+++ gnu/javax/management/Server.java 27 Aug 2008 20:07:49 -0000
@@ -48,12 +48,13 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
+
import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.ConcurrentHashMap;
import javax.management.Attribute;
import javax.management.AttributeList;
@@ -113,20 +114,20 @@
/**
* The registered beans, represented as a map of
* [EMAIL PROTECTED] javax.management.ObjectName}s to
- * [EMAIL PROTECTED] java.lang.Object}s.
+ * [EMAIL PROTECTED] gnu.javax.management.Server.ServerInfo}s.
*/
- private final Map<ObjectName,ServerInfo> beans =
- new HashMap<ObjectName,ServerInfo>();
+ private final ConcurrentHashMap<ObjectName,ServerInfo> beans =
+ new ConcurrentHashMap<ObjectName,ServerInfo>();
/**
* The default domain.
*/
- private String defaultDomain;
+ private final String defaultDomain;
/**
* The outer server.
*/
- private MBeanServer outer;
+ private final MBeanServer outer;
/**
* The class loader repository.
@@ -135,9 +136,15 @@
/**
* The map of listener delegates to the true
- * listener.
+ * listener. We wrap this in an inner class
+ * to delay initialisation until a listener
+ * is actually added.
*/
- private Map<NotificationListener,NotificationListener> listeners;
+ private static class LazyListenersHolder
+ {
+ private static final Map<NotificationListener,NotificationListener>
listeners =
+ new ConcurrentHashMap<NotificationListener,NotificationListener>();
+ }
/**
* An MBean that emits notifications when an MBean is registered and
@@ -146,6 +153,9 @@
*/
private final MBeanServerDelegate delegate;
+ /**
+ * Provides sequencing for notifications about registrations.
+ */
private static final AtomicLong sequenceNumber = new AtomicLong(1);
/**
@@ -275,7 +285,7 @@
private Object getBean(ObjectName name)
throws InstanceNotFoundException
{
- ServerInfo bean = (ServerInfo) beans.get(name);
+ ServerInfo bean = beans.get(name);
if (bean == null)
throw new InstanceNotFoundException("The bean, " + name +
", was not found.");
@@ -320,12 +330,10 @@
if (bean instanceof NotificationBroadcaster)
{
NotificationBroadcaster bbean = (NotificationBroadcaster) bean;
- if (listeners == null)
- listeners = new HashMap<NotificationListener,NotificationListener>();
NotificationListener indirection = new ServerNotificationListener(bean,
name,
listener);
bbean.addNotificationListener(indirection, filter, passback);
- listeners.put(listener, indirection);
+ LazyListenersHolder.listeners.put(listener, indirection);
}
}
@@ -952,7 +960,6 @@
return defaultDomain;
}
-
/**
* Returns an array containing all the domains used by beans registered
* with this server. The ordering of the array is undefined.
@@ -1078,7 +1085,7 @@
public ObjectInstance getObjectInstance(ObjectName name)
throws InstanceNotFoundException
{
- ServerInfo bean = (ServerInfo) beans.get(name);
+ ServerInfo bean = beans.get(name);
if (bean == null)
throw new InstanceNotFoundException("The bean, " + name +
", was not found.");
@@ -1708,14 +1715,13 @@
throw new MBeanRegistrationException(e, "Pre-registration failed.");
}
}
- if (beans.containsKey(name))
+ ObjectInstance obji = new ObjectInstance(name, className);
+ if (beans.putIfAbsent(name, new ServerInfo(obji, obj)) != null)
{
if (register != null)
register.postRegister(Boolean.FALSE);
throw new InstanceAlreadyExistsException(name + "is already
registered.");
}
- ObjectInstance obji = new ObjectInstance(name, className);
- beans.put(name, new ServerInfo(obji, obj));
if (register != null)
register.postRegister(Boolean.TRUE);
notify(name, MBeanServerNotification.REGISTRATION_NOTIFICATION);
@@ -1754,15 +1760,8 @@
if (bean instanceof NotificationBroadcaster)
{
NotificationBroadcaster bbean = (NotificationBroadcaster) bean;
- NotificationListener indirection = (NotificationListener)
- listeners.get(listener);
- if (indirection == null)
- bbean.removeNotificationListener(listener);
- else
- {
- bbean.removeNotificationListener(indirection);
- listeners.remove(listener);
- }
+ bbean.removeNotificationListener(listener);
+ LazyListenersHolder.listeners.remove(listener);
}
}
@@ -1805,15 +1804,8 @@
if (bean instanceof NotificationEmitter)
{
NotificationEmitter bbean = (NotificationEmitter) bean;
- NotificationListener indirection = (NotificationListener)
- listeners.get(listener);
- if (indirection == null)
- bbean.removeNotificationListener(listener, filter, passback);
- else
- {
- bbean.removeNotificationListener(indirection, filter, passback);
- listeners.remove(listener);
- }
+ bbean.removeNotificationListener(listener, filter, passback);
+ LazyListenersHolder.listeners.remove(listener);
}
}
@@ -2109,6 +2101,15 @@
register.postDeregister();
}
+ /**
+ * Notifies the delegate of beans being registered
+ * and unregistered.
+ *
+ * @param name the bean being registered.
+ * @param type the type of notification;
+ * [EMAIL PROTECTED] REGISTRATION_NOTIFICATION} or
+ * [EMAIL PROTECTED] UNREGISTRATION_NOTIFICATION}.
+ */
private void notify(ObjectName name, String type)
{
delegate.sendNotification