package com.jsonde.profiler.network; import com.jsonde.api.Message; import com.jsonde.api.MessageListener; import com.jsonde.profiler.DaemonThreadFactory; import com.jsonde.util.log.Log; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.Collection; import java.util.Vector; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; public class NetworkServerImpl implements NetworkServer { private static final Log log = Log.getLog(NetworkServerImpl.class); private int port; private boolean running; private boolean outputWorkerReady; private boolean inputWorkerReady; //private BlockingQueue<Message> messageQueue = new ArrayBlockingQueue<Message>(50); private BlockingQueue<Message> messageQueue = new ArrayBlockingQueue<Message>(5000); private ServerSocket serverSocket; private Socket socket; private Thread outputThread; private Thread inputThread; private Collection<MessageListener> messageListeners = new Vector<MessageListener>(); private DaemonThreadFactory daemonThreadFactory; public NetworkServerImpl(int port, DaemonThreadFactory daemonThreadFactory) { this.port = port; this.daemonThreadFactory = daemonThreadFactory; } public void start() throws NetworkServerException { try { serverSocket = new ServerSocket(port); String testProperty = System.getProperty("com.jsonde.test"); if (null != testProperty && Boolean.parseBoolean(testProperty)) { System.out.write(0); System.out.flush(); } socket = serverSocket.accept(); } catch (IOException e) { throw new NetworkServerException(e); } setRunning(true); inputThread = daemonThreadFactory.newThread(new ServerInputWorker(this, socket)); inputThread.start(); outputThread = daemonThreadFactory.newThread(new ServerOutputWorker(this, socket)); outputThread.start(); waitForInitialization(); } public void stop() throws NetworkServerException { final String METHOD_NAME = "stop()"; setRunning(false); if (null != outputThread) { try { outputThread.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.error(METHOD_NAME, e); } } // if (null != inputThread) { try { inputThread.join(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.error(METHOD_NAME, e); } if (inputThread.isAlive()) { closeSockets(); try { inputThread.join(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.error(METHOD_NAME, e); } if (inputThread.isAlive()) { inputThread.interrupt(); } } else { closeSockets(); } } else { closeSockets(); } } private synchronized void closeSockets() throws NetworkServerException { try { if (null != socket) socket.close(); if (null != serverSocket) serverSocket.close(); } catch (IOException e) { throw new NetworkServerException(e); } notifyAll(); } private synchronized void waitForInitialization() { final String METHOD_NAME = "waitForInitialization()"; while (!areWorkersReady()) { try { wait(); } catch (InterruptedException e) { log.error(METHOD_NAME, e); Thread.currentThread().interrupt(); } } notifyAll(); } public synchronized void sendMessage(Message message) { final String METHOD_NAME = "sendMessage(Message)"; try { boolean inserted = false; while (!inserted) { inserted = messageQueue.offer(message); if (inserted) { notifyAll(); } else { wait(); } } } catch (InterruptedException e) { log.error(METHOD_NAME, e); Thread.currentThread().interrupt(); } } protected synchronized boolean isMessageInQueue() throws InterruptedException { while (isRunning() && 0 == messageQueue.size()) { wait(); } return 0 != messageQueue.size(); } protected synchronized Message takeMessageFromQueue() { Message message = messageQueue.poll(); notifyAll(); return message; } protected void processMessage(Message message) { for (MessageListener messageListener : messageListeners) { messageListener.onMessage(message); } } public void addMessageListener(MessageListener messageListener) { messageListeners.add(messageListener); } public void removeMessageListener(MessageListener messageListener) { messageListeners.remove(messageListener); } public synchronized boolean isRunning() { return running; } public synchronized void setRunning(boolean running) { this.running = running; notifyAll(); } private synchronized boolean areWorkersReady() { return inputWorkerReady && outputWorkerReady; } public synchronized void setOutputWorkerReady(boolean outputWorkerReady) { this.outputWorkerReady = outputWorkerReady; notifyAll(); } public synchronized void setInputWorkerReady(boolean inputWorkerReady) { this.inputWorkerReady = inputWorkerReady; notifyAll(); } }