Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/management/NotificationEmitterSupport.java
38827 views
/*1* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.management;2627import javax.management.ListenerNotFoundException;28import javax.management.MBeanNotificationInfo;29import javax.management.Notification;30import javax.management.NotificationEmitter;31import javax.management.NotificationFilter;32import javax.management.NotificationListener;3334import java.util.List;35import java.util.ArrayList;36import java.util.ListIterator;37import java.util.Collections;3839/**40* Abstract helper class for notification emitter support.41*/42abstract class NotificationEmitterSupport implements NotificationEmitter {4344protected NotificationEmitterSupport() {45}4647private Object listenerLock = new Object();4849// Implementation of NotificationEmitter interface50// Cloned from JMX NotificationBroadcasterSupport class.51public void addNotificationListener(NotificationListener listener,52NotificationFilter filter,53Object handback) {5455if (listener == null) {56throw new IllegalArgumentException ("Listener can't be null") ;57}5859/* Adding a new listener takes O(n) time where n is the number60of existing listeners. If you have a very large number of61listeners performance could degrade. That's a fairly62surprising configuration, and it is hard to avoid this63behaviour while still retaining the property that the64listenerList is not synchronized while notifications are65being sent through it. If this becomes a problem, a66possible solution would be a multiple-readers single-writer67setup, so any number of sendNotification() calls could run68concurrently but they would exclude an69add/removeNotificationListener. A simpler but less70efficient solution would be to clone the listener list71every time a notification is sent. */72synchronized (listenerLock) {73List<ListenerInfo> newList = new ArrayList<>(listenerList.size() + 1);74newList.addAll(listenerList);75newList.add(new ListenerInfo(listener, filter, handback));76listenerList = newList;77}78}7980public void removeNotificationListener(NotificationListener listener)81throws ListenerNotFoundException {8283synchronized (listenerLock) {84List<ListenerInfo> newList = new ArrayList<>(listenerList);85/* We scan the list of listeners in reverse order because86in forward order we would have to repeat the loop with87the same index after a remove. */88for (int i=newList.size()-1; i>=0; i--) {89ListenerInfo li = newList.get(i);9091if (li.listener == listener)92newList.remove(i);93}94if (newList.size() == listenerList.size())95throw new ListenerNotFoundException("Listener not registered");96listenerList = newList;97}98}99100public void removeNotificationListener(NotificationListener listener,101NotificationFilter filter,102Object handback)103throws ListenerNotFoundException {104105boolean found = false;106107synchronized (listenerLock) {108List<ListenerInfo> newList = new ArrayList<>(listenerList);109final int size = newList.size();110for (int i = 0; i < size; i++) {111ListenerInfo li = newList.get(i);112113if (li.listener == listener) {114found = true;115if (li.filter == filter116&& li.handback == handback) {117newList.remove(i);118listenerList = newList;119return;120}121}122}123}124125if (found) {126/* We found this listener, but not with the given filter127* and handback. A more informative exception message may128* make debugging easier. */129throw new ListenerNotFoundException("Listener not registered " +130"with this filter and " +131"handback");132} else {133throw new ListenerNotFoundException("Listener not registered");134}135}136137void sendNotification(Notification notification) {138139if (notification == null) {140return;141}142143List<ListenerInfo> currentList;144synchronized (listenerLock) {145currentList = listenerList;146}147148final int size = currentList.size();149for (int i = 0; i < size; i++) {150ListenerInfo li = currentList.get(i);151152if (li.filter == null153|| li.filter.isNotificationEnabled(notification)) {154try {155li.listener.handleNotification(notification, li.handback);156} catch (Exception e) {157e.printStackTrace();158throw new AssertionError("Error in invoking listener");159}160}161}162}163164boolean hasListeners() {165synchronized (listenerLock) {166return !listenerList.isEmpty();167}168}169170private class ListenerInfo {171public NotificationListener listener;172NotificationFilter filter;173Object handback;174175public ListenerInfo(NotificationListener listener,176NotificationFilter filter,177Object handback) {178this.listener = listener;179this.filter = filter;180this.handback = handback;181}182}183184/**185* Current list of listeners, a List of ListenerInfo. The object186* referenced by this field is never modified. Instead, the field187* is set to a new object when a listener is added or removed,188* within a synchronized(this). In this way, there is no need to189* synchronize when traversing the list to send a notification to190* the listeners in it. That avoids potential deadlocks if the191* listeners end up depending on other threads that are themselves192* accessing this NotificationBroadcasterSupport.193*/194private List<ListenerInfo> listenerList = Collections.emptyList();195196abstract public MBeanNotificationInfo[] getNotificationInfo();197}198199200