Package mx4j.server.interceptor

Source Code of mx4j.server.interceptor.NotificationListenerMBeanServerInterceptor

/*
* Copyright (C) The MX4J Contributors.
* All rights reserved.
*
* This software is distributed under the terms of the MX4J License version 1.0.
* See the terms of the MX4J License in the documentation provided with this software.
*/

package mx4j.server.interceptor;

import java.util.HashMap;
import java.util.Map;

import javax.management.ListenerNotFoundException;
import javax.management.Notification;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectName;

import mx4j.server.MBeanMetaData;

/**
* Interceptor that takes care of replacing the source of Notifications to the
* ObjectName of the NotificationBroadcaster that emitted it.
*
* @version $Revision: 1.12 $
*/
public class NotificationListenerMBeanServerInterceptor extends DefaultMBeanServerInterceptor
{
   private Map wrappers = new HashMap();

   public String getType()
   {
      return "notificationlistener";
   }

   /**
    * The goal of this machinery is to make sure that, for a given emitter,
    * when a listener is removed the listener can be identity compared
    * (using ==) with a listener that has been previously added to the same emitter.
    * This is the reason why {@link ListenerWrapperKey#equals} has been implemented
    * using identity (==) and not equality (equals()).
    * The listener instance passed by the MBeanServer to the emitter when removing
    * the listener itself should be the same passed when the listener was added.
    * If for any reason the listener is not found, it will be wrapped with a new
    * wrapper that will allow the emitter to compare listener by equality
    * (what normally happens using Collection data structures) and behave correctly
    * 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)
         {
            wrapper = new ListenerWrapper(listener, metadata.getObjectName());
            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);
      }
      else
      {
         super.addNotificationListener(metadata, listener, filter, handback);
      }
   }

   public void removeNotificationListener(MBeanMetaData metadata, NotificationListener listener) throws ListenerNotFoundException
   {
      if (isEnabled())
      {
         ListenerWrapper wrapper = getListenerWrapper(metadata, listener);
         super.removeNotificationListener(metadata, wrapper);
      }
      else
      {
         super.removeNotificationListener(metadata, listener);
      }
   }

   public void removeNotificationListener(MBeanMetaData metadata, NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException
   {
      if (isEnabled())
      {
         ListenerWrapper wrapper = getListenerWrapper(metadata, listener);
         super.removeNotificationListener(metadata, wrapper, filter, handback);
      }
      else
      {
         super.removeNotificationListener(metadata, listener, filter, handback);
      }
   }

   private static class ListenerWrapper implements NotificationListener
   {
      private final NotificationListener listener;
      private final ObjectName objectName;

      private ListenerWrapper(NotificationListener listener, ObjectName name)
      {
         this.listener = listener;
         this.objectName = name;
      }

      public void handleNotification(Notification notification, Object handback)
      {
         // The JMX spec does not specify how to change the source to be the ObjectName
         // of the broadcaster. If we serialize the calls to the listeners, then it's
         // possible to change the source and restore it back to the old value before
         // calling the next listener; but if we want to support concurrent calls
         // to the listeners, this is not possible. Here I chose to support concurrent
         // calls so I change the value once and I never restore it.
         Object src = notification.getSource();
         if (!(src instanceof ObjectName))
         {
            // Change the source to be the ObjectName of the notification broadcaster
            // if we are not already an ObjectName (compliant with RI behaviour)
            notification.setSource(objectName);
         }

         // Notify the real listener
         NotificationListener listener = getTargetListener();
         listener.handleNotification(notification, handback);
      }

      private NotificationListener getTargetListener()
      {
         return listener;
      }

      public int hashCode()
      {
         return getTargetListener().hashCode();
      }

      public boolean equals(Object obj)
      {
         if (obj == null) return false;
         if (obj == this) return true;

         try
         {
            ListenerWrapper other = (ListenerWrapper)obj;
            return getTargetListener().equals(other.getTargetListener());
         }
         catch (ClassCastException ignored)
         {
         }
         return false;
      }

      public String toString()
      {
         return getTargetListener().toString();
      }
   }

   private static class ListenerWrapperKey
   {
      private final NotificationListener listener;
      private final Object mbean;

      private ListenerWrapperKey(NotificationListener listener, Object mbean)
      {
         this.listener = listener;
         this.mbean = mbean;
      }

      public boolean equals(Object obj)
      {
         if (this == obj) return true;
         if (!(obj instanceof ListenerWrapperKey)) return false;

         ListenerWrapperKey other = (ListenerWrapperKey)obj;

         if (listener != other.listener) return false;
         if (mbean != other.mbean) return false;

         return true;
      }

      public int hashCode()
      {
         int result = listener.hashCode();
         result = 29 * result + mbean.hashCode();
         return result;
      }
   }
}
TOP

Related Classes of mx4j.server.interceptor.NotificationListenerMBeanServerInterceptor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
o:coftware@gmail.com">coftware#gmail.com.