1 /* 2 * Copyright (c) 1998, 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 * 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 args += " -C-Djava.rmi.server.useCodebaseOnly=false "; 121 122 args += " " + getCodeCoverageArgs(); 123 return args; 124 } 125 126 /** 127 * Routine that creates an rmid that will run with or without a 128 * policy file. 129 */ 130 public static RMID createRMID() { 131 return createRMID(System.out, System.err, true); 132 } 133 134 public static RMID createRMID(boolean debugExec) { 135 return createRMID(System.out, System.err, debugExec); 136 } 137 138 public static RMID createRMID(OutputStream out, OutputStream err) { 139 return createRMID(out, err, true); 140 } 141 142 public static RMID createRMID(OutputStream out, OutputStream err, 143 boolean debugExec) 144 { 145 return createRMID(out, err, debugExec, true, 146 TestLibrary.getUnusedRandomPort()); 147 } 148 149 public static RMID createRMID(OutputStream out, OutputStream err, 150 boolean debugExec, boolean includePortArg, 151 int port) 152 { 153 String options = makeOptions(debugExec); 154 String args = makeArgs(includePortArg, port); 155 RMID rmid = new RMID("sun.rmi.server.Activation", options, args, 156 out, err, port); 157 rmid.setPolicyFile(TestParams.defaultRmidPolicy); 158 159 return rmid; 160 } 161 162 163 /** 164 * Test RMID should be created with the createRMID method. 165 */ 166 protected RMID(String classname, String options, String args, 167 OutputStream out, OutputStream err, int port) 168 { 169 super(classname, options, args, out, err); 170 this.port = port; 171 } 172 173 public static void removeLog() { 174 /* 175 * Remove previous log file directory before 176 * starting up rmid. 177 */ 178 File f = new File(LOGDIR, log); 179 180 if (f.exists()) { 181 mesg("removing rmid's old log file..."); 182 String[] files = f.list(); 183 184 if (files != null) { 185 for (int i=0; i<files.length; i++) { 186 (new File(f, files[i])).delete(); 187 } 188 } 189 190 if (f.delete() != true) { 191 mesg("\t" + " unable to delete old log file."); 192 } 193 } 194 } 195 196 /** 197 * This method is used for adding arguments to rmid (not its VM) 198 * for passing as VM options to its child group VMs. 199 * Returns the extra command line arguments required 200 * to turn on jcov code coverage analysis for rmid child VMs. 201 */ 202 protected static String getCodeCoverageArgs() { 203 return TestLibrary.getExtraProperty("rmid.jcov.args",""); 204 } 205 206 public void start() throws IOException { 207 start(10000); 208 } 209 210 public void slowStart() throws IOException { 211 start(60000); 212 } 213 214 /** 215 * Looks up the activation system in the registry on the given port, 216 * returning its stub, or null if it's not present. This method differs from 217 * ActivationGroup.getSystem() because this method looks on a specific port 218 * instead of using the java.rmi.activation.port property like 219 * ActivationGroup.getSystem() does. This method also returns null instead 220 * of throwing exceptions. 221 */ 222 public static ActivationSystem lookupSystem(int port) { 223 mesg("getting activation system"); 224 try { 225 return (ActivationSystem)LocateRegistry.getRegistry(port).lookup(SYSTEM_NAME); 226 } catch (RemoteException | NotBoundException ex) { 227 mesg("couldn't get activation system: " + ex); 228 return null; 229 } 230 } 231 232 public void start(long waitTime) throws IOException { 233 234 // if rmid is already running, then the test will fail with 235 // a well recognized exception (port already in use...). 236 237 mesg("starting rmid on port #" + port + "..."); 238 super.start(); 239 240 int slopFactor = 1; 241 try { 242 slopFactor = Integer.valueOf( 243 TestLibrary.getExtraProperty("jcov.sleep.multiplier","1")); 244 } catch (NumberFormatException ignore) {} 245 waitTime = waitTime * slopFactor; 246 247 // We check several times (as many as provides passed waitTime) to 248 // see if Rmid is currently running. Waiting steps last 100 msecs. 249 final long rmidStartSleepTime = 100; 250 do { 251 // Sleeping for another rmidStartSleepTime time slice. 252 try { 253 Thread.sleep(Math.min(waitTime, rmidStartSleepTime)); 254 } catch (InterruptedException ie) { 255 Thread.currentThread().interrupt(); 256 mesg("Thread interrupted while checking for start of Activation System. Giving up check."); 257 mesg("Activation System state unknown"); 258 return; 259 } 260 waitTime -= rmidStartSleepTime; 261 262 // Checking if rmid is present 263 if (lookupSystem(port) != null) { 264 /* 265 * We need to set the java.rmi.activation.port value as the 266 * activation system will use the property to determine the 267 * port #. The activation system will use this value if set. 268 * If it isn't set, the activation system will set it to an 269 * incorrect value. 270 */ 271 System.setProperty("java.rmi.activation.port", Integer.toString(port)); 272 mesg("finished starting rmid."); 273 return; 274 } 275 else { 276 mesg("rmid still not started"); 277 } 278 279 } while (waitTime > 0); 280 TestLibrary.bomb("start rmid failed... giving up", null); 281 } 282 283 public void restart() throws IOException { 284 destroy(); 285 start(); 286 } 287 288 /** 289 * Ask rmid to shutdown gracefully using a remote method call. 290 * catch any errors that might occur from rmid not being present 291 * at time of shutdown invocation. 292 * 293 * Shutdown does not nullify possible references to the rmid 294 * process object (destroy does though). 295 */ 296 public static void shutdown(int port) { 297 298 try { 299 ActivationSystem system = lookupSystem(port); 300 301 if (system == null) { 302 TestLibrary.bomb("reference to the activation system was null"); 303 } 304 305 system.shutdown(); 306 } catch (RemoteException re) { 307 mesg("shutting down the activation daemon failed"); 308 } catch (Exception e) { 309 mesg("caught exception trying to shutdown rmid"); 310 mesg(e.getMessage()); 311 e.printStackTrace(); 312 } 313 314 mesg("testlibrary finished shutting down rmid"); 315 } 316 317 /** 318 * Ask rmid to shutdown gracefully but then destroy the rmid 319 * process if it does not exit by itself. This method only works 320 * if rmid is a child process of the current VM. 321 */ 322 public void destroy() { 323 // attempt graceful shutdown of the activation system 324 shutdown(port); 325 326 if (vm != null) { 327 try { 328 /* Waiting for distant RMID process to shutdown. 329 * Waiting is bounded at a hardcoded max of 60 secs (1 min). 330 * Waiting by steps of 200 msecs, thus at most 300 such attempts 331 * for termination of distant RMID process. If process is not 332 * known to be terminated properly after that time, 333 * we give up for a gracefull termination, and thus go for 334 * forcibly destroying the process. 335 */ 336 boolean vmEnded = false; 337 int waitingTrials = 0; 338 final int maxTrials = 300; 339 final long vmProcessEndWaitInterval = 200; 340 int vmExitValue; 341 do { 342 try { 343 Thread.sleep(vmProcessEndWaitInterval); 344 waitingTrials++; 345 vmExitValue = vm.exitValue(); 346 mesg("rmid exited on shutdown request"); 347 vmEnded = true; 348 } catch (IllegalThreadStateException illegal) { 349 mesg("RMID's process still not terminated after more than " + 350 (waitingTrials * vmProcessEndWaitInterval) + " milliseconds"); 351 } 352 } 353 while (!vmEnded && 354 (waitingTrials < maxTrials)); 355 356 if (waitingTrials >= maxTrials) { 357 mesg("RMID's process still not terminated after more than " + 358 (waitingTrials * vmProcessEndWaitInterval) + " milliseconds." + 359 "Givinp up gracefull termination..."); 360 mesg("destroying RMID's process using Process.destroy()"); 361 super.destroy(); 362 } 363 364 } catch (InterruptedException ie) { 365 Thread.currentThread().interrupt(); 366 mesg("Thread interrupted while checking for termination of distant rmid vm. Giving up check."); 367 } catch (Exception e) { 368 mesg("caught unexpected exception trying to destroy rmid: " + 369 e.getMessage()); 370 e.printStackTrace(); 371 } 372 373 // rmid will not restart if its process is not null 374 vm = null; 375 } 376 } 377 378 public int getPort() {return port;} 379 }