0N/A/*
2362N/A * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage javax.management;
0N/A
0N/Aimport java.util.Collections;
0N/Aimport java.util.List;
0N/Aimport java.util.concurrent.CopyOnWriteArrayList;
0N/Aimport java.util.concurrent.Executor;
0N/A
0N/Aimport com.sun.jmx.remote.util.ClassLogger;
0N/A
0N/A/**
0N/A * <p>Provides an implementation of {@link
0N/A * javax.management.NotificationEmitter NotificationEmitter}
0N/A * interface. This can be used as the super class of an MBean that
0N/A * sends notifications.</p>
0N/A *
0N/A * <p>By default, the notification dispatch model is synchronous.
0N/A * That is, when a thread calls sendNotification, the
0N/A * <code>NotificationListener.handleNotification</code> method of each listener
0N/A * is called within that thread. You can override this default
0N/A * by overriding <code>handleNotification</code> in a subclass, or by passing an
0N/A * Executor to the constructor.</p>
0N/A *
0N/A * <p>If the method call of a filter or listener throws an {@link Exception},
0N/A * then that exception does not prevent other listeners from being invoked. However,
0N/A * if the method call of a filter or of {@code Executor.execute} or of
0N/A * {@code handleNotification} (when no {@code Excecutor} is specified) throws an
0N/A * {@link Error}, then that {@code Error} is propagated to the caller of
0N/A * {@link #sendNotification sendNotification}.</p>
0N/A *
0N/A * <p>Remote listeners added using the JMX Remote API (see JMXConnector) are not
0N/A * usually called synchronously. That is, when sendNotification returns, it is
0N/A * not guaranteed that any remote listeners have yet received the notification.</p>
0N/A *
0N/A * @since 1.5
0N/A */
1790N/Apublic class NotificationBroadcasterSupport implements NotificationEmitter {
0N/A /**
0N/A * Constructs a NotificationBroadcasterSupport where each listener is invoked by the
0N/A * thread sending the notification. This constructor is equivalent to
0N/A * {@link NotificationBroadcasterSupport#NotificationBroadcasterSupport(Executor,
0N/A * MBeanNotificationInfo[] info) NotificationBroadcasterSupport(null, null)}.
0N/A */
0N/A public NotificationBroadcasterSupport() {
0N/A this(null, (MBeanNotificationInfo[]) null);
0N/A }
0N/A
0N/A /**
0N/A * Constructs a NotificationBroadcasterSupport where each listener is invoked using
0N/A * the given {@link java.util.concurrent.Executor}. When {@link #sendNotification
0N/A * sendNotification} is called, a listener is selected if it was added with a null
0N/A * {@link NotificationFilter}, or if {@link NotificationFilter#isNotificationEnabled
0N/A * isNotificationEnabled} returns true for the notification being sent. The call to
0N/A * <code>NotificationFilter.isNotificationEnabled</code> takes place in the thread
0N/A * that called <code>sendNotification</code>. Then, for each selected listener,
0N/A * {@link Executor#execute executor.execute} is called with a command
0N/A * that calls the <code>handleNotification</code> method.
0N/A * This constructor is equivalent to
0N/A * {@link NotificationBroadcasterSupport#NotificationBroadcasterSupport(Executor,
0N/A * MBeanNotificationInfo[] info) NotificationBroadcasterSupport(executor, null)}.
0N/A * @param executor an executor used by the method <code>sendNotification</code> to
0N/A * send each notification. If it is null, the thread calling <code>sendNotification</code>
0N/A * will invoke the <code>handleNotification</code> method itself.
0N/A * @since 1.6
0N/A */
0N/A public NotificationBroadcasterSupport(Executor executor) {
0N/A this(executor, (MBeanNotificationInfo[]) null);
0N/A }
0N/A
0N/A /**
0N/A * <p>Constructs a NotificationBroadcasterSupport with information
0N/A * about the notifications that may be sent. Each listener is
0N/A * invoked by the thread sending the notification. This
0N/A * constructor is equivalent to {@link
0N/A * NotificationBroadcasterSupport#NotificationBroadcasterSupport(Executor,
0N/A * MBeanNotificationInfo[] info)
0N/A * NotificationBroadcasterSupport(null, info)}.</p>
0N/A *
0N/A * <p>If the <code>info</code> array is not empty, then it is
0N/A * cloned by the constructor as if by {@code info.clone()}, and
0N/A * each call to {@link #getNotificationInfo()} returns a new
0N/A * clone.</p>
0N/A *
0N/A * @param info an array indicating, for each notification this
0N/A * MBean may send, the name of the Java class of the notification
0N/A * and the notification type. Can be null, which is equivalent to
0N/A * an empty array.
0N/A *
0N/A * @since 1.6
0N/A */
0N/A public NotificationBroadcasterSupport(MBeanNotificationInfo... info) {
0N/A this(null, info);
0N/A }
0N/A
0N/A /**
0N/A * <p>Constructs a NotificationBroadcasterSupport with information about the notifications that may be sent,
0N/A * and where each listener is invoked using the given {@link java.util.concurrent.Executor}.</p>
0N/A *
0N/A * <p>When {@link #sendNotification sendNotification} is called, a
0N/A * listener is selected if it was added with a null {@link
0N/A * NotificationFilter}, or if {@link
0N/A * NotificationFilter#isNotificationEnabled isNotificationEnabled}
0N/A * returns true for the notification being sent. The call to
0N/A * <code>NotificationFilter.isNotificationEnabled</code> takes
0N/A * place in the thread that called
0N/A * <code>sendNotification</code>. Then, for each selected
0N/A * listener, {@link Executor#execute executor.execute} is called
0N/A * with a command that calls the <code>handleNotification</code>
0N/A * method.</p>
0N/A *
0N/A * <p>If the <code>info</code> array is not empty, then it is
0N/A * cloned by the constructor as if by {@code info.clone()}, and
0N/A * each call to {@link #getNotificationInfo()} returns a new
0N/A * clone.</p>
0N/A *
0N/A * @param executor an executor used by the method
0N/A * <code>sendNotification</code> to send each notification. If it
0N/A * is null, the thread calling <code>sendNotification</code> will
0N/A * invoke the <code>handleNotification</code> method itself.
0N/A *
0N/A * @param info an array indicating, for each notification this
0N/A * MBean may send, the name of the Java class of the notification
0N/A * and the notification type. Can be null, which is equivalent to
0N/A * an empty array.
0N/A *
0N/A * @since 1.6
0N/A */
0N/A public NotificationBroadcasterSupport(Executor executor,
0N/A MBeanNotificationInfo... info) {
0N/A this.executor = (executor != null) ? executor : defaultExecutor;
0N/A
0N/A notifInfo = info == null ? NO_NOTIFICATION_INFO : info.clone();
0N/A }
0N/A
0N/A /**
0N/A * Adds a listener.
0N/A *
0N/A * @param listener The listener to receive notifications.
0N/A * @param filter The filter object. If filter is null, no
0N/A * filtering will be performed before handling notifications.
0N/A * @param handback An opaque object to be sent back to the
0N/A * listener when a notification is emitted. This object cannot be
0N/A * used by the Notification broadcaster object. It should be
0N/A * resent unchanged with the notification to the listener.
0N/A *
0N/A * @exception IllegalArgumentException thrown if the listener is null.
0N/A *
0N/A * @see #removeNotificationListener
0N/A */
0N/A public void addNotificationListener(NotificationListener listener,
0N/A NotificationFilter filter,
0N/A Object handback) {
0N/A
0N/A if (listener == null) {
0N/A throw new IllegalArgumentException ("Listener can't be null") ;
0N/A }
0N/A
0N/A listenerList.add(new ListenerInfo(listener, filter, handback));
0N/A }
0N/A
0N/A public void removeNotificationListener(NotificationListener listener)
0N/A throws ListenerNotFoundException {
0N/A
0N/A ListenerInfo wildcard = new WildcardListenerInfo(listener);
0N/A boolean removed =
0N/A listenerList.removeAll(Collections.singleton(wildcard));
0N/A if (!removed)
0N/A throw new ListenerNotFoundException("Listener not registered");
0N/A }
0N/A
0N/A public void removeNotificationListener(NotificationListener listener,
0N/A NotificationFilter filter,
0N/A Object handback)
0N/A throws ListenerNotFoundException {
0N/A
0N/A ListenerInfo li = new ListenerInfo(listener, filter, handback);
0N/A boolean removed = listenerList.remove(li);
0N/A if (!removed) {
0N/A throw new ListenerNotFoundException("Listener not registered " +
0N/A "(with this filter and " +
0N/A "handback)");
0N/A // or perhaps not registered at all
0N/A }
0N/A }
0N/A
0N/A public MBeanNotificationInfo[] getNotificationInfo() {
0N/A if (notifInfo.length == 0)
0N/A return notifInfo;
0N/A else
0N/A return notifInfo.clone();
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Sends a notification.
0N/A *
0N/A * If an {@code Executor} was specified in the constructor, it will be given one
0N/A * task per selected listener to deliver the notification to that listener.
0N/A *
0N/A * @param notification The notification to send.
0N/A */
0N/A public void sendNotification(Notification notification) {
0N/A
0N/A if (notification == null) {
0N/A return;
0N/A }
0N/A
0N/A boolean enabled;
0N/A
0N/A for (ListenerInfo li : listenerList) {
0N/A try {
0N/A enabled = li.filter == null ||
0N/A li.filter.isNotificationEnabled(notification);
0N/A } catch (Exception e) {
0N/A if (logger.debugOn()) {
0N/A logger.debug("sendNotification", e);
0N/A }
0N/A
0N/A continue;
0N/A }
0N/A
0N/A if (enabled) {
0N/A executor.execute(new SendNotifJob(notification, li));
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * <p>This method is called by {@link #sendNotification
0N/A * sendNotification} for each listener in order to send the
0N/A * notification to that listener. It can be overridden in
0N/A * subclasses to change the behavior of notification delivery,
0N/A * for instance to deliver the notification in a separate
0N/A * thread.</p>
0N/A *
0N/A * <p>The default implementation of this method is equivalent to
0N/A * <pre>
0N/A * listener.handleNotification(notif, handback);
0N/A * </pre>
0N/A *
0N/A * @param listener the listener to which the notification is being
0N/A * delivered.
0N/A * @param notif the notification being delivered to the listener.
0N/A * @param handback the handback object that was supplied when the
0N/A * listener was added.
0N/A *
0N/A */
0N/A protected void handleNotification(NotificationListener listener,
0N/A Notification notif, Object handback) {
0N/A listener.handleNotification(notif, handback);
0N/A }
0N/A
0N/A // private stuff
0N/A private static class ListenerInfo {
0N/A NotificationListener listener;
0N/A NotificationFilter filter;
0N/A Object handback;
0N/A
0N/A ListenerInfo(NotificationListener listener,
0N/A NotificationFilter filter,
0N/A Object handback) {
0N/A this.listener = listener;
0N/A this.filter = filter;
0N/A this.handback = handback;
0N/A }
0N/A
0N/A public boolean equals(Object o) {
0N/A if (!(o instanceof ListenerInfo))
0N/A return false;
0N/A ListenerInfo li = (ListenerInfo) o;
0N/A if (li instanceof WildcardListenerInfo)
0N/A return (li.listener == listener);
0N/A else
0N/A return (li.listener == listener && li.filter == filter
0N/A && li.handback == handback);
0N/A }
0N/A }
0N/A
0N/A private static class WildcardListenerInfo extends ListenerInfo {
0N/A WildcardListenerInfo(NotificationListener listener) {
0N/A super(listener, null, null);
0N/A }
0N/A
0N/A public boolean equals(Object o) {
0N/A assert (!(o instanceof WildcardListenerInfo));
0N/A return o.equals(this);
0N/A }
0N/A }
0N/A
0N/A private List<ListenerInfo> listenerList =
0N/A new CopyOnWriteArrayList<ListenerInfo>();
0N/A
0N/A // since 1.6
0N/A private final Executor executor;
0N/A private final MBeanNotificationInfo[] notifInfo;
0N/A
0N/A private final static Executor defaultExecutor = new Executor() {
0N/A // DirectExecutor using caller thread
0N/A public void execute(Runnable r) {
0N/A r.run();
0N/A }
0N/A };
0N/A
0N/A private static final MBeanNotificationInfo[] NO_NOTIFICATION_INFO =
0N/A new MBeanNotificationInfo[0];
0N/A
0N/A private class SendNotifJob implements Runnable {
0N/A public SendNotifJob(Notification notif, ListenerInfo listenerInfo) {
0N/A this.notif = notif;
0N/A this.listenerInfo = listenerInfo;
0N/A }
0N/A
0N/A public void run() {
0N/A try {
0N/A handleNotification(listenerInfo.listener,
0N/A notif, listenerInfo.handback);
0N/A } catch (Exception e) {
0N/A if (logger.debugOn()) {
0N/A logger.debug("SendNotifJob-run", e);
0N/A }
0N/A }
0N/A }
0N/A
0N/A private final Notification notif;
0N/A private final ListenerInfo listenerInfo;
0N/A }
0N/A
0N/A private static final ClassLogger logger =
0N/A new ClassLogger("javax.management", "NotificationBroadcasterSupport");
0N/A}