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
36import java.util.*;
37import javax.management.*;
38import 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.  */
45public 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}
227