package org.smartly.commons.network.socket.server; import org.smartly.commons.Delegates; import org.smartly.commons.logging.Level; import org.smartly.commons.logging.Logger; import org.smartly.commons.logging.util.LoggingUtils; import org.smartly.commons.network.socket.messages.multipart.Multipart; import org.smartly.commons.network.socket.messages.multipart.MultipartMessagePart; import org.smartly.commons.network.socket.messages.multipart.MultipartPool; import org.smartly.commons.network.socket.server.handlers.ISocketFilter; import org.smartly.commons.network.socket.server.handlers.ISocketHandler; import org.smartly.commons.network.socket.server.handlers.impl.HandlerMultipartMessage; import org.smartly.commons.network.socket.server.handlers.pool.SocketHandlerPool; import org.smartly.commons.network.socket.messages.tools.MultipartMessageUtils; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /* * Very simple socket server example. That responds to a single object with * another object. Could be used as the basis for something more complex, but * this illustrates the basics of TCP/IP communication. * * A Client will call a Server with a message. The Server will respond with a message. * In this simplest implementation the messages can be any serializable object. * * To setup a server: * 1) Create your handler, a class that implements the simple SimpleSocketHandler * interface. * 2) Call the static Server.startServer() method with a port and an * instance of your Handler defined above. * * To call the server from a client: * 1) Call the static Client.send() method specifying the server host, port, and * message. This returns your response. */ public class Server extends Thread { public static int DEFAULT_PORT = 14444; public static final int DEFAULT_MULTIPART_TIMEOUT = 60 * 2 * 1000; // two minute timeout // -------------------------------------------------------------------- // e v e n t s // -------------------------------------------------------------------- public static interface OnStart { void handle(final Server sender); } private static final Class EVENT_ON_START = OnStart.class; private static final Class EVENT_ON_PART = Multipart.OnPartListener.class; private static final Class EVENT_ON_FULL = Multipart.OnFullListener.class; private static final Class EVENT_ON_TIME_OUT = Multipart.OnTimeOutListener.class; private static final Class EVENT_ON_ERROR = Delegates.ExceptionCallback.class; // -------------------------------------------------------------------- // f i e l d s // -------------------------------------------------------------------- private final MultipartPool _multipartPool; private final Delegates.Handlers _eventHandlers; private final int _port; private SocketHandlerPool _handlers; private ServerSocket _socket; private boolean _running; // -------------------------------------------------------------------- // c o n s t r u c t o r // -------------------------------------------------------------------- public Server(final int port) throws IOException { this(port, DEFAULT_MULTIPART_TIMEOUT, null); } public Server(final int port, final int uploadTimeout) throws IOException { this(port, uploadTimeout, null); } public Server(final int port, final int uploadTimeout, final Class<? extends ISocketFilter>[] handlers) throws IOException { super("Smartly-SocketServer"); _running = false; _port = port; _handlers = new SocketHandlerPool(handlers); _socket = new ServerSocket(_port); _multipartPool = new MultipartPool(uploadTimeout); _eventHandlers = new Delegates.Handlers(); this.init(); } @Override protected void finalize() throws Throwable { try { _multipartPool.clear(); _handlers.clear(); _eventHandlers.clear(); } catch (Throwable ignore) { } super.finalize(); } // -------------------------------------------------------------------- // e v e n t // -------------------------------------------------------------------- public void onStart(final OnStart handler) { _eventHandlers.add(handler); } public void onError(final Delegates.ExceptionCallback listener) { _eventHandlers.add(listener); } public void onMultipartPart(final Multipart.OnPartListener listener) { _eventHandlers.add(listener); } public void onMultipartFull(final Multipart.OnFullListener listener) { _eventHandlers.add(listener); } public void onMultipartTimeOut(final Multipart.OnTimeOutListener listener) { _eventHandlers.add(listener); } // -------------------------------------------------------------------- // p u b l i c // -------------------------------------------------------------------- public void run() { this.startServer(); } public void stopServer() { this.getLogger().info("Server: Stopping server..."); try { if (_socket != null) { _socket.close(); } if (null != _handlers) { _handlers.clear(); } } catch (Throwable t) { this.onError(null, t); } } public boolean isServerRunning() { return _running; } public SocketHandlerPool getHandlers() { return _handlers; } public Server addFilter(final Class<? extends ISocketFilter> handler) { _handlers.addFilter(handler); return this; } public Server removeFilter(final Class<? extends ISocketFilter> handler) { _handlers.removeFilter(handler); return this; } public Server addHandler(final Class type, final Class<? extends ISocketHandler> handler) { this.addHandler(type.getName(), handler); return this; } public Server addHandler(final String type, final Class<? extends ISocketHandler> handler) { _handlers.addHandler(type, handler); return this; } public void addMultipartMessagePart(final MultipartMessagePart part) { _multipartPool.add(part); } // -------------------------------------------------------------------- // p r i v a t e // -------------------------------------------------------------------- private Logger getLogger() { return LoggingUtils.getLogger(this); } private void init() { //-- register default handlers --// this.addHandler(HandlerMultipartMessage.TYPE, HandlerMultipartMessage.class); //-- init multipart pool --// _multipartPool.onPart(new Multipart.OnPartListener() { @Override public void handle(final Multipart sender, final MultipartMessagePart part) { onMultipartPart(sender, part); } }); _multipartPool.onFull(new Multipart.OnFullListener() { @Override public void handle(Multipart sender) { onMultipartFull(sender); } }); _multipartPool.onTimeOut(new Multipart.OnTimeOutListener() { @Override public void handle(Multipart sender) { onMultipartTimeout(sender); } }); } private void startServer() { this.getLogger().info("Starting server on port [" + _port + "] with handlers [" + _handlers.toString() + "]"); try { _running = true; this.onStart(); while (true) { // accept client final Socket client = _socket.accept(); // handle request in thread final ServerWorker st = new ServerWorker(this, client); st.start(); } } catch (Throwable t) { if (_socket != null && _socket.isClosed()) { //Ignore if closed by stopServer() call } else { this.onError(null, t); } } finally { _socket = null; _running = false; } this.getLogger().info("Stopped"); } void onStart() { _eventHandlers.trigger(EVENT_ON_START, this); } void onError(final String message, final Throwable error) { if (_eventHandlers.contains(EVENT_ON_ERROR)) { _eventHandlers.trigger(EVENT_ON_ERROR, message, error); } else { this.getLogger().log(Level.SEVERE, message, error); } } private void onMultipartPart(final Multipart multipart, final MultipartMessagePart part) { try { if (_eventHandlers.contains(EVENT_ON_PART)) { _eventHandlers.triggerAsync(EVENT_ON_PART, multipart, part); } else { // no external handlers. // handle internally } } catch (Throwable ignored) { } } private void onMultipartFull(final Multipart multipart) { try { if (_eventHandlers.contains(EVENT_ON_FULL)) { _eventHandlers.triggerAsync(EVENT_ON_FULL, multipart); } else { // no external handlers. // handle internally } } catch (Throwable ignored) { } } private void onMultipartTimeout(final Multipart multipart) { // timeout try { if (_eventHandlers.contains(EVENT_ON_TIME_OUT)) { _eventHandlers.triggerAsync(EVENT_ON_TIME_OUT, multipart); } else { // no external handlers. // handle internally try { MultipartMessageUtils.remove(multipart); } catch (Throwable t) { this.onError(null, t); } } } catch (Throwable ignored) { } } // -------------------------------------------------------------------- // S T A T I C // -------------------------------------------------------------------- public static Server startServer(final Class<ISocketFilter>[] handlers) throws Exception { return startServer(Server.DEFAULT_PORT, DEFAULT_MULTIPART_TIMEOUT, handlers); } public static Server startServer(final int port, final Class<ISocketFilter>[] handlers) throws Exception { return startServer(port, DEFAULT_MULTIPART_TIMEOUT, handlers); } public static synchronized Server startServer(final int port, final int uploadTimeout, final Class<ISocketFilter>[] handlers) throws Exception { final Server server = new Server(port, uploadTimeout, handlers); server.start(); while (!server.isServerRunning()) { Thread.sleep(100); } return server; } }