KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jmx > remote > internal > ArrayNotificationBuffer


1 /*
2  * @(#)ArrayNotificationBuffer.java 1.22 05/08/31
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package com.sun.jmx.remote.internal;
9
10 import java.io.IOException JavaDoc;
11 import java.security.AccessController JavaDoc;
12 import java.security.PrivilegedAction JavaDoc;
13 import java.security.PrivilegedActionException JavaDoc;
14 import java.security.PrivilegedExceptionAction JavaDoc;
15 import java.util.ArrayList JavaDoc;
16 import java.util.Collection JavaDoc;
17 import java.util.HashSet JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.List JavaDoc;
20 import java.util.Set JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.Map JavaDoc;
23
24 import javax.management.InstanceNotFoundException JavaDoc;
25 import javax.management.ListenerNotFoundException JavaDoc;
26 import javax.management.MalformedObjectNameException JavaDoc;
27 import javax.management.MBeanServer JavaDoc;
28 import javax.management.MBeanServerNotification JavaDoc;
29 import javax.management.Notification JavaDoc;
30 import javax.management.NotificationBroadcaster JavaDoc;
31 import javax.management.NotificationFilter JavaDoc;
32 import javax.management.NotificationFilterSupport JavaDoc;
33 import javax.management.NotificationListener JavaDoc;
34 import javax.management.ObjectName JavaDoc;
35 import javax.management.QueryEval JavaDoc;
36 import javax.management.QueryExp JavaDoc;
37
38 import javax.management.remote.NotificationResult JavaDoc;
39 import javax.management.remote.TargetedNotification JavaDoc;
40
41 import com.sun.jmx.remote.util.EnvHelp;
42 import com.sun.jmx.remote.util.ClassLogger;
43
44 /** A circular buffer of notifications received from an MBean server. */
45 public class ArrayNotificationBuffer implements NotificationBuffer {
46     
47     private boolean disposed = false;
48     
49     // FACTORY STUFF, INCLUDING SHARING
50

51     private static final
52     HashMap JavaDoc<MBeanServer JavaDoc,ArrayNotificationBuffer> mbsToBuffer =
53     new HashMap JavaDoc<MBeanServer JavaDoc,ArrayNotificationBuffer>(1);
54     private final Collection JavaDoc<ShareBuffer> sharers = new HashSet JavaDoc<ShareBuffer>(1);
55
56     public static synchronized NotificationBuffer
57         getNotificationBuffer(MBeanServer JavaDoc mbs, Map JavaDoc env) {
58     
59     //Find out queue size
60
int queueSize = EnvHelp.getNotifBufferSize(env);
61     
62     ArrayNotificationBuffer buf = mbsToBuffer.get(mbs);
63     if (buf == null) {
64         buf = new ArrayNotificationBuffer(mbs, queueSize);
65         mbsToBuffer.put(mbs, buf);
66     }
67     return buf.new ShareBuffer(queueSize);
68     }
69     
70     public static synchronized void removeNotificationBuffer(MBeanServer JavaDoc mbs) {
71     mbsToBuffer.remove(mbs);
72     }
73     
74     synchronized void addSharer(ShareBuffer sharer) {
75     if (sharer.getSize() > queueSize)
76         resize(sharer.getSize());
77     sharers.add(sharer);
78     }
79
80     void removeSharer(ShareBuffer sharer) {
81         boolean empty;
82         synchronized (this) {
83             sharers.remove(sharer);
84             empty = sharers.isEmpty();
85             if (!empty) {
86                 int max = 0;
87                 for (ShareBuffer buf : sharers) {
88                     int bufsize = buf.getSize();
89                     if (bufsize > max)
90                         max = bufsize;
91                 }
92                 if (max < queueSize)
93                     resize(max);
94             }
95         }
96         if (empty)
97             dispose();
98     }
99
100     private void resize(int newSize) {
101     if (newSize == queueSize)
102         return;
103     while (queue.size() > newSize)
104         dropNotification();
105     queue.resize(newSize);
106     queueSize = newSize;
107     }
108
109     private class ShareBuffer implements NotificationBuffer {
110     ShareBuffer(int size) {
111         this.size = size;
112         addSharer(this);
113     }
114
115     public NotificationResult JavaDoc
116         fetchNotifications(Set JavaDoc<ListenerInfo> listeners,
117                    long startSequenceNumber,
118                    long timeout,
119                    int maxNotifications)
120         throws InterruptedException JavaDoc {
121         NotificationBuffer buf = ArrayNotificationBuffer.this;
122         return buf.fetchNotifications(listeners, startSequenceNumber,
123                       timeout, maxNotifications);
124     }
125
126     public void dispose() {
127         ArrayNotificationBuffer.this.removeSharer(this);
128     }
129
130     int getSize() {
131         return size;
132     }
133
134     private final int size;
135     }
136
137
138     // ARRAYNOTIFICATIONBUFFER IMPLEMENTATION
139

140     private ArrayNotificationBuffer(MBeanServer JavaDoc mbs, int queueSize) {
141         if (logger.traceOn())
142             logger.trace("Constructor", "queueSize=" + queueSize);
143
144         if (mbs == null || queueSize < 1)
145             throw new IllegalArgumentException JavaDoc("Bad args");
146
147         this.mBeanServer = mbs;
148         this.queueSize = queueSize;
149         this.queue = new ArrayQueue<NamedNotification>(queueSize);
150         this.earliestSequenceNumber = System.currentTimeMillis();
151         this.nextSequenceNumber = this.earliestSequenceNumber;
152
153         createListeners();
154
155         logger.trace("Constructor", "ends");
156     }
157
158     private synchronized boolean isDisposed() {
159     return disposed;
160     }
161
162     public void dispose() {
163         logger.trace("dispose", "starts");
164
165     synchronized(this) {
166         removeNotificationBuffer(mBeanServer);
167         disposed = true;
168         //Notify potential waiting fetchNotification call
169
notifyAll();
170     }
171
172         destroyListeners();
173     
174         logger.trace("dispose", "ends");
175     }
176
177     /**
178      * <p>Fetch notifications that match the given listeners.</p>
179      *
180      * <p>The operation only considers notifications with a sequence
181      * number at least <code>startSequenceNumber</code>. It will take
182      * no longer than <code>timeout</code>, and will return no more
183      * than <code>maxNotifications</code> different notifications.</p>
184      *
185      * <p>If there are no notifications matching the criteria, the
186      * operation will block until one arrives, subject to the
187      * timeout.</p>
188      *
189      * @param listeners a Set of {@link ListenerInfo} that reflects
190      * the filters to be applied to notifications. Accesses to this
191      * Set are synchronized on the Set object. The Set is consulted
192      * for selected notifications that are present when the method
193      * starts, and for selected notifications that arrive while it is
194      * executing. The contents of the Set can be modified, with
195      * appropriate synchronization, while the method is running.
196      * @param startSequenceNumber the first sequence number to
197      * consider.
198      * @param timeout the maximum time to wait. May be 0 to indicate
199      * not to wait if there are no notifications.
200      * @param maxNotifications the maximum number of notifications to
201      * return. May be 0 to indicate a wait for eligible notifications
202      * that will return a usable <code>nextSequenceNumber</code>. The
203      * {@link TargetedNotification} array in the returned {@link
204      * NotificationResult} may contain more than this number of
205      * elements but will not contain more than this number of
206      * different notifications.
207      */

208     public NotificationResult JavaDoc
209         fetchNotifications(Set JavaDoc<ListenerInfo> listeners,
210                            long startSequenceNumber,
211                            long timeout,
212                            int maxNotifications)
213             throws InterruptedException JavaDoc {
214
215         logger.trace("fetchNotifications", "starts");
216
217     if (startSequenceNumber < 0 || isDisposed()) {
218         synchronized(this) {
219         return new NotificationResult JavaDoc(earliestSequenceNumber(),
220                           nextSequenceNumber(),
221                           new TargetedNotification JavaDoc[0]);
222         }
223     }
224     
225         // Check arg validity
226
if (listeners == null
227             || startSequenceNumber < 0 || timeout < 0
228             || maxNotifications < 0) {
229             logger.trace("fetchNotifications", "Bad args");
230             throw new IllegalArgumentException JavaDoc("Bad args to fetch");
231         }
232
233         if (logger.debugOn()) {
234             logger.trace("fetchNotifications",
235                   "listener-length=" + listeners.size() + "; startSeq=" +
236                   startSequenceNumber + "; timeout=" + timeout +
237                   "; max=" + maxNotifications);
238         }
239
240         if (startSequenceNumber > nextSequenceNumber()) {
241             final String JavaDoc msg = "Start sequence number too big: " +
242                 startSequenceNumber + " > " + nextSequenceNumber();
243             logger.trace("fetchNotifications", msg);
244             throw new IllegalArgumentException JavaDoc(msg);
245         }
246
247         /* Determine the end time corresponding to the timeout value.
248            Caller may legitimately supply Long.MAX_VALUE to indicate no
249            timeout. In that case the addition will overflow and produce
250            a negative end time. Set end time to Long.MAX_VALUE in that
251            case. We assume System.currentTimeMillis() is positive. */

252         long endTime = System.currentTimeMillis() + timeout;
253         if (endTime < 0) // overflow
254
endTime = Long.MAX_VALUE;
255
256         if (logger.debugOn())
257             logger.debug("fetchNotifications", "endTime=" + endTime);
258
259         /* We set earliestSeq the first time through the loop. If we
260            set it here, notifications could be dropped before we
261            started examining them, so earliestSeq might not correspond
262            to the earliest notification we examined. */

263         long earliestSeq = -1;
264         long nextSeq = startSequenceNumber;
265         List JavaDoc<TargetedNotification JavaDoc> notifs =
266             new ArrayList JavaDoc<TargetedNotification JavaDoc>();
267
268         /* On exit from this loop, notifs, earliestSeq, and nextSeq must
269            all be correct values for the returned NotificationResult. */

270         while (true) {
271             logger.debug("fetchNotifications", "main loop starts");
272
273             NamedNotification candidate;
274
275             /* Get the next available notification regardless of filters,
276                or wait for one to arrive if there is none. */

277             synchronized (this) {
278         
279                 /* First time through. The current earliestSequenceNumber
280                    is the first one we could have examined. */

281                 if (earliestSeq < 0) {
282                     earliestSeq = earliestSequenceNumber();
283                     if (logger.debugOn()) {
284                         logger.debug("fetchNotifications",
285                               "earliestSeq=" + earliestSeq);
286                     }
287                     if (nextSeq < earliestSeq) {
288                         nextSeq = earliestSeq;
289                         logger.debug("fetchNotifications",
290                      "nextSeq=earliestSeq");
291                     }
292                 } else
293                     earliestSeq = earliestSequenceNumber();
294
295                 /* If many notifications have been dropped since the
296                    last time through, nextSeq could now be earlier
297                    than the current earliest. If so, notifications
298                    may have been lost and we return now so the caller
299                    can see this next time it calls. */

300                 if (nextSeq < earliestSeq) {
301                     logger.trace("fetchNotifications",
302                           "nextSeq=" + nextSeq + " < " + "earliestSeq=" +
303                           earliestSeq + " so may have lost notifs");
304                     break;
305                 }
306
307                 if (nextSeq < nextSequenceNumber()) {
308                     candidate = notificationAt(nextSeq);
309                     if (logger.debugOn()) {
310                         logger.debug("fetchNotifications", "candidate: " +
311                      candidate);
312                         logger.debug("fetchNotifications", "nextSeq now " +
313                      nextSeq);
314                     }
315                 } else {
316                     /* nextSeq is the largest sequence number. If we
317                        already got notifications, return them now.
318                        Otherwise wait for some to arrive, with
319                        timeout. */

320                     if (notifs.size() > 0) {
321                         logger.debug("fetchNotifications",
322                               "no more notifs but have some so don't wait");
323                         break;
324                     }
325                     long toWait = endTime - System.currentTimeMillis();
326                     if (toWait <= 0) {
327                         logger.debug("fetchNotifications", "timeout");
328                         break;
329                     }
330             
331             /* dispose called */
332             if (isDisposed()) {
333             if (logger.debugOn())
334                 logger.debug("fetchNotifications",
335                      "dispose callled, no wait");
336             return new NotificationResult JavaDoc(earliestSequenceNumber(),
337                           nextSequenceNumber(),
338                           new TargetedNotification JavaDoc[0]);
339             }
340             
341             if (logger.debugOn())
342             logger.debug("fetchNotifications",
343                      "wait(" + toWait + ")");
344             wait(toWait);
345             
346                     continue;
347                 }
348             }
349         
350             /* We have a candidate notification. See if it matches
351                our filters. We do this outside the synchronized block
352                so we don't hold up everyone accessing the buffer
353                (including notification senders) while we evaluate
354                potentially slow filters. */

355             ObjectName JavaDoc name = candidate.getObjectName();
356             Notification JavaDoc notif = candidate.getNotification();
357             List JavaDoc<TargetedNotification JavaDoc> matchedNotifs =
358                 new ArrayList JavaDoc<TargetedNotification JavaDoc>();
359             logger.debug("fetchNotifications",
360              "applying filters to candidate");
361             synchronized (listeners) {
362                 for (ListenerInfo li : listeners) {
363                     ObjectName JavaDoc pattern = li.getObjectName();
364                     NotificationFilter JavaDoc filter = li.getNotificationFilter();
365
366                     if (logger.debugOn()) {
367                         logger.debug("fetchNotifications",
368                               "pattern=<" + pattern + ">; filter=" + filter);
369                     }
370
371                     if (pattern.apply(name)) {
372                         logger.debug("fetchNotifications", "pattern matches");
373                         if (filter == null
374                             || filter.isNotificationEnabled(notif)) {
375                             logger.debug("fetchNotifications",
376                      "filter matches");
377                             Integer JavaDoc listenerID = li.getListenerID();
378                             TargetedNotification JavaDoc tn =
379                                 new TargetedNotification JavaDoc(notif, listenerID);
380                             matchedNotifs.add(tn);
381                         }
382                     }
383                 }
384             }
385
386             if (matchedNotifs.size() > 0) {
387                 /* We only check the max size now, so that our
388                    returned nextSeq is as large as possible. This
389                    prevents the caller from thinking it missed
390                    interesting notifications when in fact we knew they
391                    weren't. */

392                 if (maxNotifications <= 0) {
393                     logger.debug("fetchNotifications",
394                  "reached maxNotifications");
395                     break;
396                 }
397                 --maxNotifications;
398                 if (logger.debugOn())
399                     logger.debug("fetchNotifications", "add: " +
400                  matchedNotifs);
401                 notifs.addAll(matchedNotifs);
402             }
403
404             ++nextSeq;
405         } // end while
406

407         /* Construct and return the result. */
408         int nnotifs = notifs.size();
409         TargetedNotification JavaDoc[] resultNotifs =
410             new TargetedNotification JavaDoc[nnotifs];
411         notifs.toArray(resultNotifs);
412         NotificationResult JavaDoc nr =
413             new NotificationResult JavaDoc(earliestSeq, nextSeq, resultNotifs);
414         if (logger.debugOn())
415             logger.debug("fetchNotifications", nr.toString());
416         logger.trace("fetchNotifications", "ends");
417
418         return nr;
419     }
420
421     synchronized long earliestSequenceNumber() {
422         return earliestSequenceNumber;
423     }
424
425     synchronized long nextSequenceNumber() {
426         return nextSequenceNumber;
427     }
428
429     synchronized void addNotification(NamedNotification notif) {
430         if (logger.traceOn())
431             logger.trace("addNotification", notif.toString());
432
433         while (queue.size() >= queueSize) {
434         dropNotification();
435             if (logger.debugOn()) {
436                 logger.debug("addNotification",
437                       "dropped oldest notif, earliestSeq=" +
438                       earliestSequenceNumber);
439             }
440         }
441         queue.add(notif);
442         nextSequenceNumber++;
443         if (logger.debugOn())
444             logger.debug("addNotification", "nextSeq=" + nextSequenceNumber);
445         notifyAll();
446     }
447
448     private void dropNotification() {
449     queue.remove(0);
450     earliestSequenceNumber++;
451     }
452
453     synchronized NamedNotification notificationAt(long seqNo) {
454         long index = seqNo - earliestSequenceNumber;
455         if (index < 0 || index > Integer.MAX_VALUE) {
456             final String JavaDoc msg = "Bad sequence number: " + seqNo + " (earliest "
457                 + earliestSequenceNumber + ")";
458             logger.trace("notificationAt", msg);
459             throw new IllegalArgumentException JavaDoc(msg);
460         }
461         return queue.get((int) index);
462     }
463
464     private static class NamedNotification {
465         NamedNotification(ObjectName JavaDoc sender, Notification JavaDoc notif) {
466             this.sender = sender;
467             this.notification = notif;
468         }
469
470         ObjectName JavaDoc getObjectName() {
471             return sender;
472         }
473
474         Notification JavaDoc getNotification() {
475             return notification;
476         }
477
478         public String JavaDoc toString() {
479             return "NamedNotification(" + sender + ", " + notification + ")";
480         }
481
482         private final ObjectName JavaDoc sender;
483         private final Notification JavaDoc notification;
484     }
485
486     /*
487      * Add our listener to every NotificationBroadcaster MBean
488      * currently in the MBean server and to every
489      * NotificationBroadcaster later created.
490      *
491      * It would be really nice if we could just do
492      * mbs.addNotificationListener(new ObjectName("*:*"), ...);
493      * Definitely something for the next version of JMX.
494      *
495      * There is a nasty race condition that we must handle. We
496      * first register for MBean-creation notifications so we can add
497      * listeners to new MBeans, then we query the existing MBeans to
498      * add listeners to them. The problem is that a new MBean could
499      * arrive after we register for creations but before the query has
500      * completed. Then we could see the MBean both in the query and
501      * in an MBean-creation notification, and we would end up
502      * registering our listener twice.
503      *
504      * To solve this problem, we arrange for new MBeans that arrive
505      * while the query is being done to be added to the Set createdDuringQuery
506      * and we do not add a listener immediately. When the query is done,
507      * we atomically turn off the addition of new names to createdDuringQuery
508      * and add all the names that were there to the result of the query.
509      * Since we are dealing with Sets, the result is the same whether or not
510      * the newly-created MBean was included in the query result.
511      *
512      * It is important not to hold any locks during the operation of adding
513      * listeners to MBeans. An MBean's addNotificationListener can be
514      * arbitrary user code, and this could deadlock with any locks we hold
515      * (see bug 6239400). The corollary is that we must not do any operations
516      * in this method or the methods it calls that require locks.
517      */

518     private void createListeners() {
519         logger.debug("createListeners", "starts");
520         
521         synchronized (this) {
522             createdDuringQuery = new HashSet JavaDoc<ObjectName JavaDoc>();
523         }
524
525         try {
526             addNotificationListener(delegateName,
527                                     creationListener, creationFilter, null);
528             logger.debug("createListeners", "added creationListener");
529         } catch (Exception JavaDoc e) {
530             final String JavaDoc msg = "Can't add listener to MBean server delegate: ";
531             RuntimeException JavaDoc re = new IllegalArgumentException JavaDoc(msg + e);
532             EnvHelp.initCause(re, e);
533             logger.fine("createListeners", msg + e);
534             logger.debug("createListeners", e);
535             throw re;
536         }
537
538         /* Spec doesn't say whether Set returned by QueryNames can be modified
539            so we clone it. */

540         Set JavaDoc<ObjectName JavaDoc> names = queryNames(null, broadcasterQuery);
541         names = new HashSet JavaDoc<ObjectName JavaDoc>(names);
542
543         synchronized (this) {
544             names.addAll(createdDuringQuery);
545             createdDuringQuery = null;
546         }
547
548         for (ObjectName JavaDoc name : names)
549             addBufferListener(name);
550         logger.debug("createListeners", "ends");
551     }
552
553     private void addBufferListener(ObjectName JavaDoc name) {
554         if (logger.debugOn())
555             logger.debug("addBufferListener", name.toString());
556         try {
557             addNotificationListener(name, bufferListener, null, name);
558         } catch (Exception JavaDoc e) {
559             logger.trace("addBufferListener", e);
560             /* This can happen if the MBean was unregistered just
561                after the query. Or user NotificationBroadcaster might
562                throw unexpected exception. */

563         }
564     }
565     
566     private void removeBufferListener(ObjectName JavaDoc name) {
567         if (logger.debugOn())
568             logger.debug("removeBufferListener", name.toString());
569         try {
570             removeNotificationListener(name, bufferListener);
571         } catch (Exception JavaDoc e) {
572             logger.trace("removeBufferListener", e);
573         }
574     }
575     
576     private void addNotificationListener(final ObjectName JavaDoc name,
577                                          final NotificationListener JavaDoc listener,
578                                          final NotificationFilter JavaDoc filter,
579                                          final Object JavaDoc handback)
580             throws Exception JavaDoc {
581         try {
582             AccessController.doPrivileged(new PrivilegedExceptionAction JavaDoc() {
583                 public Object JavaDoc run() throws InstanceNotFoundException JavaDoc {
584                     mBeanServer.addNotificationListener(name,
585                                                         listener,
586                                                         filter,
587                                                         handback);
588                     return null;
589                 }
590             });
591         } catch (Exception JavaDoc e) {
592             throw extractException(e);
593         }
594     }
595     
596     private void removeNotificationListener(final ObjectName JavaDoc name,
597                                             final NotificationListener JavaDoc listener)
598             throws Exception JavaDoc {
599         try {
600             AccessController.doPrivileged(new PrivilegedExceptionAction JavaDoc() {
601                 public Object JavaDoc run() throws Exception JavaDoc {
602                     mBeanServer.removeNotificationListener(name, listener);
603                     return null;
604                 }
605             });
606         } catch (Exception JavaDoc e) {
607             throw extractException(e);
608         }
609     }
610     
611     private Set JavaDoc<ObjectName JavaDoc> queryNames(final ObjectName JavaDoc name,
612                                        final QueryExp JavaDoc query) {
613         PrivilegedAction JavaDoc<Set JavaDoc<ObjectName JavaDoc>> act =
614             new PrivilegedAction JavaDoc<Set JavaDoc<ObjectName JavaDoc>>() {
615                 public Set JavaDoc<ObjectName JavaDoc> run() {
616                     return mBeanServer.queryNames(name, query);
617                 }
618             };
619         try {
620             return AccessController.doPrivileged(act);
621         } catch (RuntimeException JavaDoc e) {
622             logger.fine("queryNames", "Failed to query names: " + e);
623         logger.debug("queryNames", e);
624             throw e;
625         }
626     }
627     
628     private static boolean isInstanceOf(final MBeanServer JavaDoc mbs,
629                                         final ObjectName JavaDoc name,
630                                         final String JavaDoc className) {
631         PrivilegedExceptionAction JavaDoc<Boolean JavaDoc> act =
632             new PrivilegedExceptionAction JavaDoc<Boolean JavaDoc>() {
633                 public Boolean JavaDoc run() throws InstanceNotFoundException JavaDoc {
634                     return mbs.isInstanceOf(name, className);
635                 }
636             };
637         try {
638             return AccessController.doPrivileged(act);
639         } catch (Exception JavaDoc e) {
640             logger.fine("isInstanceOf", "failed: " + e);
641             logger.debug("isInstanceOf", e);
642             return false;
643         }
644     }
645
646     /* This method must not be synchronized. See the comment on the
647      * createListeners method.
648      *
649      * The notification could arrive after our buffer has been destroyed
650      * or even during its destruction. So we always add our listener
651      * (without synchronization), then we check if the buffer has been
652      * destroyed and if so remove the listener we just added.
653      */

654     private void createdNotification(MBeanServerNotification JavaDoc n) {
655         final String JavaDoc shouldEqual =
656             MBeanServerNotification.REGISTRATION_NOTIFICATION;
657         if (!n.getType().equals(shouldEqual)) {
658             logger.warning("createNotification", "bad type: " + n.getType());
659             return;
660         }
661
662         ObjectName JavaDoc name = n.getMBeanName();
663         if (logger.debugOn())
664             logger.debug("createdNotification", "for: " + name);
665         
666         synchronized (this) {
667             if (createdDuringQuery != null) {
668                 createdDuringQuery.add(name);
669                 return;
670             }
671         }
672
673         if (isInstanceOf(mBeanServer, name, broadcasterClass)) {
674             addBufferListener(name);
675             if (isDisposed())
676                 removeBufferListener(name);
677         }
678     }
679
680     private class BufferListener implements NotificationListener JavaDoc {
681     public void handleNotification(Notification JavaDoc notif, Object JavaDoc handback) {
682         if (logger.debugOn()) {
683         logger.debug("BufferListener.handleNotification",
684               "notif=" + notif + "; handback=" + handback);
685         }
686         ObjectName JavaDoc name = (ObjectName JavaDoc) handback;
687         addNotification(new NamedNotification(name, notif));
688     }
689     }
690
691     private final NotificationListener JavaDoc bufferListener = new BufferListener();
692
693     private static class BroadcasterQuery
694             extends QueryEval JavaDoc implements QueryExp JavaDoc {
695         public boolean apply(final ObjectName JavaDoc name) {
696             final MBeanServer JavaDoc mbs = QueryEval.getMBeanServer();
697             return isInstanceOf(mbs, name, broadcasterClass);
698         }
699     }
700     private static final QueryExp JavaDoc broadcasterQuery = new BroadcasterQuery();
701
702     private static final NotificationFilter JavaDoc creationFilter;
703     static {
704         NotificationFilterSupport JavaDoc nfs = new NotificationFilterSupport JavaDoc();
705         nfs.enableType(MBeanServerNotification.REGISTRATION_NOTIFICATION);
706         creationFilter = nfs;
707     }
708
709     private final NotificationListener JavaDoc creationListener =
710     new NotificationListener JavaDoc() {
711         public void handleNotification(Notification JavaDoc notif,
712                        Object JavaDoc handback) {
713         logger.debug("creationListener", "handleNotification called");
714         createdNotification((MBeanServerNotification JavaDoc) notif);
715         }
716     };
717
718     private void destroyListeners() {
719         logger.debug("destroyListeners", "starts");
720         try {
721             removeNotificationListener(delegateName,
722                                        creationListener);
723         } catch (Exception JavaDoc e) {
724             logger.warning("remove listener from MBeanServer delegate", e);
725         }
726         Set JavaDoc<ObjectName JavaDoc> names = queryNames(null, broadcasterQuery);
727         for (final ObjectName JavaDoc name : names) {
728             if (logger.debugOn())
729                 logger.debug("destroyListeners",
730                  "remove listener from " + name);
731             removeBufferListener(name);
732         }
733         logger.debug("destroyListeners", "ends");
734     }
735
736     /**
737      * Iterate until we extract the real exception
738      * from a stack of PrivilegedActionExceptions.
739      */

740     private static Exception JavaDoc extractException(Exception JavaDoc e) {
741         while (e instanceof PrivilegedActionException JavaDoc) {
742             e = ((PrivilegedActionException JavaDoc)e).getException();
743         }
744         return e;
745     }
746
747     private static final ClassLogger logger =
748     new ClassLogger("javax.management.remote.misc",
749             "ArrayNotificationBuffer");
750
751     private static final ObjectName JavaDoc delegateName;
752     static {
753         try {
754             delegateName =
755                 ObjectName.getInstance("JMImplementation:" +
756                                        "type=MBeanServerDelegate");
757         } catch (MalformedObjectNameException JavaDoc e) {
758             RuntimeException JavaDoc re =
759                 new RuntimeException JavaDoc("Can't create delegate name: " + e);
760             EnvHelp.initCause(re, e);
761             logger.error("<init>", "Can't create delegate name: " + e);
762         logger.debug("<init>",e);
763             throw re;
764         }
765     }
766
767     private final MBeanServer JavaDoc mBeanServer;
768     private final ArrayQueue<NamedNotification> queue;
769     private int queueSize;
770     private long earliestSequenceNumber;
771     private long nextSequenceNumber;
772     private Set JavaDoc<ObjectName JavaDoc> createdDuringQuery;
773
774     static final String JavaDoc broadcasterClass =
775         NotificationBroadcaster JavaDoc.class.getName();
776 }
777
Popular Tags