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

Reply via email to