org.xsocket.connection.http.server.RequestHandlerChain Maven / Gradle / Ivy
// $Id: HandlerChain.java 1312 2007-06-09 12:39:47Z grro $
/*
* Copyright (c) xsocket.org, 2006 - 2007. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Please refer to the LGPL license at: http://www.gnu.org/copyleft/lesser.txt
* The latest copy of this software may be found on http://www.xsocket.org/
*/
package org.xsocket.connection.http.server;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xsocket.Execution;
import org.xsocket.ILifeCycle;
import org.xsocket.Resource;
import org.xsocket.connection.IServer;
import org.xsocket.connection.http.HttpRequest;
import org.xsocket.connection.http.IBodyCompleteListener;
import org.xsocket.connection.http.IHttpConnectHandler;
import org.xsocket.connection.http.IHttpConnection;
import org.xsocket.connection.http.IHttpDisconnectHandler;
import org.xsocket.connection.http.IHttpHandler;
import org.xsocket.connection.http.InvokeOn;
import org.xsocket.connection.http.server.ServerUtils.HttpHandlerInfo;
/**
* Implements a handler chain. Each handler of the chain will be called (in the registering order),
* until a handler sends the response. In this case the chain handling will be terminated.
*
* Nested chains is not supported yet
*
*
* @author [email protected]
*/
@Execution(Execution.NONTHREADED)
public final class RequestHandlerChain implements IHttpHandler, IHttpRequestHandler, IHttpRequestTimeoutHandler, IHttpConnectHandler, IHttpDisconnectHandler, ILifeCycle {
private static final Logger LOG = Logger.getLogger(RequestHandlerChain.class.getName());
@Resource
private IServer server = null;
@Resource
private HttpProtocolAdapter protocolAdapter = null;
// handlers
private final List handlers = new ArrayList();
private final List lifeCycleChain = new ArrayList();
private boolean isOnConnectPathMultithreaded = false;
private final List connectHandlerChain = new ArrayList();
private boolean isOnRequestPathMultithreaded = false;
private Boolean isInvokeOnMessageReceived = null;
private final List requestHandlerChain = new ArrayList();
private boolean isOnRequestTimeoutPathMultithreaded = false;
private final List requestTimeoutHandlerChain = new ArrayList();
private boolean isOnDisconnectPathMultithreaded = false;
private final List disconnectHandlerChain = new ArrayList();
/**
* constructor
*
*/
public RequestHandlerChain() {
}
/**
* constructor
*
* @param handlers the initial handlers
*/
public RequestHandlerChain(List handlers) {
for (IHttpHandler hdl : handlers) {
addLast(hdl);
}
}
/**
* add a handler to the end og the chain
*
* @param handler the handler to add
*/
public void addLast(IHttpHandler handler) {
if (handler instanceof RequestHandlerChain) {
throw new RuntimeException("a nested chains are not supported");
}
handlers.add(handler);
computePath();
}
private void computePath() {
lifeCycleChain.clear();
connectHandlerChain.clear();
isOnConnectPathMultithreaded = false;
requestHandlerChain.clear();
isOnRequestPathMultithreaded = false;
isInvokeOnMessageReceived = null;
requestTimeoutHandlerChain.clear();
isOnRequestTimeoutPathMultithreaded = false;
disconnectHandlerChain.clear();
isOnDisconnectPathMultithreaded = false;
for (IHttpHandler handler : handlers) {
HttpHandlerInfo handlerInfo = ServerUtils.getHttpHandlerInfo(handler);
if (handlerInfo.isLifeCycle()) {
lifeCycleChain.add((ILifeCycle) handler);
}
if (handlerInfo.isConnectHandler()) {
connectHandlerChain.add((IHttpConnectHandler) handler);
isOnConnectPathMultithreaded = isOnConnectPathMultithreaded || handlerInfo.isConnectHandlerMultithreaded();
}
if (handlerInfo.isRequestHandler()) {
requestHandlerChain.add((IHttpRequestHandler) handler);
isOnRequestPathMultithreaded = isOnRequestPathMultithreaded || handlerInfo.isMultithreaded();
if (isInvokeOnMessageReceived == null) {
isInvokeOnMessageReceived = handlerInfo.isInvokeOnMessageReceived();
} else {
if (isInvokeOnMessageReceived != handlerInfo.isInvokeOnMessageReceived()) {
StringBuilder sb = new StringBuilder();
for (IHttpRequestHandler requestHandler : requestHandlerChain) {
boolean invokeOnMessage = ServerUtils.getHttpHandlerInfo(requestHandler).isInvokeOnMessageReceived();
sb.append(" " + requestHandler.getClass().getSimpleName() + " (");
if (invokeOnMessage) {
sb.append("InvokeOn.MESSAGE_RECEIVED)");
} else {
sb.append("InvokeOn.HEADER_RECEIVED)");
}
}
throw new RuntimeException("mixed invokeOn handlers are not supported:" + sb.toString());
}
}
}
if (handlerInfo.isRequestTimeoutHandler()) {
requestTimeoutHandlerChain.add((IHttpRequestTimeoutHandler) handler);
isOnRequestTimeoutPathMultithreaded = isOnRequestTimeoutPathMultithreaded || handlerInfo.isRequestTimeoutHandlerMultithreaded();
}
if (handlerInfo.isDisconnectHandler()) {
disconnectHandlerChain.add((IHttpDisconnectHandler) handler);
isOnDisconnectPathMultithreaded = isOnDisconnectPathMultithreaded || handlerInfo.isDisconnectHandlerMultithreaded();
}
}
}
public void onInit() {
for (IHttpHandler handler : handlers) {
ServerUtils.injectServerField(handler, server);
ServerUtils.injectProtocolAdapter(handler, protocolAdapter);
}
for (ILifeCycle lifeCycle : lifeCycleChain) {
lifeCycle.onInit();
}
}
public void onDestroy() throws IOException {
for (ILifeCycle lifeCycle : lifeCycleChain) {
lifeCycle.onDestroy();
}
}
public boolean onConnect(IHttpConnection httpConnection) throws IOException {
if (connectHandlerChain.isEmpty()) {
if (LOG.isLoggable(Level.FINER)) {
LOG.finer("no connect handler set. ignore callback");
}
return false;
}
if (isOnConnectPathMultithreaded) {
((HttpServerConnection) httpConnection).getWorkerPool().execute(new OnConnectCaller(httpConnection));
} else {
callOnConnectCallback(httpConnection);
}
return true;
}
private boolean callOnConnectCallback(IHttpConnection connection) throws IOException {
for (IHttpConnectHandler connectHandler : connectHandlerChain) {
boolean result = connectHandler.onConnect(connection);
if (result == true) {
return true;
}
}
return false;
}
@InvokeOn(InvokeOn.HEADER_RECEIVED)
public void onRequest(HttpRequest request, HttpResponseContext responseContext) throws IOException {
if (requestHandlerChain.isEmpty()) {
if (LOG.isLoggable(Level.FINER)) {
LOG.finer("no request handler set. ignore callback");
}
return;
}
if (isInvokeOnMessageReceived && request.hasBody()) {
request.getNonBlockingBody().addCompleteListener(new BodyCompleteListener(request, responseContext));
} else {
callOnRequestCallback(request, responseContext);
}
}
private void callOnRequestCallback(HttpRequest request, HttpResponseContext responseContext) throws IOException {
if (isOnRequestPathMultithreaded) {
responseContext.getWorkerPool().execute(new OnRequestCaller(request, responseContext));
} else {
performOnRequestCallback(request, responseContext);
}
}
private void performOnRequestCallback(HttpRequest request, HttpResponseContext responseContext) throws IOException {
for (IHttpRequestHandler requestHandler : requestHandlerChain) {
requestHandler.onRequest(request, responseContext);
if (responseContext.isResponseSent()) {
return;
}
}
}
public boolean onRequestTimeout(IHttpConnection httpConnection)throws IOException {
if (requestTimeoutHandlerChain.isEmpty()) {
if (LOG.isLoggable(Level.FINER)) {
LOG.finer("no request timeout handler set. ignore callback");
}
return false;
}
if (isOnRequestTimeoutPathMultithreaded) {
((HttpServerConnection) httpConnection).getWorkerPool().execute(new OnRequestTimeoutCaller(httpConnection));
} else {
callOnRequestTimeoutCallback(httpConnection);
}
return true;
}
private boolean callOnRequestTimeoutCallback(IHttpConnection connection) throws IOException {
for (IHttpRequestTimeoutHandler requestTimeoutHandler : requestTimeoutHandlerChain) {
boolean result = requestTimeoutHandler.onRequestTimeout(connection);
if (result == true) {
return true;
}
}
return false;
}
public boolean onDisconnect(IHttpConnection httpConnection) throws IOException {
if (disconnectHandlerChain.isEmpty()) {
if (LOG.isLoggable(Level.FINER)) {
LOG.finer("no disconnect handler set. ignore callback");
}
return false;
}
if (isOnDisconnectPathMultithreaded) {
((HttpServerConnection) httpConnection).getWorkerPool().execute(new OnDisconnectCaller(httpConnection));
} else {
callOnDisconnectCallback(httpConnection);
}
return true;
}
private boolean callOnDisconnectCallback(IHttpConnection connection) throws IOException {
for (IHttpDisconnectHandler disconnectHandler : disconnectHandlerChain) {
boolean result = disconnectHandler.onDisconnect(connection);
if (result == true) {
return true;
}
}
return false;
}
private final class BodyCompleteListener implements IBodyCompleteListener {
private HttpRequest request = null;
private HttpResponseContext responseContext = null;
public BodyCompleteListener(HttpRequest request, HttpResponseContext responseContext) {
this.request = request;
this.responseContext = responseContext;
}
@Execution(Execution.NONTHREADED)
public final void onComplete() {
try {
callOnRequestCallback(request, responseContext);
} catch (IOException ioe) {
responseContext.onRequestHandlingException(ioe);
}
}
}
private final class OnRequestCaller implements Runnable {
private HttpRequest request = null;
private HttpResponseContext responseContext = null;
public OnRequestCaller(HttpRequest request, HttpResponseContext responseContext) {
this.request = request;
this.responseContext = responseContext;
}
public void run() {
try {
performOnRequestCallback(request, responseContext);
} catch (IOException ioe) {
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("Error occured by calling onRequest callback " + ioe.toString());
}
}
}
}
private final class OnRequestTimeoutCaller implements Runnable {
private IHttpConnection httpConnection = null;
public OnRequestTimeoutCaller(IHttpConnection httpConnection) {
this.httpConnection = httpConnection;
}
public void run() {
try {
callOnRequestTimeoutCallback(httpConnection);
} catch (IOException ioe) {
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("Error occured by calling onRequestTimeout callback " + ioe.toString());
}
}
}
}
private final class OnConnectCaller implements Runnable {
private IHttpConnection httpConnection = null;
public OnConnectCaller(IHttpConnection httpConnection) {
this.httpConnection = httpConnection;
}
public void run() {
try {
callOnConnectCallback(httpConnection);
} catch (IOException ioe) {
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("Error occured by calling onConnect callback " + ioe.toString());
}
}
}
}
private final class OnDisconnectCaller implements Runnable {
private IHttpConnection httpConnection = null;
public OnDisconnectCaller(IHttpConnection httpConnection) {
this.httpConnection = httpConnection;
}
public void run() {
try {
callOnDisconnectCallback(httpConnection);
} catch (IOException ioe) {
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("Error occured by calling onDisconnect callback " + ioe.toString());
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy