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
26import java.rmi.*;
27import java.rmi.registry.*;
28import 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 */
35public 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
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     */
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     */
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
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     */
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     */
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
149    public static void main(String[] args) {
150        int port = init(args);
151        notify(port);
152    }
153}
154