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