1 /*
2  * Copyright (c) 1999, 2017, Oracle and/or its affiliates. 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package javax.management.monitor;
27 
28 import static com.sun.jmx.defaults.JmxProperties.MONITOR_LOGGER;
29 import java.lang.System.Logger.Level;
30 import javax.management.ObjectName;
31 import javax.management.MBeanNotificationInfo;
32 import static javax.management.monitor.MonitorNotification.*;
33 
34 /**
35  * Defines a monitor MBean designed to observe the values of a string
36  * attribute.
37  * <P>
38  * A string monitor sends notifications as follows:
39  * <UL>
40  * <LI> if the attribute value matches the string to compare value,
41  *      a {@link MonitorNotification#STRING_TO_COMPARE_VALUE_MATCHED
42  *      match notification} is sent.
43  *      The notify match flag must be set to <CODE>true</CODE>.
44  *      <BR>Subsequent matchings of the string to compare values do not
45  *      cause further notifications unless
46  *      the attribute value differs from the string to compare value.
47  * <LI> if the attribute value differs from the string to compare value,
48  *      a {@link MonitorNotification#STRING_TO_COMPARE_VALUE_DIFFERED
49  *      differ notification} is sent.
50  *      The notify differ flag must be set to <CODE>true</CODE>.
51  *      <BR>Subsequent differences from the string to compare value do
52  *      not cause further notifications unless
53  *      the attribute value matches the string to compare value.
54  * </UL>
55  *
56  *
57  * @since 1.5
58  */
59 public class StringMonitor extends Monitor implements StringMonitorMBean {
60 
61     /*
62      * ------------------------------------------
63      *  PACKAGE CLASSES
64      * ------------------------------------------
65      */
66 
67     static class StringMonitorObservedObject extends ObservedObject {
68 
StringMonitorObservedObject(ObjectName observedObject)69         public StringMonitorObservedObject(ObjectName observedObject) {
70             super(observedObject);
71         }
72 
getStatus()73         public final synchronized int getStatus() {
74             return status;
75         }
setStatus(int status)76         public final synchronized void setStatus(int status) {
77             this.status = status;
78         }
79 
80         private int status;
81     }
82 
83     /*
84      * ------------------------------------------
85      *  PRIVATE VARIABLES
86      * ------------------------------------------
87      */
88 
89     /**
90      * String to compare with the observed attribute.
91      * <BR>The default value is an empty character sequence.
92      */
93     private String stringToCompare = "";
94 
95     /**
96      * Flag indicating if the string monitor notifies when matching
97      * the string to compare.
98      * <BR>The default value is set to <CODE>false</CODE>.
99      */
100     private boolean notifyMatch = false;
101 
102     /**
103      * Flag indicating if the string monitor notifies when differing
104      * from the string to compare.
105      * <BR>The default value is set to <CODE>false</CODE>.
106      */
107     private boolean notifyDiffer = false;
108 
109     private static final String[] types = {
110         RUNTIME_ERROR,
111         OBSERVED_OBJECT_ERROR,
112         OBSERVED_ATTRIBUTE_ERROR,
113         OBSERVED_ATTRIBUTE_TYPE_ERROR,
114         STRING_TO_COMPARE_VALUE_MATCHED,
115         STRING_TO_COMPARE_VALUE_DIFFERED
116     };
117 
118     private static final MBeanNotificationInfo[] notifsInfo = {
119         new MBeanNotificationInfo(
120             types,
121             "javax.management.monitor.MonitorNotification",
122             "Notifications sent by the StringMonitor MBean")
123     };
124 
125     // Flags needed to implement the matching/differing mechanism.
126     //
127     private static final int MATCHING                   = 0;
128     private static final int DIFFERING                  = 1;
129     private static final int MATCHING_OR_DIFFERING      = 2;
130 
131     /*
132      * ------------------------------------------
133      *  CONSTRUCTORS
134      * ------------------------------------------
135      */
136 
137     /**
138      * Default constructor.
139      */
StringMonitor()140     public StringMonitor() {
141     }
142 
143     /*
144      * ------------------------------------------
145      *  PUBLIC METHODS
146      * ------------------------------------------
147      */
148 
149     /**
150      * Starts the string monitor.
151      */
start()152     public synchronized void start() {
153         if (isActive()) {
154             MONITOR_LOGGER.log(Level.TRACE, "the monitor is already active");
155             return;
156         }
157         // Reset values.
158         //
159         for (ObservedObject o : observedObjects) {
160             final StringMonitorObservedObject smo =
161                 (StringMonitorObservedObject) o;
162             smo.setStatus(MATCHING_OR_DIFFERING);
163         }
164         doStart();
165     }
166 
167     /**
168      * Stops the string monitor.
169      */
stop()170     public synchronized void stop() {
171         doStop();
172     }
173 
174     // GETTERS AND SETTERS
175     //--------------------
176 
177     /**
178      * Gets the derived gauge of the specified object, if this object is
179      * contained in the set of observed MBeans, or <code>null</code> otherwise.
180      *
181      * @param object the name of the MBean whose derived gauge is required.
182      *
183      * @return The derived gauge of the specified object.
184      *
185      */
186     @Override
getDerivedGauge(ObjectName object)187     public synchronized String getDerivedGauge(ObjectName object) {
188         return (String) super.getDerivedGauge(object);
189     }
190 
191     /**
192      * Gets the derived gauge timestamp of the specified object, if
193      * this object is contained in the set of observed MBeans, or
194      * <code>0</code> otherwise.
195      *
196      * @param object the name of the object whose derived gauge
197      * timestamp is to be returned.
198      *
199      * @return The derived gauge timestamp of the specified object.
200      *
201      */
202     @Override
getDerivedGaugeTimeStamp(ObjectName object)203     public synchronized long getDerivedGaugeTimeStamp(ObjectName object) {
204         return super.getDerivedGaugeTimeStamp(object);
205     }
206 
207     /**
208      * Returns the derived gauge of the first object in the set of
209      * observed MBeans.
210      *
211      * @return The derived gauge.
212      *
213      * @deprecated As of JMX 1.2, replaced by
214      * {@link #getDerivedGauge(ObjectName)}
215      */
216     @Deprecated
getDerivedGauge()217     public synchronized String getDerivedGauge() {
218         if (observedObjects.isEmpty()) {
219             return null;
220         } else {
221             return (String) observedObjects.get(0).getDerivedGauge();
222         }
223     }
224 
225     /**
226      * Gets the derived gauge timestamp of the first object in the set
227      * of observed MBeans.
228      *
229      * @return The derived gauge timestamp.
230      *
231      * @deprecated As of JMX 1.2, replaced by
232      * {@link #getDerivedGaugeTimeStamp(ObjectName)}
233      */
234     @Deprecated
getDerivedGaugeTimeStamp()235     public synchronized long getDerivedGaugeTimeStamp() {
236         if (observedObjects.isEmpty()) {
237             return 0;
238         } else {
239             return observedObjects.get(0).getDerivedGaugeTimeStamp();
240         }
241     }
242 
243     /**
244      * Gets the string to compare with the observed attribute common
245      * to all observed MBeans.
246      *
247      * @return The string value.
248      *
249      * @see #setStringToCompare
250      */
getStringToCompare()251     public synchronized String getStringToCompare() {
252         return stringToCompare;
253     }
254 
255     /**
256      * Sets the string to compare with the observed attribute common
257      * to all observed MBeans.
258      *
259      * @param value The string value.
260      *
261      * @exception IllegalArgumentException The specified
262      * string to compare is null.
263      *
264      * @see #getStringToCompare
265      */
setStringToCompare(String value)266     public synchronized void setStringToCompare(String value)
267         throws IllegalArgumentException {
268 
269         if (value == null) {
270             throw new IllegalArgumentException("Null string to compare");
271         }
272 
273         if (stringToCompare.equals(value))
274             return;
275         stringToCompare = value;
276 
277         // Reset values.
278         //
279         for (ObservedObject o : observedObjects) {
280             final StringMonitorObservedObject smo =
281                 (StringMonitorObservedObject) o;
282             smo.setStatus(MATCHING_OR_DIFFERING);
283         }
284     }
285 
286     /**
287      * Gets the matching notification's on/off switch value common to
288      * all observed MBeans.
289      *
290      * @return <CODE>true</CODE> if the string monitor notifies when
291      * matching the string to compare, <CODE>false</CODE> otherwise.
292      *
293      * @see #setNotifyMatch
294      */
getNotifyMatch()295     public synchronized boolean getNotifyMatch() {
296         return notifyMatch;
297     }
298 
299     /**
300      * Sets the matching notification's on/off switch value common to
301      * all observed MBeans.
302      *
303      * @param value The matching notification's on/off switch value.
304      *
305      * @see #getNotifyMatch
306      */
setNotifyMatch(boolean value)307     public synchronized void setNotifyMatch(boolean value) {
308         if (notifyMatch == value)
309             return;
310         notifyMatch = value;
311     }
312 
313     /**
314      * Gets the differing notification's on/off switch value common to
315      * all observed MBeans.
316      *
317      * @return <CODE>true</CODE> if the string monitor notifies when
318      * differing from the string to compare, <CODE>false</CODE> otherwise.
319      *
320      * @see #setNotifyDiffer
321      */
getNotifyDiffer()322     public synchronized boolean getNotifyDiffer() {
323         return notifyDiffer;
324     }
325 
326     /**
327      * Sets the differing notification's on/off switch value common to
328      * all observed MBeans.
329      *
330      * @param value The differing notification's on/off switch value.
331      *
332      * @see #getNotifyDiffer
333      */
setNotifyDiffer(boolean value)334     public synchronized void setNotifyDiffer(boolean value) {
335         if (notifyDiffer == value)
336             return;
337         notifyDiffer = value;
338     }
339 
340     /**
341      * Returns a <CODE>NotificationInfo</CODE> object containing the name of
342      * the Java class of the notification and the notification types sent by
343      * the string monitor.
344      */
345     @Override
getNotificationInfo()346     public MBeanNotificationInfo[] getNotificationInfo() {
347         return notifsInfo.clone();
348     }
349 
350     /*
351      * ------------------------------------------
352      *  PACKAGE METHODS
353      * ------------------------------------------
354      */
355 
356     /**
357      * Factory method for ObservedObject creation.
358      *
359      * @since 1.6
360      */
361     @Override
createObservedObject(ObjectName object)362     ObservedObject createObservedObject(ObjectName object) {
363         final StringMonitorObservedObject smo =
364             new StringMonitorObservedObject(object);
365         smo.setStatus(MATCHING_OR_DIFFERING);
366         return smo;
367     }
368 
369     /**
370      * Check that the type of the supplied observed attribute
371      * value is one of the value types supported by this monitor.
372      */
373     @Override
isComparableTypeValid(ObjectName object, String attribute, Comparable<?> value)374     synchronized boolean isComparableTypeValid(ObjectName object,
375                                                String attribute,
376                                                Comparable<?> value) {
377         // Check that the observed attribute is of type "String".
378         //
379         if (value instanceof String) {
380             return true;
381         }
382         return false;
383     }
384 
385     @Override
onErrorNotification(MonitorNotification notification)386     synchronized void onErrorNotification(MonitorNotification notification) {
387         final StringMonitorObservedObject o = (StringMonitorObservedObject)
388             getObservedObject(notification.getObservedObject());
389         if (o == null)
390             return;
391 
392         // Reset values.
393         //
394         o.setStatus(MATCHING_OR_DIFFERING);
395     }
396 
397     @Override
buildAlarmNotification( ObjectName object, String attribute, Comparable<?> value)398     synchronized MonitorNotification buildAlarmNotification(
399                                                ObjectName object,
400                                                String attribute,
401                                                Comparable<?> value) {
402         String type = null;
403         String msg = null;
404         Object trigger = null;
405 
406         final StringMonitorObservedObject o =
407             (StringMonitorObservedObject) getObservedObject(object);
408         if (o == null)
409             return null;
410 
411         // Send matching notification if notifyMatch is true.
412         // Send differing notification if notifyDiffer is true.
413         //
414         if (o.getStatus() == MATCHING_OR_DIFFERING) {
415             if (o.getDerivedGauge().equals(stringToCompare)) {
416                 if (notifyMatch) {
417                     type = STRING_TO_COMPARE_VALUE_MATCHED;
418                     msg = "";
419                     trigger = stringToCompare;
420                 }
421                 o.setStatus(DIFFERING);
422             } else {
423                 if (notifyDiffer) {
424                     type = STRING_TO_COMPARE_VALUE_DIFFERED;
425                     msg = "";
426                     trigger = stringToCompare;
427                 }
428                 o.setStatus(MATCHING);
429             }
430         } else {
431             if (o.getStatus() == MATCHING) {
432                 if (o.getDerivedGauge().equals(stringToCompare)) {
433                     if (notifyMatch) {
434                         type = STRING_TO_COMPARE_VALUE_MATCHED;
435                         msg = "";
436                         trigger = stringToCompare;
437                     }
438                     o.setStatus(DIFFERING);
439                 }
440             } else if (o.getStatus() == DIFFERING) {
441                 if (!o.getDerivedGauge().equals(stringToCompare)) {
442                     if (notifyDiffer) {
443                         type = STRING_TO_COMPARE_VALUE_DIFFERED;
444                         msg = "";
445                         trigger = stringToCompare;
446                     }
447                     o.setStatus(MATCHING);
448                 }
449             }
450         }
451 
452         return new MonitorNotification(type,
453                                        this,
454                                        0,
455                                        0,
456                                        msg,
457                                        null,
458                                        null,
459                                        null,
460                                        trigger);
461     }
462 }
463