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