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 try { 224 return (ActivationSystem)LocateRegistry.getRegistry(port).lookup(SYSTEM_NAME); 225 } catch (RemoteException | NotBoundException ex) { 226 return null; 227 } 228 } 229 230 public void start(long waitTime) throws IOException { 231 232 // if rmid is already running, then the test will fail with 233 // a well recognized exception (port already in use...). 234 235 mesg("starting rmid on port #" + port + "..."); 236 super.start(); 237 238 int slopFactor = 1; 239 try { 240 slopFactor = Integer.valueOf( 241 TestLibrary.getExtraProperty("jcov.sleep.multiplier","1")); 242 } catch (NumberFormatException ignore) {} 243 waitTime = waitTime * slopFactor; 244 245 // We check several times (as many as provides passed waitTime) to 246 // see if Rmid is currently running. Waiting steps last 100 msecs. 247 final long rmidStartSleepTime = 100; 248 do { 249 // Sleeping for another rmidStartSleepTime time slice. 250 try { 251 Thread.sleep(Math.min(waitTime, rmidStartSleepTime)); 252 } catch (InterruptedException ie) { 253 Thread.currentThread().interrupt(); 254 mesg("Thread interrupted while checking for start of Activation System. Giving up check."); 255 mesg("Activation System state unknown"); 256 return; 257 } 258 waitTime -= rmidStartSleepTime; 259 260 // Checking if rmid is present 261 if (lookupSystem(port) != null) { 262 /* 263 * We need to set the java.rmi.activation.port value as the 264 * activation system will use the property to determine the 265 * port #. The activation system will use this value if set. 266 * If it isn't set, the activation system will set it to an 267 * incorrect value. 268 */ 269 System.setProperty("java.rmi.activation.port", Integer.toString(port)); 270 mesg("finished starting rmid."); 271 return; 272 } else { 273 if (waitTime > 0) { 274 mesg("rmid not started, will retry for " + waitTime + "ms"); 275 } 276 } 277 } while (waitTime > 0); 278 TestLibrary.bomb("start rmid failed... giving up", null); 279 } 280 281 public void restart() throws IOException { 282 destroy(); 283 start(); 284 } 285 286 /** 287 * Ask rmid to shutdown gracefully using a remote method call. 288 * catch any errors that might occur from rmid not being present 289 * at time of shutdown invocation. 290 * 291 * Shutdown does not nullify possible references to the rmid 292 * process object (destroy does though). 293 */ 294 public static void shutdown(int port) { 295 296 try { 297 ActivationSystem system = lookupSystem(port); 298 299 if (system == null) { 300 TestLibrary.bomb("reference to the activation system was null"); 301 } 302 303 system.shutdown(); 304 } catch (RemoteException re) { 305 mesg("shutting down the activation daemon failed"); 306 } catch (Exception e) { 307 mesg("caught exception trying to shutdown rmid"); 308 mesg(e.getMessage()); 309 e.printStackTrace(); 310 } 311 312 mesg("testlibrary finished shutting down rmid"); 313 } 314 315 /** 316 * Ask rmid to shutdown gracefully but then destroy the rmid 317 * process if it does not exit by itself. This method only works 318 * if rmid is a child process of the current VM. 319 */ 320 public void destroy() { 321 // attempt graceful shutdown of the activation system 322 shutdown(port); 323 324 if (vm != null) { 325 try { 326 /* Waiting for distant RMID process to shutdown. 327 * Waiting is bounded at a hardcoded max of 60 secs (1 min). 328 * Waiting by steps of 200 msecs, thus at most 300 such attempts 329 * for termination of distant RMID process. If process is not 330 * known to be terminated properly after that time, 331 * we give up for a gracefull termination, and thus go for 332 * forcibly destroying the process. 333 */ 334 boolean vmEnded = false; 335 int waitingTrials = 0; 336 final int maxTrials = 300; 337 final long vmProcessEndWaitInterval = 200; 338 int vmExitValue; 339 do { 340 try { 341 Thread.sleep(vmProcessEndWaitInterval); 342 waitingTrials++; 343 vmExitValue = vm.exitValue(); 344 mesg("rmid exited on shutdown request"); 345 vmEnded = true; 346 } catch (IllegalThreadStateException illegal) { 347 mesg("RMID's process still not terminated after more than " + 348 (waitingTrials * vmProcessEndWaitInterval) + " milliseconds"); 349 } 350 } 351 while (!vmEnded && 352 (waitingTrials < maxTrials)); 353 354 if (waitingTrials >= maxTrials) { 355 mesg("RMID's process still not terminated after more than " + 356 (waitingTrials * vmProcessEndWaitInterval) + " milliseconds." + 357 "Givinp up gracefull termination..."); 358 mesg("destroying RMID's process using Process.destroy()"); 359 super.destroy(); 360 } 361 362 } catch (InterruptedException ie) { 363 Thread.currentThread().interrupt(); 364 mesg("Thread interrupted while checking for termination of distant rmid vm. Giving up check."); 365 } catch (Exception e) { 366 mesg("caught unexpected exception trying to destroy rmid: " + 367 e.getMessage()); 368 e.printStackTrace(); 369 } 370 371 // rmid will not restart if its process is not null 372 vm = null; 373 } 374 } 375 376 public int getPort() {return port;} 377 }