Home » openjdk-7 » javax » management » [javadoc | source]

    1   /*
    2    * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package javax.management;
   27   
   28   import java.util.Collections;
   29   import java.util.List;
   30   import java.util.concurrent.CopyOnWriteArrayList;
   31   import java.util.concurrent.Executor;
   32   
   33   import com.sun.jmx.remote.util.ClassLogger;
   34   
   35   /**
   36    * <p>Provides an implementation of {@link
   37    * javax.management.NotificationEmitter NotificationEmitter}
   38    * interface.  This can be used as the super class of an MBean that
   39    * sends notifications.</p>
   40    *
   41    * <p>By default, the notification dispatch model is synchronous.
   42    * That is, when a thread calls sendNotification, the
   43    * <code>NotificationListener.handleNotification</code> method of each listener
   44    * is called within that thread. You can override this default
   45    * by overriding <code>handleNotification</code> in a subclass, or by passing an
   46    * Executor to the constructor.</p>
   47    *
   48    * <p>If the method call of a filter or listener throws an {@link Exception},
   49    * then that exception does not prevent other listeners from being invoked.  However,
   50    * if the method call of a filter or of {@code Executor.execute} or of
   51    * {@code handleNotification} (when no {@code Excecutor} is specified) throws an
   52    * {@link Error}, then that {@code Error} is propagated to the caller of
   53    * {@link #sendNotification sendNotification}.</p>
   54    *
   55    * <p>Remote listeners added using the JMX Remote API (see JMXConnector) are not
   56    * usually called synchronously.  That is, when sendNotification returns, it is
   57    * not guaranteed that any remote listeners have yet received the notification.</p>
   58    *
   59    * @since 1.5
   60    */
   61   public class NotificationBroadcasterSupport implements NotificationEmitter {
   62       /**
   63        * Constructs a NotificationBroadcasterSupport where each listener is invoked by the
   64        * thread sending the notification. This constructor is equivalent to
   65        * {@link NotificationBroadcasterSupport#NotificationBroadcasterSupport(Executor,
   66        * MBeanNotificationInfo[] info) NotificationBroadcasterSupport(null, null)}.
   67        */
   68       public NotificationBroadcasterSupport() {
   69           this(null, (MBeanNotificationInfo[]) null);
   70       }
   71   
   72       /**
   73        * Constructs a NotificationBroadcasterSupport where each listener is invoked using
   74        * the given {@link java.util.concurrent.Executor}. When {@link #sendNotification
   75        * sendNotification} is called, a listener is selected if it was added with a null
   76        * {@link NotificationFilter}, or if {@link NotificationFilter#isNotificationEnabled
   77        * isNotificationEnabled} returns true for the notification being sent. The call to
   78        * <code>NotificationFilter.isNotificationEnabled</code> takes place in the thread
   79        * that called <code>sendNotification</code>. Then, for each selected listener,
   80        * {@link Executor#execute executor.execute} is called with a command
   81        * that calls the <code>handleNotification</code> method.
   82        * This constructor is equivalent to
   83        * {@link NotificationBroadcasterSupport#NotificationBroadcasterSupport(Executor,
   84        * MBeanNotificationInfo[] info) NotificationBroadcasterSupport(executor, null)}.
   85        * @param executor an executor used by the method <code>sendNotification</code> to
   86        * send each notification. If it is null, the thread calling <code>sendNotification</code>
   87        * will invoke the <code>handleNotification</code> method itself.
   88        * @since 1.6
   89        */
   90       public NotificationBroadcasterSupport(Executor executor) {
   91           this(executor, (MBeanNotificationInfo[]) null);
   92       }
   93   
   94       /**
   95        * <p>Constructs a NotificationBroadcasterSupport with information
   96        * about the notifications that may be sent.  Each listener is
   97        * invoked by the thread sending the notification.  This
   98        * constructor is equivalent to {@link
   99        * NotificationBroadcasterSupport#NotificationBroadcasterSupport(Executor,
  100        * MBeanNotificationInfo[] info)
  101        * NotificationBroadcasterSupport(null, info)}.</p>
  102        *
  103        * <p>If the <code>info</code> array is not empty, then it is
  104        * cloned by the constructor as if by {@code info.clone()}, and
  105        * each call to {@link #getNotificationInfo()} returns a new
  106        * clone.</p>
  107        *
  108        * @param info an array indicating, for each notification this
  109        * MBean may send, the name of the Java class of the notification
  110        * and the notification type.  Can be null, which is equivalent to
  111        * an empty array.
  112        *
  113        * @since 1.6
  114        */
  115       public NotificationBroadcasterSupport(MBeanNotificationInfo... info) {
  116           this(null, info);
  117       }
  118   
  119       /**
  120        * <p>Constructs a NotificationBroadcasterSupport with information about the notifications that may be sent,
  121        * and where each listener is invoked using the given {@link java.util.concurrent.Executor}.</p>
  122        *
  123        * <p>When {@link #sendNotification sendNotification} is called, a
  124        * listener is selected if it was added with a null {@link
  125        * NotificationFilter}, or if {@link
  126        * NotificationFilter#isNotificationEnabled isNotificationEnabled}
  127        * returns true for the notification being sent. The call to
  128        * <code>NotificationFilter.isNotificationEnabled</code> takes
  129        * place in the thread that called
  130        * <code>sendNotification</code>. Then, for each selected
  131        * listener, {@link Executor#execute executor.execute} is called
  132        * with a command that calls the <code>handleNotification</code>
  133        * method.</p>
  134        *
  135        * <p>If the <code>info</code> array is not empty, then it is
  136        * cloned by the constructor as if by {@code info.clone()}, and
  137        * each call to {@link #getNotificationInfo()} returns a new
  138        * clone.</p>
  139        *
  140        * @param executor an executor used by the method
  141        * <code>sendNotification</code> to send each notification. If it
  142        * is null, the thread calling <code>sendNotification</code> will
  143        * invoke the <code>handleNotification</code> method itself.
  144        *
  145        * @param info an array indicating, for each notification this
  146        * MBean may send, the name of the Java class of the notification
  147        * and the notification type.  Can be null, which is equivalent to
  148        * an empty array.
  149        *
  150        * @since 1.6
  151        */
  152       public NotificationBroadcasterSupport(Executor executor,
  153                                             MBeanNotificationInfo... info) {
  154           this.executor = (executor != null) ? executor : defaultExecutor;
  155   
  156           notifInfo = info == null ? NO_NOTIFICATION_INFO : info.clone();
  157       }
  158   
  159       /**
  160        * Adds a listener.
  161        *
  162        * @param listener The listener to receive notifications.
  163        * @param filter The filter object. If filter is null, no
  164        * filtering will be performed before handling notifications.
  165        * @param handback An opaque object to be sent back to the
  166        * listener when a notification is emitted. This object cannot be
  167        * used by the Notification broadcaster object. It should be
  168        * resent unchanged with the notification to the listener.
  169        *
  170        * @exception IllegalArgumentException thrown if the listener is null.
  171        *
  172        * @see #removeNotificationListener
  173        */
  174       public void addNotificationListener(NotificationListener listener,
  175                                           NotificationFilter filter,
  176                                           Object handback) {
  177   
  178           if (listener == null) {
  179               throw new IllegalArgumentException ("Listener can't be null") ;
  180           }
  181   
  182           listenerList.add(new ListenerInfo(listener, filter, handback));
  183       }
  184   
  185       public void removeNotificationListener(NotificationListener listener)
  186               throws ListenerNotFoundException {
  187   
  188           ListenerInfo wildcard = new WildcardListenerInfo(listener);
  189           boolean removed =
  190               listenerList.removeAll(Collections.singleton(wildcard));
  191           if (!removed)
  192               throw new ListenerNotFoundException("Listener not registered");
  193       }
  194   
  195       public void removeNotificationListener(NotificationListener listener,
  196                                              NotificationFilter filter,
  197                                              Object handback)
  198               throws ListenerNotFoundException {
  199   
  200           ListenerInfo li = new ListenerInfo(listener, filter, handback);
  201           boolean removed = listenerList.remove(li);
  202           if (!removed) {
  203               throw new ListenerNotFoundException("Listener not registered " +
  204                                                   "(with this filter and " +
  205                                                   "handback)");
  206               // or perhaps not registered at all
  207           }
  208       }
  209   
  210       public MBeanNotificationInfo[] getNotificationInfo() {
  211           if (notifInfo.length == 0)
  212               return notifInfo;
  213           else
  214               return notifInfo.clone();
  215       }
  216   
  217   
  218       /**
  219        * Sends a notification.
  220        *
  221        * If an {@code Executor} was specified in the constructor, it will be given one
  222        * task per selected listener to deliver the notification to that listener.
  223        *
  224        * @param notification The notification to send.
  225        */
  226       public void sendNotification(Notification notification) {
  227   
  228           if (notification == null) {
  229               return;
  230           }
  231   
  232           boolean enabled;
  233   
  234           for (ListenerInfo li : listenerList) {
  235               try {
  236                   enabled = li.filter == null ||
  237                       li.filter.isNotificationEnabled(notification);
  238               } catch (Exception e) {
  239                   if (logger.debugOn()) {
  240                       logger.debug("sendNotification", e);
  241                   }
  242   
  243                   continue;
  244               }
  245   
  246               if (enabled) {
  247                   executor.execute(new SendNotifJob(notification, li));
  248               }
  249           }
  250       }
  251   
  252       /**
  253        * <p>This method is called by {@link #sendNotification
  254        * sendNotification} for each listener in order to send the
  255        * notification to that listener.  It can be overridden in
  256        * subclasses to change the behavior of notification delivery,
  257        * for instance to deliver the notification in a separate
  258        * thread.</p>
  259        *
  260        * <p>The default implementation of this method is equivalent to
  261        * <pre>
  262        * listener.handleNotification(notif, handback);
  263        * </pre>
  264        *
  265        * @param listener the listener to which the notification is being
  266        * delivered.
  267        * @param notif the notification being delivered to the listener.
  268        * @param handback the handback object that was supplied when the
  269        * listener was added.
  270        *
  271        */
  272       protected void handleNotification(NotificationListener listener,
  273                                         Notification notif, Object handback) {
  274           listener.handleNotification(notif, handback);
  275       }
  276   
  277       // private stuff
  278       private static class ListenerInfo {
  279           NotificationListener listener;
  280           NotificationFilter filter;
  281           Object handback;
  282   
  283           ListenerInfo(NotificationListener listener,
  284                        NotificationFilter filter,
  285                        Object handback) {
  286               this.listener = listener;
  287               this.filter = filter;
  288               this.handback = handback;
  289           }
  290   
  291           public boolean equals(Object o) {
  292               if (!(o instanceof ListenerInfo))
  293                   return false;
  294               ListenerInfo li = (ListenerInfo) o;
  295               if (li instanceof WildcardListenerInfo)
  296                   return (li.listener == listener);
  297               else
  298                   return (li.listener == listener && li.filter == filter
  299                           && li.handback == handback);
  300           }
  301       }
  302   
  303       private static class WildcardListenerInfo extends ListenerInfo {
  304           WildcardListenerInfo(NotificationListener listener) {
  305               super(listener, null, null);
  306           }
  307   
  308           public boolean equals(Object o) {
  309               assert (!(o instanceof WildcardListenerInfo));
  310               return o.equals(this);
  311           }
  312       }
  313   
  314       private List<ListenerInfo> listenerList =
  315           new CopyOnWriteArrayList<ListenerInfo>();
  316   
  317       // since 1.6
  318       private final Executor executor;
  319       private final MBeanNotificationInfo[] notifInfo;
  320   
  321       private final static Executor defaultExecutor = new Executor() {
  322               // DirectExecutor using caller thread
  323               public void execute(Runnable r) {
  324                   r.run();
  325               }
  326           };
  327   
  328       private static final MBeanNotificationInfo[] NO_NOTIFICATION_INFO =
  329           new MBeanNotificationInfo[0];
  330   
  331       private class SendNotifJob implements Runnable {
  332           public SendNotifJob(Notification notif, ListenerInfo listenerInfo) {
  333               this.notif = notif;
  334               this.listenerInfo = listenerInfo;
  335           }
  336   
  337           public void run() {
  338               try {
  339                   handleNotification(listenerInfo.listener,
  340                                      notif, listenerInfo.handback);
  341               } catch (Exception e) {
  342                   if (logger.debugOn()) {
  343                       logger.debug("SendNotifJob-run", e);
  344                   }
  345               }
  346           }
  347   
  348           private final Notification notif;
  349           private final ListenerInfo listenerInfo;
  350       }
  351   
  352       private static final ClassLogger logger =
  353           new ClassLogger("javax.management", "NotificationBroadcasterSupport");
  354   }

Home » openjdk-7 » javax » management » [javadoc | source]