1 /*
2 * Copyright 1999-2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package javax.management.monitor;
27
28 import static com.sun.jmx.defaults.JmxProperties.MONITOR_LOGGER;
29 import com.sun.jmx.mbeanserver.GetPropertyAction;
30 import com.sun.jmx.mbeanserver.Introspector;
31 import java.io.IOException;
32 import java.security.AccessControlContext;
33 import java.security.AccessController;
34 import java.security.PrivilegedAction;
35 import java.util.List;
36 import java.util.concurrent.CopyOnWriteArrayList;
37 import java.util.concurrent.ExecutorService;
38 import java.util.concurrent.Executors;
39 import java.util.concurrent.Future;
40 import java.util.concurrent.LinkedBlockingQueue;
41 import java.util.concurrent.ScheduledExecutorService;
42 import java.util.concurrent.ScheduledFuture;
43 import java.util.concurrent.ThreadFactory;
44 import java.util.concurrent.ThreadPoolExecutor;
45 import java.util.concurrent.TimeUnit;
46 import java.util.concurrent.atomic.AtomicInteger;
47 import java.util.concurrent.atomic.AtomicLong;
48 import java.util.logging.Level;
49 import javax.management.AttributeNotFoundException;
50 import javax.management.InstanceNotFoundException;
51 import javax.management.IntrospectionException;
52 import javax.management.MBeanAttributeInfo;
53 import javax.management.MBeanException;
54 import javax.management.MBeanInfo;
55 import javax.management.MBeanRegistration;
56 import javax.management.MBeanServer;
57 import javax.management.MBeanServerConnection;
58 import javax.management.NotificationBroadcasterSupport;
59 import javax.management.ObjectName;
60 import javax.management.ReflectionException;
61 import static javax.management.monitor.MonitorNotification.*;
62
63 /**
64 * Defines the part common to all monitor MBeans.
65 * A monitor MBean monitors values of an attribute common to a set of observed
66 * MBeans. The observed attribute is monitored at intervals specified by the
67 * granularity period. A gauge value (derived gauge) is derived from the values
68 * of the observed attribute.
69 *
70 *
71 * @since 1.5
72 */
73 public abstract class Monitor
74 extends NotificationBroadcasterSupport
75 implements MonitorMBean, MBeanRegistration {
76
77 /*
78 * ------------------------------------------
79 * PACKAGE CLASSES
80 * ------------------------------------------
81 */
82
83 static class ObservedObject {
84
85 public ObservedObject(ObjectName observedObject) {
86 this.observedObject = observedObject;
87 }
88
89 public final ObjectName getObservedObject() {
90 return observedObject;
91 }
92 public final synchronized int getAlreadyNotified() {
93 return alreadyNotified;
94 }
95 public final synchronized void setAlreadyNotified(int alreadyNotified) {
96 this.alreadyNotified = alreadyNotified;
97 }
98 public final synchronized Object getDerivedGauge() {
99 return derivedGauge;
100 }
101 public final synchronized void setDerivedGauge(Object derivedGauge) {
102 this.derivedGauge = derivedGauge;
103 }
104 public final synchronized long getDerivedGaugeTimeStamp() {
105 return derivedGaugeTimeStamp;
106 }
107 public final synchronized void setDerivedGaugeTimeStamp(
108 long derivedGaugeTimeStamp) {
109 this.derivedGaugeTimeStamp = derivedGaugeTimeStamp;
110 }
111
112 private final ObjectName observedObject;
113 private int alreadyNotified;
114 private Object derivedGauge;
115 private long derivedGaugeTimeStamp;
116 }
117
118 /*
119 * ------------------------------------------
120 * PRIVATE VARIABLES
121 * ------------------------------------------
122 */
123
124 /**
125 * Attribute to observe.
126 */
127 private String observedAttribute;
128
129 /**
130 * Monitor granularity period (in milliseconds).
131 * The default value is set to 10 seconds.
132 */
133 private long granularityPeriod = 10000;
134
135 /**
136 * Monitor state.
137 * The default value is set to <CODE>false</CODE>.
138 */
139 private boolean isActive = false;
140
141 /**
142 * Monitor sequence number.
143 * The default value is set to 0.
144 */
145 private final AtomicLong sequenceNumber = new AtomicLong();
146
147 /**
148 * Complex type attribute flag.
149 * The default value is set to <CODE>false</CODE>.
150 */
151 private boolean isComplexTypeAttribute = false;
152
153 /**
154 * First attribute name extracted from complex type attribute name.
155 */
156 private String firstAttribute;
157
158 /**
159 * Remaining attribute names extracted from complex type attribute name.
160 */
161 private final List<String> remainingAttributes =
162 new CopyOnWriteArrayList<String>();
163
164 /**
165 * AccessControlContext of the Monitor.start() caller.
166 */
167 private AccessControlContext acc;
168
169 /**
170 * Scheduler Service.
171 */
172 private static final ScheduledExecutorService scheduler =
173 Executors.newSingleThreadScheduledExecutor(
174 new DaemonThreadFactory("Scheduler"));
175
176 /**
177 * Maximum Pool Size
178 */
179 private static final int maximumPoolSize;
180
181 /**
182 * Executor Service.
183 */
184 private static final ExecutorService executor;
185 static {
186 final String maximumPoolSizeSysProp = "jmx.x.monitor.maximum.pool.size";
187 final String maximumPoolSizeStr = AccessController.doPrivileged(
188 new GetPropertyAction(maximumPoolSizeSysProp));
189 if (maximumPoolSizeStr == null ||
190 maximumPoolSizeStr.trim().length() == 0) {
191 maximumPoolSize = 10;
192 } else {
193 int maximumPoolSizeTmp = 10;
194 try {
195 maximumPoolSizeTmp = Integer.parseInt(maximumPoolSizeStr);
196 } catch (NumberFormatException e) {
197 if (MONITOR_LOGGER.isLoggable(Level.FINER)) {
198 MONITOR_LOGGER.logp(Level.FINER, Monitor.class.getName(),
199 "<static initializer>",
200 "Wrong value for " + maximumPoolSizeSysProp +
201 " system property", e);
202 MONITOR_LOGGER.logp(Level.FINER, Monitor.class.getName(),
203 "<static initializer>",
204 maximumPoolSizeSysProp + " defaults to 10");
205 }
206 maximumPoolSizeTmp = 10;
207 }
208 if (maximumPoolSizeTmp < 1) {
209 maximumPoolSize = 1;
210 } else {
211 maximumPoolSize = maximumPoolSizeTmp;
212 }
213 }
214 executor = new ThreadPoolExecutor(
215 maximumPoolSize,
216 maximumPoolSize,
217 60L,
218 TimeUnit.SECONDS,
219 new LinkedBlockingQueue<Runnable>(),
220 new DaemonThreadFactory("Executor"));
221 ((ThreadPoolExecutor)executor).allowCoreThreadTimeOut(true);
222 }
223
224 /**
225 * Monitor task to be executed by the Executor Service.
226 */
227 private final MonitorTask monitorTask = new MonitorTask();
228
229 /**
230 * Future associated to the current monitor task.
231 */
232 private Future<?> monitorFuture;
233
234 /**
235 * Scheduler task to be executed by the Scheduler Service.
236 */
237 private final SchedulerTask schedulerTask = new SchedulerTask(monitorTask);
238
239 /**
240 * ScheduledFuture associated to the current scheduler task.
241 */
242 private ScheduledFuture<?> schedulerFuture;
243
244 /*
245 * ------------------------------------------
246 * PROTECTED VARIABLES
247 * ------------------------------------------
248 */
249
250 /**
251 * The amount by which the capacity of the monitor arrays are
252 * automatically incremented when their size becomes greater than
253 * their capacity.
254 */
255 protected final static int capacityIncrement = 16;
256
257 /**
258 * The number of valid components in the vector of observed objects.
259 *
260 */
261 protected int elementCount = 0;
262
263 /**
264 * Monitor errors that have already been notified.
265 * @deprecated equivalent to {@link #alreadyNotifieds}[0].
266 */
267 @Deprecated
268 protected int alreadyNotified = 0;
269
270 /**
271 * <p>Selected monitor errors that have already been notified.</p>
272 *
273 * <p>Each element in this array corresponds to an observed object
274 * in the vector. It contains a bit mask of the flags {@link
275 * #OBSERVED_OBJECT_ERROR_NOTIFIED} etc, indicating whether the
276 * corresponding notification has already been sent for the MBean
277 * being monitored.</p>
278 *
279 */
280 protected int alreadyNotifieds[] = new int[capacityIncrement];
281
282 /**
283 * Reference to the MBean server. This reference is null when the
284 * monitor MBean is not registered in an MBean server. This
285 * reference is initialized before the monitor MBean is registered
286 * in the MBean server.
287 * @see #preRegister(MBeanServer server, ObjectName name)
288 */
289 protected MBeanServer server;
290
291 // Flags defining possible monitor errors.
292 //
293
294 /**
295 * This flag is used to reset the {@link #alreadyNotifieds
296 * alreadyNotifieds} monitor attribute.
297 */
298 protected static final int RESET_FLAGS_ALREADY_NOTIFIED = 0;
299
300 /**
301 * Flag denoting that a notification has occurred after changing
302 * the observed object. This flag is used to check that the new
303 * observed object is registered in the MBean server at the time
304 * of the first notification.
305 */
306 protected static final int OBSERVED_OBJECT_ERROR_NOTIFIED = 1;
307
308 /**
309 * Flag denoting that a notification has occurred after changing
310 * the observed attribute. This flag is used to check that the
311 * new observed attribute belongs to the observed object at the
312 * time of the first notification.
313 */
314 protected static final int OBSERVED_ATTRIBUTE_ERROR_NOTIFIED = 2;
315
316 /**
317 * Flag denoting that a notification has occurred after changing
318 * the observed object or the observed attribute. This flag is
319 * used to check that the observed attribute type is correct
320 * (depending on the monitor in use) at the time of the first
321 * notification.
322 */
323 protected static final int OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED = 4;
324
325 /**
326 * Flag denoting that a notification has occurred after changing
327 * the observed object or the observed attribute. This flag is
328 * used to notify any exception (except the cases described above)
329 * when trying to get the value of the observed attribute at the
330 * time of the first notification.
331 */
332 protected static final int RUNTIME_ERROR_NOTIFIED = 8;
333
334 /**
335 * This field is retained for compatibility but should not be referenced.
336 *
337 * @deprecated No replacement.
338 */
339 @Deprecated
340 protected String dbgTag = Monitor.class.getName();
341
342 /*
343 * ------------------------------------------
344 * PACKAGE VARIABLES
345 * ------------------------------------------
346 */
347
348 /**
349 * List of ObservedObjects to which the attribute to observe belongs.
350 */
351 final List<ObservedObject> observedObjects =
352 new CopyOnWriteArrayList<ObservedObject>();
353
354 /**
355 * Flag denoting that a notification has occurred after changing
356 * the threshold. This flag is used to notify any exception
357 * related to invalid thresholds settings.
358 */
359 static final int THRESHOLD_ERROR_NOTIFIED = 16;
360
361 /**
362 * Enumeration used to keep trace of the derived gauge type
363 * in counter and gauge monitors.
364 */
365 enum NumericalType { BYTE, SHORT, INTEGER, LONG, FLOAT, DOUBLE };
366
367 /**
368 * Constant used to initialize all the numeric values.
369 */
370 static final Integer INTEGER_ZERO = 0;
371
372
373 /*
374 * ------------------------------------------
375 * PUBLIC METHODS
376 * ------------------------------------------
377 */
378
379 /**
380 * Allows the monitor MBean to perform any operations it needs
381 * before being registered in the MBean server.
382 * <P>
383 * Initializes the reference to the MBean server.
384 *
385 * @param server The MBean server in which the monitor MBean will
386 * be registered.
387 * @param name The object name of the monitor MBean.
388 *
389 * @return The name of the monitor MBean registered.
390 *
391 * @exception Exception
392 */
393 public ObjectName preRegister(MBeanServer server, ObjectName name)
394 throws Exception {
395
396 MONITOR_LOGGER.logp(Level.FINER, Monitor.class.getName(),
397 "preRegister(MBeanServer, ObjectName)",
398 "initialize the reference on the MBean server");
399
400 this.server = server;
401 return name;
402 }
403
404 /**
405 * Allows the monitor MBean to perform any operations needed after
406 * having been registered in the MBean server or after the
407 * registration has failed.
408 * <P>
409 * Not used in this context.
410 */
411 public void postRegister(Boolean registrationDone) {
412 }
413
414 /**
415 * Allows the monitor MBean to perform any operations it needs
416 * before being unregistered by the MBean server.
417 * <P>
418 * Stops the monitor.
419 *
420 * @exception Exception
421 */
422 public void preDeregister() throws Exception {
423
424 MONITOR_LOGGER.logp(Level.FINER, Monitor.class.getName(),
425 "preDeregister()", "stop the monitor");
426
427 // Stop the Monitor.
428 //
429 stop();
430 }
431
432 /**
433 * Allows the monitor MBean to perform any operations needed after
434 * having been unregistered by the MBean server.
435 * <P>
436 * Not used in this context.
437 */
438 public void postDeregister() {
439 }
440
441 /**
442 * Starts the monitor.
443 */
444 public abstract void start();
445
446 /**
447 * Stops the monitor.
448 */
449 public abstract void stop();
450
451 // GETTERS AND SETTERS
452 //--------------------
453
454 /**
455 * Returns the object name of the first object in the set of observed
456 * MBeans, or <code>null</code> if there is no such object.
457 *
458 * @return The object being observed.
459 *
460 * @see #setObservedObject(ObjectName)
461 *
462 * @deprecated As of JMX 1.2, replaced by {@link #getObservedObjects}
463 */
464 @Deprecated
465 public synchronized ObjectName getObservedObject() {
466 if (observedObjects.isEmpty()) {
467 return null;
468 } else {
469 return observedObjects.get(0).getObservedObject();
470 }
471 }
472
473 /**
474 * Removes all objects from the set of observed objects, and then adds the
475 * specified object.
476 *
477 * @param object The object to observe.
478 * @exception IllegalArgumentException The specified
479 * object is null.
480 *
481 * @see #getObservedObject()
482 *
483 * @deprecated As of JMX 1.2, replaced by {@link #addObservedObject}
484 */
485 @Deprecated
486 public synchronized void setObservedObject(ObjectName object)
487 throws IllegalArgumentException {
488 if (object == null)
489 throw new IllegalArgumentException("Null observed object");
490 if (observedObjects.size() == 1 && containsObservedObject(object))
491 return;
492 observedObjects.clear();
493 addObservedObject(object);
494 }
495
496 /**
497 * Adds the specified object in the set of observed MBeans, if this object
498 * is not already present.
499 *
500 * @param object The object to observe.
501 * @exception IllegalArgumentException The specified object is null.
502 *
503 */
504 public synchronized void addObservedObject(ObjectName object)
505 throws IllegalArgumentException {
506
507 if (object == null) {
508 throw new IllegalArgumentException("Null observed object");
509 }
510
511 // Check that the specified object is not already contained.
512 //
513 if (containsObservedObject(object))
514 return;
515
516 // Add the specified object in the list.
517 //
518 ObservedObject o = createObservedObject(object);
519 o.setAlreadyNotified(RESET_FLAGS_ALREADY_NOTIFIED);
520 o.setDerivedGauge(null);
521 o.setDerivedGaugeTimeStamp(System.currentTimeMillis());
522 observedObjects.add(o);
523
524 // Update legacy protected stuff.
525 //
526 createAlreadyNotified();
527 }
528
529 /**
530 * Removes the specified object from the set of observed MBeans.
531 *
532 * @param object The object to remove.
533 *
534 */
535 public synchronized void removeObservedObject(ObjectName object) {
536 // Check for null object.
537 //
538 if (object == null)
539 return;
540
541 final ObservedObject o = getObservedObject(object);
542 if (o != null) {
543 // Remove the specified object from the list.
544 //
545 observedObjects.remove(o);
546 // Update legacy protected stuff.
547 //
548 createAlreadyNotified();
549 }
550 }
551
552 /**
553 * Tests whether the specified object is in the set of observed MBeans.
554 *
555 * @param object The object to check.
556 * @return <CODE>true</CODE> if the specified object is present,
557 * <CODE>false</CODE> otherwise.
558 *
559 */
560 public synchronized boolean containsObservedObject(ObjectName object) {
561 return getObservedObject(object) != null;
562 }
563
564 /**
565 * Returns an array containing the objects being observed.
566 *
567 * @return The objects being observed.
568 *
569 */
570 public synchronized ObjectName[] getObservedObjects() {
571 ObjectName[] names = new ObjectName[observedObjects.size()];
572 for (int i = 0; i < names.length; i++)
573 names[i] = observedObjects.get(i).getObservedObject();
574 return names;
575 }
576
577 /**
578 * Gets the attribute being observed.
579 * <BR>The observed attribute is not initialized by default (set to null).
580 *
581 * @return The attribute being observed.
582 *
583 * @see #setObservedAttribute
584 */
585 public synchronized String getObservedAttribute() {
586 return observedAttribute;
587 }
588
589 /**
590 * Sets the attribute to observe.
591 * <BR>The observed attribute is not initialized by default (set to null).
592 *
593 * @param attribute The attribute to observe.
594 * @exception IllegalArgumentException The specified
595 * attribute is null.
596 *
597 * @see #getObservedAttribute
598 */
599 public void setObservedAttribute(String attribute)
600 throws IllegalArgumentException {
601
602 if (attribute == null) {
603 throw new IllegalArgumentException("Null observed attribute");
604 }
605
606 // Update alreadyNotified array.
607 //
608 synchronized (this) {
609 if (observedAttribute != null &&
610 observedAttribute.equals(attribute))
611 return;
612 observedAttribute = attribute;
613
614 // Reset the complex type attribute information
615 // such that it is recalculated again.
616 //
617 cleanupIsComplexTypeAttribute();
618
619 int index = 0;
620 for (ObservedObject o : observedObjects) {
621 resetAlreadyNotified(o, index++,
622 OBSERVED_ATTRIBUTE_ERROR_NOTIFIED |
623 OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED);
624 }
625 }
626 }
627
628 /**
629 * Gets the granularity period (in milliseconds).
630 * <BR>The default value of the granularity period is 10 seconds.
631 *
632 * @return The granularity period value.
633 *
634 * @see #setGranularityPeriod
635 */
636 public synchronized long getGranularityPeriod() {
637 return granularityPeriod;
638 }
639
640 /**
641 * Sets the granularity period (in milliseconds).
642 * <BR>The default value of the granularity period is 10 seconds.
643 *
644 * @param period The granularity period value.
645 * @exception IllegalArgumentException The granularity
646 * period is less than or equal to zero.
647 *
648 * @see #getGranularityPeriod
649 */
650 public synchronized void setGranularityPeriod(long period)
651 throws IllegalArgumentException {
652
653 if (period <= 0) {
654 throw new IllegalArgumentException("Nonpositive granularity " +
655 "period");
656 }
657
658 if (granularityPeriod == period)
659 return;
660 granularityPeriod = period;
661
662 // Reschedule the scheduler task if the monitor is active.
663 //
664 if (isActive()) {
665 cleanupFutures();
666 schedulerFuture = scheduler.schedule(schedulerTask,
667 period,
668 TimeUnit.MILLISECONDS);
669 }
670 }
671
672 /**
673 * Tests whether the monitor MBean is active. A monitor MBean is
674 * marked active when the {@link #start start} method is called.
675 * It becomes inactive when the {@link #stop stop} method is
676 * called.
677 *
678 * @return <CODE>true</CODE> if the monitor MBean is active,
679 * <CODE>false</CODE> otherwise.
680 */
681 /* This method must be synchronized so that the monitoring thread will
682 correctly see modifications to the isActive variable. See the MonitorTask
683 action executed by the Scheduled Executor Service. */
684 public synchronized boolean isActive() {
685 return isActive;
686 }
687
688 /*
689 * ------------------------------------------
690 * PACKAGE METHODS
691 * ------------------------------------------
692 */
693
694 /**
695 * Starts the monitor.
696 */
697 void doStart() {
698 MONITOR_LOGGER.logp(Level.FINER, Monitor.class.getName(),
699 "doStart()", "start the monitor");
700
701 synchronized (this) {
702 if (isActive()) {
703 MONITOR_LOGGER.logp(Level.FINER, Monitor.class.getName(),
704 "doStart()", "the monitor is already active");
705 return;
706 }
707
708 isActive = true;
709
710 // Reset the complex type attribute information
711 // such that it is recalculated again.
712 //
713 cleanupIsComplexTypeAttribute();
714
715 // Cache the AccessControlContext of the Monitor.start() caller.
716 // The monitor tasks will be executed within this context.
717 //
718 acc = AccessController.getContext();
719
720 // Start the scheduler.
721 //
722 cleanupFutures();
723 schedulerFuture = scheduler.schedule(schedulerTask,
724 getGranularityPeriod(),
725 TimeUnit.MILLISECONDS);
726 }
727 }
728
729 /**
730 * Stops the monitor.
731 */
732 void doStop() {
733 MONITOR_LOGGER.logp(Level.FINER, Monitor.class.getName(),
734 "doStop()", "stop the monitor");
735
736 synchronized (this) {
737 if (!isActive()) {
738 MONITOR_LOGGER.logp(Level.FINER, Monitor.class.getName(),
739 "doStop()", "the monitor is not active");
740 return;
741 }
742
743 isActive = false;
744
745 // Cancel the scheduler task associated with the
746 // scheduler and its associated monitor task.
747 //
748 cleanupFutures();
749
750 // Reset the AccessControlContext.
751 //
752 acc = null;
753
754 // Reset the complex type attribute information
755 // such that it is recalculated again.
756 //
757 cleanupIsComplexTypeAttribute();
758 }
759 }
760
761 /**
762 * Gets the derived gauge of the specified object, if this object is
763 * contained in the set of observed MBeans, or <code>null</code> otherwise.
764 *
765 * @param object the name of the object whose derived gauge is to
766 * be returned.
767 *
768 * @return The derived gauge of the specified object.
769 *
770 * @since 1.6
771 */
772 synchronized Object getDerivedGauge(ObjectName object) {
773 final ObservedObject o = getObservedObject(object);
774 return o == null ? null : o.getDerivedGauge();
775 }
776
777 /**
778 * Gets the derived gauge timestamp of the specified object, if
779 * this object is contained in the set of observed MBeans, or
780 * <code>0</code> otherwise.
781 *
782 * @param object the name of the object whose derived gauge
783 * timestamp is to be returned.
784 *
785 * @return The derived gauge timestamp of the specified object.
786 *
787 */
788 synchronized long getDerivedGaugeTimeStamp(ObjectName object) {
789 final ObservedObject o = getObservedObject(object);
790 return o == null ? 0 : o.getDerivedGaugeTimeStamp();
791 }
792
793 Object getAttribute(MBeanServerConnection mbsc,
794 ObjectName object,
795 String attribute)
796 throws AttributeNotFoundException,
797 InstanceNotFoundException,
798 MBeanException,
799 ReflectionException,
800 IOException {
801 // Check for "ObservedAttribute" replacement.
802 // This could happen if a thread A called setObservedAttribute()
803 // while other thread B was in the middle of the monitor() method
804 // and received the old observed attribute value.
805 //
806 final boolean lookupMBeanInfo;
807 synchronized (this) {
808 if (!isActive())
809 throw new IllegalArgumentException(
810 "The monitor has been stopped");
811 if (!attribute.equals(getObservedAttribute()))
812 throw new IllegalArgumentException(
813 "The observed attribute has been changed");
814 lookupMBeanInfo =
815 (firstAttribute == null && attribute.indexOf('.') != -1);
816 }
817
818 // Look up MBeanInfo if needed
819 //
820 final MBeanInfo mbi;
821 if (lookupMBeanInfo) {
822 try {
823 mbi = mbsc.getMBeanInfo(object);
824 } catch (IntrospectionException e) {
825 throw new IllegalArgumentException(e);
826 }
827 } else {
828 mbi = null;
829 }
830
831 // Check for complex type attribute
832 //
833 final String fa;
834 synchronized (this) {
835 if (!isActive())
836 throw new IllegalArgumentException(
837 "The monitor has been stopped");
838 if (!attribute.equals(getObservedAttribute()))
839 throw new IllegalArgumentException(
840 "The observed attribute has been changed");
841 if (firstAttribute == null) {
842 if (attribute.indexOf('.') != -1) {
843 MBeanAttributeInfo mbaiArray[] = mbi.getAttributes();
844 for (MBeanAttributeInfo mbai : mbaiArray) {
845 if (attribute.equals(mbai.getName())) {
846 firstAttribute = attribute;
847 break;
848 }
849 }
850 if (firstAttribute == null) {
851 String tokens[] = attribute.split("\\.", -1);
852 firstAttribute = tokens[0];
853 for (int i = 1; i < tokens.length; i++)
854 remainingAttributes.add(tokens[i]);
855 isComplexTypeAttribute = true;
856 }
857 } else {
858 firstAttribute = attribute;
859 }
860 }
861 fa = firstAttribute;
862 }
863 return mbsc.getAttribute(object, fa);
864 }
865
866 Comparable<?> getComparableFromAttribute(ObjectName object,
867 String attribute,
868 Object value)
869 throws AttributeNotFoundException {
870 if (isComplexTypeAttribute) {
871 Object v = value;
872 for (String attr : remainingAttributes)
873 v = Introspector.elementFromComplex(v, attr);
874 return (Comparable<?>) v;
875 } else {
876 return (Comparable<?>) value;
877 }
878 }
879
880 boolean isComparableTypeValid(ObjectName object,
881 String attribute,
882 Comparable<?> value) {
883 return true;
884 }
885
886 String buildErrorNotification(ObjectName object,
887 String attribute,
888 Comparable<?> value) {
889 return null;
890 }
891
892 void onErrorNotification(MonitorNotification notification) {
893 }
894
895 Comparable<?> getDerivedGaugeFromComparable(ObjectName object,
896 String attribute,
897 Comparable<?> value) {
898 return (Comparable<?>) value;
899 }
900
901 MonitorNotification buildAlarmNotification(ObjectName object,
902 String attribute,
903 Comparable<?> value){
904 return null;
905 }
906
907 boolean isThresholdTypeValid(ObjectName object,
908 String attribute,
909 Comparable<?> value) {
910 return true;
911 }
912
913 static Class<? extends Number> classForType(NumericalType type) {
914 switch (type) {
915 case BYTE:
916 return Byte.class;
917 case SHORT:
918 return Short.class;
919 case INTEGER:
920 return Integer.class;
921 case LONG:
922 return Long.class;
923 case FLOAT:
924 return Float.class;
925 case DOUBLE:
926 return Double.class;
927 default:
928 throw new IllegalArgumentException(
929 "Unsupported numerical type");
930 }
931 }
932
933 static boolean isValidForType(Object value, Class<? extends Number> c) {
934 return ((value == INTEGER_ZERO) || c.isInstance(value));
935 }
936
937 /**
938 * Get the specified {@code ObservedObject} if this object is
939 * contained in the set of observed MBeans, or {@code null}
940 * otherwise.
941 *
942 * @param object the name of the {@code ObservedObject} to retrieve.
943 *
944 * @return The {@code ObservedObject} associated to the supplied
945 * {@code ObjectName}.
946 *
947 * @since 1.6
948 */
949 synchronized ObservedObject getObservedObject(ObjectName object) {
950 for (ObservedObject o : observedObjects)
951 if (o.getObservedObject().equals(object))
952 return o;
953 return null;
954 }
955
956 /**
957 * Factory method for ObservedObject creation.
958 *
959 * @since 1.6
960 */
961 ObservedObject createObservedObject(ObjectName object) {
962 return new ObservedObject(object);
963 }
964
965 /**
966 * Create the {@link #alreadyNotified} array from
967 * the {@code ObservedObject} array list.
968 */
969 synchronized void createAlreadyNotified() {
970 // Update elementCount.
971 //
972 elementCount = observedObjects.size();
973
974 // Update arrays.
975 //
976 alreadyNotifieds = new int[elementCount];
977 for (int i = 0; i < elementCount; i++) {
978 alreadyNotifieds[i] = observedObjects.get(i).getAlreadyNotified();
979 }
980 updateDeprecatedAlreadyNotified();
981 }
982
983 /**
984 * Update the deprecated {@link #alreadyNotified} field.
985 */
986 synchronized void updateDeprecatedAlreadyNotified() {
987 if (elementCount > 0)
988 alreadyNotified = alreadyNotifieds[0];
989 else
990 alreadyNotified = 0;
991 }
992
993 /**
994 * Update the {@link #alreadyNotifieds} array element at the given index
995 * with the already notified flag in the given {@code ObservedObject}.
996 * Ensure the deprecated {@link #alreadyNotified} field is updated
997 * if appropriate.
998 */
999 synchronized void updateAlreadyNotified(ObservedObject o, int index) {
1000 alreadyNotifieds[index] = o.getAlreadyNotified();
1001 if (index == 0)
1002 updateDeprecatedAlreadyNotified();
1003 }
1004
1005 /**
1006 * Check if the given bits in the given element of {@link #alreadyNotifieds}
1007 * are set.
1008 */
1009 synchronized boolean isAlreadyNotified(ObservedObject o, int mask) {
1010 return ((o.getAlreadyNotified() & mask) != 0);
1011 }
1012
1013 /**
1014 * Set the given bits in the given element of {@link #alreadyNotifieds}.
1015 * Ensure the deprecated {@link #alreadyNotified} field is updated
1016 * if appropriate.
1017 */
1018 synchronized void setAlreadyNotified(ObservedObject o, int index,
1019 int mask, int an[]) {
1020 final int i = computeAlreadyNotifiedIndex(o, index, an);
1021 if (i == -1)
1022 return;
1023 o.setAlreadyNotified(o.getAlreadyNotified() | mask);
1024 updateAlreadyNotified(o, i);
1025 }
1026
1027 /**
1028 * Reset the given bits in the given element of {@link #alreadyNotifieds}.
1029 * Ensure the deprecated {@link #alreadyNotified} field is updated
1030 * if appropriate.
1031 */
1032 synchronized void resetAlreadyNotified(ObservedObject o,
1033 int index, int mask) {
1034 o.setAlreadyNotified(o.getAlreadyNotified() & ~mask);
1035 updateAlreadyNotified(o, index);
1036 }
1037
1038 /**
1039 * Reset all bits in the given element of {@link #alreadyNotifieds}.
1040 * Ensure the deprecated {@link #alreadyNotified} field is updated
1041 * if appropriate.
1042 */
1043 synchronized void resetAllAlreadyNotified(ObservedObject o,
1044 int index, int an[]) {
1045 final int i = computeAlreadyNotifiedIndex(o, index, an);
1046 if (i == -1)
1047 return;
1048 o.setAlreadyNotified(RESET_FLAGS_ALREADY_NOTIFIED);
1049 updateAlreadyNotified(o, index);
1050 }
1051
1052 /**
1053 * Check if the {@link #alreadyNotifieds} array has been modified.
1054 * If true recompute the index for the given observed object.
1055 */
1056 synchronized int computeAlreadyNotifiedIndex(ObservedObject o,
1057 int index, int an[]) {
1058 if (an == alreadyNotifieds) {
1059 return index;
1060 } else {
1061 return observedObjects.indexOf(o);
1062 }
1063 }
1064
1065 /*
1066 * ------------------------------------------
1067 * PRIVATE METHODS
1068 * ------------------------------------------
1069 */
1070
1071 /**
1072 * This method is used by the monitor MBean to create and send a
1073 * monitor notification to all the listeners registered for this
1074 * kind of notification.
1075 *
1076 * @param type The notification type.
1077 * @param timeStamp The notification emission date.
1078 * @param msg The notification message.
1079 * @param derGauge The derived gauge.
1080 * @param trigger The threshold/string (depending on the monitor
1081 * type) that triggered off the notification.
1082 * @param object The ObjectName of the observed object that triggered
1083 * off the notification.
1084 * @param onError Flag indicating if this monitor notification is
1085 * an error notification or an alarm notification.
1086 */
1087 private void sendNotification(String type, long timeStamp, String msg,
1088 Object derGauge, Object trigger,
1089 ObjectName object, boolean onError) {
1090 if (!isActive())
1091 return;
1092
1093 if (MONITOR_LOGGER.isLoggable(Level.FINER)) {
1094 MONITOR_LOGGER.logp(Level.FINER, Monitor.class.getName(),
1095 "sendNotification", "send notification: " +
1096 "\n\tNotification observed object = " + object +
1097 "\n\tNotification observed attribute = " + observedAttribute +
1098 "\n\tNotification derived gauge = " + derGauge);
1099 }
1100
1101 long seqno = sequenceNumber.getAndIncrement();
1102
1103 MonitorNotification mn =
1104 new MonitorNotification(type,
1105 this,
1106 seqno,
1107 timeStamp,
1108 msg,
1109 object,
1110 observedAttribute,
1111 derGauge,
1112 trigger);
1113 if (onError)
1114 onErrorNotification(mn);
1115 sendNotification(mn);
1116 }
1117
1118 /**
1119 * This method is called by the monitor each time
1120 * the granularity period has been exceeded.
1121 * @param o The observed object.
1122 */
1123 private void monitor(ObservedObject o, int index, int an[]) {
1124
1125 String attribute;
1126 String notifType = null;
1127 String msg = null;
1128 Object derGauge = null;
1129 Object trigger = null;
1130 ObjectName object;
1131 Comparable<?> value = null;
1132 MonitorNotification alarm = null;
1133
1134 if (!isActive())
1135 return;
1136
1137 // Check that neither the observed object nor the
1138 // observed attribute are null. If the observed
1139 // object or observed attribute is null, this means
1140 // that the monitor started before a complete
1141 // initialization and nothing is done.
1142 //
1143 synchronized (this) {
1144 object = o.getObservedObject();
1145 attribute = getObservedAttribute();
1146 if (object == null || attribute == null) {
1147 return;
1148 }
1149 }
1150
1151 // Check that the observed object is registered in the
1152 // MBean server and that the observed attribute
1153 // belongs to the observed object.
1154 //
1155 Object attributeValue = null;
1156 try {
1157 attributeValue = getAttribute(server, object, attribute);
1158 if (attributeValue == null)
1159 if (isAlreadyNotified(
1160 o, OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED))
1161 return;
1162 else {
1163 notifType = OBSERVED_ATTRIBUTE_TYPE_ERROR;
1164 setAlreadyNotified(
1165 o, index, OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED, an);
1166 msg = "The observed attribute value is null.";
1167 MONITOR_LOGGER.logp(Level.FINEST, Monitor.class.getName(),
1168 "monitor", msg);
1169 }
1170 } catch (NullPointerException np_ex) {
1171 if (isAlreadyNotified(o, RUNTIME_ERROR_NOTIFIED))
1172 return;
1173 else {
1174 notifType = RUNTIME_ERROR;
1175 setAlreadyNotified(o, index, RUNTIME_ERROR_NOTIFIED, an);
1176 msg =
1177 "The monitor must be registered in the MBean " +
1178 "server or an MBeanServerConnection must be " +
1179 "explicitly supplied.";
1180 MONITOR_LOGGER.logp(Level.FINEST, Monitor.class.getName(),
1181 "monitor", msg);
1182 MONITOR_LOGGER.logp(Level.FINEST, Monitor.class.getName(),
1183 "monitor", np_ex.toString());
1184 }
1185 } catch (InstanceNotFoundException inf_ex) {
1186 if (isAlreadyNotified(o, OBSERVED_OBJECT_ERROR_NOTIFIED))
1187 return;
1188 else {
1189 notifType = OBSERVED_OBJECT_ERROR;
1190 setAlreadyNotified(
1191 o, index, OBSERVED_OBJECT_ERROR_NOTIFIED, an);
1192 msg =
1193 "The observed object must be accessible in " +
1194 "the MBeanServerConnection.";
1195 MONITOR_LOGGER.logp(Level.FINEST, Monitor.class.getName(),
1196 "monitor", msg);
1197 MONITOR_LOGGER.logp(Level.FINEST, Monitor.class.getName(),
1198 "monitor", inf_ex.toString());
1199 }
1200 } catch (AttributeNotFoundException anf_ex) {
1201 if (isAlreadyNotified(o, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED))
1202 return;
1203 else {
1204 notifType = OBSERVED_ATTRIBUTE_ERROR;
1205 setAlreadyNotified(
1206 o, index, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED, an);
1207 msg =
1208 "The observed attribute must be accessible in " +
1209 "the observed object.";
1210 MONITOR_LOGGER.logp(Level.FINEST, Monitor.class.getName(),
1211 "monitor", msg);
1212 MONITOR_LOGGER.logp(Level.FINEST, Monitor.class.getName(),
1213 "monitor", anf_ex.toString());
1214 }
1215 } catch (MBeanException mb_ex) {
1216 if (isAlreadyNotified(o, RUNTIME_ERROR_NOTIFIED))
1217 return;
1218 else {
1219 notifType = RUNTIME_ERROR;
1220 setAlreadyNotified(o, index, RUNTIME_ERROR_NOTIFIED, an);
1221 msg = mb_ex.getMessage() == null ? "" : mb_ex.getMessage();
1222 MONITOR_LOGGER.logp(Level.FINEST, Monitor.class.getName(),
1223 "monitor", msg);
1224 MONITOR_LOGGER.logp(Level.FINEST, Monitor.class.getName(),
1225 "monitor", mb_ex.toString());
1226 }
1227 } catch (ReflectionException ref_ex) {
1228 if (isAlreadyNotified(o, RUNTIME_ERROR_NOTIFIED)) {
1229 return;
1230 } else {
1231 notifType = RUNTIME_ERROR;
1232 setAlreadyNotified(o, index, RUNTIME_ERROR_NOTIFIED, an);
1233 msg = ref_ex.getMessage() == null ? "" : ref_ex.getMessage();
1234 MONITOR_LOGGER.logp(Level.FINEST, Monitor.class.getName(),
1235 "monitor", msg);
1236 MONITOR_LOGGER.logp(Level.FINEST, Monitor.class.getName(),
1237 "monitor", ref_ex.toString());
1238 }
1239 } catch (IOException io_ex) {
1240 if (isAlreadyNotified(o, RUNTIME_ERROR_NOTIFIED))
1241 return;
1242 else {
1243 notifType = RUNTIME_ERROR;
1244 setAlreadyNotified(o, index, RUNTIME_ERROR_NOTIFIED, an);
1245 msg = io_ex.getMessage() == null ? "" : io_ex.getMessage();
1246 MONITOR_LOGGER.logp(Level.FINEST, Monitor.class.getName(),
1247 "monitor", msg);
1248 MONITOR_LOGGER.logp(Level.FINEST, Monitor.class.getName(),
1249 "monitor", io_ex.toString());
1250 }
1251 } catch (RuntimeException rt_ex) {
1252 if (isAlreadyNotified(o, RUNTIME_ERROR_NOTIFIED))
1253 return;
1254 else {
1255 notifType = RUNTIME_ERROR;
1256 setAlreadyNotified(o, index, RUNTIME_ERROR_NOTIFIED, an);
1257 msg = rt_ex.getMessage() == null ? "" : rt_ex.getMessage();
1258 MONITOR_LOGGER.logp(Level.FINEST, Monitor.class.getName(),
1259 "monitor", msg);
1260 MONITOR_LOGGER.logp(Level.FINEST, Monitor.class.getName(),
1261 "monitor", rt_ex.toString());
1262 }
1263 }
1264
1265 synchronized (this) {
1266
1267 // Check if the monitor has been stopped.
1268 //
1269 if (!isActive())
1270 return;
1271
1272 // Check if the observed attribute has been changed.
1273 //
1274 // Avoid race condition where mbs.getAttribute() succeeded but
1275 // another thread replaced the observed attribute meanwhile.
1276 //
1277 // Avoid setting computed derived gauge on erroneous attribute.
1278 //
1279 if (!attribute.equals(getObservedAttribute()))
1280 return;
1281
1282 // Derive a Comparable object from the ObservedAttribute value
1283 // if the type of the ObservedAttribute value is a complex type.
1284 //
1285 if (msg == null) {
1286 try {
1287 value = getComparableFromAttribute(object,
1288 attribute,
1289 attributeValue);
1290 } catch (ClassCastException e) {
1291 if (isAlreadyNotified(
1292 o, OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED))
1293 return;
1294 else {
1295 notifType = OBSERVED_ATTRIBUTE_TYPE_ERROR;
1296 setAlreadyNotified(o, index,
1297 OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED, an);
1298 msg =
1299 "The observed attribute value does not " +
1300 "implement the Comparable interface.";
1301 MONITOR_LOGGER.logp(Level.FINEST,
1302 Monitor.class.getName(), "monitor", msg);
1303 MONITOR_LOGGER.logp(Level.FINEST,
1304 Monitor.class.getName(), "monitor", e.toString());
1305 }
1306 } catch (AttributeNotFoundException e) {
1307 if (isAlreadyNotified(o, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED))
1308 return;
1309 else {
1310 notifType = OBSERVED_ATTRIBUTE_ERROR;
1311 setAlreadyNotified(
1312 o, index, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED, an);
1313 msg =
1314 "The observed attribute must be accessible in " +
1315 "the observed object.";
1316 MONITOR_LOGGER.logp(Level.FINEST,
1317 Monitor.class.getName(), "monitor", msg);
1318 MONITOR_LOGGER.logp(Level.FINEST,
1319 Monitor.class.getName(), "monitor", e.toString());
1320 }
1321 } catch (RuntimeException e) {
1322 if (isAlreadyNotified(o, RUNTIME_ERROR_NOTIFIED))
1323 return;
1324 else {
1325 notifType = RUNTIME_ERROR;
1326 setAlreadyNotified(o, index,
1327 RUNTIME_ERROR_NOTIFIED, an);
1328 msg = e.getMessage() == null ? "" : e.getMessage();
1329 MONITOR_LOGGER.logp(Level.FINEST,
1330 Monitor.class.getName(), "monitor", msg);
1331 MONITOR_LOGGER.logp(Level.FINEST,
1332 Monitor.class.getName(), "monitor", e.toString());
1333 }
1334 }
1335 }
1336
1337 // Check that the observed attribute type is supported by this
1338 // monitor.
1339 //
1340 if (msg == null) {
1341 if (!isComparableTypeValid(object, attribute, value)) {
1342 if (isAlreadyNotified(
1343 o, OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED))
1344 return;
1345 else {
1346 notifType = OBSERVED_ATTRIBUTE_TYPE_ERROR;
1347 setAlreadyNotified(o, index,
1348 OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED, an);
1349 msg = "The observed attribute type is not valid.";
1350 MONITOR_LOGGER.logp(Level.FINEST,
1351 Monitor.class.getName(), "monitor", msg);
1352 }
1353 }
1354 }
1355
1356 // Check that threshold type is supported by this monitor.
1357 //
1358 if (msg == null) {
1359 if (!isThresholdTypeValid(object, attribute, value)) {
1360 if (isAlreadyNotified(o, THRESHOLD_ERROR_NOTIFIED))
1361 return;
1362 else {
1363 notifType = THRESHOLD_ERROR;
1364 setAlreadyNotified(o, index,
1365 THRESHOLD_ERROR_NOTIFIED, an);
1366 msg = "The threshold type is not valid.";
1367 MONITOR_LOGGER.logp(Level.FINEST,
1368 Monitor.class.getName(), "monitor", msg);
1369 }
1370 }
1371 }
1372
1373 // Let someone subclassing the monitor to perform additional
1374 // monitor consistency checks and report errors if necessary.
1375 //
1376 if (msg == null) {
1377 msg = buildErrorNotification(object, attribute, value);
1378 if (msg != null) {
1379 if (isAlreadyNotified(o, RUNTIME_ERROR_NOTIFIED))
1380 return;
1381 else {
1382 notifType = RUNTIME_ERROR;
1383 setAlreadyNotified(o, index,
1384 RUNTIME_ERROR_NOTIFIED, an);
1385 MONITOR_LOGGER.logp(Level.FINEST,
1386 Monitor.class.getName(), "monitor", msg);
1387 }
1388 }
1389 }
1390
1391 // If no errors were found then clear all error flags and
1392 // let the monitor decide if a notification must be sent.
1393 //
1394 if (msg == null) {
1395 // Clear all already notified flags.
1396 //
1397 resetAllAlreadyNotified(o, index, an);
1398
1399 // Get derived gauge from comparable value.
1400 //
1401 derGauge = getDerivedGaugeFromComparable(object,
1402 attribute,
1403 value);
1404
1405 o.setDerivedGauge(derGauge);
1406 o.setDerivedGaugeTimeStamp(System.currentTimeMillis());
1407
1408 // Check if an alarm must be fired.
1409 //
1410 alarm = buildAlarmNotification(object,
1411 attribute,
1412 (Comparable<?>) derGauge);
1413 }
1414
1415 }
1416
1417 // Notify monitor errors
1418 //
1419 if (msg != null)
1420 sendNotification(notifType,
1421 System.currentTimeMillis(),
1422 msg,
1423 derGauge,
1424 trigger,
1425 object,
1426 true);
1427
1428 // Notify monitor alarms
1429 //
1430 if (alarm != null && alarm.getType() != null)
1431 sendNotification(alarm.getType(),
1432 System.currentTimeMillis(),
1433 alarm.getMessage(),
1434 derGauge,
1435 alarm.getTrigger(),
1436 object,
1437 false);
1438 }
1439
1440 /**
1441 * Cleanup the scheduler and monitor tasks futures.
1442 */
1443 private synchronized void cleanupFutures() {
1444 if (schedulerFuture != null) {
1445 schedulerFuture.cancel(false);
1446 schedulerFuture = null;
1447 }
1448 if (monitorFuture != null) {
1449 monitorFuture.cancel(false);
1450 monitorFuture = null;
1451 }
1452 }
1453
1454 /**
1455 * Cleanup the "is complex type attribute" info.
1456 */
1457 private synchronized void cleanupIsComplexTypeAttribute() {
1458 firstAttribute = null;
1459 remainingAttributes.clear();
1460 isComplexTypeAttribute = false;
1461 }
1462
1463 /**
1464 * SchedulerTask nested class: This class implements the Runnable interface.
1465 *
1466 * The SchedulerTask is executed periodically with a given fixed delay by
1467 * the Scheduled Executor Service.
1468 */
1469 private class SchedulerTask implements Runnable {
1470
1471 private Runnable task = null;
1472
1473 /*
1474 * ------------------------------------------
1475 * CONSTRUCTORS
1476 * ------------------------------------------
1477 */
1478
1479 public SchedulerTask(Runnable task) {
1480 this.task = task;
1481 }
1482
1483 /*
1484 * ------------------------------------------
1485 * PUBLIC METHODS
1486 * ------------------------------------------
1487 */
1488
1489 public void run() {
1490 synchronized (Monitor.this) {
1491 Monitor.this.monitorFuture = executor.submit(task);
1492 }
1493 }
1494 }
1495
1496 /**
1497 * MonitorTask nested class: This class implements the Runnable interface.
1498 *
1499 * The MonitorTask is executed periodically with a given fixed delay by the
1500 * Scheduled Executor Service.
1501 */
1502 private class MonitorTask implements Runnable {
1503
1504 /*
1505 * ------------------------------------------
1506 * CONSTRUCTORS
1507 * ------------------------------------------
1508 */
1509
1510 public MonitorTask() {
1511 }
1512
1513 /*
1514 * ------------------------------------------
1515 * PUBLIC METHODS
1516 * ------------------------------------------
1517 */
1518
1519 public void run() {
1520 final ScheduledFuture<?> sf;
1521 synchronized (Monitor.this) {
1522 sf = Monitor.this.schedulerFuture;
1523 }
1524 AccessController.doPrivileged(new PrivilegedAction<Void>() {
1525 public Void run() {
1526 if (Monitor.this.isActive()) {
1527 final int an[] = alreadyNotifieds;
1528 int index = 0;
1529 for (ObservedObject o : Monitor.this.observedObjects) {
1530 if (Monitor.this.isActive()) {
1531 Monitor.this.monitor(o, index++, an);
1532 }
1533 }
1534 }
1535 return null;
1536 }
1537 }, Monitor.this.acc);
1538 synchronized (Monitor.this) {
1539 if (Monitor.this.isActive() &&
1540 Monitor.this.schedulerFuture == sf) {
1541 Monitor.this.monitorFuture = null;
1542 Monitor.this.schedulerFuture =
1543 scheduler.schedule(Monitor.this.schedulerTask,
1544 Monitor.this.getGranularityPeriod(),
1545 TimeUnit.MILLISECONDS);
1546 }
1547 }
1548 }
1549 }
1550
1551 /**
1552 * Daemon thread factory used by the monitor executors.
1553 * <P>
1554 * This factory creates all new threads used by an Executor in
1555 * the same ThreadGroup. If there is a SecurityManager, it uses
1556 * the group of System.getSecurityManager(), else the group of
1557 * the thread instantiating this DaemonThreadFactory. Each new
1558 * thread is created as a daemon thread with priority
1559 * Thread.NORM_PRIORITY. New threads have names accessible via
1560 * Thread.getName() of "JMX Monitor <pool-name> Pool [Thread-M]",
1561 * where M is the sequence number of the thread created by this
1562 * factory.
1563 */
1564 private static class DaemonThreadFactory implements ThreadFactory {
1565 final ThreadGroup group;
1566 final AtomicInteger threadNumber = new AtomicInteger(1);
1567 final String namePrefix;
1568 static final String nameSuffix = "]";
1569
1570 public DaemonThreadFactory(String poolName) {
1571 SecurityManager s = System.getSecurityManager();
1572 group = (s != null) ? s.getThreadGroup() :
1573 Thread.currentThread().getThreadGroup();
1574 namePrefix = "JMX Monitor " + poolName + " Pool [Thread-";
1575 }
1576
1577 public Thread newThread(Runnable r) {
1578 Thread t = new Thread(group,
1579 r,
1580 namePrefix +
1581 threadNumber.getAndIncrement() +
1582 nameSuffix,
1583 0);
1584 t.setDaemon(true);
1585 if (t.getPriority() != Thread.NORM_PRIORITY)
1586 t.setPriority(Thread.NORM_PRIORITY);
1587 return t;
1588 }
1589 }
1590 }