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