1 28 package org.objectweb.carol.jtests.conform.util; 29 30 import java.io.BufferedReader ; 31 import java.io.File ; 32 import java.io.IOException ; 33 import java.io.InputStreamReader ; 34 import java.io.UnsupportedEncodingException ; 35 import java.lang.reflect.InvocationTargetException ; 36 import java.lang.reflect.Method ; 37 import java.net.ServerSocket ; 38 import java.net.Socket ; 39 40 63 public class ProcessRunner { 64 65 68 public static final String STREAM_ENCODING = "US-ASCII"; 69 70 73 public static final String SHUTDOWN_COMMAND = "shutdown"; 74 75 78 private ProcessRunner() { 79 80 } 81 82 87 public static void main(String [] args) { 88 deleteExitStamp(); 89 90 final int nServerArgs = args.length - 1; 91 if (nServerArgs < 0) { 92 throw new IllegalArgumentException ("server class name expected"); 93 } 94 final String serverClass = args[0]; 95 final String [] serverArgs = new String [nServerArgs]; 96 System.arraycopy(args, 1, serverArgs, 0, nServerArgs); 97 98 final int remaining = getNShutdowns(); 99 final Runner runner = new Runner(serverClass, serverArgs, remaining); 100 runner.start(); 101 102 int listenerPort = getListenerPort(); 103 104 ServerSocket listenerSocket; 105 try { 106 listenerSocket = new ServerSocket (listenerPort); 107 } catch (IOException ex) { 108 throw new RuntimeException ("Couldn't bind to " + listenerPort, ex); 109 } 110 111 try { 112 for (int ii = 0; ii < remaining; ii++) { 113 new Listener(listenerPort, listenerSocket.accept(), runner).start(); 114 } 115 } catch (IOException ex) { 116 throw new RuntimeException ("Error accepting connection", ex); 117 } 118 } 119 120 private static String getExitStamp() { 121 String exitStamp = System.getProperty("process.runner.exit.stamp"); 122 if ("".equals(exitStamp)) { 123 exitStamp = null; 124 } 125 return exitStamp; 126 } 127 128 private static void deleteExitStamp() { 129 final String exitStamp = getExitStamp(); 130 131 if (exitStamp != null) { 132 File exitStampFile = new File (exitStamp); 133 if (exitStampFile.exists()) { 134 exitStampFile.delete(); 135 } 136 } 137 } 138 139 private static int getListenerPort() { 140 String TCP_LISTENER_PORT = "process.runner.tcp.port"; 141 142 String port = System.getProperty(TCP_LISTENER_PORT); 143 if (port == null) { 144 throw new IllegalArgumentException ("The " + TCP_LISTENER_PORT + " property not set"); 145 } 146 try { 147 return Integer.parseInt(port); 148 } catch (NumberFormatException ex) { 149 throw (IllegalArgumentException ) new IllegalArgumentException ("The value of " + TCP_LISTENER_PORT 150 + " is not a integer: " + port).initCause(ex); 151 } 152 } 153 154 private static int getNShutdowns() { 155 String N_SHUTDOWNS = "process.runner.n.shutdowns"; 156 157 String nShutdowns = System.getProperty(N_SHUTDOWNS); 158 if (nShutdowns == null) { 159 throw new IllegalArgumentException ("The " + N_SHUTDOWNS + " property not set"); 160 } 161 try { 162 return Integer.parseInt(nShutdowns); 163 } catch (NumberFormatException ex) { 164 throw (IllegalArgumentException ) new IllegalArgumentException ("The value of " + N_SHUTDOWNS 165 + " is not a integer: " + nShutdowns).initCause(ex); 166 } 167 } 168 169 private static class Listener extends Thread { 170 171 private Socket m_socket; 172 173 private Runner m_runner; 174 175 Listener(int port, Socket socket, Runner runner) { 176 m_socket = socket; 177 m_runner = runner; 178 } 179 180 public void run() { 181 try { 182 BufferedReader reader = new BufferedReader (new InputStreamReader (m_socket.getInputStream(), 183 STREAM_ENCODING)); 184 String command; 185 while (null != (command = reader.readLine())) { 186 if (SHUTDOWN_COMMAND.equals(command)) { 187 possiblyShutdown(); 188 189 try { 190 m_socket.close(); 191 } catch (IOException ex) { 192 ; 193 } 194 break; 195 } 196 } 197 } catch (UnsupportedEncodingException ex) { 198 throw new RuntimeException ("can't happen", ex); 199 } catch (IOException ex) { 200 throw new RuntimeException (ex); 201 } 202 } 203 204 private void possiblyShutdown() { 205 synchronized (m_runner) { 206 m_runner.decrementRemaining(); 207 if (!m_runner.hasRemaining()) { 208 final String exitStamp = getExitStamp(); 209 if (exitStamp != null) { 210 File exitStampFile = new File (exitStamp); 211 try { 212 exitStampFile.createNewFile(); 213 } catch (IOException ex) { 214 throw new RuntimeException ("Couldn't create " + exitStamp, ex); 215 } 216 } 217 System.exit(0); 218 } 219 } 220 } 221 } 222 223 private static class Runner extends Thread { 224 225 private final String [] m_serverArgs; 226 227 private final Method m_main; 228 229 private int m_nRemaining; 230 231 Runner(String serverClassname, String [] serverArgs, int remaining) { 232 m_nRemaining = remaining; 233 m_serverArgs = serverArgs; 234 235 final Class serverClass; 236 try { 237 serverClass = Class.forName(serverClassname); 238 } catch (ClassNotFoundException ex) { 239 throw new RuntimeException (serverClassname, ex); 240 } 241 242 try { 243 m_main = serverClass.getMethod("main", new Class [] {String [].class}); 244 } catch (NoSuchMethodException ex) { 245 throw new RuntimeException (serverClassname + " does not have a main method", ex); 246 } catch (SecurityException ex) { 247 throw new RuntimeException (serverClassname + " does not have a public main method", ex); 248 } 249 setDaemon(true); 250 } 251 252 255 public void decrementRemaining() { 256 m_nRemaining--; 257 } 258 259 262 public boolean hasRemaining() { 263 return m_nRemaining > 0; 264 } 265 266 public void run() { 267 try { 268 m_main.invoke(null, new Object [] {m_serverArgs}); 269 } catch (IllegalAccessException ex) { 270 die(ex); 271 } catch (IllegalArgumentException ex) { 272 die(ex); 273 } catch (InvocationTargetException ex) { 274 die(ex); 275 } 276 } 277 278 private static void die(Exception ex) { 279 throw new RuntimeException (ex); 280 } 281 } 282 } | Popular Tags |