jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java
changeset 7170 285c02ecbb8a
parent 5506 202f599c92aa
child 14210 042f1a001234
--- a/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java	Fri Nov 05 08:18:46 2010 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java	Fri Nov 05 17:15:44 2010 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. 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
@@ -45,6 +45,8 @@
 import javax.management.ListenerNotFoundException;
 import javax.management.MBeanPermission;
 import javax.management.MBeanServer;
+import javax.management.MBeanServerDelegate;
+import javax.management.MBeanServerNotification;
 import javax.management.Notification;
 import javax.management.NotificationBroadcaster;
 import javax.management.NotificationFilter;
@@ -272,6 +274,7 @@
             nr = notifBuffer.fetchNotifications(bufferFilter,
                 startSequenceNumber,
                 t, maxNotifications);
+            snoopOnUnregister(nr);
         } catch (InterruptedException ire) {
             nr = new NotificationResult(0L, 0L, new TargetedNotification[0]);
         }
@@ -283,6 +286,34 @@
         return nr;
     }
 
+    // The standard RMI connector client will register a listener on the MBeanServerDelegate
+    // in order to be told when MBeans are unregistered.  We snoop on fetched notifications
+    // so that we can know too, and remove the corresponding entry from the listenerMap.
+    // See 6957378.
+    private void snoopOnUnregister(NotificationResult nr) {
+        Set<IdAndFilter> delegateSet = listenerMap.get(MBeanServerDelegate.DELEGATE_NAME);
+        if (delegateSet == null || delegateSet.isEmpty()) {
+            return;
+        }
+        for (TargetedNotification tn : nr.getTargetedNotifications()) {
+            Integer id = tn.getListenerID();
+            for (IdAndFilter idaf : delegateSet) {
+                if (idaf.id == id) {
+                    // This is a notification from the MBeanServerDelegate.
+                    Notification n = tn.getNotification();
+                    if (n instanceof MBeanServerNotification &&
+                            n.getType().equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) {
+                        MBeanServerNotification mbsn = (MBeanServerNotification) n;
+                        ObjectName gone = mbsn.getMBeanName();
+                        synchronized (listenerMap) {
+                            listenerMap.remove(gone);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     public void terminate() {
         if (logger.traceOn()) {
             logger.trace("terminate", "Be called.");
@@ -418,10 +449,12 @@
             return this.filter;
         }
 
+        @Override
         public int hashCode() {
             return id.hashCode();
         }
 
+        @Override
         public boolean equals(Object o) {
             return ((o instanceof IdAndFilter) &&
                     ((IdAndFilter) o).getId().equals(getId()));