mx4j/src/core/mx4j/server/interceptor NotificationListenerMBeanServerInterceptor.java,1.12,1.13

Simone Bordet <[email protected]> Sun, 23 Oct 2005 21:04:46 +0000
Newsgroups gmane.comp.java.mx4j.cvs
Message-ID <[email protected]>
Update of /cvsroot/mx4j/mx4j/src/core/mx4j/server/interceptor
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19023/src/core/mx4j/server/interceptor

Modified Files:
	NotificationListenerMBeanServerInterceptor.java 
Log Message:
Fix and tests for bug #1335766: NotificationListenerMBeanServerInterceptor leaked memory in case of add of a listener and then remove of it, or in case of add of a listener and the unregistering of the MBean

Index: NotificationListenerMBeanServerInterceptor.java
===================================================================
RCS file: /cvsroot/mx4j/mx4j/src/core/mx4j/server/interceptor/NotificationListenerMBeanServerInterceptor.java,v
retrieving revision 1.12
retrieving revision 1.13
diff -C2 -d -r1.12 -r1.13
*** NotificationListenerMBeanServerInterceptor.java	15 Feb 2005 10:22:44 -0000	1.12
--- NotificationListenerMBeanServerInterceptor.java	23 Oct 2005 21:04:43 -0000	1.13
***************
*** 9,16 ****
  package mx4j.server.interceptor;
  
  import java.util.HashMap;
  import java.util.Map;
! 
  import javax.management.ListenerNotFoundException;
  import javax.management.Notification;
  import javax.management.NotificationFilter;
--- 9,21 ----
  package mx4j.server.interceptor;
  
+ import java.util.ArrayList;
  import java.util.HashMap;
+ import java.util.HashSet;
+ import java.util.Iterator;
+ import java.util.List;
  import java.util.Map;
! import java.util.Set;
  import javax.management.ListenerNotFoundException;
+ import javax.management.MBeanRegistrationException;
  import javax.management.Notification;
  import javax.management.NotificationFilter;
***************
*** 28,32 ****
  public class NotificationListenerMBeanServerInterceptor extends DefaultMBeanServerInterceptor
  {
!    private Map wrappers = new HashMap();
  
     public String getType()
--- 33,38 ----
  public class NotificationListenerMBeanServerInterceptor extends DefaultMBeanServerInterceptor
  {
!    private final Map wrappers = new HashMap();
!    private final Map objectNames = new HashMap();
  
     public String getType()
***************
*** 48,58 ****
      * most of the times (certainly MX4J's NotificationBroadcasterSupport will do).
      */
!    private ListenerWrapper getListenerWrapper(MBeanMetaData metadata, NotificationListener listener)
     {
!       ListenerWrapperKey key = new ListenerWrapperKey(listener, metadata.getMBean());
        ListenerWrapper wrapper = null;
        synchronized (wrappers)
        {
!          wrapper = (ListenerWrapper)wrappers.get(key);
           if (wrapper == null)
           {
--- 54,64 ----
      * most of the times (certainly MX4J's NotificationBroadcasterSupport will do).
      */
!    private ListenerWrapper getOrCreateListenerWrapper(MBeanMetaData metadata, NotificationListener listener)
     {
!       ListenerWrapperKey key = new ListenerWrapperKey(listener, metadata.getObjectName());
        ListenerWrapper wrapper = null;
        synchronized (wrappers)
        {
!          wrapper = getListenerWrapper(key);
           if (wrapper == null)
           {
***************
*** 60,72 ****
              wrappers.put(key, wrapper);
           }
        }
        return wrapper;
     }
  
     public void addNotificationListener(MBeanMetaData metadata, NotificationListener listener, NotificationFilter filter, Object handback)
     {
        if (isEnabled())
        {
!          ListenerWrapper wrapper = getListenerWrapper(metadata, listener);
           super.addNotificationListener(metadata, wrapper, filter, handback);
        }
--- 66,162 ----
              wrappers.put(key, wrapper);
           }
+ 
+          List keys = (List)objectNames.get(metadata.getObjectName());
+          if (keys == null)
+          {
+             keys = new ArrayList();
+             objectNames.put(metadata.getObjectName(), keys);
+          }
+          keys.add(key);
        }
        return wrapper;
     }
  
+    private ListenerWrapper removeListenerWrapper(MBeanMetaData metadata, NotificationListener listener)
+    {
+       ListenerWrapperKey key = new ListenerWrapperKey(listener, metadata.getObjectName());
+       return removeListenerWrapper(key);
+    }
+ 
+    private ListenerWrapper removeListenerWrapper(ListenerWrapperKey key)
+    {
+       synchronized (wrappers)
+       {
+          ListenerWrapper wrapper = (ListenerWrapper)wrappers.remove(key);
+ 
+          List keys = (List)objectNames.get(key.getObjectName());
+          if (keys != null)
+          {
+ 
+          }
+ 
+          return wrapper;
+       }
+    }
+ 
+    private ListenerWrapper decreaseOrRemoveListenerWrapper(MBeanMetaData metadata, NotificationListener listener)
+    {
+       ListenerWrapperKey key = new ListenerWrapperKey(listener, metadata.getObjectName());
+       synchronized (wrappers)
+       {
+          ListenerWrapper wrapper = getListenerWrapper(key);
+          if (wrapper == null) return null;
+          if (wrapper.getReferenceCount() == 1) removeListenerWrapper(key);
+          return wrapper;
+       }
+    }
+ 
+    private ListenerWrapper getListenerWrapper(ListenerWrapperKey key)
+    {
+       synchronized(wrappers)
+       {
+          return (ListenerWrapper)wrappers.get(key);
+       }
+    }
+ 
     public void addNotificationListener(MBeanMetaData metadata, NotificationListener listener, NotificationFilter filter, Object handback)
     {
        if (isEnabled())
        {
!          ListenerWrapper wrapper = null;
!          synchronized (wrappers)
!          {
!             ListenerWrapperKey key = new ListenerWrapperKey(listener, metadata.getObjectName());
!             wrapper = (ListenerWrapper)wrappers.get(key);
!             if (wrapper == null)
!             {
!                wrapper = new ListenerWrapper(listener, metadata.getObjectName());
!                wrappers.put(key, wrapper);
!                wrapper.increaseReferenceCount();
!             }
!             else
!             {
!                // In case the listener is added twice to the same MBean,
!                // for example with different handbacks or filters
!                wrapper.increaseReferenceCount();
!             }
! 
!             Set keys = (Set)objectNames.get(metadata.getObjectName());
!             if (keys == null)
!             {
!                // The MBean has no listeners
!                keys = new HashSet();
!                objectNames.put(metadata.getObjectName(), keys);
!                keys.add(key);
!             }
!             else
!             {
!                // The MBean has other listeners; in case the same listener
!                // is added twice to the same MBean, for example with different
!                // handback or filters, the Set semantic will retain the key only once.
!                keys.add(key);
!             }
!          }
! 
           super.addNotificationListener(metadata, wrapper, filter, handback);
        }
***************
*** 81,85 ****
        if (isEnabled())
        {
!          ListenerWrapper wrapper = getListenerWrapper(metadata, listener);
           super.removeNotificationListener(metadata, wrapper);
        }
--- 171,186 ----
        if (isEnabled())
        {
!          ListenerWrapper wrapper = null;
!          synchronized (wrappers)
!          {
!             ListenerWrapperKey key = new ListenerWrapperKey(listener, metadata.getObjectName());
!             wrapper = (ListenerWrapper)wrappers.remove(key);
!             if (wrapper == null) throw new ListenerNotFoundException("Could not find listener " + listener);
!             wrapper.resetReferenceCount();
! 
!             Set keys = (Set)objectNames.get(metadata.getObjectName());
!             keys.remove(key);
!             if (keys.isEmpty()) objectNames.remove(metadata.getObjectName());
!          }
           super.removeNotificationListener(metadata, wrapper);
        }
***************
*** 94,98 ****
        if (isEnabled())
        {
!          ListenerWrapper wrapper = getListenerWrapper(metadata, listener);
           super.removeNotificationListener(metadata, wrapper, filter, handback);
        }
--- 195,213 ----
        if (isEnabled())
        {
!          ListenerWrapper wrapper = null;
!          synchronized (wrappers)
!          {
!             ListenerWrapperKey key = new ListenerWrapperKey(listener, metadata.getObjectName());
!             wrapper = (ListenerWrapper)wrappers.get(key);
!             if (wrapper == null) throw new ListenerNotFoundException("Could not find listener " + listener);
!             wrapper.decreaseReferenceCount();
!             if (wrapper.getReferenceCount() == 0)
!             {
!                wrappers.remove(key);
!                Set keys = (Set)objectNames.get(metadata.getObjectName());
!                keys.remove(key);
!                if (keys.isEmpty()) objectNames.remove(metadata.getObjectName());
!             }
!          }
           super.removeNotificationListener(metadata, wrapper, filter, handback);
        }
***************
*** 103,110 ****
--- 218,263 ----
     }
  
+    public void registration(MBeanMetaData metadata, int operation) throws MBeanRegistrationException
+    {
+       if (operation == POST_DEREGISTER)
+       {
+          // We must clean up in case the MBean is unregistered
+          // and the listeners are not removed
+          synchronized (wrappers)
+          {
+             Set keys = (Set)objectNames.remove(metadata.getObjectName());
+             for (Iterator iterator = keys.iterator(); iterator.hasNext();)
+             {
+                ListenerWrapperKey key = (ListenerWrapperKey)iterator.next();
+                ListenerWrapper wrapper = (ListenerWrapper)wrappers.remove(key);
+                wrapper.resetReferenceCount();
+             }
+          }
+       }
+ 
+       super.registration(metadata, operation);
+    }
+ 
+    public Map getNotificationListenerWrappers()
+    {
+       return wrappers;
+    }
+ 
+    public int getNotificationListenerWrapperReferenceCount(Object wrapper)
+    {
+       ListenerWrapper listenerWrapper = (ListenerWrapper)wrapper;
+       return listenerWrapper.getReferenceCount();
+    }
+ 
+    public Map getObjectNames()
+    {
+       return objectNames;
+    }
+ 
     private static class ListenerWrapper implements NotificationListener
     {
        private final NotificationListener listener;
        private final ObjectName objectName;
+       private int referenceCount;
  
        private ListenerWrapper(NotificationListener listener, ObjectName name)
***************
*** 140,143 ****
--- 293,316 ----
        }
  
+       private int increaseReferenceCount()
+       {
+          return ++referenceCount;
+       }
+ 
+       private int decreaseReferenceCount()
+       {
+          return --referenceCount;
+       }
+ 
+       public void resetReferenceCount()
+       {
+          referenceCount = 0;
+       }
+ 
+       private int getReferenceCount()
+       {
+          return referenceCount;
+       }
+ 
        public int hashCode()
        {
***************
*** 170,179 ****
     {
        private final NotificationListener listener;
!       private final Object mbean;
  
!       private ListenerWrapperKey(NotificationListener listener, Object mbean)
        {
           this.listener = listener;
!          this.mbean = mbean;
        }
  
--- 343,357 ----
     {
        private final NotificationListener listener;
!       private final ObjectName objectName;
  
!       private ListenerWrapperKey(NotificationListener listener, ObjectName objectName)
        {
           this.listener = listener;
!          this.objectName = objectName;
!       }
! 
!       public ObjectName getObjectName()
!       {
!          return objectName;
        }
  
***************
*** 186,190 ****
  
           if (listener != other.listener) return false;
!          if (mbean != other.mbean) return false;
  
           return true;
--- 364,368 ----
  
           if (listener != other.listener) return false;
!          if (!objectName.equals(other.objectName)) return false;
  
           return true;
***************
*** 194,198 ****
        {
           int result = listener.hashCode();
!          result = 29 * result + mbean.hashCode();
           return result;
        }
--- 372,376 ----
        {
           int result = listener.hashCode();
!          result = 29 * result + objectName.hashCode();
           return result;
        }



-------------------------------------------------------
This SF.Net email is sponsored by the JBoss Inc.
Get Certified Today * Register for a JBoss Training Course
Free Certification Exam for All Training Attendees Through End of 2005
Visit http://www.jboss.com/services/certification for more information