/* * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * @test * @bug 4984057 * @key randomness * @summary Test that monitors can sample a large number of attributes * @author Eamonn McManus * * @run clean MultiMonitorTest * @run build MultiMonitorTest * @run main MultiMonitorTest */ import java.util.*; import javax.management.*; import javax.management.monitor.*; /* We create N MBeans and three monitors, one for each different monitor type. Each monitor monitors a single attribute in each of the N MBeans. We arrange for the trigger condition to be satisfied, so the listener we register on each monitor should get N notifications. */ public class MultiMonitorTest { static final int N = 100; static final ObjectName[] mbeanNames = new ObjectName[N]; static final Monitored[] monitored = new Monitored[N]; static final int COUNTER_THRESHOLD = 1000; static final int OVER_COUNTER_THRESHOLD = 2000; static final double GAUGE_THRESHOLD = 1000.0; static final double OVER_GAUGE_THRESHOLD = 2000.0; static final String STRING_TO_COMPARE = "chou"; static final String DIFFERENT_STRING = "chevre"; public static void main(String[] args) throws Exception { System.out.println("Test that monitors can sample a large " + "number of attributes"); final MBeanServer mbs = MBeanServerFactory.createMBeanServer(); for (int i = 0; i < N; i++) { mbeanNames[i] = new ObjectName(":type=Monitored,instance=" + i); monitored[i] = new Monitored(); mbs.registerMBean(monitored[i], mbeanNames[i]); } final ObjectName counterMonitor = new ObjectName(":type=CounterMonitor"); final ObjectName gaugeMonitor = new ObjectName(":type=GaugeMonitor"); final ObjectName stringMonitor = new ObjectName(":type=StringMonitor"); final ObjectName[] monitorNames = new ObjectName[] {counterMonitor, gaugeMonitor, stringMonitor}; final String[] attrNames = new String[] {"CounterValue", "GaugeValue", "StringValue"}; mbs.createMBean(CounterMonitor.class.getName(), counterMonitor); mbs.createMBean(GaugeMonitor.class.getName(), gaugeMonitor); mbs.createMBean(StringMonitor.class.getName(), stringMonitor); final CounterMonitorMBean counterProxy = (CounterMonitorMBean) MBeanServerInvocationHandler .newProxyInstance(mbs, counterMonitor, CounterMonitorMBean.class, false); final GaugeMonitorMBean gaugeProxy = (GaugeMonitorMBean) MBeanServerInvocationHandler .newProxyInstance(mbs, gaugeMonitor, GaugeMonitorMBean.class, false); final StringMonitorMBean stringProxy = (StringMonitorMBean) MBeanServerInvocationHandler .newProxyInstance(mbs, stringMonitor, StringMonitorMBean.class, false); final MonitorMBean[] proxies = new MonitorMBean[] { counterProxy, gaugeProxy, stringProxy, }; for (int i = 0; i < 3; i++) { proxies[i].setGranularityPeriod(1); proxies[i].setObservedAttribute(attrNames[i]); for (int j = 0; j < N; j++) proxies[i].addObservedObject(mbeanNames[j]); } final CountListener[] listeners = new CountListener[] { new CountListener(), new CountListener(), new CountListener() }; for (int i = 0; i < 3; i++) { mbs.addNotificationListener(monitorNames[i], listeners[i], null, null); } counterProxy.setInitThreshold(new Integer(COUNTER_THRESHOLD)); counterProxy.setNotify(true); gaugeProxy.setThresholds(new Double(GAUGE_THRESHOLD), new Double(0.0)); gaugeProxy.setNotifyHigh(true); stringProxy.setStringToCompare(STRING_TO_COMPARE); stringProxy.setNotifyDiffer(true); // A couple of granularity periods to detect bad behaviour Thread.sleep(2); if (!listenersAreAll(0, listeners)) { System.out.println("TEST FAILED: listeners not all 0"); System.exit(1); } for (int i = 0; i < 3; i++) proxies[i].start(); long startTime = System.currentTimeMillis(); while (!listenersAreAll(N, listeners) && System.currentTimeMillis() < startTime + 5000) Thread.sleep(1); // More time for bad behaviour Thread.sleep(1000); if (!listenersAreAll(N, listeners)) { System.out.print("TEST FAILED: listener counts wrong:"); for (int i = 0; i < listeners.length; i++) System.out.print(" " + listeners[i].getCount()); System.out.println(); System.exit(1); } for (int i = 0; i < 3; i++) { proxies[i].stop(); for (int j = 0; j < N; j++) proxies[i].removeObservedObject(mbeanNames[j]); ObjectName[] observed = proxies[i].getObservedObjects(); if (observed.length != 0) { System.out.println("TEST FAILED: not all observed objects " + "removed: " + Arrays.asList(observed)); System.exit(1); } } System.out.println("Test passed"); } public static interface MonitoredMBean { public int getCounterValue(); public double getGaugeValue(); public String getStringValue(); } public static class Monitored implements MonitoredMBean { /* We give a small random number of normal readings (possibly zero) before giving a reading that provokes a notification. */ private int okCounter = randomInt(5); private int okGauge = randomInt(5); private int okString = randomInt(5); public synchronized int getCounterValue() { if (--okCounter >= 0) return 0; else return OVER_COUNTER_THRESHOLD; } public synchronized double getGaugeValue() { if (--okGauge >= 0) return 0.0; else return OVER_GAUGE_THRESHOLD; } public synchronized String getStringValue() { if (--okString >= 0) return STRING_TO_COMPARE; else return DIFFERENT_STRING; } } public static class CountListener implements NotificationListener { private int count; public synchronized void handleNotification(Notification n, Object h) { if (!(n instanceof MonitorNotification)) { System.out.println("TEST FAILED: bad notif: " + n.getClass().getName()); System.exit(1); } if (n.getType().indexOf("error") >= 0) { System.out.println("TEST FAILED: error notif: " + n.getType()); System.exit(1); } count++; } public synchronized int getCount() { return count; } } private static boolean listenersAreAll(int n, CountListener[] listeners) { for (int i = 0; i < listeners.length; i++) { if (listeners[i].getCount() != n) return false; } return true; } private static final Random random = new Random(); static synchronized int randomInt(int n) { return random.nextInt(n); } }