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 /* @test
  25  *
  26  * @bug 4105043
  27  * @summary cannot set java.rmi.server.hostname on children of rmid in time
  28  *
  29  * @bug 4097357
  30  * @summary activation group should not overwrite system properties
  31  *
  32  * @bug 4107184
  33  * @summary activation groups should be able to control their JVM properties
  34  *
  35  * @author Adrian Colley
  36  *
  37  * @library ../../testlibrary
  38  * @modules java.rmi/sun.rmi.registry
  39  *          java.rmi/sun.rmi.server
  40  *          java.rmi/sun.rmi.transport
  41  *          java.rmi/sun.rmi.transport.tcp
  42  * @build TestLibrary RMID ActivationLibrary
  43  *     Eliza Retireable Doctor Doctor_Stub
  44  * @run main/othervm/timeout=240/policy=security.policy
  45  *     -Djava.compiler=NONE SetChildEnv
  46  */
  47 import java.rmi.*;
  48 import java.util.Properties;
  49 import java.io.*;
  50 import java.util.StringTokenizer;
  51 import java.util.Set;
  52 import java.util.HashSet;
  53 import java.util.Arrays;
  54 import java.rmi.activation.*;
  55 
  56 public class SetChildEnv
  57 {
  58     public static void main(String argv[])
  59         throws Exception
  60     {
  61         int runningPort = TestLibrary.getUnusedRandomPort();
  62 
  63         System.out.println("java.compiler=" + System.getProperty("java.compiler"));
  64         // don't embed spaces in any of the test args/props, because
  65         // they won't be parsed properly
  66         runwith (new String[0], new String[0], runningPort);
  67 
  68         runwith (
  69             new String[] { "-verbosegc" },
  70             new String[] { "foo.bar=SetChildEnvTest",
  71                            "sun.rmi.server.doSomething=true" },
  72             runningPort
  73             );
  74 
  75         runwith (
  76             new String[] { },
  77             new String[] { "parameter.count=zero" },
  78             runningPort
  79             );
  80 
  81         runwith (
  82             new String[] { "-Xmx32m" },
  83             new String[] { },
  84             runningPort
  85             );
  86     }
  87 
  88     private static void runwith(
  89         String[] params,        // extra args
  90         String[] props,         // extra system properties
  91         int port                // port on which to communicate
  92     )
  93         throws Exception
  94     {
  95         TestLibrary.suggestSecurityManager(TestParams.defaultSecurityManager);
  96 
  97         // make a "watcher" which listens on a pipe and searches for
  98         // the debugExec line while teeing to System.err
  99         DebugExecWatcher watcher = DebugExecWatcher.makeWithPipe();
 100 
 101         RMID.removeLog();
 102         RMID rmid = RMID.createRMIDOnEphemeralPort(watcher.otherEnd(), watcher.otherEnd(),
 103                                     true,  // debugExec turned on
 104                                     true, port);
 105 
 106         rmid.start();
 107 
 108         // compile props
 109         Properties p = new Properties();
 110         p.put("java.security.policy", TestParams.defaultGroupPolicy);
 111         p.put("java.security.manager", TestParams.defaultSecurityManager);
 112         //p.put("java.rmi.server.logCalls", "true");
 113         int i;
 114         for (i = 0; i < props.length; i++) {
 115             p.put(props[i].substring(0, props[i].indexOf('=')),
 116                   props[i].substring(props[i].indexOf('=')+1));
 117         }
 118 
 119         // create CommandEnvironment and ActivationGroupDesc
 120         ActivationGroupDesc.CommandEnvironment cmdenv =
 121                 new ActivationGroupDesc.CommandEnvironment(
 122                     null,
 123                     params);
 124 
 125         ActivationGroupDesc gdesc = new ActivationGroupDesc(
 126                 p, cmdenv);
 127 
 128         // register group
 129         ActivationSystem actsys = ActivationGroup.getSystem();
 130         ActivationGroupID gid = actsys.registerGroup(gdesc);
 131 
 132         // create ActivationDesc
 133         ActivationDesc odesc = new ActivationDesc(gid, // group
 134                                                   "Doctor", // class
 135                                                   null, // codesource
 136                                                   null); // closure data
 137 
 138         // register activatable object
 139         Eliza doctor = (Eliza)Activatable.register(odesc);
 140 
 141         // invoke a call with oh-so-humorous sample text
 142         System.out.println ("Invoking complain()...");
 143         String complaint =
 144                 "HELP ME, DOCTOR.  I FEEL VIOLENT TOWARDS PEOPLE " +
 145                 "WHO INQUIRE ABOUT MY PARENTS.";
 146 
 147         System.out.println(complaint);
 148         //Runtime.getRuntime().traceMethodCalls(true);
 149         String res = doctor.complain(complaint);
 150         //Runtime.getRuntime().traceMethodCalls(false);
 151         System.out.println (" => " + res);
 152 
 153         // Get debugExec line, allowing 15 seconds for it to flush
 154         // through the buffers and pipes.
 155         String found = watcher.found;
 156         if (found == null) {
 157             int fudge = 15;
 158             while (found == null && --fudge > 0) {
 159                 Thread.sleep(1000);
 160                 found = watcher.found;
 161             }
 162             if (found == null) {
 163                 TestLibrary.bomb("rmid subprocess produced no " +
 164                                  "recognizable debugExec line");
 165             }
 166         }
 167 
 168         System.err.println("debugExec found: <<" + found + ">>");
 169         // q: first double-quote after debugExec
 170         int q = found.indexOf('"', found.indexOf("rmid: debugExec"));
 171         // qe: last double-quote on debugExec line
 172         int qe = found.lastIndexOf('"');
 173         if (q <= 1 || qe <= q) {
 174             TestLibrary.bomb("rmid subprocess produced " +
 175                              "mangled debugExec line");
 176         }
 177 
 178         // split args by whitespace
 179         StringTokenizer tk = new StringTokenizer(found.substring(q+1, qe));
 180         tk.nextToken();         // skip command path/name
 181 
 182         // Now check off the requested args.  Order isn't important, and
 183         // any extra args are ignored, even if they're inconsistent or
 184         // bargage, or duplicates.
 185 
 186         Set argset = new HashSet(tk.countTokens());
 187         while (tk.hasMoreTokens()) {
 188             argset.add(tk.nextToken());
 189         }
 190 
 191         int m;
 192         for (m = 0; m < params.length; m++) {
 193             if(!argset.contains(params[m]))
 194                 TestLibrary.bomb("Parameter \"" + params[m] + "\" not set");
 195         }
 196 
 197         for (m = 0; m < props.length; m++) {
 198             if (!argset.contains("-D" + props[m])) {
 199                 TestLibrary.bomb("Property binding \"" + props[m] +
 200                                  "\" not set");
 201             }
 202         }
 203 
 204         // End doctor
 205         if (doctor instanceof Retireable)
 206             ((Retireable)doctor).retire();
 207         actsys.unregisterGroup(gid);
 208 
 209         Thread.sleep(5000);
 210         rmid.cleanup();
 211     }
 212 
 213     public static class DebugExecWatcher
 214         extends Thread
 215     {
 216         public String found;
 217         private BufferedReader str;
 218         private OutputStream otherEnd;
 219 
 220         private DebugExecWatcher(InputStream readStream, OutputStream wrStream)
 221         {
 222             super("DebugExecWatcher");
 223             found = null;
 224             str = new BufferedReader(new InputStreamReader(readStream));
 225             otherEnd = wrStream;
 226         }
 227 
 228         static public DebugExecWatcher makeWithPipe()
 229             throws IOException
 230         {
 231             PipedOutputStream wr = new PipedOutputStream();
 232             PipedInputStream rd = new PipedInputStream(wr);
 233             DebugExecWatcher embryo = new DebugExecWatcher(rd, wr);
 234             embryo.start();
 235             return embryo;
 236         }
 237 
 238         public OutputStream otherEnd()
 239         {
 240             return otherEnd;
 241         }
 242 
 243         public synchronized void notifyLine(String s)
 244         {
 245             if (s != null && s.indexOf("rmid: debugExec") != -1)
 246                 found = s;
 247         }
 248 
 249         public void run()
 250         {
 251             try {
 252                 String line;
 253                 while ((line = str.readLine()) != null) {
 254                     this.notifyLine(line);
 255                     System.err.println(line);
 256                 }
 257             } catch (IOException e) {
 258                 /* During termination of distant rmid, StreamPipes will be broken when
 259                  * distant vm terminates. A "Pipe broken" exception is expected because
 260                  * DebugExecWatcher points to the same streams as StreamPipes used by RMID.
 261                  * If we get this exception. We just terminate the thread.
 262                  */
 263                 if (e.getMessage().equals("Pipe broken")) {
 264                     try {
 265                         str.close();
 266                     } catch (IOException ioe) {}
 267                 }
 268                 else {
 269                     e.printStackTrace();
 270                 }
 271             }
 272         }
 273     }
 274 }
 275 
 276 /*
 277    code graveyard
 278 
 279         // activation should have proceeded by writing a wrapper.out
 280         // when test.src/actgrpwrapper was run.
 281 
 282         // Read and check wrapper.out
 283         BufferedReader r = new BufferedReader(new FileReader(wrapout));
 284         String[] realArgs = null;
 285         String line;
 286 
 287         while ( (line = r.readLine()) != null) {
 288             StringTokenizer tkz = new StringTokenizer(line);
 289             if (!tkz.nextToken().equals("actgrpwrapper")) {
 290                 // could throw an exception, but let's benignly
 291                 // assume that something unrelated is spewing.
 292                 continue;
 293             }
 294             String x;   // writer's block
 295             x = tkz.nextToken();
 296             if (x.equals("argc")) {
 297                 if (realArgs != null) {
 298                     throw new RuntimeException(
 299                             "SetChildEnv: two argc lines in wrapper.out");
 300                 }
 301                 realArgs = new String[Integer.parseInt(tkz.nextToken())];
 302             } else if (x.equals("argv")) {
 303                 if (realArgs == null)
 304                     throw new RuntimeException("SetChildEnv: missing argc");
 305                 int n = Integer.parseInt(tkz.nextToken());
 306                 if (n < 1 || n > realArgs.length) {
 307                     throw new RuntimeException("SetChildEnv: argc=" +
 308                             realArgs.length + "; argv[" + n + "]");
 309                 }
 310                 // Hack: manually skip the "actgrpwrapper argv 5 "
 311                 String remainder = line.substring(
 312                         1 + line.indexOf(' ',
 313                                 1 + line.indexOf(' ',
 314                                         1 + line.indexOf(' '))));
 315                 realArgs[n-1] = remainder;
 316             } else {
 317                 throw new RuntimeException("SetChildEnv: bad token \"" + x + "\"");
 318             }
 319         }
 320         r.close();
 321 
 322     private static void ensureLocalExecutable(String fname)
 323         throws Exception
 324     {
 325         File target = new File(fname);
 326         File source = new File(Dot, fname);
 327         if (!target.exists()) {
 328             // copy from source
 329             System.err.println("Copying " + source.getPath() +
 330                                " to " + target.getPath());
 331             java.io.InputStream in = new java.io.FileInputStream(source);
 332             java.io.OutputStream out = new java.io.FileOutputStream(target);
 333             byte[] buf = new byte[512];
 334             int n;
 335             while ((n = in.read(buf, 0, 512)) > 0) {
 336                 out.write(buf, 0, n);
 337             }
 338             out.close();
 339             in.close();
 340         }
 341         // chmod
 342         System.err.println("Doing: /bin/chmod 755 " + fname);
 343         Runtime.getRuntime().exec("/bin/chmod 755 " + fname).waitFor();
 344     }
 345 
 346 */