package org.yajul.net;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yajul.collections.CollectionUtil;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.List;
/**
* Represents the server side of an accepted client connection.
* User: jdavis
* Date: Dec 11, 2003
* Time: 11:46:47 AM
*
* @author jdavis
*/
public class ClientConnection {
private static final Logger log = LoggerFactory.getLogger(ClientConnection.class);
private final SocketListener listener;
private Socket socket;
private final List<TaskWrapper> taskWrappers;
public ClientConnection(SocketListener listener,
Socket socket) throws IOException {
this.listener = listener;
this.socket = socket;
this.taskWrappers = CollectionUtil.newArrayList();
socket.setSoTimeout(listener.getConnectionTimeout());
}
private class TaskWrapper implements Runnable {
private ClientTask task;
private TaskWrapper(ClientTask task) {
this.task = task;
}
public void run() {
try {
task.runClient();
} catch (Throwable t) {
unexpected(t);
} finally {
taskCompleted(this);
}
}
}
private void taskCompleted(TaskWrapper wrapper) {
boolean shouldClose = false;
synchronized (taskWrappers) {
taskWrappers.remove(wrapper);
shouldClose = taskWrappers.isEmpty();
}
if (shouldClose)
close();
}
private TaskWrapper addWrapper(ClientTask task) {
synchronized (taskWrappers) {
TaskWrapper wrapper = new TaskWrapper(task);
taskWrappers.add(wrapper);
return wrapper;
}
}
protected final void start() {
List<ClientTask> tasks = getTasks();
if (log.isDebugEnabled())
log.debug("start() : tasks = " + tasks);
for (ClientTask task : tasks) {
TaskWrapper wrapper = addWrapper(task);
taskWrappers.add(wrapper);
if (log.isDebugEnabled())
log.debug("start() : Launching " + wrapper);
listener.getExecutor().execute(wrapper);
}
}
protected List<ClientTask> getTasks() {
return listener.getClientTaskFactory().createClientTasks(this);
}
/**
* Handle an unexpected exception.
*
* @param t The unexpected exception.
*/
protected void unexpected(Throwable t) {
Logger logger = LoggerFactory.getLogger(this.getClass());
logger.error("Unexpected: " + t, t);
}
/**
* Notifies the server that this connection has been closed.
*/
protected void onClose() {
listener.clientClosed(this);
}
public void close() {
closeSocket();
onClose();
}
private void closeSocket() {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
listener.unexpected(e);
}
}
}
public InputStream getInputStream() throws IOException {
return socket.getInputStream();
}
public OutputStream getOutputStream() throws IOException {
return socket.getOutputStream();
}
/**
* Returns the incoming client socket.
*
* @return The socket.
*/
public Socket getSocket() {
return socket;
}
/**
* Stops and closes the client connection.
*/
void shutdown() {
closeSocket();
}
@Override
public String toString() {
return "ClientConnection{" +
"socket=" + socket +
'}';
}
}