package vn.edu.rmit.sadi; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class TriviaServer { private Map<String, String> qaMap = new HashMap<String, String>(); private int clientCount = 0; public static void main(String[] arguments) { new TriviaServer(); } public TriviaServer() { initializeData(); startServer(); } private void initializeData() { try { InputStream is = ClassLoader.getSystemResourceAsStream("vn/edu/rmit/sadi/qa.txt"); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String key; while ((key = br.readLine()) != null) { qaMap.put(key, br.readLine()); } } catch (FileNotFoundException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } private void startServer() { ServerSocket server; try { server = new ServerSocket(4415); System.out.println("TriviaServer is up and running ..."); } catch (IOException ex) { throw new RuntimeException(ex); } while (true) { try { new TriviaThread(server.accept()).start(); } catch (IOException ex) { throw new RuntimeException(ex); } } } private enum GameState { PrepareToSendQuestion, WaitForAnswer, WaitForConfirm } class TriviaThread extends Thread { private Socket client = null; private GameState state = GameState.PrepareToSendQuestion; private Iterator<Map.Entry<String, String>> entryIter; private Map.Entry<String, String> currentEntry; public TriviaThread(Socket sock) { super("TriviaThread"); client = sock; } @Override public void run() { System.out.println("TriviaThread #" + ++clientCount + " started ..."); try { BufferedReader reader = getReader(); PrintWriter writer = getWriter(); executeGameLoop(writer, reader); cleanUpResources(writer, reader); } catch (IOException ex) {} } private void executeGameLoop(PrintWriter writer, BufferedReader reader) throws IOException { String msgToClient = getMessageToClient(null); while (msgToClient != null) { writer.println(msgToClient); String msgFromClient = reader.readLine(); msgToClient = getMessageToClient(msgFromClient); } } private String getMessageToClient(String msgFromClient) { switch (state) { case PrepareToSendQuestion: state = GameState.WaitForAnswer; return generateQuestion(); case WaitForAnswer: state = GameState.WaitForConfirm; if (msgFromClient != null && msgFromClient.equalsIgnoreCase(currentEntry.getValue())) { return "That's correct! Want another (y/n)?"; } return "Wrong, the correct answer is " + currentEntry.getValue() + ". Want another (y/n)?"; case WaitForConfirm: if (msgFromClient != null && msgFromClient.equalsIgnoreCase("y")) { state = GameState.WaitForAnswer; return generateQuestion(); } return null; default: throw new RuntimeException("Invalid state"); } } private String generateQuestion() { if (entryIter == null || !entryIter.hasNext()) { entryIter = qaMap.entrySet().iterator(); } currentEntry = entryIter.next(); return currentEntry.getKey(); } private void cleanUpResources(PrintWriter writer, BufferedReader reader) throws IOException { writer.close(); reader.close(); client.close(); } private BufferedReader getReader() throws IOException { InputStreamReader isr = new InputStreamReader(client.getInputStream()); return new BufferedReader(isr); } private PrintWriter getWriter() throws IOException { return new PrintWriter(new BufferedOutputStream(client.getOutputStream()), true); } } }