1. /*
  2. * @(#)CounterMonitor.java 1.74 04/05/18
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.management.monitor;
  8. // java imports
  9. //
  10. import java.util.Date;
  11. import java.util.Timer;
  12. import java.util.TimerTask;
  13. // jmx imports
  14. //
  15. import javax.management.ObjectName;
  16. import javax.management.MBeanNotificationInfo;
  17. import javax.management.AttributeNotFoundException;
  18. import javax.management.InstanceNotFoundException;
  19. import javax.management.MBeanException;
  20. import javax.management.ReflectionException;
  21. /**
  22. * Defines a monitor MBean designed to observe the values of a counter
  23. * attribute.
  24. *
  25. * <P> A counter monitor sends a {@link
  26. * MonitorNotification#THRESHOLD_VALUE_EXCEEDED threshold
  27. * notification} when the value of the counter reaches or exceeds a
  28. * threshold known as the comparison level. The notify flag must be
  29. * set to <CODE>true</CODE>.
  30. *
  31. * <P> In addition, an offset mechanism enables particular counting
  32. * intervals to be detected. If the offset value is not zero,
  33. * whenever the threshold is triggered by the counter value reaching a
  34. * comparison level, that comparison level is incremented by the
  35. * offset value. This is regarded as taking place instantaneously,
  36. * that is, before the count is incremented. Thus, for each level,
  37. * the threshold triggers an event notification every time the count
  38. * increases by an interval equal to the offset value.
  39. *
  40. * <P> If the counter can wrap around its maximum value, the modulus
  41. * needs to be specified. The modulus is the value at which the
  42. * counter is reset to zero.
  43. *
  44. * <P> If the counter difference mode is used, the value of the
  45. * derived gauge is calculated as the difference between the observed
  46. * counter values for two successive observations. If this difference
  47. * is negative, the value of the derived gauge is incremented by the
  48. * value of the modulus. The derived gauge value (V[t]) is calculated
  49. * using the following method:
  50. *
  51. * <UL>
  52. * <LI>if (counter[t] - counter[t-GP]) is positive then
  53. * V[t] = counter[t] - counter[t-GP]
  54. * <LI>if (counter[t] - counter[t-GP]) is negative then
  55. * V[t] = counter[t] - counter[t-GP] + MODULUS
  56. * </UL>
  57. *
  58. * This implementation of the counter monitor requires the observed
  59. * attribute to be of the type integer (<CODE>Byte</CODE>,
  60. * <CODE>Integer</CODE>, <CODE>Short</CODE>, <CODE>Long</CODE>).
  61. *
  62. * @version 1.74 05/18/04
  63. * @author Sun Microsystems, Inc
  64. *
  65. * @since 1.5
  66. */
  67. public class CounterMonitor extends Monitor implements CounterMonitorMBean {
  68. /*
  69. * ------------------------------------------
  70. * PRIVATE VARIABLES
  71. * ------------------------------------------
  72. */
  73. private static final Integer INTEGER_ZERO = new Integer(0);
  74. /**
  75. * Counter thresholds.
  76. * <BR>Each element in this array corresponds to an observed
  77. * object in the list.
  78. */
  79. private Number threshold[] = new Number[capacityIncrement];
  80. /**
  81. * Counter modulus.
  82. * <BR>The default value is a null Integer object.
  83. */
  84. private Number modulus = INTEGER_ZERO;
  85. /**
  86. * Counter offset.
  87. * <BR>The default value is a null Integer object.
  88. */
  89. private Number offset = INTEGER_ZERO;
  90. /**
  91. * Flag indicating if the counter monitor notifies when exceeding
  92. * the threshold. The default value is set to
  93. * <CODE>false</CODE>.
  94. */
  95. private boolean notify = false;
  96. /**
  97. * Flag indicating if the counter difference mode is used. If the
  98. * counter difference mode is used, the derived gauge is the
  99. * difference between two consecutive observed values. Otherwise,
  100. * the derived gauge is directly the value of the observed
  101. * attribute. The default value is set to <CODE>false</CODE>.
  102. */
  103. private boolean differenceMode = false;
  104. /**
  105. * Initial counter threshold. This value is used to initialize
  106. * the threshold when a new object is added to the list and reset
  107. * the threshold to its initial value each time the counter
  108. * resets.
  109. */
  110. private Number initThreshold = INTEGER_ZERO;
  111. /**
  112. * Derived gauges.
  113. *
  114. * <BR>Each element in this array corresponds to an observed
  115. * object in the list.
  116. */
  117. private Number derivedGauge[] = new Number[capacityIncrement];
  118. /**
  119. * Derived gauge timestamp.
  120. * <BR>Each element in this array corresponds to an observed
  121. * object in the list.
  122. */
  123. private long derivedGaugeTimestamp[] = new long[capacityIncrement];
  124. /**
  125. * Scan counter value captured by the previous observation.
  126. * <BR>Each element in this array corresponds to an observed
  127. * object in the list.
  128. */
  129. private Number previousScanCounter[] = new Number[capacityIncrement];
  130. /**
  131. * Flag indicating if the modulus has been exceeded by the
  132. * threshold. This flag is used to reset the threshold once we
  133. * are sure that the counter has been resetted.
  134. * <BR>Each element in this array corresponds to an observed
  135. * object in the list.
  136. */
  137. private boolean modulusExceeded[] = new boolean[capacityIncrement];
  138. /**
  139. * Derived gauge captured when the modulus has been exceeded by
  140. * the threshold. This value is used to check if the counter has
  141. * been resetted (in order to reset the threshold).
  142. * <BR>Each element in this array corresponds to an observed
  143. * object in the list.
  144. */
  145. private Number derivedGaugeExceeded[] = new Number[capacityIncrement];
  146. /**
  147. * This flag is used to notify only once between two granularity
  148. * periods.
  149. * <BR>Each element in this array corresponds to an observed
  150. * object in the list.
  151. */
  152. private boolean eventAlreadyNotified[] = new boolean[capacityIncrement];
  153. /**
  154. * This attribute is used to keep the derived gauge type.
  155. * <BR>Each element in this array corresponds to an observed
  156. * object in the list.
  157. */
  158. private int type[] = new int[capacityIncrement];
  159. // Flags needed to keep trace of the derived gauge type.
  160. // Integer types only are allowed.
  161. //
  162. private static final int INTEGER = 0;
  163. private static final int BYTE = 1;
  164. private static final int SHORT = 2;
  165. private static final int LONG = 3;
  166. // New flags defining possible counter monitor errors.
  167. // Flag denoting that a notification has occured after changing
  168. // the threshold.
  169. // This flag is used to check that the threshold, offset and
  170. // modulus types are the same as the counter.
  171. //
  172. private static final int THRESHOLD_ERROR_NOTIFIED = 16;
  173. /**
  174. * Timer.
  175. */
  176. private Timer timer = null;
  177. // TRACES & DEBUG
  178. //---------------
  179. String makeDebugTag() {
  180. return "CounterMonitor";
  181. }
  182. /*
  183. * ------------------------------------------
  184. * CONSTRUCTORS
  185. * ------------------------------------------
  186. */
  187. /**
  188. * Default constructor.
  189. */
  190. public CounterMonitor() {
  191. dbgTag = makeDebugTag();
  192. }
  193. /*
  194. * ------------------------------------------
  195. * PUBLIC METHODS
  196. * ------------------------------------------
  197. */
  198. /**
  199. * Allows the counter monitor MBean to perform any operations it
  200. * needs before being unregistered by the MBean server.
  201. *
  202. * <P>Resets the threshold values.
  203. *
  204. * @exception java.lang.Exception
  205. */
  206. public void preDeregister() throws java.lang.Exception {
  207. // Stop the CounterMonitor.
  208. //
  209. super.preDeregister();
  210. if (isTraceOn()) {
  211. trace("preDeregister", "reset the threshold values");
  212. }
  213. // Reset values for serialization.
  214. //
  215. synchronized (this) {
  216. for (int i = 0; i < elementCount; i++) {
  217. threshold[i] = initThreshold;
  218. }
  219. }
  220. }
  221. /**
  222. * Starts the counter monitor.
  223. */
  224. public synchronized void start() {
  225. if (isTraceOn()) {
  226. trace("start", "start the counter monitor");
  227. }
  228. if (isActive()) {
  229. if (isTraceOn()) {
  230. trace("start", "the counter monitor is already activated");
  231. }
  232. return;
  233. }
  234. isActive = true;
  235. // Reset values.
  236. //
  237. for (int i = 0; i < elementCount; i++) {
  238. threshold[i] = initThreshold;
  239. modulusExceeded[i] = false;
  240. eventAlreadyNotified[i] = false;
  241. previousScanCounter[i] = null;
  242. }
  243. // Start the timer.
  244. //
  245. timer = new Timer();
  246. timer.schedule(new CounterAlarmClock(this), getGranularityPeriod(),
  247. getGranularityPeriod());
  248. }
  249. /**
  250. * Stops the counter monitor.
  251. *
  252. * This method is not synchronized, because if it were there could
  253. * be a deadlock with a thread that attempted to get the lock on
  254. * the monitor before being interrupted or noticing that it had
  255. * been interrupted.
  256. */
  257. public synchronized void stop() {
  258. if (isTraceOn()) {
  259. trace("stop", "stop the counter monitor");
  260. }
  261. if (isTraceOn()) {
  262. trace("stop", "the counter monitor is not started");
  263. return;
  264. }
  265. isActive = false;
  266. // Stop the timer.
  267. //
  268. if (timer != null) {
  269. timer.cancel();
  270. timer = null;
  271. }
  272. }
  273. // GETTERS AND SETTERS
  274. //--------------------
  275. /**
  276. * Sets the granularity period (in milliseconds).
  277. * <BR>The default value of the granularity period is 10 seconds.
  278. *
  279. * @param period The granularity period value.
  280. * @exception java.lang.IllegalArgumentException The granularity
  281. * period is less than or equal to zero.
  282. *
  283. * @see Monitor#setGranularityPeriod(long)
  284. */
  285. public synchronized void setGranularityPeriod(long period)
  286. throws IllegalArgumentException {
  287. super.setGranularityPeriod(period);
  288. // Reschedule timer task if timer is already running
  289. //
  290. if (isActive()) {
  291. timer.cancel();
  292. timer = new Timer();
  293. timer.schedule(new CounterAlarmClock(this),
  294. getGranularityPeriod(), getGranularityPeriod());
  295. }
  296. }
  297. /**
  298. * Gets the derived gauge of the specified object, if this object is
  299. * contained in the set of observed MBeans, or <code>null</code> otherwise.
  300. *
  301. * @param object the name of the object whose derived gauge is to
  302. * be returned.
  303. *
  304. * @return The derived gauge of the specified object.
  305. *
  306. * @since.unbundled JMX 1.2
  307. */
  308. public synchronized Number getDerivedGauge(ObjectName object) {
  309. int index = indexOf(object);
  310. if (index != -1)
  311. return derivedGauge[index];
  312. else
  313. return null;
  314. }
  315. /**
  316. * Gets the derived gauge timestamp of the specified object, if
  317. * this object is contained in the set of observed MBeans, or
  318. * <code>null</code> otherwise.
  319. *
  320. * @param object the name of the object whose derived gauge
  321. * timestamp is to be returned.
  322. *
  323. * @return The derived gauge timestamp of the specified object.
  324. *
  325. * @since.unbundled JMX 1.2
  326. */
  327. public synchronized long getDerivedGaugeTimeStamp(ObjectName object) {
  328. int index = indexOf(object);
  329. if (index != -1)
  330. return derivedGaugeTimestamp[index];
  331. else
  332. return 0;
  333. }
  334. /**
  335. * Gets the current threshold value of the specified object, if
  336. * this object is contained in the set of observed MBeans, or
  337. * <code>null</code> otherwise.
  338. *
  339. * @param object the name of the object whose threshold is to be
  340. * returned.
  341. *
  342. * @return The threshold value of the specified object.
  343. *
  344. * @see #setThreshold
  345. *
  346. * @since.unbundled JMX 1.2
  347. */
  348. public synchronized Number getThreshold(ObjectName object) {
  349. int index = indexOf(object);
  350. if (index != -1)
  351. return threshold[index];
  352. else
  353. return null;
  354. }
  355. /**
  356. * Gets the initial threshold value common to all observed objects.
  357. *
  358. * @return The initial threshold.
  359. *
  360. * @see #setInitThreshold
  361. *
  362. * @since.unbundled JMX 1.2
  363. */
  364. public synchronized Number getInitThreshold() {
  365. return initThreshold;
  366. }
  367. /**
  368. * Sets the initial threshold value common to all observed objects.
  369. *
  370. * <BR>The current threshold of every object in the set of
  371. * observed MBeans is updated consequently.
  372. *
  373. * @param value The initial threshold value.
  374. * @exception java.lang.IllegalArgumentException The specified
  375. * threshold is null or the threshold value is less than zero.
  376. *
  377. * @see #getInitThreshold
  378. *
  379. * @since.unbundled JMX 1.2
  380. */
  381. public synchronized void setInitThreshold(Number value)
  382. throws IllegalArgumentException {
  383. if (value == null) {
  384. throw new IllegalArgumentException("Null threshold");
  385. }
  386. if (value.longValue() < 0L) {
  387. throw new IllegalArgumentException("Negative threshold");
  388. }
  389. initThreshold = value;
  390. for (int i = 0; i < elementCount; i++) {
  391. threshold[i] = value;
  392. resetAlreadyNotified(i, THRESHOLD_ERROR_NOTIFIED);
  393. // Reset values.
  394. //
  395. modulusExceeded[i] = false;
  396. eventAlreadyNotified[i] = false;
  397. }
  398. }
  399. /**
  400. * Returns the derived gauge of the first object in the set of
  401. * observed MBeans.
  402. *
  403. * @return The derived gauge.
  404. * @deprecated As of JMX 1.2, replaced by {@link #getDerivedGauge(ObjectName)}
  405. */
  406. @Deprecated
  407. public synchronized Number getDerivedGauge() {
  408. return derivedGauge[0];
  409. }
  410. /**
  411. * Gets the derived gauge timestamp of the first object in the set
  412. * of observed MBeans.
  413. *
  414. * @return The derived gauge timestamp.
  415. * @deprecated As of JMX 1.2, replaced by
  416. * {@link #getDerivedGaugeTimeStamp(ObjectName)}
  417. */
  418. @Deprecated
  419. public synchronized long getDerivedGaugeTimeStamp() {
  420. return derivedGaugeTimestamp[0];
  421. }
  422. /**
  423. * Gets the threshold value of the first object in the set of
  424. * observed MBeans.
  425. *
  426. * @return The threshold value.
  427. *
  428. * @see #setThreshold(Number)
  429. *
  430. * @deprecated As of JMX 1.2, replaced by {@link #getThreshold(ObjectName)}
  431. */
  432. @Deprecated
  433. public synchronized Number getThreshold() {
  434. return threshold[0];
  435. }
  436. /**
  437. * Sets the initial threshold value.
  438. *
  439. * @param value The initial threshold value.
  440. * @exception IllegalArgumentException The specified threshold is
  441. * null or the threshold value is less than zero.
  442. *
  443. * @see #getThreshold()
  444. *
  445. * @deprecated As of JMX 1.2, replaced by {@link #setInitThreshold}
  446. */
  447. @Deprecated
  448. public synchronized void setThreshold(Number value)
  449. throws IllegalArgumentException {
  450. setInitThreshold(value);
  451. }
  452. /**
  453. * Gets the offset value common to all observed MBeans.
  454. *
  455. * @return The offset value.
  456. *
  457. * @see #setOffset
  458. */
  459. public synchronized Number getOffset() {
  460. return offset;
  461. }
  462. /**
  463. * Sets the offset value common to all observed MBeans.
  464. *
  465. * @param value The offset value.
  466. * @exception java.lang.IllegalArgumentException The specified
  467. * offset is null or the offset value is less than zero.
  468. *
  469. * @see #getOffset
  470. */
  471. public synchronized void setOffset(Number value)
  472. throws IllegalArgumentException {
  473. if (value == null) {
  474. throw new IllegalArgumentException("Null offset");
  475. }
  476. if (value.longValue() < 0L) {
  477. throw new IllegalArgumentException("Negative offset");
  478. }
  479. offset = value;
  480. for (int i = 0; i < elementCount; i++) {
  481. resetAlreadyNotified(i, THRESHOLD_ERROR_NOTIFIED);
  482. }
  483. }
  484. /**
  485. * Gets the modulus value common to all observed MBeans.
  486. *
  487. * @see #setModulus
  488. *
  489. * @return The modulus value.
  490. */
  491. public synchronized Number getModulus() {
  492. return modulus;
  493. }
  494. /**
  495. * Sets the modulus value common to all observed MBeans.
  496. *
  497. * @param value The modulus value.
  498. * @exception java.lang.IllegalArgumentException The specified
  499. * modulus is null or the modulus value is less than zero.
  500. *
  501. * @see #getModulus
  502. */
  503. public synchronized void setModulus(Number value)
  504. throws IllegalArgumentException {
  505. if (value == null) {
  506. throw new IllegalArgumentException("Null modulus");
  507. }
  508. if (value.longValue() < 0L) {
  509. throw new IllegalArgumentException("Negative modulus");
  510. }
  511. modulus = value;
  512. for (int i = 0; i < elementCount; i++) {
  513. resetAlreadyNotified(i, THRESHOLD_ERROR_NOTIFIED);
  514. // Reset values.
  515. //
  516. modulusExceeded[i] = false;
  517. }
  518. }
  519. /**
  520. * Gets the notification's on/off switch value common to all
  521. * observed MBeans.
  522. *
  523. * @return <CODE>true</CODE> if the counter monitor notifies when
  524. * exceeding the threshold, <CODE>false</CODE> otherwise.
  525. *
  526. * @see #setNotify
  527. */
  528. public synchronized boolean getNotify() {
  529. return notify;
  530. }
  531. /**
  532. * Sets the notification's on/off switch value common to all
  533. * observed MBeans.
  534. *
  535. * @param value The notification's on/off switch value.
  536. *
  537. * @see #getNotify
  538. */
  539. public synchronized void setNotify(boolean value) {
  540. notify = value;
  541. }
  542. /**
  543. * Gets the difference mode flag value common to all observed MBeans.
  544. *
  545. * @return <CODE>true</CODE> if the difference mode is used,
  546. * <CODE>false</CODE> otherwise.
  547. *
  548. * @see #setDifferenceMode
  549. */
  550. public synchronized boolean getDifferenceMode() {
  551. return differenceMode;
  552. }
  553. /**
  554. * Sets the difference mode flag value common to all observed MBeans.
  555. *
  556. * @param value The difference mode flag value.
  557. *
  558. * @see #getDifferenceMode
  559. */
  560. public synchronized void setDifferenceMode(boolean value) {
  561. differenceMode = value;
  562. for (int i = 0; i < elementCount; i++) {
  563. // Reset values.
  564. //
  565. threshold[i] = initThreshold;
  566. modulusExceeded[i] = false;
  567. eventAlreadyNotified[i] = false;
  568. previousScanCounter[i] = null;
  569. }
  570. }
  571. /**
  572. * Returns a <CODE>NotificationInfo</CODE> object containing the
  573. * name of the Java class of the notification and the notification
  574. * types sent by the counter monitor.
  575. */
  576. public MBeanNotificationInfo[] getNotificationInfo() {
  577. String[] types = { MonitorNotification.RUNTIME_ERROR,
  578. MonitorNotification.OBSERVED_OBJECT_ERROR,
  579. MonitorNotification.OBSERVED_ATTRIBUTE_ERROR,
  580. MonitorNotification.OBSERVED_ATTRIBUTE_TYPE_ERROR,
  581. MonitorNotification.THRESHOLD_ERROR,
  582. MonitorNotification.THRESHOLD_VALUE_EXCEEDED};
  583. MBeanNotificationInfo[] notifsInfo = {
  584. new MBeanNotificationInfo(types,
  585. "javax.management.monitor.MonitorNotification",
  586. "Notifications sent by the CounterMonitor MBean")
  587. };
  588. return notifsInfo;
  589. }
  590. /*
  591. * ------------------------------------------
  592. * PRIVATE METHODS
  593. * ------------------------------------------
  594. */
  595. /**
  596. * Updates the derived gauge and the derived gauge timestamp attributes
  597. * of the observed object at the specified index.
  598. *
  599. * @param scanCounter The value of the observed attribute.
  600. * @param index The index of the observed object.
  601. * @return <CODE>true</CODE> if the derived gauge value is valid,
  602. * <CODE>false</CODE> otherwise. The derived gauge value is
  603. * invalid when the differenceMode flag is set to
  604. * <CODE>true</CODE> and it is the first notification (so we
  605. * haven't 2 consecutive values to update the derived gauge).
  606. */
  607. private synchronized boolean updateDerivedGauge(Object scanCounter,
  608. int index) {
  609. boolean is_derived_gauge_valid;
  610. derivedGaugeTimestamp[index] = System.currentTimeMillis();
  611. // The counter difference mode is used.
  612. //
  613. if (differenceMode) {
  614. // The previous scan counter has been initialized.
  615. //
  616. if (previousScanCounter[index] != null) {
  617. setDerivedGaugeWithDifference((Number)scanCounter, null, index);
  618. // If derived gauge is negative it means that the
  619. // counter has wrapped around and the value of the
  620. // threshold needs to be reset to its initial value.
  621. //
  622. if (derivedGauge[index].longValue() < 0L) {
  623. if (modulus.longValue() > 0L) {
  624. setDerivedGaugeWithDifference((Number)scanCounter,
  625. (Number)modulus, index);
  626. }
  627. threshold[index] = initThreshold;
  628. eventAlreadyNotified[index] = false;
  629. }
  630. is_derived_gauge_valid = true;
  631. }
  632. // The previous scan counter has not been initialized.
  633. // We cannot update the derived gauge...
  634. //
  635. else {
  636. is_derived_gauge_valid = false;
  637. }
  638. previousScanCounter[index] = (Number)scanCounter;
  639. }
  640. // The counter difference mode is not used.
  641. //
  642. else {
  643. derivedGauge[index] = (Number)scanCounter;
  644. is_derived_gauge_valid = true;
  645. }
  646. return is_derived_gauge_valid;
  647. }
  648. /**
  649. * Updates the notification attribute of the observed object at the
  650. * specified index and notifies the listeners only once if the notify flag
  651. * is set to <CODE>true</CODE>.
  652. * @param index The index of the observed object.
  653. */
  654. private void updateNotifications(int index) {
  655. boolean sendNotif = false;
  656. String notifType = null;
  657. long timeStamp = 0;
  658. String msg = null;
  659. Object derGauge = null;
  660. Object trigger = null;
  661. synchronized(this) {
  662. // Send notification if notify is true.
  663. //
  664. if (!eventAlreadyNotified[index]) {
  665. if (derivedGauge[index].longValue() >=
  666. threshold[index].longValue()) {
  667. if (notify) {
  668. sendNotif = true;
  669. notifType = MonitorNotification.THRESHOLD_VALUE_EXCEEDED;
  670. timeStamp = derivedGaugeTimestamp[index];
  671. msg = "";
  672. derGauge = derivedGauge[index];
  673. trigger = threshold[index];
  674. }
  675. if (!differenceMode) {
  676. eventAlreadyNotified[index] = true;
  677. }
  678. }
  679. } else {
  680. if (isTraceOn()) {
  681. trace("updateNotifications", "the notification:" +
  682. "\n\tNotification observed object = " +
  683. getObservedObject(index) +
  684. "\n\tNotification observed attribute = " +
  685. getObservedAttribute() +
  686. "\n\tNotification derived gauge = " +
  687. derivedGauge[index] +
  688. "\nhas already been sent");
  689. }
  690. }
  691. }
  692. if (sendNotif) {
  693. sendNotification(notifType, timeStamp, msg, derGauge, trigger, index);
  694. }
  695. }
  696. /**
  697. * Updates the threshold attribute of the observed object at the
  698. * specified index.
  699. * @param index The index of the observed object.
  700. */
  701. private synchronized void updateThreshold(int index) {
  702. // Calculate the new threshold value if the threshold has been
  703. // exceeded and if the offset value is greater than zero.
  704. //
  705. if (derivedGauge[index].longValue() >= threshold[index].longValue()) {
  706. if (offset.longValue() > 0L) {
  707. // Increment the threshold until its value is greater
  708. // than the one for the current derived gauge.
  709. //
  710. long threshold_value = threshold[index].longValue();
  711. while (derivedGauge[index].longValue() >= threshold_value) {
  712. threshold_value += offset.longValue();
  713. }
  714. // Set threshold attribute.
  715. //
  716. switch(type[index]) {
  717. case INTEGER:
  718. threshold[index] = new Integer((int)threshold_value);
  719. break;
  720. case BYTE:
  721. threshold[index] = new Byte((byte)threshold_value);
  722. break;
  723. case SHORT:
  724. threshold[index] = new Short((short)threshold_value);
  725. break;
  726. case LONG:
  727. threshold[index] = new Long((long)threshold_value);
  728. break;
  729. default:
  730. // Should never occur...
  731. if (isDebugOn()) {
  732. debug("updateThreshold", "the threshold type is invalid");
  733. }
  734. break;
  735. }
  736. // If the counter can wrap around when it reaches its maximum
  737. // and we are not dealing with counter differences then we need
  738. // to reset the threshold to its initial value too.
  739. //
  740. if (!differenceMode) {
  741. if (modulus.longValue() > 0L) {
  742. if (threshold[index].longValue() > modulus.longValue()) {
  743. modulusExceeded[index] = true;
  744. derivedGaugeExceeded[index] = derivedGauge[index];
  745. }
  746. }
  747. }
  748. // Threshold value has been modified so we can notify again.
  749. //
  750. eventAlreadyNotified[index] = false;
  751. }
  752. else {
  753. modulusExceeded[index] = true;
  754. derivedGaugeExceeded[index] = derivedGauge[index];
  755. }
  756. }
  757. }
  758. /**
  759. * Tests if the threshold, offset and modulus of the specified index are
  760. * of the same type as the counter. Only integer types are allowed.
  761. *
  762. * Note:
  763. * If the optional offset or modulus have not been initialized, their
  764. * default value is an Integer object with a value equal to zero.
  765. *
  766. * @param index The index of the observed object.
  767. * @return <CODE>true</CODE> if type is the same,
  768. * <CODE>false</CODE> otherwise.
  769. */
  770. private synchronized boolean isThresholdTypeValid(int index) {
  771. switch(type[index]) {
  772. case INTEGER:
  773. return ((threshold[index] instanceof Integer) &&
  774. ((offset == INTEGER_ZERO) ||
  775. (offset instanceof Integer)) &&
  776. ((modulus == INTEGER_ZERO) ||
  777. (modulus instanceof Integer)));
  778. case BYTE:
  779. return ((threshold[index] instanceof Byte) &&
  780. ((offset == INTEGER_ZERO) ||
  781. (offset instanceof Byte)) &&
  782. ((modulus == INTEGER_ZERO) ||
  783. (modulus instanceof Byte)));
  784. case SHORT:
  785. return ((threshold[index] instanceof Short) &&
  786. ((offset == INTEGER_ZERO) ||
  787. (offset instanceof Short)) &&
  788. ((modulus == INTEGER_ZERO) ||
  789. (modulus instanceof Short)));
  790. case LONG:
  791. return ((threshold[index] instanceof Long) &&
  792. ((offset == INTEGER_ZERO) ||
  793. (offset instanceof Long)) &&
  794. ((modulus == INTEGER_ZERO) ||
  795. (modulus instanceof Long)));
  796. default:
  797. // Should never occured...
  798. if (isDebugOn()) {
  799. debug("isThresholdTypeValid", "The threshold type is invalid");
  800. }
  801. return false;
  802. }
  803. }
  804. /**
  805. * Sets the derived gauge of the specified index when the
  806. * differenceMode flag is set to <CODE>true</CODE>. Integer types
  807. * only are allowed.
  808. *
  809. * @param scanCounter The value of the observed attribute.
  810. * @param mod The counter modulus value.
  811. * @param index The index of the observed object.
  812. */
  813. private synchronized void setDerivedGaugeWithDifference(Number scanCounter,
  814. Number mod,
  815. int index) {
  816. /* We do the arithmetic using longs here even though the
  817. result may end up in a smaller type. Since
  818. l == (byte)l (mod 256) for any long l,
  819. (byte) ((byte)l1 + (byte)l2) == (byte) (l1 + l2),
  820. and likewise for subtraction. So it's the same as if
  821. we had done the arithmetic in the smaller type.*/
  822. long derived =
  823. scanCounter.longValue() - previousScanCounter[index].longValue();
  824. if (mod != null)
  825. derived += modulus.longValue();
  826. switch (type[index]) {
  827. case INTEGER: derivedGauge[index] = new Integer((int) derived); break;
  828. case BYTE: derivedGauge[index] = new Byte((byte) derived); break;
  829. case SHORT: derivedGauge[index] = new Short((short) derived); break;
  830. case LONG: derivedGauge[index] = new Long(derived); break;
  831. default:
  832. // Should never occur...
  833. if (isDebugOn()) {
  834. debug("setDerivedGaugeWithDifference",
  835. "the threshold type is invalid");
  836. }
  837. break;
  838. }
  839. }
  840. /*
  841. * ------------------------------------------
  842. * PACKAGE METHODS
  843. * ------------------------------------------
  844. */
  845. /**
  846. * This method is called by the counter monitor each time
  847. * the granularity period has been exceeded.
  848. * @param index The index of the observed object.
  849. */
  850. void notifyAlarmClock(int index) {
  851. long timeStamp = 0;
  852. String msg = null;
  853. Object derGauge = null;
  854. Object scan_counter = null;
  855. String notif_type = null;
  856. synchronized(this) {
  857. if (!isActive())
  858. return;
  859. // Check if the observed object and observed attribute are valid.
  860. //
  861. // Check that neither the observed object nor the
  862. // observed attribute are null. If the observed
  863. // object or observed attribute is null, this means
  864. // that the monitor started before a complete
  865. // initialization and nothing is done.
  866. //
  867. if ((getObservedObject(index) == null) ||
  868. (getObservedAttribute() == null)) {
  869. return;
  870. }
  871. // Check that the observed object is registered in the
  872. // MBean server and that the observed attribute
  873. // belongs to the observed object.
  874. //
  875. try {
  876. scan_counter = server.getAttribute(getObservedObject(index),
  877. getObservedAttribute());
  878. if (scan_counter == null)
  879. return;
  880. } catch (NullPointerException np_ex) {
  881. if (alreadyNotified(index, RUNTIME_ERROR_NOTIFIED))
  882. return;
  883. else {
  884. notif_type = MonitorNotification.RUNTIME_ERROR;
  885. setAlreadyNotified(index, RUNTIME_ERROR_NOTIFIED);
  886. msg =
  887. "The counter monitor must be registered in " +
  888. "the MBean server.";
  889. }
  890. } catch (InstanceNotFoundException inf_ex) {
  891. if (alreadyNotified(index, OBSERVED_OBJECT_ERROR_NOTIFIED))
  892. return;
  893. else {
  894. notif_type = MonitorNotification.OBSERVED_OBJECT_ERROR;
  895. setAlreadyNotified(index, OBSERVED_OBJECT_ERROR_NOTIFIED);
  896. msg =
  897. "The observed object must be registered in " +
  898. "the MBean server.";
  899. }
  900. } catch (AttributeNotFoundException anf_ex) {
  901. if (alreadyNotified(index, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED))
  902. return;
  903. else {
  904. notif_type = MonitorNotification.OBSERVED_ATTRIBUTE_ERROR;
  905. setAlreadyNotified(index, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED);
  906. msg =
  907. "The observed attribute must be accessible in " +
  908. "the observed object.";
  909. }
  910. } catch (MBeanException mb_ex) {
  911. if (alreadyNotified(index, RUNTIME_ERROR_NOTIFIED))
  912. return;
  913. else {
  914. notif_type = MonitorNotification.RUNTIME_ERROR;
  915. setAlreadyNotified(index, RUNTIME_ERROR_NOTIFIED);
  916. msg = mb_ex.getMessage();
  917. }
  918. } catch (ReflectionException ref_ex) {
  919. if (alreadyNotified(index, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED)) {
  920. return;
  921. } else {
  922. notif_type = MonitorNotification.OBSERVED_ATTRIBUTE_ERROR;
  923. setAlreadyNotified(index, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED);
  924. msg = ref_ex.getMessage();
  925. }
  926. }
  927. if (msg == null) {
  928. // Check that the observed attribute is of type "Integer".
  929. //
  930. if (scan_counter instanceof Integer) {
  931. type[index] = INTEGER;
  932. } else if (scan_counter instanceof Byte) {
  933. type[index] = BYTE;
  934. } else if (scan_counter instanceof Short) {
  935. type[index] = SHORT;
  936. } else if (scan_counter instanceof Long) {
  937. type[index] = LONG;
  938. } else {
  939. if (alreadyNotified(index,
  940. OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED))
  941. return;
  942. else {
  943. notif_type =
  944. MonitorNotification.OBSERVED_ATTRIBUTE_TYPE_ERROR;
  945. setAlreadyNotified(index,
  946. OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED);
  947. msg =
  948. "The observed attribute type must be " +
  949. "an integer type.";
  950. }
  951. }
  952. }
  953. if (msg == null) {
  954. // Check that threshold, offset and modulus have
  955. // values that fit in the counter's type
  956. //
  957. if (!isThresholdTypeValid(index)) {
  958. if (alreadyNotified(index, THRESHOLD_ERROR_NOTIFIED))
  959. return;
  960. else {
  961. notif_type = MonitorNotification.THRESHOLD_ERROR;
  962. setAlreadyNotified(index, THRESHOLD_ERROR_NOTIFIED);
  963. msg =
  964. "The threshold, offset and modulus must " +
  965. "be of the same type as the counter.";
  966. }
  967. }
  968. }
  969. if (msg == null) {
  970. // Clear all already notified flags.
  971. //
  972. resetAllAlreadyNotified(index);
  973. // Check if counter has wrapped around.
  974. //
  975. if (modulusExceeded[index]) {
  976. if (derivedGauge[index].longValue() <
  977. derivedGaugeExceeded[index].longValue()) {
  978. threshold[index] = initThreshold;
  979. modulusExceeded[index] = false;
  980. eventAlreadyNotified[index] = false;
  981. }
  982. }
  983. // Update the derived gauge attributes and check the
  984. // validity of the new value. The derived gauge value
  985. // is invalid when the differenceMode flag is set to
  986. // true and it is the first notification (so we
  987. // haven't 2 consecutive values to update the derived
  988. // gauge).
  989. //
  990. boolean is_derived_gauge_valid =
  991. updateDerivedGauge(scan_counter, index);
  992. // Notify the listeners and update the threshold if
  993. // the updated derived gauge value is valid.
  994. //
  995. if (is_derived_gauge_valid) {
  996. updateNotifications(index);
  997. updateThreshold(index);
  998. }
  999. } else {
  1000. // msg != null, will send an error notification
  1001. timeStamp = derivedGaugeTimestamp[index];
  1002. derGauge = derivedGauge[index];
  1003. // Reset values.
  1004. //
  1005. modulusExceeded[index] = false;
  1006. eventAlreadyNotified[index] = false;
  1007. previousScanCounter[index] = null;
  1008. }
  1009. }
  1010. if (msg != null) {
  1011. sendNotification(notif_type,
  1012. timeStamp,
  1013. msg,
  1014. derGauge,
  1015. null,
  1016. index);
  1017. }
  1018. }
  1019. /**
  1020. * This method is called when adding a new observed object in the vector.
  1021. * It updates all the counter specific arrays.
  1022. * @param index The index of the observed object.
  1023. */
  1024. synchronized void insertSpecificElementAt(int index) {
  1025. // Update threshold, derivedGauge, derivedGaugeTimestamp,
  1026. // previousScanCounter, modulusExceeded, derivedGaugeExceeded,
  1027. // eventAlreadyNotified and type values.
  1028. if (index != elementCount)
  1029. throw new Error("Internal error: index != elementCount");
  1030. if (elementCount >= threshold.length) {
  1031. threshold = expandArray(threshold);
  1032. derivedGauge = expandArray(derivedGauge);
  1033. previousScanCounter = expandArray(previousScanCounter);
  1034. derivedGaugeExceeded = expandArray(derivedGaugeExceeded);
  1035. derivedGaugeTimestamp = expandArray(derivedGaugeTimestamp);
  1036. modulusExceeded = expandArray(modulusExceeded);
  1037. eventAlreadyNotified = expandArray(eventAlreadyNotified);
  1038. type = expandArray(type);
  1039. }
  1040. threshold[index] = INTEGER_ZERO;
  1041. derivedGauge[index] = INTEGER_ZERO;
  1042. previousScanCounter[index] = null;
  1043. derivedGaugeExceeded[index] = null;
  1044. derivedGaugeTimestamp[index] = System.currentTimeMillis();
  1045. modulusExceeded[index] = false;
  1046. eventAlreadyNotified[index] = false;
  1047. type[index] = INTEGER;
  1048. }
  1049. /**
  1050. * This method is called when removing an observed object from the vector.
  1051. * It updates all the counter specific arrays.
  1052. * @param index The index of the observed object.
  1053. */
  1054. synchronized void removeSpecificElementAt(int index) {
  1055. // Update threshold, derivedGauge, derivedGaugeTimestamp,
  1056. // previousScanCounter, modulusExceeded, derivedGaugeExceeded,
  1057. // eventAlreadyNotified and type values.
  1058. //
  1059. removeElementAt(threshold, index);
  1060. removeElementAt(derivedGauge, index);
  1061. removeElementAt(previousScanCounter, index);
  1062. removeElementAt(derivedGaugeExceeded, index);
  1063. removeElementAt(derivedGaugeTimestamp, index);
  1064. removeElementAt(modulusExceeded, index);
  1065. removeElementAt(eventAlreadyNotified, index);
  1066. removeElementAt(type, index);
  1067. }
  1068. /**
  1069. * CounterAlarmClock inner class: This class provides a simple
  1070. * implementation of an alarm clock MBean. The aim of this MBean is
  1071. * to set up an alarm which wakes up the counter monitor every
  1072. * granularity period.
  1073. */
  1074. private static class CounterAlarmClock extends TimerTask {
  1075. CounterMonitor listener = null;
  1076. /*
  1077. * ------------------------------------------
  1078. * CONSTRUCTORS
  1079. * ------------------------------------------
  1080. */
  1081. public CounterAlarmClock(CounterMonitor listener) {
  1082. this.listener = listener;
  1083. }
  1084. /*
  1085. * ------------------------------------------
  1086. * PUBLIC METHODS
  1087. * ------------------------------------------
  1088. */
  1089. /**
  1090. * This method is called by the CounterAlarmClock thread when
  1091. * it is started.
  1092. */
  1093. public void run() {
  1094. if (listener.isActive()) {
  1095. for (int i = 0; i < listener.elementCount; i++) {
  1096. listener.notifyAlarmClock(i);
  1097. }
  1098. }
  1099. }
  1100. }
  1101. }