1 /*
2  * Copyright (c) 1999, 2017, 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 import java.rmi.*;
27 import java.rmi.registry.*;
28 import java.rmi.server.*;
29 
30 /**
31  * Class to run a registry whose VM can be told to exit remotely; using
32  * a registry (in a sub-process) in this fashion makes tests more robust under
33  * windows where Process.destroy() seems not to be 100% reliable.
34  */
35 public class RegistryRunner extends UnicastRemoteObject
36     implements RemoteExiter
37 {
38     private static final String PORT_LABEL_START = "RegistryRunner.port.start:";
39     private static final String PORT_LABEL_END = ":RegistryRunner.port.end";
40 
41     protected static Registry registry = null;
42     protected static RemoteExiter exiter = null;
43 
RegistryRunner()44     public RegistryRunner() throws RemoteException {
45     }
46 
47     /**
48      * Ask the registry to exit instead of forcing it do so; this
49      * works better on windows...
50      */
exit()51     public void exit() throws RemoteException {
52         // REMIND: create a thread to do this to avoid
53         // a remote exception?
54         System.err.println("received call to exit");
55         System.exit(0);
56     }
57 
58     /**
59      * Request that the registry process exit and handle
60      * related exceptions.
61      */
requestExit(int port)62     public static void requestExit(int port) {
63 
64         try {
65             RemoteExiter e =
66                 (RemoteExiter)
67                 Naming.lookup("rmi://localhost:" +
68                               port +
69                               "/RemoteExiter");
70             try {
71                 e.exit();
72             } catch (RemoteException re) {
73             }
74             e = null;
75 
76         } catch (java.net.MalformedURLException mfue) {
77             // will not happen
78         } catch (NotBoundException nbe) {
79             TestLibrary.bomb("exiter not bound?", nbe);
80         } catch (RemoteException re) {
81             TestLibrary.bomb("remote exception trying to exit",
82                              re);
83         }
84     }
85 
getRegistryPort(String output)86     public static int getRegistryPort(String output) {
87         int idxStart = output.indexOf(PORT_LABEL_START);
88         int idxEnd = output.indexOf(PORT_LABEL_END);
89         if (idxStart == -1 || idxEnd == -1) {
90             return -1;
91         }
92         idxStart = idxStart+PORT_LABEL_START.length();
93         String portStr = output.substring(idxStart, idxEnd);
94         int port = Integer.valueOf(portStr);
95         System.err.println("registry is running at port: " + port);
96         return port;
97     }
98 
99     /**
100      * port 0 means to use ephemeral port to start registry.
101      *
102      * @param args command line arguments passed in from main
103      * @return the port number on which registry accepts requests
104      */
init(String[] args)105     protected static int init(String[] args) {
106         try {
107             if (args.length == 0) {
108                 System.err.println("Usage: <port>");
109                 System.exit(0);
110             }
111             int port = -1;
112             port = Integer.parseInt(args[0]);
113 
114             // create a registry
115             registry = LocateRegistry.createRegistry(port);
116             if (port == 0) {
117                 port = TestLibrary.getRegistryPort(registry);
118             }
119 
120             // create a remote object to tell this VM to exit
121             exiter = new RegistryRunner();
122             Naming.rebind("rmi://localhost:" + port +
123                           "/RemoteExiter", exiter);
124 
125             return port;
126         } catch (Exception e) {
127             System.err.println(e.getMessage());
128             e.printStackTrace();
129             System.exit(-1);
130         }
131         return -1;
132     }
133 
134     /**
135      * RegistryVM.start() will filter the output of registry subprocess,
136      * when valid port is detected, RegistryVM.start() returns.
137      * So, for subclass, it's important to call this method after registry
138      * is initialized and necessary remote objects have been bound.
139      *
140      * @param port the port on which registry accepts requests
141      */
notify(int port)142     protected static void notify(int port) {
143         // this output is important for RegistryVM to get the port
144         // where rmiregistry is serving
145         System.out.println(PORT_LABEL_START + port + PORT_LABEL_END);
146         System.out.flush();
147     }
148 
main(String[] args)149     public static void main(String[] args) {
150         int port = init(args);
151         notify(port);
152     }
153 }
154