1 /* 2 * Copyright (c) 1998, 2014, 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 * 26 */ 27 28 import java.io.*; 29 import java.rmi.*; 30 import java.rmi.activation.*; 31 import java.rmi.registry.*; 32 33 /** 34 * Utility class that creates an instance of rmid with a policy 35 * file of name <code>TestParams.defaultPolicy</code>. 36 * 37 * Activation groups should run with the same security manager as the 38 * test. 39 */ 40 public class RMID extends JavaVM { 41 42 private static final String SYSTEM_NAME = ActivationSystem.class.getName(); 43 // "java.rmi.activation.ActivationSystem" 44 45 public static String MANAGER_OPTION="-Djava.security.manager="; 46 47 /** Test port for rmid */ 48 private final int port; 49 50 /** Initial log name */ 51 protected static String log = "log"; 52 /** rmid's logfile directory; currently must be "." */ 53 protected static String LOGDIR = "."; 54 55 private static void mesg(Object mesg) { 56 System.err.println("RMID: " + mesg.toString()); 57 } 58 59 /** make test options and arguments */ 60 private static String makeOptions(boolean debugExec) { 61 62 String options = " -Dsun.rmi.server.activation.debugExec=" + 63 debugExec; 64 // + 65 //" -Djava.compiler= "; 66 67 // if test params set, want to propagate them 68 if (!TestParams.testSrc.equals("")) { 69 options += " -Dtest.src=" + TestParams.testSrc + " "; 70 } 71 //if (!TestParams.testClasses.equals("")) { 72 // options += " -Dtest.classes=" + TestParams.testClasses + " "; 73 //} 74 options += " -Dtest.classes=" + TestParams.testClasses //; 75 + 76 " -Djava.rmi.server.logLevel=v "; 77 78 // + 79 // " -Djava.security.debug=all "; 80 81 // Set execTimeout to 60 sec (default is 30 sec) 82 // to avoid spurious timeouts on slow machines. 83 options += " -Dsun.rmi.activation.execTimeout=60000"; 84 85 return options; 86 } 87 88 private static String makeArgs(boolean includePortArg, int port) { 89 String propagateManager = null; 90 91 // rmid will run with a security manager set, but no policy 92 // file - it should not need one. 93 if (System.getSecurityManager() == null) { 94 propagateManager = MANAGER_OPTION + 95 TestParams.defaultSecurityManager; 96 } else { 97 propagateManager = MANAGER_OPTION + 98 System.getSecurityManager().getClass().getName(); 99 } 100 101 // getAbsolutePath requires permission to read user.dir 102 String args = 103 " -log " + (new File(LOGDIR, log)).getAbsolutePath(); 104 105 if (includePortArg) { 106 args += " -port " + port; 107 } 108 109 // + 110 // " -C-Djava.compiler= "; 111 112 // if test params set, want to propagate them 113 if (!TestParams.testSrc.equals("")) { 114 args += " -C-Dtest.src=" + TestParams.testSrc; 115 } 116 if (!TestParams.testClasses.equals("")) { 117 args += " -C-Dtest.classes=" + TestParams.testClasses; 118 } 119 120 if (!TestParams.testJavaOpts.equals("")) { 121 for (String a : TestParams.testJavaOpts.split(" +")) { 122 args += " -C" + a; 123 } 124 } 125 126 if (!TestParams.testVmOpts.equals("")) { 127 for (String a : TestParams.testVmOpts.split(" +")) { 128 args += " -C" + a; 129 } 130 } 131 132 args += " -C-Djava.rmi.server.useCodebaseOnly=false "; 133 134 args += " " + getCodeCoverageArgs(); 135 return args; 136 } 137 138 /** 139 * Routine that creates an rmid that will run with or without a 140 * policy file. 141 */ 142 public static RMID createRMID() { 143 return createRMID(System.out, System.err, true); 144 } 145 146 public static RMID createRMID(boolean debugExec) { 147 return createRMID(System.out, System.err, debugExec); 148 } 149 150 public static RMID createRMID(OutputStream out, OutputStream err) { 151 return createRMID(out, err, true); 152 } 153 154 public static RMID createRMID(OutputStream out, OutputStream err, 155 boolean debugExec) 156 { 157 return createRMID(out, err, debugExec, true, 158 TestLibrary.getUnusedRandomPort()); 159 } 160 161 public static RMID createRMID(OutputStream out, OutputStream err, 162 boolean debugExec, boolean includePortArg, 163 int port) 164 { 165 String options = makeOptions(debugExec); 166 String args = makeArgs(includePortArg, port); 167 RMID rmid = new RMID("sun.rmi.server.Activation", options, args, 168 out, err, port); 169 rmid.setPolicyFile(TestParams.defaultRmidPolicy); 170 171 return rmid; 172 } 173 174 175 /** 176 * Test RMID should be created with the createRMID method. 177 */ 178 protected RMID(String classname, String options, String args, 179 OutputStream out, OutputStream err, int port) 180 { 181 super(classname, options, args, out, err); 182 this.port = port; 183 } 184 185 public static void removeLog() { 186 /* 187 * Remove previous log file directory before 188 * starting up rmid. 189 */ 190 File f = new File(LOGDIR, log); 191 192 if (f.exists()) { 193 mesg("removing rmid's old log file..."); 194 String[] files = f.list(); 195 196 if (files != null) { 197 for (int i=0; i<files.length; i++) { 198 (new File(f, files[i])).delete(); 199 } 200 } 201 202 if (f.delete() != true) { 203 mesg("\t" + " unable to delete old log file."); 204 } 205 } 206 } 207 208 /** 209 * This method is used for adding arguments to rmid (not its VM) 210 * for passing as VM options to its child group VMs. 211 * Returns the extra command line arguments required 212 * to turn on jcov code coverage analysis for rmid child VMs. 213 */ 214 protected static String getCodeCoverageArgs() { 215 return TestLibrary.getExtraProperty("rmid.jcov.args",""); 216 } 217 218 public void start() throws IOException { 219 start(10000); 220 } 221 222 public void slowStart() throws IOException { 223 start(60000); 224 } 225 226 /** 227 * Looks up the activation system in the registry on the given port, 228 * returning its stub, or null if it's not present. This method differs from 229 * ActivationGroup.getSystem() because this method looks on a specific port 230 * instead of using the java.rmi.activation.port property like 231 * ActivationGroup.getSystem() does. This method also returns null instead 232 * of throwing exceptions. 233 */ 234 public static ActivationSystem lookupSystem(int port) { 235 try { 236 return (ActivationSystem)LocateRegistry.getRegistry(port).lookup(SYSTEM_NAME); 237 } catch (RemoteException | NotBoundException ex) { 238 return null; 239 } 240 } 241 242 public void start(long waitTime) throws IOException { 243 244 // if rmid is already running, then the test will fail with 245 // a well recognized exception (port already in use...). 246 247 mesg("starting rmid on port #" + port + "..."); 248 super.start(); 249 250 int slopFactor = 1; 251 try { 252 slopFactor = Integer.valueOf( 253 TestLibrary.getExtraProperty("jcov.sleep.multiplier","1")); 254 } catch (NumberFormatException ignore) {} 255 waitTime = waitTime * slopFactor; 256 257 // We check several times (as many as provides passed waitTime) to 258 // see if Rmid is currently running. Waiting steps last 100 msecs. 259 final long rmidStartSleepTime = 100; 260 do { 261 // Sleeping for another rmidStartSleepTime time slice. 262 try { 263 Thread.sleep(Math.min(waitTime, rmidStartSleepTime)); 264 } catch (InterruptedException ie) { 265 Thread.currentThread().interrupt(); 266 mesg("Thread interrupted while checking for start of Activation System. Giving up check."); 267 mesg("Activation System state unknown"); 268 return; 269 } 270 waitTime -= rmidStartSleepTime; 271 272 // Checking if rmid is present 273 if (lookupSystem(port) != null) { 274 /* 275 * We need to set the java.rmi.activation.port value as the 276 * activation system will use the property to determine the 277 * port #. The activation system will use this value if set. 278 * If it isn't set, the activation system will set it to an 279 * incorrect value. 280 */ 281 System.setProperty("java.rmi.activation.port", Integer.toString(port)); 282 mesg("finished starting rmid."); 283 return; 284 } else { 285 if (waitTime > 0) { 286 mesg("rmid not started, will retry for " + waitTime + "ms"); 287 } 288 } 289 } while (waitTime > 0); 290 TestLibrary.bomb("start rmid failed... giving up", null); 291 } 292 293 public void restart() throws IOException { 294 destroy(); 295 start(); 296 } 297 298 /** 299 * Ask rmid to shutdown gracefully using a remote method call. 300 * catch any errors that might occur from rmid not being present 301 * at time of shutdown invocation. 302 * 303 * Shutdown does not nullify possible references to the rmid 304 * process object (destroy does though). 305 */ 306 public static void shutdown(int port) { 307 308 try { 309 ActivationSystem system = lookupSystem(port); 310 311 if (system == null) { 312 TestLibrary.bomb("reference to the activation system was null"); 313 } 314 315 system.shutdown(); 316 } catch (RemoteException re) { 317 mesg("shutting down the activation daemon failed"); 318 } catch (Exception e) { 319 mesg("caught exception trying to shutdown rmid"); 320 mesg(e.getMessage()); 321 e.printStackTrace(); 322 } 323 324 mesg("testlibrary finished shutting down rmid"); 325 } 326 327 /** 328 * Ask rmid to shutdown gracefully but then destroy the rmid 329 * process if it does not exit by itself. This method only works 330 * if rmid is a child process of the current VM. 331 */ 332 public void destroy() { 333 // attempt graceful shutdown of the activation system 334 shutdown(port); 335 336 if (vm != null) { 337 try { 338 /* Waiting for distant RMID process to shutdown. 339 * Waiting is bounded at a hardcoded max of 60 secs (1 min). 340 * Waiting by steps of 200 msecs, thus at most 300 such attempts 341 * for termination of distant RMID process. If process is not 342 * known to be terminated properly after that time, 343 * we give up for a gracefull termination, and thus go for 344 * forcibly destroying the process. 345 */ 346 boolean vmEnded = false; 347 int waitingTrials = 0; 348 final int maxTrials = 300; 349 final long vmProcessEndWaitInterval = 200; 350 int vmExitValue; 351 do { 352 try { 353 Thread.sleep(vmProcessEndWaitInterval); 354 waitingTrials++; 355 vmExitValue = vm.exitValue(); 356 mesg("rmid exited on shutdown request"); 357 vmEnded = true; 358 } catch (IllegalThreadStateException illegal) { 359 mesg("RMID's process still not terminated after more than " + 360 (waitingTrials * vmProcessEndWaitInterval) + " milliseconds"); 361 } 362 } 363 while (!vmEnded && 364 (waitingTrials < maxTrials)); 365 366 if (waitingTrials >= maxTrials) { 367 mesg("RMID's process still not terminated after more than " + 368 (waitingTrials * vmProcessEndWaitInterval) + " milliseconds." + 369 "Givinp up gracefull termination..."); 370 mesg("destroying RMID's process using Process.destroy()"); 371 super.destroy(); 372 } 373 374 } catch (InterruptedException ie) { 375 Thread.currentThread().interrupt(); 376 mesg("Thread interrupted while checking for termination of distant rmid vm. Giving up check."); 377 } catch (Exception e) { 378 mesg("caught unexpected exception trying to destroy rmid: " + 379 e.getMessage()); 380 e.printStackTrace(); 381 } 382 383 // rmid will not restart if its process is not null 384 vm = null; 385 } 386 } 387 388 public int getPort() {return port;} 389 }