1 /*
2  * Copyright (c) 1998, 2019, 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  *          java.base/sun.nio.ch
43  * @build TestLibrary RMID ActivationLibrary RMIDSelectorProvider
44  *     Eliza Retireable Doctor Doctor_Stub
45  * @run main/othervm/timeout=240/policy=security.policy SetChildEnv 0 0
46  * @run main/othervm/timeout=240/policy=security.policy SetChildEnv 1 -verbosegc
47  *                       2 foo.bar=SetChildEnvTest sun.rmi.server.doSomething=true
48  * @run main/othervm/timeout=240/policy=security.policy SetChildEnv 0 1 parameter.count=zero
49  * @run main/othervm/timeout=240/policy=security.policy SetChildEnv 1 -Xmx32m 0
50  */
51 import java.rmi.*;
52 import java.util.Properties;
53 import java.io.*;
54 import java.util.StringTokenizer;
55 import java.util.Set;
56 import java.util.HashSet;
57 import java.util.Arrays;
58 import java.rmi.activation.*;
59 
60 public class SetChildEnv
61 {
62     public static void main(String argv[]) throws Exception {
63         RMID rmid = null;
64         try {
65             System.out.println("java.compiler=" + System.getProperty("java.compiler"));
66             int paramCount = Integer.valueOf(argv[0]);
67             String[] params = paramCount == 0 ?
68                     new String[0] : Arrays.copyOfRange(argv, 1, paramCount+1);
69             int propCount = Integer.valueOf(argv[paramCount+1]);
70             String[] props = propCount == 0 ?
71                     new String[0] :
72                     Arrays.copyOfRange(argv, paramCount+2, paramCount+propCount+2);
73 
74             TestLibrary.suggestSecurityManager(TestParams.defaultSecurityManager);
75 
76             // make a "watcher" which listens on a pipe and searches for
77             // the debugExec line while teeing to System.err
78             DebugExecWatcher watcher = DebugExecWatcher.makeWithPipe();
79 
80             RMID.removeLog();
81             rmid = RMID.createRMIDOnEphemeralPort(watcher.otherEnd(),
82                                                   watcher.otherEnd(), true);
83 
84             rmid.start();
85 
86             // compile props
87             Properties p = new Properties();
88             p.put("java.security.policy", TestParams.defaultGroupPolicy);
89             p.put("java.security.manager", TestParams.defaultSecurityManager);
90             //p.put("java.rmi.server.logCalls", "true");
91             int i;
92             for (i = 0; i < props.length; i++) {
93                 p.put(props[i].substring(0, props[i].indexOf('=')),
94                       props[i].substring(props[i].indexOf('=')+1));
95             }
96 
97             // create CommandEnvironment and ActivationGroupDesc
98             ActivationGroupDesc.CommandEnvironment cmdenv =
99                     new ActivationGroupDesc.CommandEnvironment(
100                         null,
101                         params);
102 
103             ActivationGroupDesc gdesc = new ActivationGroupDesc(
104                     p, cmdenv);
105 
106             // register group
107             ActivationSystem actsys = ActivationGroup.getSystem();
108             ActivationGroupID gid = actsys.registerGroup(gdesc);
109 
110             // create ActivationDesc
111             ActivationDesc odesc = new ActivationDesc(gid, // group
112                                                       "Doctor", // class
113                                                       null, // codesource
114                                                       null); // closure data
115 
116             // register activatable object
117             Eliza doctor = (Eliza)Activatable.register(odesc);
118 
119             // invoke a call with oh-so-humorous sample text
120             System.out.println ("Invoking complain()...");
121             String complaint =
122                     "HELP ME, DOCTOR.  I FEEL VIOLENT TOWARDS PEOPLE " +
123                     "WHO INQUIRE ABOUT MY PARENTS.";
124 
125             System.out.println(complaint);
126             String res = doctor.complain(complaint);
127             System.out.println (" => " + res);
128 
129             // Get debugExec line, allowing 15 seconds for it to flush
130             // through the buffers and pipes.
131             String found = watcher.found;
132             if (found == null) {
133                 int fudge = 15;
134                 while (found == null && --fudge > 0) {
135                     Thread.sleep(1000);
136                     found = watcher.found;
137                 }
138                 if (found == null) {
139                     TestLibrary.bomb("rmid subprocess produced no " +
140                                      "recognizable debugExec line");
141                 }
142             }
143 
144             System.err.println("debugExec found: <<" + found + ">>");
145             // q: first double-quote after debugExec
146             int q = found.indexOf('"', found.indexOf("rmid: debugExec"));
147             // qe: last double-quote on debugExec line
148             int qe = found.lastIndexOf('"');
149             if (q <= 1 || qe <= q) {
150                 TestLibrary.bomb("rmid subprocess produced " +
151                                  "mangled debugExec line");
152             }
153 
154             // split args by whitespace
155             StringTokenizer tk = new StringTokenizer(found.substring(q+1, qe));
156             tk.nextToken();         // skip command path/name
157 
158             // Now check off the requested args.  Order isn't important, and
159             // any extra args are ignored, even if they're inconsistent or
160             // bargage, or duplicates.
161 
162             Set argset = new HashSet(tk.countTokens());
163             while (tk.hasMoreTokens()) {
164                 argset.add(tk.nextToken());
165             }
166 
167             int m;
168             for (m = 0; m < params.length; m++) {
169                 if(!argset.contains(params[m]))
170                     TestLibrary.bomb("Parameter \"" + params[m] + "\" not set");
171             }
172 
173             for (m = 0; m < props.length; m++) {
174                 if (!argset.contains("-D" + props[m])) {
175                     TestLibrary.bomb("Property binding \"" + props[m] +
176                                      "\" not set");
177                 }
178             }
179 
180             // End doctor
181             if (doctor instanceof Retireable)
182                 ((Retireable)doctor).retire();
183             actsys.unregisterGroup(gid);
184         } finally {
185             Thread.sleep(5000);
186             if (rmid != null) {
187                 rmid.cleanup();
188             }
189         }
190     }
191 
192     public static class DebugExecWatcher
193         extends Thread
194     {
195         public String found;
196         private BufferedReader str;
197         private OutputStream otherEnd;
198 
199         private DebugExecWatcher(InputStream readStream, OutputStream wrStream)
200         {
201             super("DebugExecWatcher");
202             found = null;
203             str = new BufferedReader(new InputStreamReader(readStream));
204             otherEnd = wrStream;
205         }
206 
207         static public DebugExecWatcher makeWithPipe()
208             throws IOException
209         {
210             PipedOutputStream wr = new PipedOutputStream();
211             PipedInputStream rd = new PipedInputStream(wr);
212             DebugExecWatcher embryo = new DebugExecWatcher(rd, wr);
213             embryo.start();
214             return embryo;
215         }
216 
217         public OutputStream otherEnd()
218         {
219             return otherEnd;
220         }
221 
222         public synchronized void notifyLine(String s)
223         {
224             if (s != null && s.indexOf("rmid: debugExec") != -1)
225                 found = s;
226         }
227 
228         public void run()
229         {
230             try {
231                 String line;
232                 while ((line = str.readLine()) != null) {
233                     this.notifyLine(line);
234                     System.err.println(line);
235                 }
236             } catch (IOException e) {
237                 /* During termination of distant rmid, StreamPipes will be broken when
238                  * distant vm terminates. A "Pipe broken" exception is expected because
239                  * DebugExecWatcher points to the same streams as StreamPipes used by RMID.
240                  * If we get this exception. We just terminate the thread.
241                  */
242                 if (e.getMessage().equals("Pipe broken")) {
243                     try {
244                         str.close();
245                     } catch (IOException ioe) {}
246                 }
247                 else {
248                     e.printStackTrace();
249                 }
250             }
251         }
252     }
253 }
254