1 /*
   2  * Copyright (c) 1999, 2016, 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  * the rmiregistry 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     private static Registry registry = null;
  42     private 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         } catch (java.net.MalformedURLException mfue) {
  76             // will not happen
  77         } catch (NotBoundException nbe) {
  78             TestLibrary.bomb("exiter not bound?", nbe);
  79         } catch (RemoteException re) {
  80             TestLibrary.bomb("remote exception trying to exit",
  81                              re);
  82         }
  83     }
  84 
  85     public static int getRegistryPort(String output) {
  86         int idxStart = output.indexOf(PORT_LABEL_START);
  87         int idxEnd = output.indexOf(PORT_LABEL_END);
  88         if (idxStart == -1 || idxEnd == -1) {
  89             return -1;
  90         }
  91         idxStart = idxStart+PORT_LABEL_START.length();
  92         String portStr = output.substring(idxStart, idxEnd);
  93         int port = Integer.valueOf(portStr);
  94         System.err.println("registry is running at port: " + port);
  95         return port;
  96     }
  97 
  98     /**
  99      * port 0 means to use ephemeral port to start registry.
 100      */
 101     protected static int init(String[] args) {
 102         try {
 103             if (args.length == 0) {
 104                 System.err.println("Usage: <port>");
 105                 System.exit(0);
 106             }
 107             int port = -1;
 108             port = Integer.parseInt(args[0]);
 109 
 110             // create a registry
 111             registry = LocateRegistry.createRegistry(port);
 112             if (port == 0) {
 113                 port = TestLibrary.getRegistryPort(registry);
 114             }
 115 
 116             // create a remote object to tell this VM to exit
 117             exiter = new RegistryRunner();
 118             Naming.rebind("rmi://localhost:" + port +
 119                           "/RemoteExiter", exiter);
 120 
 121             return port;
 122         } catch (Exception e) {
 123             System.err.println(e.getMessage());
 124             e.printStackTrace();
 125             System.exit(-1);
 126         }
 127         return -1;
 128     }
 129 
 130     /**
 131      * REGISTRY.start() will filter the output of registry subprocess,
 132      * when valid port is detected, REGISTRY.start() returns.
 133      * So, for subclass, it's important to call this method after registry
 134      * is initialized and necessary remote objects have been bound.
 135      */
 136     protected static void notify(int port) {
 137         // this output is important for REGISTRY to get the port
 138         // where rmiregistry is serving
 139         System.out.println(PORT_LABEL_START + port + PORT_LABEL_END);
 140         System.out.flush();
 141     }
 142 
 143     public static void main(String[] args) {
 144         int port = init(args);
 145         notify(port);
 146     }
 147 }