View Javadoc
1   /*
2    * Copyright (c) 2004, 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.
8    *
9    * This code is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12   * version 2 for more details (a copy is included in the LICENSE file that
13   * accompanied this code).
14   *
15   * You should have received a copy of the GNU General Public License version
16   * 2 along with this work; if not, write to the Free Software Foundation,
17   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18   *
19   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20   * or visit www.oracle.com if you need additional information or have any
21   * questions.
22   */
23  
24  /*
25   * @test
26   * @bug 4984057
27   * @key randomness
28   * @summary Test that monitors can sample a large number of attributes
29   * @author Eamonn McManus
30   *
31   * @run clean MultiMonitorTest
32   * @run build MultiMonitorTest
33   * @run main MultiMonitorTest
34   */
35  
36  import java.util.*;
37  import javax.management.*;
38  import javax.management.monitor.*;
39  
40  /* We create N MBeans and three monitors, one for each different
41     monitor type.  Each monitor monitors a single attribute in each of
42     the N MBeans.  We arrange for the trigger condition to be
43     satisfied, so the listener we register on each monitor should get N
44     notifications.  */
45  public class MultiMonitorTest {
46      static final int N = 100;
47      static final ObjectName[] mbeanNames = new ObjectName[N];
48      static final Monitored[] monitored = new Monitored[N];
49      static final int COUNTER_THRESHOLD = 1000;
50      static final int OVER_COUNTER_THRESHOLD = 2000;
51      static final double GAUGE_THRESHOLD = 1000.0;
52      static final double OVER_GAUGE_THRESHOLD = 2000.0;
53      static final String STRING_TO_COMPARE = "chou";
54      static final String DIFFERENT_STRING = "chevre";
55  
56      public static void main(String[] args) throws Exception {
57          System.out.println("Test that monitors can sample a large " +
58                             "number of attributes");
59  
60          final MBeanServer mbs = MBeanServerFactory.createMBeanServer();
61          for (int i = 0; i < N; i++) {
62              mbeanNames[i] = new ObjectName(":type=Monitored,instance=" + i);
63              monitored[i] = new Monitored();
64              mbs.registerMBean(monitored[i], mbeanNames[i]);
65          }
66          final ObjectName counterMonitor =
67              new ObjectName(":type=CounterMonitor");
68          final ObjectName gaugeMonitor =
69              new ObjectName(":type=GaugeMonitor");
70          final ObjectName stringMonitor =
71              new ObjectName(":type=StringMonitor");
72          final ObjectName[] monitorNames =
73              new ObjectName[] {counterMonitor, gaugeMonitor, stringMonitor};
74          final String[] attrNames =
75              new String[] {"CounterValue", "GaugeValue", "StringValue"};
76          mbs.createMBean(CounterMonitor.class.getName(), counterMonitor);
77          mbs.createMBean(GaugeMonitor.class.getName(), gaugeMonitor);
78          mbs.createMBean(StringMonitor.class.getName(), stringMonitor);
79          final CounterMonitorMBean counterProxy = (CounterMonitorMBean)
80              MBeanServerInvocationHandler
81              .newProxyInstance(mbs, counterMonitor, CounterMonitorMBean.class,
82                                false);
83          final GaugeMonitorMBean gaugeProxy = (GaugeMonitorMBean)
84              MBeanServerInvocationHandler
85              .newProxyInstance(mbs, gaugeMonitor, GaugeMonitorMBean.class,
86                                false);
87          final StringMonitorMBean stringProxy = (StringMonitorMBean)
88              MBeanServerInvocationHandler
89              .newProxyInstance(mbs, stringMonitor, StringMonitorMBean.class,
90                                false);
91          final MonitorMBean[] proxies = new MonitorMBean[] {
92              counterProxy, gaugeProxy, stringProxy,
93          };
94          for (int i = 0; i < 3; i++) {
95              proxies[i].setGranularityPeriod(1);
96              proxies[i].setObservedAttribute(attrNames[i]);
97              for (int j = 0; j < N; j++)
98                  proxies[i].addObservedObject(mbeanNames[j]);
99          }
100 
101         final CountListener[] listeners = new CountListener[] {
102             new CountListener(), new CountListener(), new CountListener()
103         };
104         for (int i = 0; i < 3; i++) {
105             mbs.addNotificationListener(monitorNames[i], listeners[i],
106                                         null, null);
107         }
108 
109         counterProxy.setInitThreshold(new Integer(COUNTER_THRESHOLD));
110         counterProxy.setNotify(true);
111         gaugeProxy.setThresholds(new Double(GAUGE_THRESHOLD), new Double(0.0));
112         gaugeProxy.setNotifyHigh(true);
113         stringProxy.setStringToCompare(STRING_TO_COMPARE);
114         stringProxy.setNotifyDiffer(true);
115 
116         // A couple of granularity periods to detect bad behaviour
117         Thread.sleep(2);
118 
119         System.out.println("Checking for all listeners to be 0");
120         if (!listenersAreAll(0, listeners)) {
121             System.out.println("TEST FAILED: listeners not all 0");
122             System.exit(1);
123         }
124 
125         for (int i = 0; i < 3; i++)
126             proxies[i].start();
127 
128         System.out.println("Waiting for listeners to all : " + N);
129         int iterations = 0;
130         while (!listenersAreAll(N, listeners)) {
131             Thread.sleep(500);
132 
133             if (++iterations == 10) {
134                for (int i = 0; i < listeners.length; i++) {
135                    System.out.print(" " + listeners[i].getCount());
136                }
137                System.out.println();
138                iterations = 0;
139             }
140         }
141 
142         for (int i = 0; i < 3; i++) {
143             proxies[i].stop();
144             for (int j = 0; j < N; j++)
145                 proxies[i].removeObservedObject(mbeanNames[j]);
146             ObjectName[] observed = proxies[i].getObservedObjects();
147             if (observed.length != 0) {
148                 System.out.println("TEST FAILED: not all observed objects " +
149                                    "removed: " + Arrays.asList(observed));
150                 System.exit(1);
151             }
152         }
153 
154         System.out.println("Test passed");
155     }
156 
157     public static interface MonitoredMBean {
158         public int getCounterValue();
159         public double getGaugeValue();
160         public String getStringValue();
161     }
162 
163     public static class Monitored implements MonitoredMBean {
164         /* We give a small random number of normal readings (possibly
165            zero) before giving a reading that provokes a
166            notification.  */
167         private int okCounter = randomInt(5);
168         private int okGauge = randomInt(5);
169         private int okString = randomInt(5);
170 
171         public synchronized int getCounterValue() {
172             if (--okCounter >= 0)
173                 return 0;
174             else
175                 return OVER_COUNTER_THRESHOLD;
176         }
177 
178         public synchronized double getGaugeValue() {
179             if (--okGauge >= 0)
180                 return 0.0;
181             else
182                 return OVER_GAUGE_THRESHOLD;
183         }
184 
185         public synchronized String getStringValue() {
186             if (--okString >= 0)
187                 return STRING_TO_COMPARE;
188             else
189                 return DIFFERENT_STRING;
190         }
191     }
192 
193     public static class CountListener implements NotificationListener {
194         private int count;
195 
196         public synchronized void handleNotification(Notification n, Object h) {
197             if (!(n instanceof MonitorNotification)) {
198                 System.out.println("TEST FAILED: bad notif: " +
199                                    n.getClass().getName());
200                 System.exit(1);
201             }
202             if (n.getType().indexOf("error") >= 0) {
203                 System.out.println("TEST FAILED: error notif: " + n.getType());
204                 System.exit(1);
205             }
206             count++;
207         }
208 
209         public synchronized int getCount() {
210             return count;
211         }
212     }
213 
214     private static boolean listenersAreAll(int n, CountListener[] listeners) {
215         for (int i = 0; i < listeners.length; i++) {
216             if (listeners[i].getCount() != n)
217                 return false;
218         }
219         return true;
220     }
221 
222     private static final Random random = new Random();
223     static synchronized int randomInt(int n) {
224         return random.nextInt(n);
225     }
226 }