1 /* 2 * Copyright (c) 2004, 2015, 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 if (!listenersAreAll(0, listeners)) { 120 System.out.println("TEST FAILED: listeners not all 0"); 121 System.exit(1); 122 } 123 124 for (int i = 0; i < 3; i++) 125 proxies[i].start(); 126 127 long startTime = System.currentTimeMillis(); 128 while (!listenersAreAll(N, listeners) 129 && System.currentTimeMillis() < startTime + 5000) 130 Thread.sleep(1); 131 132 // More time for bad behaviour 133 Thread.sleep(1000); 134 135 if (!listenersAreAll(N, listeners)) { 136 System.out.print("TEST FAILED: listener counts wrong:"); 137 for (int i = 0; i < listeners.length; i++) 138 System.out.print(" " + listeners[i].getCount()); 139 System.out.println(); 140 System.exit(1); 141 } 142 143 for (int i = 0; i < 3; i++) { 144 proxies[i].stop(); 145 for (int j = 0; j < N; j++) 146 proxies[i].removeObservedObject(mbeanNames[j]); 147 ObjectName[] observed = proxies[i].getObservedObjects(); 148 if (observed.length != 0) { 149 System.out.println("TEST FAILED: not all observed objects " + 150 "removed: " + Arrays.asList(observed)); 151 System.exit(1); 152 } 153 } 154 155 System.out.println("Test passed"); 156 } 157 158 public static interface MonitoredMBean { 159 public int getCounterValue(); 160 public double getGaugeValue(); 161 public String getStringValue(); 162 } 163 164 public static class Monitored implements MonitoredMBean { 165 /* We give a small random number of normal readings (possibly 166 zero) before giving a reading that provokes a 167 notification. */ 168 private int okCounter = randomInt(5); 169 private int okGauge = randomInt(5); 170 private int okString = randomInt(5); 171 172 public synchronized int getCounterValue() { 173 if (--okCounter >= 0) 174 return 0; 175 else 176 return OVER_COUNTER_THRESHOLD; 177 } 178 179 public synchronized double getGaugeValue() { 180 if (--okGauge >= 0) 181 return 0.0; 182 else 183 return OVER_GAUGE_THRESHOLD; 184 } 185 186 public synchronized String getStringValue() { 187 if (--okString >= 0) 188 return STRING_TO_COMPARE; 189 else 190 return DIFFERENT_STRING; 191 } 192 } 193 194 public static class CountListener implements NotificationListener { 195 private int count; 196 197 public synchronized void handleNotification(Notification n, Object h) { 198 if (!(n instanceof MonitorNotification)) { 199 System.out.println("TEST FAILED: bad notif: " + 200 n.getClass().getName()); 201 System.exit(1); 202 } 203 if (n.getType().indexOf("error") >= 0) { 204 System.out.println("TEST FAILED: error notif: " + n.getType()); 205 System.exit(1); 206 } 207 count++; 208 } 209 210 public synchronized int getCount() { 211 return count; 212 } 213 } 214 215 private static boolean listenersAreAll(int n, CountListener[] listeners) { 216 for (int i = 0; i < listeners.length; i++) { 217 if (listeners[i].getCount() != n) 218 return false; 219 } 220 return true; 221 } 222 223 private static final Random random = new Random(); 224 static synchronized int randomInt(int n) { 225 return random.nextInt(n); 226 } 227 }