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