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