/*==========================================================================*\ | $Id: MetaRequestHandler.java,v 1.6 2012/06/22 16:23:18 aallowat Exp $ |*-------------------------------------------------------------------------*| | Copyright (C) 2011-2012 Virginia Tech | | This file is part of Web-CAT. | | Web-CAT is free software; you can redistribute it and/or modify | it under the terms of the GNU Affero General Public License as published | by the Free Software Foundation; either version 3 of the License, or | (at your option) any later version. | | Web-CAT 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 General Public License for more details. | | You should have received a copy of the GNU Affero General Public License | along with Web-CAT; if not, see <http://www.gnu.org/licenses/>. \*==========================================================================*/ package org.webcat.core.http; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import org.webcat.core.Application; import com.webobjects.appserver.WOApplication; import com.webobjects.appserver.WOContext; import com.webobjects.appserver.WOMessage; import com.webobjects.appserver.WORequest; import com.webobjects.appserver.WORequestHandler; import com.webobjects.appserver.WOResponse; //------------------------------------------------------------------------- /** * <p> * A WebObjects request handler that allows requests to be delegated to any of * a set of sub-handlers that are specified using path suffixes or regular * expressions. * </p><p> * This class is based on similar code found in the example servlet found in * the JGit library. * </p> * * @author Tony Allevato * @author Last changed by $Author: aallowat $ * @version $Revision: 1.6 $, $Date: 2012/06/22 16:23:18 $ */ public abstract class MetaRequestHandler extends WORequestHandler { //~ Constructors .......................................................... // ---------------------------------------------------------- /** * Creates a new {@code MetaRequestHandler}. */ public MetaRequestHandler() { bindings = new ArrayList<RequestHandlerBinderImpl>(); } //~ Methods ............................................................... // ---------------------------------------------------------- /** * Handles the request by delegating it to a matching request handler. * * @param request the request * @return the response */ @Override public final WOResponse handleRequest(WORequest request) { WOContext context; if (request.context() != null) { context = request.context(); } else { context = Application.application().createContextForRequest( request); } if (log.isDebugEnabled()) { log.debug("> REQUEST: " + request.toString()); } WOResponse response = WOApplication.application().createResponseInContext(context); context._setResponse(response); String wosid = request.cookieValueForKey("wosid"); context._setRequestSessionID(wosid); try { UrlPipeline pipeline = findPipeline(request); if (pipeline != null) { pipeline.handleRequest(request, response); } else { new ErrorRequestHandler(WOMessage.HTTP_STATUS_NOT_FOUND) .handleRequest(request, response); } } catch (Exception e) { log.error("(500) An unhandled exception occurred", e); WOResponse errorResponse = Application.wcApplication().handleException(e, context); response.setContent(errorResponse.content()); response.setStatus(WOMessage.HTTP_STATUS_INTERNAL_ERROR); } response._finalizeInContext(context); if (log.isDebugEnabled()) { String responseString = response.toString(); if (response.content().length() > 512) { int index = responseString.indexOf("formValues={"); if (index == -1) { log.debug("< RESPONSE: " + responseString); } else { log.debug("< RESPONSE: " + responseString.substring(0, index)); } } else { log.debug("< RESPONSE: " + responseString); } } return response; } // ---------------------------------------------------------- /** * Returns a binder that can be used to configure how requests that match * the specified path are serviced. * * @param path the path, which must currently be a suffix path that starts * with "*" * @return a binder that can be used to configure the request handler */ public RequestHandlerBinder serve(String path) { if (path.startsWith("*")) { return register(new SuffixPipeline.Binder(path.substring(1))); } else { throw new IllegalArgumentException("Paths not starting with \"*\"" + " are not currently supported."); } } // ---------------------------------------------------------- /** * Returns a binder that can be used to configure how requests that match * the specified regular expression are serviced. * * @param regex the regular expression * @return a binder that can be used to configure the request handler */ public RequestHandlerBinder serveRegex(String regex) { return register(new RegexPipeline.Binder(regex)); } // ---------------------------------------------------------- private UrlPipeline findPipeline(WORequest request) { for (UrlPipeline pipeline : pipelines()) { if (pipeline.matches(request)) { return pipeline; } } return null; } // ---------------------------------------------------------- private RequestHandlerBinder register(RequestHandlerBinderImpl binder) { synchronized (bindings) { if (pipelines != null) { throw new IllegalStateException("Request handler has already " + "been initialized."); } else { bindings.add(binder); } } return register((RequestHandlerBinder) binder); } // ---------------------------------------------------------- /** * Called when a configured binder is being registered with the request * handler. Subclasses can override this to provide common manipulation for * all request handlers; for example, a user may want to insert filters * that disable caching on all requests, or require authentication. * * @param binder the binder * @return the binder that should be used instead of the specified binder */ protected RequestHandlerBinder register(RequestHandlerBinder binder) { return binder; } // ---------------------------------------------------------- private UrlPipeline[] pipelines() { UrlPipeline[] r = pipelines; if (r == null) { synchronized (bindings) { r = pipelines; if (r == null) { r = createPipelines(); pipelines = r; } } } return r; } // ---------------------------------------------------------- private UrlPipeline[] createPipelines() { UrlPipeline[] array = new UrlPipeline[bindings.size()]; for (int i = 0; i < bindings.size(); i++) { array[i] = bindings.get(i).create(); } return array; } //~ Static/instance variables ............................................. public static final String REGEX_FILTER_PATH_KEY = "org.webcat.core.http.RegexFilterPathKey"; public static final String REGEX_CAPTURE_GROUPS_KEY = "org.webcat.core.http.RegexCaptureGroupsKey"; private List<RequestHandlerBinderImpl> bindings; private volatile UrlPipeline[] pipelines; private static final Logger log = Logger.getLogger( MetaRequestHandler.class); }