package edu.brown.protorpc;
import java.util.concurrent.LinkedBlockingQueue;
import com.google.protobuf.Descriptors.MethodDescriptor;
import com.google.protobuf.Message;
import com.google.protobuf.RpcCallback;
import com.google.protobuf.RpcChannel;
import com.google.protobuf.RpcController;
import com.google.protobuf.Service;
/** Runs a service in a separate thread. */
public class ThreadChannel extends Thread implements RpcChannel {
public final class TableTask implements RpcCallback<Message>, Runnable {
private final MethodDescriptor method;
private final Message request;
private final RpcCallback<Message> finalCallback;
private Message response;
public TableTask(MethodDescriptor method, Message request,
RpcCallback<Message> finalCallback) {
this.method = method;
this.request = request;
this.finalCallback = finalCallback;
}
public RpcCallback<Message> getFinalCallback() { return finalCallback; }
// RpcCallback: used when finished processing inside this thread
@Override
public void run(Message parameter) {
assert response == null;
assert parameter != null;
response = parameter;
// System.out.println("scheduling callback in original thread");
outputEventLoop.runInEventThread(this);
}
// Callback: used to call the finalCallback in the EventLoop thread
@Override
public void run() {
// System.out.println("calling callback in original thread");
assert response != null;
finalCallback.run(response);
response = null;
}
}
private final LinkedBlockingQueue<TableTask> inputQueue = new LinkedBlockingQueue<TableTask>();
// private final TableService table = new TableServer();
private final EventLoop outputEventLoop;
private final Service service;
public ThreadChannel(EventLoop outputEventLoop, Service service) {
this.outputEventLoop = outputEventLoop;
this.service = service;
}
public void run() {
while (true) {
TableTask task;
try {
task = inputQueue.take();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (task.request == null) {
// TODO: Abort outstanding transactions?
return;
}
// System.out.println("calling task in thread");
service.callMethod(task.method, null, task.request, task);
}
}
@Override
public void callMethod(MethodDescriptor method, RpcController controller,
Message request, Message responsePrototype,
RpcCallback<Message> done) {
// System.out.println("added task to thread");
inputQueue.add(new TableTask(method, request, done));
}
public void shutDownThread() {
inputQueue.add(new TableTask(null, null, null));
}
}