/**
* Copyright (C) 2010-2013 Eugen Feller, INRIA <eugen.feller@inria.fr>
*
* This file is part of Snooze, a scalable, autonomic, and
* energy-aware virtual machine (VM) management framework.
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses>.
*/
package org.inria.myriads.snoozenode.tcpip;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;
import org.inria.myriads.snoozecommon.communication.NetworkAddress;
import org.inria.myriads.snoozecommon.guard.Guard;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* TCP data receiver.
*
* @author Eugen Feller
*/
public abstract class TCPDataReceiver
implements Runnable
{
/** Define the logger. */
private static final Logger log_ = LoggerFactory.getLogger(TCPDataReceiver.class);
/** Server socket. */
private ServerSocket serverSocket_;
/** Failure event handler reference. */
private DataListener dataHandler_;
/** Worker threads list. */
private List<TCPWorkerThread> workerThreads_;
/** Timeout. */
private int timeout_;
/** Signals termination. */
private boolean isTerminated_;
/**
* Constructor.
*
* @param networkAddress The network address
* @param timeout The timeout
* @throws IOException The I/O exception
*/
public TCPDataReceiver(NetworkAddress networkAddress, int timeout)
throws IOException
{
Guard.check(networkAddress, timeout);
log_.debug(String.format("Initializing the data receiver at address: %s, port: %d, timeout: %s",
networkAddress.getAddress(), networkAddress.getPort(), timeout));
timeout_ = timeout;
workerThreads_ = new ArrayList<TCPWorkerThread>();
serverSocket_ = new ServerSocket();
SocketAddress socketAddress = new InetSocketAddress(networkAddress.getAddress(), networkAddress.getPort());
serverSocket_.bind(socketAddress);
}
/**
* Sets the failure event handler.
*
* @param danaHandler The data handler
*/
public void setHandler(DataListener danaHandler)
{
Guard.check(danaHandler);
dataHandler_ = danaHandler;
}
/**
* Accepts new clients and reads data.
*/
public void run()
{
Socket clientSocket = null;
try
{
while (!isTerminated_)
{
log_.debug("Waiting for incoming connections");
clientSocket = serverSocket_.accept();
clientSocket.setSoTimeout(timeout_);
log_.debug("New connected estabilished");
TCPWorkerThread workerThread = new TCPWorkerThread(clientSocket, dataHandler_);
workerThreads_.add(workerThread);
new Thread(workerThread, "WorkerThread : " + clientSocket.toString()).start();
}
}
catch (IOException exception)
{
if (!isTerminated_)
{
log_.error("I/O exception during communication", exception);
try
{
closeSocket();
}
catch (Exception socketException)
{
log_.error("Unable to close the server socket", socketException);
}
}
}
}
/**
* Terminates the receiver.
*/
public void terminate()
{
log_.debug("Terminating all worker threads");
for (TCPWorkerThread worrkerThread : workerThreads_)
{
worrkerThread.terminate();
}
isTerminated_ = true;
try
{
closeSocket();
}
catch (IOException exception)
{
log_.error("I/O exception while closing the server socket", exception);
}
}
/**
* Closes the socket.
*
* @throws IOException The I/O exception
*/
private synchronized void closeSocket()
throws IOException
{
if (serverSocket_ != null)
{
serverSocket_.close();
}
}
}