package code.google.nfs.rpc.grizzly.server;
/**
* nfs-rpc
* Apache License
*
* http://code.google.com/p/nfs-rpc (c) 2011
*/
import java.io.IOException;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.glassfish.grizzly.WriteResult;
import org.glassfish.grizzly.filterchain.BaseFilter;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.filterchain.NextAction;
import code.google.nfs.rpc.ProtocolFactory;
import code.google.nfs.rpc.RequestWrapper;
import code.google.nfs.rpc.ResponseWrapper;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import org.glassfish.grizzly.Connection;
import org.glassfish.grizzly.EmptyCompletionHandler;
/**
* Grizzly Server Handler
*
* @author <a href="mailto:bluedavy@gmail.com">bluedavy</a>
*/
public class GrizzlyServerHandler extends BaseFilter {
private static final Log LOGGER = LogFactory.getLog(GrizzlyServerHandler.class);
private final ExecutorService threadPool;
public GrizzlyServerHandler(final ExecutorService threadPool) {
this.threadPool = threadPool;
}
public NextAction handleRead(final FilterChainContext ctx) throws IOException {
final Object message = ctx.getMessage();
final Connection connection = ctx.getConnection();
try {
threadPool.execute(new HandlerRunnable(connection, message, threadPool));
} catch (RejectedExecutionException exception) {
LOGGER.error("server threadpool full,threadpool maxsize is:"
+ ((ThreadPoolExecutor) threadPool).getMaximumPoolSize());
if (message instanceof List) {
List<RequestWrapper> requests = (List<RequestWrapper>) message;
for (final RequestWrapper request : requests) {
sendErrorResponse(connection, request);
}
} else {
sendErrorResponse(connection, (RequestWrapper) message);
}
}
return ctx.getStopAction();
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void sendErrorResponse(final Connection connection, final RequestWrapper request) throws IOException {
ResponseWrapper responseWrapper = new ResponseWrapper(request.getId(), request.getCodecType(), request.getProtocolType());
responseWrapper.setException(new Exception("server threadpool full,maybe because server is slow or too many requests"));
connection.write(responseWrapper, new EmptyCompletionHandler<WriteResult>() {
@Override
public void failed(Throwable throwable) {
LOGGER.error("server write response error,request id is: " + request.getId());
}
});
}
class HandlerRunnable implements Runnable {
private final Connection connection;
private final Object message;
private final ExecutorService threadPool;
public HandlerRunnable(Connection connection,
Object message,
ExecutorService threadPool) {
this.connection = connection;
this.message = message;
this.threadPool = threadPool;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public void run() {
// pipeline
if (message instanceof List) {
List messages = (List) message;
for (Object messageObject : messages) {
threadPool.execute(new HandlerRunnable(connection, messageObject, threadPool));
}
} else {
RequestWrapper request = (RequestWrapper) message;
long beginTime = System.currentTimeMillis();
ResponseWrapper responseWrapper = ProtocolFactory.getServerHandler(request.getProtocolType()).handleRequest(request);
final int id = request.getId();
// already timeout,so not return
if ((System.currentTimeMillis() - beginTime) >= request.getTimeout()) {
LOGGER.warn("timeout,so give up send response to client,requestId is:"
+ id
+ ",client is:"
+ connection.getPeerAddress() + ",consumetime is:" + (System.currentTimeMillis() - beginTime) + ",timeout is:" + request.getTimeout());
return;
}
connection.write(responseWrapper, new EmptyCompletionHandler<WriteResult>() {
@Override
public void failed(Throwable throwable) {
LOGGER.error("server write response error,request id is: " + id);
}
});
}
}
}
}