package ch.ethz.syslab.telesto.server.network;
import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import ch.ethz.syslab.telesto.common.network.Connection;
import ch.ethz.syslab.telesto.common.protocol.ErrorPacket;
import ch.ethz.syslab.telesto.common.protocol.Packet;
import ch.ethz.syslab.telesto.common.protocol.handler.PacketProcessingException;
import ch.ethz.syslab.telesto.common.util.ErrorType;
import ch.ethz.syslab.telesto.common.util.Log;
import ch.ethz.syslab.telesto.profile.BenchmarkLog;
import ch.ethz.syslab.telesto.profile.Stopwatch;
import ch.ethz.syslab.telesto.profile.Stopwatch.Phase;
public class DataHandler extends Thread {
static private Log LOGGER = new Log(DataHandler.class);
private ArrayBlockingQueue<Connection> clientQueue;
private int id;
private boolean running = true;
private Stopwatch stopwatch;
public DataHandler(ArrayBlockingQueue<Connection> clientQueue, int id, BenchmarkLog log) {
this.clientQueue = clientQueue;
this.id = id;
stopwatch = new Stopwatch(log);
}
@Override
public void run() {
while (running) {
stopwatch.enterPhase(Phase.WAITING);
Connection connection = nextClient();
stopwatch.enterPhase(Phase.PARSING);
Packet packet = connection.readPacket();
if (packet != null) {
LOGGER.info("Received packet %s (%d)", packet, id);
if (connection.dataRemaining()) {
clientQueue.add(connection);
}
Packet response;
stopwatch.enterPhase(Phase.DATABASE);
try {
response = connection.handle(packet);
} catch (PacketProcessingException e) {
LOGGER.info("Error while processing packet '%s': %s", packet, e.getMessage());
response = new ErrorPacket(e.type, e.getMessage());
} catch (Exception e) {
LOGGER.info("Unexpected error while processing packet '%s': %s", packet, e.getMessage());
response = new ErrorPacket(ErrorType.INTERNAL_ERROR, e.getMessage());
}
if (response == null) {
LOGGER.info("Packet handler for '%s' returned null", packet);
response = new ErrorPacket(ErrorType.INTERNAL_ERROR, "No response from packet handler");
}
response.packetId = packet.packetId;
stopwatch.enterPhase(Phase.RESPONSE);
try {
connection.send(response);
} catch (IOException e) {
LOGGER.warning(e, "Failed to send %s to %s", response, connection);
connection.disconnect();
}
}
}
}
private Connection nextClient() {
Connection client = null;
while (client == null) {
try {
client = clientQueue.take();
} catch (InterruptedException e) {
LOGGER.info("Interrupt in message handler loop");
continue;
}
}
return client;
}
public void shutdown() {
running = false;
}
}