package info.fitnesse; import fitnesse.slim.*; import fitnesse.socketservice.SocketServer; import util.StreamReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.net.Socket; import java.util.List; public class TransactionalSlimServer implements SocketServer { private StreamReader reader; private BufferedWriter writer; private ListExecutor executor; private boolean verbose; private RollbackIntf rollbackProcessingBean; public TransactionalSlimServer(boolean verbose) { this.verbose = verbose; } public void serve(Socket s) { try { rollbackProcessingBean = FitnesseSpringContext.getRollbackBean(); } catch (Throwable e) { e.printStackTrace(); closeEnclosingServiceInSeparateThread(); } try { tryProcessInstructions(s); } catch (Throwable e) { e.printStackTrace(); } finally { close(); closeEnclosingServiceInSeparateThread(); } } private void closeEnclosingServiceInSeparateThread() { new Thread(new Runnable() { public void run() { try { TransactionalSlimService.instance.close(); } catch (Exception e) { } } } ).start(); } private void tryProcessInstructions(Socket s) throws Exception { initialize(s); boolean more = true; while (more) { if (verbose) System.err.println("processing instruction set"); more = processOneSetOfInstructions(); if (verbose) System.err.println("instruction set processed"); } } private void initialize(Socket s) throws IOException { try { executor = new JavaSlimFactory().getListExecutor(verbose); reader = new StreamReader(s.getInputStream()); writer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); writer.write(String.format("Slim -- %s\n", SlimVersion.VERSION)); writer.flush(); } catch (Exception e) { System.err.println("fail! " + e.getMessage()); } } private boolean processOneSetOfInstructions() throws Exception { String instructions = getInstructionsFromClient(); return instructions == null || processTheInstructions(instructions); } private class InstructionRunner implements Runnable { private String instructions; public InstructionRunner(String instructions) { this.instructions = instructions; } public void run() { List<Object> results = executeInstructions(instructions); try { sendResultsToClient(results); } catch (IOException iex) { throw new Error(iex); } } } private boolean processTheInstructions(String instructions) throws IOException { if (instructions.equalsIgnoreCase("bye")) { return false; } else { try { rollbackProcessingBean.process(new InstructionRunner(instructions)); } catch (RollbackNow rn) { if (verbose) System.err.println("rolling back now" + "\n"); } return true; } } private String getInstructionsFromClient() throws Exception { int instructionLength = Integer.parseInt(reader.read(6)); reader.read(1); return reader.read(instructionLength); } private List<Object> executeInstructions(String instructions) { List<Object> statements = ListDeserializer.deserialize(instructions); return executor.execute(statements); } private void sendResultsToClient(List<Object> results) throws IOException { String resultString = ListSerializer.serialize(results); writer.write(String.format("%06d:%s", resultString.length(), resultString)); writer.flush(); } private void close() { try { reader.close(); writer.close(); } catch (Exception e) { } } }