/******************************************************************************* * Copyright (c) 2010 Association for Decentralized Information Management in * Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.databoard.method; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.logging.Level; import java.util.logging.Logger; import org.simantics.databoard.method.TcpConnection.ConnectionListener; /** * Server opens a server socket and accepts incoming connections. *

* Methods are invoked in read thread. Therefore method invocation blocks * the whole socket. * It is highly recommended that that MethodInterface implementation is * non-blocking. * * @author Toni Kalajainen */ public class Server { static Logger LOGGER = Logger.getLogger(Server.class.getName()); ServerSocket socket; Thread acceptThread; MethodInterface handler; List connections = new CopyOnWriteArrayList(); /** * Create new method interface server. * * @param port * @param handler method handler of local methods or * @throws IOException */ public Server(int port, MethodInterface handler) throws IOException { this.handler = handler; socket = new ServerSocket(port); acceptThread = new Thread() { @Override public void run() { while(true) { Socket s; try { s = socket.accept(); } catch (IOException e) { return; } try { Handshake local = new Handshake(); local.methods = Server.this.handler.getInterface().getMethodDefinitions(); Handshake remote = TcpConnection.handshake(s, local); final TcpConnection c = new TcpConnection(s, Server.this.handler, local, remote); c.addConnectionListener(new ConnectionListener() { @Override public void onClosed() { connections.remove(c); } @Override public void onError(Exception error) { connections.remove(c); } }); connections.add( c ); if (c.getSocket().isClosed()) connections.remove(c); } catch (IOException e) { LOGGER.log(Level.FINER, "Connection Closed"); try { s.close(); } catch (IOException e1) { } } } } }; acceptThread.setDaemon(true); acceptThread.start(); } /** * Stop listening for new connections and shutdown existing connections. */ public void close() { try { socket.close(); } catch (IOException e) { } for (TcpConnection c : connections) { c.close(); try { c.getSocket().close(); } catch (IOException e) { } } } /** * @return The port the server is listening. */ public int getPort() { return socket.getLocalPort(); } }