package com.oracle.mxtool.compilerserver;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public abstract class CompilerDaemon {
protected void logf(String commandLine, Object... args) {
if (verbose) {
System.err.printf(commandLine, args);
}
}
private boolean verbose = false;
private volatile boolean running;
private ThreadPoolExecutor threadPool;
private ServerSocket serverSocket;
public void run(String[] args) throws Exception {
int jobsArg = -1;
int i = 0;
while (i < args.length) {
String arg = args[i];
if (arg.equals("-v")) {
verbose = true;
} else if (arg.equals("-j") && ++i < args.length) {
try {
jobsArg = Integer.parseInt(args[i]);
} catch (NumberFormatException e) {
usage();
}
} else {
usage();
}
i++;
}
serverSocket = new ServerSocket(0);
int port = serverSocket.getLocalPort();
int threadCount = Math.max(2, jobsArg > 0 ? jobsArg : Runtime.getRuntime().availableProcessors());
threadPool = new ThreadPoolExecutor(threadCount, threadCount, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {
public Thread newThread(Runnable runnable) {
return new Thread(runnable);
}
});
System.out.printf("Started server on port %d [%d threads]\n", port, threadCount);
running = true;
while (running) {
try {
threadPool.submit(new Connection(serverSocket.accept(), createCompiler()));
} catch (SocketException e) {
if (running) {
e.printStackTrace();
} else {
}
}
}
}
private static void usage() {
System.err.println("Usage: [ -v ] [ -j NUM ]");
System.exit(1);
}
abstract Compiler createCompiler();
interface Compiler {
int compile(String[] args) throws Exception;
}
String join(String delim, String[] strings) {
if (strings.length == 0) {
return "";
}
StringBuilder sb = new StringBuilder(strings[0]);
for (int i = 1; i < strings.length; i++) {
sb.append(delim);
sb.append(strings[i]);
}
return sb.toString();
}
public class Connection implements Runnable {
private final Socket connectionSocket;
private final Compiler compiler;
public Connection(Socket connectionSocket, Compiler compiler) {
this.connectionSocket = connectionSocket;
this.compiler = compiler;
}
public void run() {
try {
BufferedReader input = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream(), "UTF-8"));
OutputStreamWriter output = new OutputStreamWriter(connectionSocket.getOutputStream(), "UTF-8");
try {
String commandLine = input.readLine();
if (commandLine == null || commandLine.length() == 0) {
logf("Shutting down\n");
running = false;
while (threadPool.getActiveCount() > 1) {
threadPool.awaitTermination(50, TimeUnit.MILLISECONDS);
}
serverSocket.close();
System.exit(0);
} else {
String[] args = commandLine.split("\u0000");
logf("Compiling %s\n", join(" ", args));
int result = compiler.compile(args);
logf("Result = %d\n", result);
output.write(result + "\n");
}
} finally {
output.close();
input.close();
connectionSocket.close();
}
} catch (Exception ioe) {
ioe.printStackTrace();
}
}
}
}