/*******************************************************************************
* 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();
}
}