1/* 2 * Copyright (c) 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 24import java.io.OutputStream; 25import java.io.IOException; 26 27/** 28 * Class to run and control registry/rmiregistry in a sub-process. 29 * The behaviour changes when use different runner, currently 30 * there are 2 built-in runners, RegistryRunner and RMIRegistryRunner. 31 * 32 * We can't kill a registry if we have too-close control 33 * over it. We must make it in a subprocess, and then kill the 34 * subprocess when it has served our needs. 35 */ 36public class RegistryVM extends JavaVM { 37 38 private static final double START_TIMEOUT = 39 20_000 * TestLibrary.getTimeoutFactor(); 40 private static final String DEFAULT_RUNNER = "RegistryRunner"; 41 42 private int port = -1; 43 44 private RegistryVM(String runner, OutputStream out, OutputStream err, 45 String options, int port) { 46 super(runner, options, Integer.toString(port), out, err); 47 try { 48 Class runnerClass = Class.forName(runner); 49 if (!RegistryRunner.class.isAssignableFrom(runnerClass)) { 50 throw new RuntimeException("runner class must be RegistryRunner" 51 + " or its sub class"); 52 } 53 } catch (ClassNotFoundException ex) { 54 throw new RuntimeException(ex); 55 } 56 this.port = port; 57 } 58 59 /** 60 * Create a RegistryVM instance on an ephemeral port. 61 * 62 * @return a RegistryVM instance 63 */ 64 public static RegistryVM createRegistryVM() { 65 return createRegistryVMWithRunner(DEFAULT_RUNNER, System.out, System.err, "", 0); 66 } 67 68 /** 69 * Create a RegistryVM instance on an ephemeral port with additional 70 * command line options. 71 * 72 * @param options command line options 73 * @return a RegistryVM instance 74 */ 75 public static RegistryVM createRegistryVM(String options) { 76 return createRegistryVMWithRunner( 77 DEFAULT_RUNNER, System.out, System.err, options, 0); 78 } 79 80 /** 81 * Create a RegistryVM instance on a specified port capturing stdout and 82 * stderr with additional command line options. 83 * 84 * @param out the OutputStream where the normal output of the 85 * registry subprocess goes 86 * @param err the OutputStream where the error output of the 87 * registry subprocess goes 88 * @param options the command line options 89 * @param port the port on which Registry accepts requests 90 * @return a RegistryVM instance 91 */ 92 public static RegistryVM createRegistryVM(OutputStream out, OutputStream err, 93 String options, int port) { 94 return createRegistryVMWithRunner(DEFAULT_RUNNER, out, err, options, port); 95 } 96 97 /** 98 * Create a RegistryVM instance on an ephemeral port with additional 99 * command line options and a specified runner. 100 * 101 * @param runner the runner class name 102 * @param options command line options 103 * @return a RegistryVM instance 104 */ 105 public static RegistryVM createRegistryVMWithRunner(String runner, String options) { 106 return createRegistryVMWithRunner(runner, System.out, System.err, options, 0); 107 } 108 109 /** 110 * Create a RegistryVM instance on a specified port capturing stdout and 111 * stderr with additional command line options and a specified runner. 112 * 113 * @param runner the runner class name 114 * @param out the OutputStream where the normal output of the 115 * registry subprocess goes 116 * @param err the OutputStream where the error output of the 117 * registry subprocess goes 118 * @param options the command line options 119 * @param port the port on which Registry accepts requests 120 * @return a RegistryVM instance 121 */ 122 public static RegistryVM createRegistryVMWithRunner(String runner, OutputStream out, 123 OutputStream err, String options, int port) { 124 options += " --add-exports=java.rmi/sun.rmi.registry=ALL-UNNAMED" 125 + " --add-exports=java.rmi/sun.rmi.server=ALL-UNNAMED" 126 + " --add-exports=java.rmi/sun.rmi.transport=ALL-UNNAMED" 127 + " --add-exports=java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED"; 128 RegistryVM reg = new RegistryVM(runner, out, err, options, port); 129 reg.setPolicyFile(TestParams.defaultRegistryPolicy); 130 return reg; 131 } 132 133 /** 134 * Starts the registry in a sub-process and waits up to 135 * the given timeout period to confirm that it's running, 136 * and get the port where it's running. 137 * 138 * @throws IOException if fails to start subprocess 139 */ 140 public void start() throws IOException { 141 super.start(); 142 long startTime = System.currentTimeMillis(); 143 long deadline = TestLibrary.computeDeadline(startTime, (long)START_TIMEOUT); 144 while (true) { 145 try { 146 Thread.sleep(1000); 147 } catch (InterruptedException ignore) { } 148 149 String output = outputStream.ba.toString(); 150 port = RegistryRunner.getRegistryPort(output); 151 if (port != -1) { 152 break; 153 } 154 try { 155 int exit = vm.exitValue(); 156 TestLibrary.bomb("[RegistryVM] registry sub-process exited with status " 157 + exit + "."); 158 } catch (IllegalThreadStateException ignore) { } 159 160 if (System.currentTimeMillis() > deadline) { 161 TestLibrary.bomb("Failed to start registry, giving up after " + 162 (System.currentTimeMillis() - startTime) + "ms.", null); 163 } 164 } 165 } 166 167 /** 168 * Shuts down the registry. 169 */ 170 @Override 171 public void cleanup() { 172 RegistryRunner.requestExit(port); 173 super.destroy(); 174 } 175 176 /** 177 * Gets the port where the registry is serving. 178 * 179 * @return the port where the registry is serving 180 */ 181 public int getPort() { 182 return port; 183 } 184} 185