1 /* 2 * Copyright (c) 2003, 2013, 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 4886838 4886830 8025204 27 * @summary Tests that idle timeouts happen at appropriate times 28 * @author Eamonn McManus 29 * @run clean IdleTimeoutTest 30 * @run build IdleTimeoutTest 31 * @run main IdleTimeoutTest 32 */ 33 34 import java.util.Arrays; 35 import java.util.ArrayList; 36 import java.util.Iterator; 37 import java.util.List; 38 import java.util.HashMap; 39 import java.util.Map; 40 import javax.management.MBeanServer; 41 import javax.management.MBeanServerConnection; 42 import javax.management.MBeanServerFactory; 43 import javax.management.MBeanServerNotification; 44 import javax.management.Notification; 45 import javax.management.NotificationListener; 46 import javax.management.ObjectName; 47 import javax.management.remote.JMXConnector; 48 import javax.management.remote.JMXConnectorFactory; 49 import javax.management.remote.JMXConnectorServer; 50 import javax.management.remote.JMXConnectorServerFactory; 51 import javax.management.remote.JMXServiceURL; 52 import com.sun.jmx.remote.util.EnvHelp; 53 54 public class IdleTimeoutTest { 55 56 static boolean isPresent(String cn) { 57 try { 58 Class.forName(cn); 59 return true; 60 } catch (ClassNotFoundException x) { 61 return false; 62 } 63 } 64 65 public static void main(String[] args) throws Exception { 66 boolean ok = true; 67 List protos; 68 if (args.length > 0) 69 protos = Arrays.asList(args); 70 else { 71 protos = new ArrayList(Arrays.asList(new String[] {"rmi"})); 72 if (isPresent("javax.management.remote.rmi._RMIConnectionImpl_Tie")) 73 protos.add("iiop"); 74 if (isPresent("javax.management.remote.jmxmp.JMXMPConnectorServer")) 75 protos.add("jmxmp"); 76 } 77 for (Iterator it = protos.iterator(); it.hasNext(); ) { 78 String proto = (String) it.next(); 79 int liCount; 80 if (proto.equals("jmxmp")) liCount=1; 81 else liCount=2; 82 if (test(proto,4,liCount)) 83 System.out.println("Test for protocol " + proto + " passed"); 84 else { 85 System.out.println("Test for protocol " + proto + " FAILED"); 86 ok = false; 87 } 88 } 89 if (!ok) { 90 throw new RuntimeException("Some tests failed - see log for details"); 91 } 92 } 93 94 private static long getIdleTimeout(MBeanServer mbs, JMXServiceURL url) 95 throws Exception 96 { 97 JMXConnectorServer server = 98 JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs); 99 server.start(); 100 try { 101 url = server.getAddress(); 102 103 // Force initialization (class loading, JIT, etc...) 104 // 105 JMXConnector client = JMXConnectorFactory.connect(url); 106 try { 107 String connId = client.getConnectionId(); 108 MBeanServerConnection conn = client.getMBeanServerConnection(); 109 } finally { 110 client.close(); 111 } 112 113 // Do the time measurement 114 // 115 final long firstTime = System.currentTimeMillis(); 116 final long endtime; 117 client = JMXConnectorFactory.connect(url); 118 try { 119 String connId = client.getConnectionId(); 120 MBeanServerConnection conn = client.getMBeanServerConnection(); 121 endtime = System.currentTimeMillis(); 122 } finally { 123 client.close(); 124 } 125 126 // multipled by 10 for a slow machine, plus 1500 for a fast one. 127 return 10*(endtime - firstTime) + 1500; 128 } finally { 129 server.stop(); 130 } 131 } 132 133 private static class NotificationCounter 134 implements NotificationListener { 135 private final int[] listenerCount; 136 private final String listenerName; 137 NotificationCounter(int[] counter, String name) { 138 listenerCount=counter; 139 listenerName=name; 140 } 141 142 public void handleNotification(Notification n, 143 Object h) { 144 MBeanServerNotification mbsn = 145 (MBeanServerNotification) n; 146 System.out.println(listenerName + " got notification: " 147 + mbsn.getMBeanName()); 148 synchronized (listenerCount) { 149 listenerCount[0]++; 150 listenerCount.notify(); 151 } 152 } 153 public String toString() { 154 return listenerName; 155 } 156 } 157 158 private static boolean test(String proto,int opCount,int liCount) 159 throws Exception { 160 System.out.println("Idle timeout test for protocol " + proto); 161 ObjectName delegateName = 162 ObjectName.getInstance("JMImplementation:" + 163 "type=MBeanServerDelegate"); 164 MBeanServer mbs = MBeanServerFactory.createMBeanServer(); 165 JMXServiceURL url = new JMXServiceURL("service:jmx:" + proto + "://"); 166 167 final long timeout = getIdleTimeout(mbs,url); 168 System.out.println("Timeout for " + proto + " is: " + 169 timeout + " ms"); 170 171 Map idleMap = new HashMap(); 172 idleMap.put(EnvHelp.SERVER_CONNECTION_TIMEOUT, new Long(timeout)); 173 JMXConnectorServer server = 174 JMXConnectorServerFactory.newJMXConnectorServer(url,idleMap,mbs); 175 176 final int[] listenerCount = new int[1]; 177 final NotificationListener countListeners[] = 178 new NotificationListener[liCount]; 179 int i; 180 for (i=0; i<countListeners.length; i++) { 181 countListeners[i] = 182 new NotificationCounter(listenerCount,"Listener"+i); 183 } 184 185 server.start(); 186 try { 187 url = server.getAddress(); 188 final long firstTime = System.currentTimeMillis(); 189 JMXConnector client = JMXConnectorFactory.connect(url); 190 long elapsed, startIdle=0; 191 try { 192 String connId = client.getConnectionId(); 193 MBeanServerConnection conn = 194 client.getMBeanServerConnection(); 195 elapsed = System.currentTimeMillis() - firstTime; 196 System.out.println("Idle Time: " + elapsed + "ms"); 197 198 for (i=0; i<countListeners.length; i++) { 199 System.out.println("add " + countListeners[i] + 200 ": starting at " + elapsed + "ms"); 201 conn.addNotificationListener(delegateName, 202 countListeners[i], 203 null,null); 204 } 205 206 System.out.println("connId=" + connId); 207 for (i = 0; i < opCount; i++) { 208 elapsed = System.currentTimeMillis() - firstTime; 209 System.out.println("Operation[" + (i+1) 210 +"]: starting at " + 211 elapsed + "ms"); 212 final String name = "d:type=mlet,instance=" + i; 213 mbs.createMBean("javax.management.loading.MLet", 214 new ObjectName(name)); 215 if (i == (opCount-1)) 216 startIdle = System.currentTimeMillis(); 217 Thread.sleep(2); 218 } 219 220 // Wait for notifs to arrive before doing removeNListener 221 long startTime = System.currentTimeMillis(); 222 long deadline = startTime + 10000; 223 224 System.out.println("Waiting for notifs: starting at " + 225 (startTime - firstTime) + "ms"); 226 227 final int expectedCount = opCount*countListeners.length; 228 while (System.currentTimeMillis() < deadline) { 229 synchronized (listenerCount) { 230 if (listenerCount[0] >= expectedCount) 231 break; 232 listenerCount.wait(); 233 } 234 } 235 236 long elapsedWait = System.currentTimeMillis() - startTime; 237 System.out.println("Waited " + elapsedWait + 238 "ms for notifs to arrive"); 239 240 if (listenerCount[0] != expectedCount) { 241 System.out.println("Did not get expected " + 242 expectedCount + " notifications: " 243 + listenerCount[0]); 244 return false; 245 } 246 247 elapsed = System.currentTimeMillis() - firstTime; 248 249 System.out.println("idle time since last operation: " + 250 (elapsed + firstTime - startIdle) + "ms"); 251 System.out.println("Requesting conn id at: " + 252 elapsed + "ms"); 253 final String cid = client.getConnectionId(); 254 255 elapsed = System.currentTimeMillis() - firstTime; 256 System.out.println("Got conn id <" + cid + "> at: " + 257 elapsed + "ms"); 258 259 if (!connId.equals(cid)) { 260 System.out.println("Client id changed: <" + connId + 261 "> -> <" + cid + 262 ">"); 263 return false; 264 } 265 266 List ids = Arrays.asList(server.getConnectionIds()); 267 if (!ids.contains(connId)) { 268 System.out.println("Server ids don't contain our id: " + 269 ids + " - " + connId); 270 return false; 271 } 272 273 for (i=0;i<countListeners.length;i++) { 274 System.out.println("Removing notification listener: " + 275 countListeners[i]); 276 conn.removeNotificationListener(delegateName, 277 countListeners[i]); 278 } 279 280 System.out.println("Waiting for id list to drop ours"); 281 // pass or timed out by test harness - see 8025204 282 do { 283 Thread.sleep(100); 284 ids = Arrays.asList(server.getConnectionIds()); 285 } while (ids.contains(connId)); 286 287 conn.getDefaultDomain(); 288 if (connId.equals(client.getConnectionId())) { 289 System.out.println("Client id did not change: <" + connId + 290 ">: idle timeout did not happen?"); 291 return false; 292 } else { 293 System.out.println("Client id changed as expected: <" + 294 connId + "> -> <" + 295 client.getConnectionId() + ">"); 296 } 297 } finally { 298 client.close(); 299 System.out.println("Connection id list on server after " + 300 "client close: " + 301 Arrays.asList(server.getConnectionIds())); 302 } 303 } finally { 304 server.stop(); 305 } 306 System.out.println("*** ------------------------------------------"); 307 System.out.println("*** Test passed for " + proto); 308 System.out.println("*** ------------------------------------------"); 309 return true; 310 } 311 }