All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xsocket.connection.http.server.RequestHandlerChain Maven / Gradle / Ivy

There is a newer version: 2.0-beta-1
Show newest version
// $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