Return-Path: Delivered-To: apmail-tomcat-dev-archive@www.apache.org Received: (qmail 15209 invoked from network); 2 Sep 2006 04:30:51 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 2 Sep 2006 04:30:51 -0000 Received: (qmail 44451 invoked by uid 500); 2 Sep 2006 04:30:48 -0000 Delivered-To: apmail-tomcat-dev-archive@tomcat.apache.org Received: (qmail 44382 invoked by uid 500); 2 Sep 2006 04:30:48 -0000 Mailing-List: contact dev-help@tomcat.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "Tomcat Developers List" Delivered-To: mailing list dev@tomcat.apache.org Received: (qmail 44371 invoked by uid 500); 2 Sep 2006 04:30:48 -0000 Delivered-To: apmail-jakarta-tomcat-dev@jakarta.apache.org Received: (qmail 44368 invoked by uid 99); 2 Sep 2006 04:30:48 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 01 Sep 2006 21:30:48 -0700 X-ASF-Spam-Status: No, hits=-8.6 required=10.0 tests=ALL_TRUSTED,INFO_TLD,NO_REAL_NAME X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: local policy) Received: from [140.211.166.113] (HELO eris.apache.org) (140.211.166.113) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 01 Sep 2006 21:30:43 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id 3EE531A981A; Fri, 1 Sep 2006 21:30:23 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r439527 [1/2] - in /tomcat/sandbox/tomcat-lite: ./ java/org/apache/tomcat/lite/ java/org/apache/tomcat/lite/http/ java/org/apache/tomcat/lite/webmap/ java/org/apache/tomcat/servlets/config/ java/org/apache/tomcat/servlets/deploy/ java/org/a... Date: Sat, 02 Sep 2006 04:30:18 -0000 To: tomcat-dev@jakarta.apache.org From: costin@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20060902043023.3EE531A981A@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: costin Date: Fri Sep 1 21:30:15 2006 New Revision: 439527 URL: http://svn.apache.org/viewvc?rev=439527&view=rev Log: Many fixes and improvements, now alost everything I tried works ( I ran the old watchdog once, all old servlet tests are passing ). The JSP integration is working again - but in a much cleaner way, no hacks ( and it can be used independent of tomcat in a simpler way than the old jasper servlet ) Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseIncludeWrapper.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/jsp/JspCompileServlet.java tomcat/sandbox/tomcat-lite/webapps/ROOT/test.jsp tomcat/sandbox/tomcat-lite/webapps/__x_classpath/ tomcat/sandbox/tomcat-lite/webapps/__x_classpath/WEB-INF/ tomcat/sandbox/tomcat-lite/webapps/__x_classpath/WEB-INF/lib/ Modified: tomcat/sandbox/tomcat-lite/build.xml tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/RequestDispatcherImpl.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletConfigImpl.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletContextImpl.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestImpl.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseImpl.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/TomcatLite.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/http/CoyoteAdapter.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/webmap/WebappServletMapper.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/ServletData.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/ReloadServlet.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/WebXml.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/jsp/JspProxyServlet.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/sec/SimpleAuthServlet.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/session/SessionManagerServlet.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/loader/Module.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/loader/Repository.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/net/http11/Http11Processor.java tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/net/nio/NioEndpoint.java tomcat/sandbox/tomcat-lite/webapps/ROOT/index.html tomcat/sandbox/tomcat-lite/webapps/__x_engine/WEB-INF/web.xml tomcat/sandbox/tomcat-lite/webapps/__x_protocol/WEB-INF/web.xml Modified: tomcat/sandbox/tomcat-lite/build.xml URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/build.xml?rev=439527&r1=439526&r2=439527&view=diff ============================================================================== --- tomcat/sandbox/tomcat-lite/build.xml (original) +++ tomcat/sandbox/tomcat-lite/build.xml Fri Sep 1 21:30:15 2006 @@ -102,6 +102,13 @@ + + + + + + Modified: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/RequestDispatcherImpl.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/RequestDispatcherImpl.java?rev=439527&r1=439526&r2=439527&view=diff ============================================================================== --- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/RequestDispatcherImpl.java (original) +++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/RequestDispatcherImpl.java Fri Sep 1 21:30:15 2006 @@ -34,60 +34,25 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.lite.util.MappingData; import org.apache.tomcat.lite.webmap.WebappFilterMapper; +import org.apache.tomcat.util.buf.CharChunk; +import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.res.StringManager; /** - * Standard implementation of RequestDispatcher that allows a - * request to be forwarded to a different resource to create the ultimate - * response, or to include the output of another resource in the response - * from this resource. This implementation allows application level servlets - * to wrap the request and/or response objects that are passed on to the - * called resource, as long as the wrapping classes extend - * javax.servlet.ServletRequestWrapper and - * javax.servlet.ServletResponseWrapper. * - * @author Craig R. McClanahan - * @version $Revision: 303947 $ $Date: 2005-06-08 22:50:26 -0700 (Wed, 08 Jun 2005) $ */ - final class RequestDispatcherImpl implements RequestDispatcher { + /** + * Thread local mapping data. + */ + private transient ThreadLocal localMappingData = new ThreadLocal(); - public RequestDispatcherImpl(ServletConfigImpl wrapper, String name) { - this.wrapper = wrapper; - this.name = name; - this.context = (ServletContextImpl) wrapper.getParent(); - - } - /** - * Construct a new instance of this class, configured according to the - * specified parameters. If both servletPath and pathInfo are - * null, it will be assumed that this RequestDispatcher - * was acquired by name, rather than by path. - * - * @param wrapper The Wrapper associated with the resource that will - * be forwarded to or included (required) - * @param requestURI The request URI to this resource (if any) - * @param servletPath The revised servlet path to this resource (if any) - * @param pathInfo The revised extra path information to this resource - * (if any) - * @param queryString Query string parameters included with this request - * (if any) - * @param name Servlet name (if a named dispatcher was created) - * else null - */ - public RequestDispatcherImpl(ServletConfigImpl wrapper, - String requestURI, String servletPath, - String pathInfo, String queryString) { - this.wrapper = wrapper; - this.context = (ServletContextImpl) wrapper.getParent(); - this.requestURI = requestURI; - this.servletPath = servletPath; - this.origServletPath = servletPath; - this.pathInfo = pathInfo; - this.queryString = queryString; - } + * Thread local URI message bytes. + */ + private transient ThreadLocal localUriMB = new ThreadLocal(); /** * The request attribute under which the original servlet path is stored @@ -186,10 +151,11 @@ private static Log log = LogFactory.getLog(RequestDispatcherImpl.class); + private String path; /** * The Context this RequestDispatcher is associated with. */ - private ServletContextImpl context = null; + private ServletContextImpl ctx = null; /** * The servlet name for a named dispatcher. @@ -265,6 +231,20 @@ private Servlet servlet; + /** Named dispatcher + */ + public RequestDispatcherImpl(ServletConfigImpl wrapper, String name) { + this.wrapper = wrapper; + this.name = name; + this.ctx = (ServletContextImpl) wrapper.getServletContext(); + + } + + public RequestDispatcherImpl(ServletContextImpl ctx, String path) { + this.path = path; + this.ctx = ctx; + } + /** @@ -283,17 +263,12 @@ { // Reset any output that has been buffered, but keep headers/cookies if (response.isCommitted()) { - if ( log.isDebugEnabled() ) - log.debug(" Forward on committed response --> ISE"); - throw new IllegalStateException - (sm.getString("applicationDispatcher.forward.ise")); + throw new IllegalStateException("forward(): response.isComitted()"); } try { response.resetBuffer(); } catch (IllegalStateException e) { - if ( log.isDebugEnabled() ) - log.debug(" Forward resetBuffer() returned ISE: " + e); throw e; } @@ -301,30 +276,27 @@ setup(request, response, false); // Identify the HTTP-specific request and response objects (if any) - HttpServletRequest hrequest = null; - hrequest = (HttpServletRequest) request; - HttpServletResponse hresponse = null; - hresponse = (HttpServletResponse) response; - - // Handle a nn-HTTP forward by passing the existing request/response - if ((servletPath == null) && (pathInfo == null)) { - ServletRequestWrapperImpl wrequest = - (ServletRequestWrapperImpl) wrapRequest(); + HttpServletRequest hrequest = (HttpServletRequest) request; + + ServletRequestWrapperImpl wrequest = + (ServletRequestWrapperImpl) wrapRequest(); + + + if (name != null) { wrequest.setRequestURI(hrequest.getRequestURI()); wrequest.setContextPath(hrequest.getContextPath()); wrequest.setServletPath(hrequest.getServletPath()); wrequest.setPathInfo(hrequest.getPathInfo()); wrequest.setQueryString(hrequest.getQueryString()); - processRequest(request,response); - - wrequest.recycle(); - unwrapRequest(); + } else { // path based - ServletRequestWrapperImpl wrequest = - (ServletRequestWrapperImpl) wrapRequest(); - - String contextPath = context.getContextPath(); + mapPath(); + if (wrapper == null) { + throw new ServletException("Forward not found " + + path); + } + String contextPath = ctx.getContextPath(); if (hrequest.getAttribute(FORWARD_REQUEST_URI_ATTR) == null) { wrequest.setAttribute(FORWARD_REQUEST_URI_ATTR, hrequest.getRequestURI()); @@ -346,20 +318,19 @@ wrequest.setQueryString(queryString); wrequest.setQueryParams(queryString); } - - processRequest(request,response); - - wrequest.recycle(); - unwrapRequest(); - } + processRequest(outerRequest, outerResponse); + + wrequest.recycle(); + unwrapRequest(); // This is not a real close in order to support error processing if ( log.isDebugEnabled() ) log.debug(" Disabling the response for futher output"); if (response instanceof ServletResponseImpl) { - ((ServletResponseImpl) response).finish(); + ((ServletResponseImpl) response).flushBuffer(); + ((ServletResponseImpl) response).setSuspended(true); } else { // Servlet SRV.6.2.2. The Resquest/Response may have been wrapped // and may no longer be instance of RequestFacade @@ -385,7 +356,6 @@ ; } } - } @@ -409,48 +379,24 @@ setup(request, response, true); // Create a wrapped response to use for this request - ServletResponse wresponse = wrapResponse(true); + // this actually gets inserted somewhere in the chain - it's not + // the last one, but first non-user response + wrapResponse(); + ServletRequestWrapperImpl wrequest = + (ServletRequestWrapperImpl) wrapRequest(); - // Handle a non-HTTP include - if (!(request instanceof HttpServletRequest) || - !(response instanceof HttpServletResponse)) { - - if ( log.isDebugEnabled() ) - log.debug(" Non-HTTP Include"); - request.setAttribute(WebappFilterMapper.DISPATCHER_TYPE_ATTR, - new Integer(WebappFilterMapper.INCLUDE)); - request.setAttribute(WebappFilterMapper.DISPATCHER_REQUEST_PATH_ATTR, origServletPath); - invoke(request, outerResponse); - } // Handle an HTTP named dispatcher include - else if (name != null) { - - if ( log.isDebugEnabled() ) - log.debug(" Named Dispatcher Include"); - - ServletRequestWrapperImpl wrequest = - (ServletRequestWrapperImpl) wrapRequest(); + if (name != null) { wrequest.setAttribute(NAMED_DISPATCHER_ATTR, name); - if (servletPath != null) - wrequest.setServletPath(servletPath); + if (servletPath != null) wrequest.setServletPath(servletPath); wrequest.setAttribute(WebappFilterMapper.DISPATCHER_TYPE_ATTR, - new Integer(WebappFilterMapper.INCLUDE)); - wrequest.setAttribute(WebappFilterMapper.DISPATCHER_REQUEST_PATH_ATTR, origServletPath); - invoke(outerRequest, wresponse); - - wrequest.recycle(); - } - - // Handle an HTTP path based include - else { - - if ( log.isDebugEnabled() ) - log.debug(" Path Based Include"); - - ServletRequestWrapperImpl wrequest = - (ServletRequestWrapperImpl) wrapRequest(); - String contextPath = context.getContextPath(); + new Integer(WebappFilterMapper.INCLUDE)); + wrequest.setAttribute(WebappFilterMapper.DISPATCHER_REQUEST_PATH_ATTR, + origServletPath); + } else { + mapPath(); + String contextPath = ctx.getContextPath(); if (requestURI != null) wrequest.setAttribute(INCLUDE_REQUEST_URI_ATTR, requestURI); @@ -470,19 +416,94 @@ } wrequest.setAttribute(WebappFilterMapper.DISPATCHER_TYPE_ATTR, - new Integer(WebappFilterMapper.INCLUDE)); - wrequest.setAttribute(WebappFilterMapper.DISPATCHER_REQUEST_PATH_ATTR, origServletPath); - invoke(outerRequest, wresponse); - - wrequest.recycle(); + new Integer(WebappFilterMapper.INCLUDE)); + wrequest.setAttribute(WebappFilterMapper.DISPATCHER_REQUEST_PATH_ATTR, + origServletPath); } - + invoke(outerRequest, outerResponse); + + wrequest.recycle(); + unwrapRequest(); + unwrapResponse(); } // -------------------------------------------------------- Private Methods + public void mapPath() { + if (path == null || servletPath != null) return; + + // Retrieve the thread local URI, used for mapping + // TODO: recycle RequestDispatcher stack and associated objects + // instead of this object + + MessageBytes uriMB = (MessageBytes) localUriMB.get(); + if (uriMB == null) { + uriMB = MessageBytes.newInstance(); + CharChunk uriCC = uriMB.getCharChunk(); + uriCC.setLimit(-1); + localUriMB.set(uriMB); + } else { + uriMB.recycle(); + } + + // Get query string + int pos = path.indexOf('?'); + if (pos >= 0) { + queryString = path.substring(pos + 1); + } else { + pos = path.length(); + } + + // Retrieve the thread local mapping data + MappingData mappingData = (MappingData) localMappingData.get(); + if (mappingData == null) { + mappingData = new MappingData(); + localMappingData.set(mappingData); + } + + // Map the URI + CharChunk uriCC = uriMB.getCharChunk(); + try { + /* + * Ignore any trailing path params (separated by ';') for mapping + * purposes. + * This is sometimes broken - path params can be on any path + * component, not just last. + */ + int semicolon = path.indexOf(';'); + if (pos >= 0 && semicolon > pos) { + semicolon = -1; + } + if (ctx.getContextPath().length() > 1 ) + uriCC.append(ctx.getContextPath()); + uriCC.append(path, 0, semicolon > 0 ? semicolon : pos); + + ctx.getMapper().map(uriMB, mappingData); + + // at least default wrapper must be returned + + /* + * Append any trailing path params (separated by ';') that were + * ignored for mapping purposes, so that they're reflected in the + * RequestDispatcher's requestURI + */ + if (semicolon > 0) { + uriCC.append(path, semicolon, pos - semicolon); + } + } catch (Exception e) { + log.error("getRequestDispatcher()", e); + } + + wrapper = (ServletConfigImpl) mappingData.wrapper; + servletPath = mappingData.wrapperPath.toString(); + pathInfo = mappingData.pathInfo.toString(); + + mappingData.recycle(); + + } + /** * Prepare the request based on the filter configuration. @@ -512,6 +533,7 @@ } + /** * Ask the resource represented by this RequestDispatcher to process @@ -535,7 +557,7 @@ // classloader. If it's not, we're saving it, and setting the context // classloader to the Context classloader ClassLoader oldCCL = Thread.currentThread().getContextClassLoader(); - ClassLoader contextClassLoader = context.getClassLoader(); + ClassLoader contextClassLoader = ctx.getClassLoader(); if (oldCCL != contextClassLoader) { Thread.currentThread().setContextClassLoader(contextClassLoader); @@ -570,18 +592,18 @@ filterChain.doFilter(request, response); } } catch (IOException e) { - wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", + ctx.getLogger().error(sm.getString("applicationDispatcher.serviceException", wrapper.getServletName()), e); ioException = e; } catch (UnavailableException e) { - wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", + ctx.getLogger().error(sm.getString("applicationDispatcher.serviceException", wrapper.getServletName()), e); servletException = e; wrapper.unavailable(e); } catch (ServletException e) { servletException = e; } catch (RuntimeException e) { - wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", + ctx.getLogger().error(sm.getString("applicationDispatcher.serviceException", wrapper.getServletName()), e); runtimeException = e; } @@ -618,20 +640,8 @@ private ServletException servletDealocate(ServletException servletException) { - try { - if (servlet != null) { - wrapper.deallocate(servlet); - } - } catch (ServletException e) { - wrapper.getLogger().error(sm.getString("applicationDispatcher.deallocateException", - wrapper.getServletName()), e); - servletException = e; - } catch (Throwable e) { - wrapper.getLogger().error(sm.getString("applicationDispatcher.deallocateException", - wrapper.getServletName()), e); - servletException = new ServletException - (sm.getString("applicationDispatcher.deallocateException", - wrapper.getServletName()), e); + if (servlet != null) { + wrapper.deallocate(servlet); } return servletException; } @@ -644,7 +654,7 @@ // Check for the servlet being marked unavailable if (wrapper.isUnavailable()) { - wrapper.getLogger().warn( + ctx.getLogger().warn( sm.getString("applicationDispatcher.isUnavailable", wrapper.getServletName())); long available = wrapper.getAvailable(); @@ -662,12 +672,14 @@ servlet = wrapper.allocate(); } } catch (ServletException e) { - wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException", - wrapper.getServletName()), ServletConfigImpl.getRootCause(e)); + ctx.getLogger().error("RequestDispatcher: allocate " + + wrapper.getServletName() + " " + + wrapper.getJspFile() + + " " + wrapper.getServletClass()); servletException = e; servlet = null; } catch (Throwable e) { - wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException", + ctx.getLogger().error(sm.getString("applicationDispatcher.allocateException", wrapper.getServletName()), e); servletException = new ServletException (sm.getString("applicationDispatcher.allocateException", @@ -773,24 +785,32 @@ break; if (current instanceof ServletRequestImpl) break; + // user-specified previous = current; current = ((ServletRequestWrapper) current).getRequest(); } + // now previous will be a user-specified wrapper, + // and current one of our own wrappers ( deeper in stack ) + // ... current USER_previous USER USER + // previous is null if the top request is ours. // Instantiate a new wrapper at this point and insert it in the chain ServletRequest wrapper = null; // Compute a crossContext flag - HttpServletRequest hcurrent = (HttpServletRequest) current; boolean crossContext = isCrossContext(); - wrapper = - new ServletRequestWrapperImpl(hcurrent, context, crossContext); + new ServletRequestWrapperImpl((HttpServletRequest) current, + ctx, crossContext); - if (previous == null) + if (previous == null) { + // outer becomes the wrapper, includes orig wrapper inside outerRequest = wrapper; - else + } else { + // outer remains user-specified sersvlet, delegating to + // our wrapper, which delegates to real request or our wrapper. ((ServletRequestWrapper) previous).setRequest(wrapper); + } wrapRequest = wrapper; return (wrapper); } @@ -808,7 +828,7 @@ // Forward contextPath = houterRequest.getContextPath(); } - crossContext = !(context.getContextPath().equals(contextPath)); + crossContext = !(ctx.getContextPath().equals(contextPath)); } return crossContext; } @@ -817,16 +837,17 @@ /** * Create and return a response wrapper that has been inserted in the * appropriate spot in the response chain. + * + * Side effect: updates outerResponse, wrapResponse. + * The chain is updated with a wrapper below lowest user wrapper */ - private ServletResponse wrapResponse(boolean including) { + private ServletResponse wrapResponse() { // Locate the response we should insert in front of ServletResponse previous = null; ServletResponse current = outerResponse; while (current != null) { if (!(current instanceof ServletResponseWrapper)) break; - if (current instanceof ServletResponseWrapperImpl) - break; if (current instanceof ServletResponseImpl) break; previous = current; @@ -834,14 +855,17 @@ } // Instantiate a new wrapper at this point and insert it in the chain - ServletResponse wrapper = null; - wrapper = - new ServletResponseWrapperImpl((HttpServletResponse) current, - including); - if (previous == null) + ServletResponse wrapper = + new ServletResponseIncludeWrapper(current); + + if (previous == null) { + // outer is ours, we can wrap on top outerResponse = wrapper; - else + } else { + // outer is user-specified, leave it alone. + // we insert ourself below the lowest user-specified response ((ServletResponseWrapper) previous).setResponse(wrapper); + } wrapResponse = wrapper; return (wrapper); Modified: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletConfigImpl.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletConfigImpl.java?rev=439527&r1=439526&r2=439527&view=diff ============================================================================== --- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletConfigImpl.java (original) +++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletConfigImpl.java Fri Sep 1 21:30:15 2006 @@ -22,26 +22,19 @@ import java.io.Serializable; import java.lang.reflect.Method; import java.util.Enumeration; -import java.util.HashMap; import java.util.HashSet; -import java.util.Map; import java.util.Stack; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; import javax.servlet.SingleThreadModel; import javax.servlet.UnavailableException; -import org.apache.catalina.LifecycleException; -import org.apache.commons.logging.Log; import org.apache.tomcat.servlets.config.ServletData; import org.apache.tomcat.servlets.util.Enumerator; import org.apache.tomcat.util.IntrospectionUtils; -import org.apache.tomcat.util.res.StringManager; /** * Based on Wrapper. @@ -53,58 +46,25 @@ * @author Craig R. McClanahan * @author Remy Maucherat */ -public class ServletConfigImpl implements ServletConfig, Serializable { +public class ServletConfigImpl implements ServletConfig { - private transient static org.apache.commons.logging.Log log= + private static org.apache.commons.logging.Log log= org.apache.commons.logging.LogFactory.getLog( ServletConfigImpl.class ); private static final String[] DEFAULT_SERVLET_METHODS = new String[] { "GET", "HEAD", "POST" }; - static transient StringManager sm = - StringManager.getManager("org.apache.tomcat.lite"); - public static final String JSP_SERVLET_CLASS = - "org.apache.jasper.servlet.JspServlet"; + "org.apache.tomcat.servlets.jsp.JspProxyServlet"; - public static final String JSP_SERVLET_NAME = "jsp"; - - public ServletConfigImpl() { - super(); - } + public static final String SINGLE_THREADED_PROXY = + "org.apache.tomcat.servlets.jsp.SingleThreadedProxyServlet"; - public ServletConfigImpl(ServletContextImpl ctx, ServletData sd) { - data = sd; - setParent((ServletContextImpl) ctx); - ctx.facade.notifyAdd(this); - } + public static final String JSP_SERVLET_NAME = "jsp"; ServletData data; /** - * The context-relative URI of the JSP file for this servlet. - */ - private String jspFile = null; - - /** - * The security role references for this servlet, keyed by role name - * used in the servlet. The corresponding value is the role name of - * the web application itself. - */ - private HashMap references = new HashMap(); - - /** - * The run-as identity for this servlet. - */ - private String runAs = null; - - /** - * True if this StandardWrapper is for the JspServlet - */ - private boolean isJspServlet; - - - /** * The date and time at which this servlet will become available (in * milliseconds since the epoch), or zero if the servlet is available. * If this value equals Long.MAX_VALUE, the unavailability of this @@ -118,45 +78,38 @@ */ private transient int countAllocated = 0; + private ServletContextImpl ctx; + /** * The (single) initialized instance of this servlet. */ private transient Servlet instance = null; - + /** * Are we unloading our servlet instance at the moment? */ private transient boolean unloading = false; // Support for SingleThreaded + private Class classClass = null; private transient boolean singleThreadModel = false; - /** * Stack containing the STM instances. */ private transient Stack instancePool = null; + // Statistics private transient long loadTime=0; private transient int classLoadTime=0; - - private ServletContextImpl parent; - - /** - * Static class array used when the SecurityManager is turned on and - * Servlet.init is invoked. - */ - private static Class[] classType = new Class[]{ServletConfig.class}; - - /** - * Static class array used when the SecurityManager is turned on and - * Servlet.service is invoked. - */ - private static Class[] classTypeUsedInService = new Class[]{ - ServletRequest.class, - ServletResponse.class}; // ------------------------------------------------------------- Properties + public ServletConfigImpl(ServletContextImpl ctx, ServletData sd) { + data = sd; + this.ctx = (ServletContextImpl) ctx; + ctx.facade.notifyAdd(this); + } + /** * Return the available date/time for this servlet, in milliseconds since @@ -167,9 +120,7 @@ * the servlet is currently available. */ public long getAvailable() { - return (this.available); - } @@ -203,117 +154,31 @@ } /** - * Return the context-relative URI of the JSP file for this servlet. + * Return the jsp-file setting for this servlet. */ public String getJspFile() { - return (this.jspFile); - } - - - /** - * Set the context-relative URI of the JSP file for this servlet. - * - * @param jspFile JSP file URI - */ - public void setJspFile(String jspFile) { - - String oldJspFile = this.jspFile; - this.jspFile = jspFile; -// support.firePropertyChange("jspFile", oldJspFile, this.jspFile); - - // Each jsp-file needs to be represented by its own JspServlet and - // corresponding JspMonitoring mbean, because it may be initialized - // with its own init params - isJspServlet = true; - + return data.jspFile; } - /** * Return the load-on-startup order value (negative value means * load on first call). */ public int getLoadOnStartup() { - - if (isJspServlet && this.data.loadOnStartup < 0) { - /* - * JspServlet must always be preloaded, because its instance is - * used during registerJMX (when registering the JSP - * monitoring mbean) - */ - return Integer.MAX_VALUE; - } else { - return (this.data.loadOnStartup); - } - } - - /** - * Set the parent Container of this Wrapper, but only if it is a Context. - * - * @param container Proposed parent Container - */ - public void setParent(ServletContextImpl container) { - this.parent = container; - } - - public ServletContextImpl getParent() { - return parent; - } - - /** - * Return the run-as identity for this servlet. - */ - public String getRunAs() { - - return (this.runAs); - + return data.loadOnStartup; } - - /** - * Set the run-as identity for this servlet. - * - * @param runAs New run-as identity value - */ - public void setRunAs(String runAs) { - - String oldRunAs = this.runAs; - this.runAs = runAs; -// support.firePropertyChange("runAs", oldRunAs, this.runAs); - - } - - /** * Return the fully qualified servlet class name for this servlet. */ public String getServletClass() { - - return (this.data.servletClass); - - } - - /** - * Return true if the servlet class represented by this - * component implements the SingleThreadModel interface. - */ - public boolean isSingleThreadModel() { - - try { - loadServlet(); - } catch (Throwable t) { - ; - } - return (singleThreadModel); - + return data.servletClass; } - /** * Is this servlet currently unavailable? */ public boolean isUnavailable() { - if (available == 0L) return (false); else if (available <= System.currentTimeMillis()) { @@ -395,97 +260,85 @@ return rootCause; } - - /** - * Add a new security role reference record to the set of records for - * this servlet. - * - * @param name Role name used within this servlet - * @param link Role name used within the web application - */ - public void addSecurityReference(String name, String link) { - - synchronized (references) { - references.put(name, link); - } -// fireContainerEvent("addSecurityReference", name); - - } - /** - * Allocate an initialized instance of this Servlet that is ready to have - * its service() method called. If the servlet class does - * not implement SingleThreadModel, the (only) initialized - * instance may be returned immediately. If the servlet class implements - * SingleThreadModel, the Wrapper implementation must ensure - * that this instance is not allocated again until it is deallocated by a - * call to deallocate(). - * - * @exception ServletException if the servlet init() method threw - * an exception - * @exception ServletException if a loading error occurs + * MUST be called before service() + * This method should be called to get the servlet. After + * service(), dealocate should be called. This deals with STM and + * update use counters. + * + * Normally called from RequestDispatcher and TomcatLite. */ public Servlet allocate() throws ServletException { // If we are currently unloading this servlet, throw an exception - if (unloading) + if (unloading) throw new ServletException - (sm.getString("standardWrapper.unloading", getServletName())); + ("allocate() while unloading " + getServletName()); - // If not SingleThreadedModel, return the same instance every time - if (!singleThreadModel) { - if (instance == null) { - synchronized (this) { - if (instance == null) { - try { - if (log.isDebugEnabled()) - log.debug("Allocating non-STM instance"); - - instance = loadServlet(); - } catch (ServletException e) { - throw e; - } catch (Throwable e) { - throw new ServletException - (sm.getString("standardWrapper.allocate"), e); - } + Servlet servlet = null; + if (instance == null && !singleThreadModel) { + // never loaded. + synchronized (this) { + if (instance == null && !singleThreadModel) { + try { + servlet = loadServlet(); + } catch (ServletException e) { + throw e; + } catch (Throwable e) { + throw new ServletException("loadServlet()", e); + } + if (servlet != null && !singleThreadModel) { + instance = servlet; } } } + } + + // If not SingleThreadedModel, return the same instance every time + if (instance != null) { countAllocated++; + System.err.println("New servet " + instance + " " + + countAllocated + " " + getServletName()); return (instance); } - + // Simpler policy for ST: unbound number of servlets ( can grow to // one per thread ) synchronized (instancePool) { if (instancePool.isEmpty()) { try { - Servlet newServlet = loadServlet(); + if (servlet != null) { + // this is the first invocation + countAllocated++; + return servlet; + } countAllocated++; + Servlet newServlet = loadServlet(); + System.err.println("New STM servet " + newServlet + " " + + countAllocated); return newServlet; } catch (ServletException e) { throw e; } catch (Throwable e) { - throw new ServletException - (sm.getString("standardWrapper.allocate"), e); + throw new ServletException("allocate " + getServletName(), + e); } - } - return (Servlet) instancePool.pop(); + } + System.err.println("Get from pool " + instancePool.size() + " " + + countAllocated); + Servlet s = (Servlet) instancePool.pop(); + countAllocated++; + System.err.println("After get " + instancePool.size() + " " + s + + " " + countAllocated); + return s; } } /** - * Return this previously allocated servlet to the pool of available - * instances. If this servlet class does not implement SingleThreadModel, - * no action is actually required. - * - * @param servlet The servlet to be returned - * - * @exception ServletException if a deallocation error occurs + * MUST be called after service(). */ - public void deallocate(Servlet servlet) throws ServletException { - + public void deallocate(Servlet servlet) { // If not SingleThreadModel, no action is required if (!singleThreadModel) { countAllocated--; @@ -495,61 +348,15 @@ // Unlock and free this instance synchronized (instancePool) { countAllocated--; + if (instancePool.contains(servlet)) { + System.err.println("Aleady in pool " + servlet + " " + + instancePool.size()+ " " + countAllocated); + return; + } + System.err.println("return pool " + servlet + " " + + instancePool.size() + " " + countAllocated); instancePool.push(servlet); } - - } - - - /** - * Return the security role link for the specified security role - * reference name, if any; otherwise return null. - * - * @param name Security role reference used within this servlet - */ - public String findSecurityReference(String name) { - - synchronized (references) { - return ((String) references.get(name)); - } - - } - - - /** - * Return the set of security role reference names associated with - * this servlet, if any; otherwise return a zero-length array. - */ - public String[] findSecurityReferences() { - - synchronized (references) { - String results[] = new String[references.size()]; - return ((String[]) references.keySet().toArray(results)); - } - - } - - /** - * Load and initialize an instance of this servlet, if there is not already - * at least one initialized instance. This can be used, for example, to - * load servlets that are marked in the deployment descriptor to be loaded - * at server startup time. - *

- * IMPLEMENTATION NOTE: Servlets whose classnames begin with - * org.apache.catalina. (so-called "container" servlets) - * are loaded by the same classloader that loaded this class, rather than - * the classloader for the current web application. - * This gives such classes access to Catalina internals, which are - * prevented for classes loaded for web applications. - * - * @exception ServletException if the servlet init() method threw - * an exception - * @exception ServletException if some other loading problem occurs - */ - public synchronized void load() throws ServletException { - if(instance == null) { - instance = loadServlet(); - } } @@ -564,76 +371,30 @@ if (!singleThreadModel && (instance != null)) return instance; - PrintStream out = System.out; - Servlet servlet; long t1=System.currentTimeMillis(); - // If this "servlet" is really a JSP file, get the right class. - // HOLD YOUR NOSE - this is a kludge that avoids having to do special - // case Catalina-specific code in Jasper - it also requires that the - // servlet path be replaced by the element content in - // order to be completely effective String actualClass = data.servletClass; -// if ((actualClass == null) && (jspFile != null)) { -// ServletConfigImpl jspWrapper = (ServletConfigImpl) -// ((ServletContextImpl) getParent()).getServletConfig(JSP_SERVLET_NAME); -// if (jspWrapper != null) { -// actualClass = jspWrapper.getServletClass(); -// // Merge init parameters -// String paramNames[] = jspWrapper.findInitParameters(); -// for (int i = 0; i < paramNames.length; i++) { -// if (parameters.get(paramNames[i]) == null) { -// parameters.put -// (paramNames[i], -// jspWrapper.findInitParameter(paramNames[i])); -// } -// } -// } -// } - - // Complain if no servlet class has been specified - if (actualClass == null) { - unavailable(null); - throw new ServletException - (sm.getString("standardWrapper.notClass", getServletName())); - } - - ClassLoader classLoader = parent.getClassLoader(); - if (classLoader == null ) - classLoader = this.getClass().getClassLoader(); - - // Special case class loader for a container provided servlet - // - if (isContainerProvidedServlet(actualClass) && - ! ((ServletContextImpl)getParent()).getPrivileged() ) { - // If it is a priviledged context - using its own - // class loader will work, since it's a child of the container - // loader - classLoader = this.getClass().getClassLoader(); - } + + // jsp-file case. Load the JspProxyServlet instead, with the + // right params. Note the JspProxyServlet is _not_ jasper, + // nor 'jsp' servlet - it is just a proxy with no special + // params. It calls the jsp servlet and jasper to generate the + // real class. + + // this is quite different from catalina, where an ugly kludge was + // used to use the same jsp servlet in 2 roles + + // the jsp proxy is replaced by the web.xml processor - // Load the specified servlet class from the appropriate class loader - Class classClass = null; - try { - if (classLoader != null) { - classClass = classLoader.loadClass(actualClass); - } else { - classClass = Class.forName(actualClass); - } - } catch (ClassNotFoundException e) { - unavailable(null); - getServletContext().log( "Error loading " + classLoader + " " + actualClass, e ); - throw new ServletException - (sm.getString("standardWrapper.missingClass", actualClass), - e); + if (classClass == null) { + loadClass(actualClass); } - + if (classClass == null) { unavailable(null); - throw new ServletException - (sm.getString("standardWrapper.missingClass", actualClass)); + throw new UnavailableException("ClassNotFound: " + actualClass); } // Instantiate and initialize an instance of the servlet class itself @@ -641,21 +402,22 @@ servlet = (Servlet) classClass.newInstance(); } catch (ClassCastException e) { unavailable(null); - // Restore the context ClassLoader - throw new ServletException - (sm.getString("standardWrapper.notServlet", actualClass), e); + throw new UnavailableException("ClassCast: (Servlet)" + + actualClass); } catch (Throwable e) { unavailable(null); // Added extra log statement for Bugzilla 36630: // http://issues.apache.org/bugzilla/show_bug.cgi?id=36630 if(log.isDebugEnabled()) { - log.debug(sm.getString("standardWrapper.instantiate", actualClass), e); + log.debug("newInstance() error: servlet-name: " + + getServletName() + + " servlet-class: " + actualClass, e); } // Restore the context ClassLoader - throw new ServletException - (sm.getString("standardWrapper.instantiate", actualClass), e); + throw new ServletException("newInstance() error " + getServletName() + + " " + actualClass, e); } classLoadTime=(int) (System.currentTimeMillis() -t1); @@ -663,8 +425,6 @@ // Call the initialization method of this servlet try { servlet.init(this); - - jspLoadOnStartup(servlet); } catch (UnavailableException f) { unavailable(f); throw f; @@ -672,8 +432,7 @@ throw f; } catch (Throwable f) { getServletContext().log("StandardWrapper.Throwable", f ); - throw new ServletException - (sm.getString("standardWrapper.initException", getServletName()), f); + throw new ServletException("Servlet.init()", f); } // Register our newly initialized instance @@ -684,43 +443,36 @@ } loadTime=System.currentTimeMillis() -t1; return servlet; - } - private void jspLoadOnStartup(Servlet servlet) throws ServletException, - IOException - { - // Invoke jspInit on JSP pages - if ((data.loadOnStartup >= 0) && (jspFile != null)) { - // Invoking jspInit - ServletRequestImpl req = new ServletRequestImpl(); - req.setServletPath(jspFile); - req.setQueryString("jsp_precompile=true"); - ServletResponseImpl res = new ServletResponseImpl(); - servlet.service(req, res); + private void loadClass(String actualClass) throws ServletException { + // Complain if no servlet class has been specified + if (actualClass == null) { + unavailable(null); + throw new ServletException("servlet-class missing " + + getServletName()); } - } - - /** - * Remove any security role reference for the specified role name. - * - * @param name Security role used within this servlet to be removed - */ - public void removeSecurityReference(String name) { - synchronized (references) { - references.remove(name); + + ClassLoader classLoader = ctx.getClassLoader(); + if (classLoader == null ) + classLoader = this.getClass().getClassLoader(); + + // Load the specified servlet class from the appropriate class loader + try { + classClass = classLoader.loadClass(actualClass); + } catch (ClassNotFoundException e) { + classClass = null; } } - /** * Return a String representation of this component. */ public String toString() { StringBuffer sb = new StringBuffer(); - if (getParent() != null) { - sb.append(getParent().toString()); + if (ctx != null) { + sb.append(ctx.toString()); sb.append("."); } sb.append("StandardWrapper["); @@ -738,7 +490,7 @@ * to mark this servlet as permanently unavailable */ public void unavailable(UnavailableException unavailable) { - getServletContext().log(sm.getString("standardWrapper.unavailable", getServletName())); + getServletContext().log("UnavailableException:" + getServletName()); if (unavailable == null) setAvailable(Long.MAX_VALUE); else if (unavailable.isPermanent()) @@ -765,6 +517,7 @@ * destroy() method */ public synchronized void unload() throws ServletException { + setAvailable(Long.MAX_VALUE); // Nothing to do if we have never loaded the instance if (!singleThreadModel && (instance == null)) @@ -775,11 +528,11 @@ // (possibly more than once if non-STM) if (countAllocated > 0) { int nRetries = 0; - long delay = parent.getUnloadDelay() / 20; + long delay = ctx.getUnloadDelay() / 20; while ((nRetries < 21) && (countAllocated > 0)) { if ((nRetries % 10) == 0) { - log.info(sm.getString("standardWrapper.waiting", - new Integer(countAllocated))); + log.info("Servlet.unload() timeout " + + countAllocated); } try { Thread.sleep(delay); @@ -792,29 +545,31 @@ ClassLoader oldCtxClassLoader = Thread.currentThread().getContextClassLoader(); - ClassLoader classLoader = instance.getClass().getClassLoader(); - - PrintStream out = System.out; - // Call the servlet destroy() method - try { - Thread.currentThread().setContextClassLoader(classLoader); - instance.destroy(); - } catch (Throwable t) { + if (instance != null) { + ClassLoader classLoader = instance.getClass().getClassLoader(); + + PrintStream out = System.out; + // Call the servlet destroy() method + try { + Thread.currentThread().setContextClassLoader(classLoader); + instance.destroy(); + } catch (Throwable t) { + instance = null; + //instancePool = null; + unloading = false; + throw new ServletException("Servlet.destroy() " + + getServletName(), t); + } finally { + // restore the context ClassLoader + Thread.currentThread().setContextClassLoader(oldCtxClassLoader); + } + + // Deregister the destroyed instance instance = null; - instancePool = null; - unloading = false; - throw new ServletException - (sm.getString("standardWrapper.destroyException", getServletName()), - t); - } finally { - // restore the context ClassLoader - Thread.currentThread().setContextClassLoader(oldCtxClassLoader); } - - // Deregister the destroyed instance - instance = null; if (singleThreadModel && (instancePool != null)) { try { + ClassLoader classLoader = ctx.getClassLoader(); Thread.currentThread().setContextClassLoader(classLoader); while (!instancePool.isEmpty()) { ((Servlet) instancePool.pop()).destroy(); @@ -822,9 +577,7 @@ } catch (Throwable t) { instancePool = null; unloading = false; - throw new ServletException - (sm.getString("standardWrapper.destroyException", - getServletName()), t); + throw new ServletException("Servlet.destroy() " + getServletName(), t); } finally { // restore the context ClassLoader Thread.currentThread().setContextClassLoader @@ -869,7 +622,7 @@ * Return the servlet context with which this servlet is associated. */ public ServletContext getServletContext() { - return parent; + return ctx; } @@ -877,7 +630,7 @@ * Return the name of this servlet. */ public String getServletName() { - return data.serlvetName; + return data.servletName; } // public long getProcessingTime() { @@ -944,35 +697,6 @@ // -------------------------------------------------------- Private Methods - - /** - * Add a default Mapper implementation if none have been configured - * explicitly. - * - * @param mapperClass Java class name of the default Mapper - */ - protected void addDefaultMapper(String mapperClass) { - - ; // No need for a default Mapper on a Wrapper - - } - - - /** - * Return true if the specified class name represents a - * container provided servlet class that should be loaded by the - * server class loader. - * - * @param classname Name of the class to be checked - */ - private boolean isContainerProvidedServlet(String classname) { - if (classname.startsWith("org.apache.tomcat.")) { - return (true); - } - return false; - } - - private Method[] getAllDeclaredMethods(Class c) { if (c.equals(javax.servlet.http.HttpServlet.class)) { @@ -1000,42 +724,6 @@ return thisMethods; } - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Start this component, pre-loading the servlet if the load-on-startup - * value is set appropriately. - * - * @exception LifecycleException if a fatal error occurs during startup - */ - public void start() { - setAvailable(0L); - } - - - /** - * Stop this component, gracefully shutting down the servlet if it has - * been initialized. - * - * @exception LifecycleException if a fatal error occurs during shutdown - */ - public void stop() { - setAvailable(Long.MAX_VALUE); - // Shut down our servlet instance (if it has been initialized) - try { - unload(); - } catch (ServletException e) { - getServletContext().log(sm.getString - ("standardWrapper.unloadException", getServletName()), e); - } - } - - public Log getLogger() { - return parent.getLogger(); - } - /** Specify the instance. Avoids the class lookup, disables unloading. * Use for embedded case, or to control the allocation. * @@ -1043,6 +731,10 @@ */ public void setServlet(Servlet servlet) { instance = servlet; + } + + public String getSecurityRoleRef(String role) { + return (String)data.securityRoleRef.get(role); } Modified: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletContextImpl.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletContextImpl.java?rev=439527&r1=439526&r2=439527&view=diff ============================================================================== --- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletContextImpl.java (original) +++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletContextImpl.java Fri Sep 1 21:30:15 2006 @@ -21,12 +21,12 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; -import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; @@ -48,11 +48,11 @@ import javax.servlet.ServletContextListener; import javax.servlet.ServletException; +import org.apache.catalina.util.RequestUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.tomcat.lite.TomcatLite.ContextConfigData; import org.apache.tomcat.lite.util.CharsetMapper; -import org.apache.tomcat.lite.util.MappingData; import org.apache.tomcat.lite.webmap.WebappFilterMapper; import org.apache.tomcat.lite.webmap.WebappServletMapper; import org.apache.tomcat.servlets.config.FilterData; @@ -61,12 +61,9 @@ import org.apache.tomcat.servlets.config.WebAppData; import org.apache.tomcat.servlets.deploy.WebXml; import org.apache.tomcat.servlets.file.WebdavServlet; +import org.apache.tomcat.servlets.session.SessionManagerServlet; import org.apache.tomcat.servlets.util.Enumerator; import org.apache.tomcat.servlets.util.UrlUtils; -import org.apache.tomcat.servlets.session.SessionManagerServlet; - -import org.apache.tomcat.util.buf.CharChunk; -import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.loader.Repository; import org.apache.tomcat.util.res.StringManager; @@ -92,9 +89,6 @@ public class ServletContextImpl implements ServletContext, Serializable { - public ServletContextImpl() { - } - /** * Empty collection to serve as the basis for empty enumerations. * DO NOT ADD ANY ELEMENTS TO THIS COLLECTION! @@ -167,28 +161,25 @@ private WebappFilterMapper webappFilterMapper = new WebappFilterMapper(this); - /** - * Thread local mapping data. - */ - private transient ThreadLocal localMappingData = new ThreadLocal(); - - /** - * Thread local URI message bytes. - */ - private transient ThreadLocal localUriMB = new ThreadLocal(); transient CharsetMapper charsetMapper = new CharsetMapper(); transient Repository repository; - transient TomcatLite facade = TomcatLite.getServletImpl(); + transient TomcatLite facade; private WebAppData webAppData; private ContextConfigData contextConfig; // ------------------------------------------------- ServletContext Methods - + public ServletContextImpl(TomcatLite facade) { + this.facade = facade; + } + + public ServletContextImpl() { + + } public CharsetMapper getCharsetMapper() { return charsetMapper; @@ -395,7 +386,7 @@ * Return the major version of the Java Servlet API that we implement. */ public int getMajorVersion() { - return 3; + return 2; } @@ -425,6 +416,20 @@ return contentTypes.getProperty(extension); } + /** + * Return the real path for a given virtual path, if possible; otherwise + * return null. + * + * @param path The path to the desired resource + */ + public String getRealPath(String path) { + if (path == null) { + return null; + } + + File file = new File(basePath, path); + return (file.getAbsolutePath()); + } /** * Return a RequestDispatcher object that acts as a @@ -443,21 +448,6 @@ /** - * Return the real path for a given virtual path, if possible; otherwise - * return null. - * - * @param path The path to the desired resource - */ - public String getRealPath(String path) { - if (path == null) { - return null; - } - - File file = new File(basePath, path); - return (file.getAbsolutePath()); - } - - /** * Return a RequestDispatcher instance that acts as a * wrapper for the resource at the given path. The path must begin * with a "/" and is interpreted as relative to the current context root. @@ -473,78 +463,36 @@ path = UrlUtils.normalize(path); if (path == null) return (null); - // Retrieve the thread local URI, used for mapping - MessageBytes uriMB = (MessageBytes) localUriMB.get(); - if (uriMB == null) { - uriMB = MessageBytes.newInstance(); - CharChunk uriCC = uriMB.getCharChunk(); - uriCC.setLimit(-1); - localUriMB.set(uriMB); - } else { - uriMB.recycle(); - } + + return new RequestDispatcherImpl(this, path); + } - // Get query string - String queryString = null; - int pos = path.indexOf('?'); - if (pos >= 0) { - queryString = path.substring(pos + 1); - } else { - pos = path.length(); - } - - // Retrieve the thread local mapping data - MappingData mappingData = (MappingData) localMappingData.get(); - if (mappingData == null) { - mappingData = new MappingData(); - localMappingData.set(mappingData); - } + public RequestDispatcher getRequestDispatcher(String path, + int type, + String dispatcherPath) { + RequestDispatcher dispatcher = getRequestDispatcher(path); + //((RequestDispatcherImpl)dispatcher); + return dispatcher; + } - // Map the URI - CharChunk uriCC = uriMB.getCharChunk(); - try { - uriCC.append(path, 0, path.length()); - /* - * Ignore any trailing path params (separated by ';') for mapping - * purposes - */ - int semicolon = path.indexOf(';'); - if (pos >= 0 && semicolon > pos) { - semicolon = -1; - } - uriCC.append(path, 0, semicolon > 0 ? semicolon : pos); - - getMapper().map(uriMB, mappingData); - if (mappingData.wrapper == null) { - return null; - } - - /* - * Append any trailing path params (separated by ';') that were - * ignored for mapping purposes, so that they're reflected in the - * RequestDispatcher's requestURI - */ - if (semicolon > 0) { - uriCC.append(path, semicolon, pos - semicolon); - } - } catch (Exception e) { - log("getRequestDispatcher()", e); - return (null); + ThreadLocal requestDispatcherStack = new ThreadLocal(); + + private RequestDispatcherImpl getRequestDispatcher() { + ArrayList list = + (ArrayList)requestDispatcherStack.get(); + if (list == null) { + list = new ArrayList(); + requestDispatcherStack.set(list); } - - ServletConfigImpl wrapper = (ServletConfigImpl) mappingData.wrapper; - String wrapperPath = mappingData.wrapperPath.toString(); - String pathInfo = mappingData.pathInfo.toString(); - - mappingData.recycle(); - - return new RequestDispatcherImpl(wrapper, uriCC.toString(), - wrapperPath, pathInfo, - queryString); + + + return null; } - - + public void resetDispatcherStack() { + + } + /** * Return the URL to the resource that is mapped to a specified path. * The path must begin with a "/" and is interpreted as relative to the @@ -892,7 +840,8 @@ try { fc.getFilter(); // will triger init() } catch (Throwable e) { - log.warn("Error initializing filter " + fc.getFilterName(), e); + log.warn(getContextPath() + " Filter.init() " + + fc.getFilterName(), e); } } @@ -902,14 +851,16 @@ while (fI.hasNext()) { ServletConfigImpl fc = (ServletConfigImpl)fI.next(); if (fc.getLoadOnStartup() > 0 ) { - try { - fc.loadServlet(); - } catch (Throwable e) { - log.warn("Error initializing " + fc.getServletName(), e); - } + try { + fc.loadServlet(); + } catch (Throwable e) { + log.warn("Error initializing " + fc.getServletName(), e); + } } } } + + public static final String INTERNAL_PREFIX = "_SERVLET_IMPL_"; public void initListeners() throws ServletException { Iterator fI = webAppData.listenerClass.iterator(); @@ -924,7 +875,10 @@ } } + setAttribute(INTERNAL_PREFIX + ".EventListeners", lifecycleListeners); + } + public static String CONTAINER_PREFIX = "__x_"; public ClassLoader getClassLoader() { if( repository != null ) @@ -939,18 +893,30 @@ public void processWebAppData(WebAppData d) throws ServletException { this.webAppData = d; - + initDefaults(); + for(Entry k: d.mimeMapping.entrySet()) { addMimeType(k.getKey(), k.getValue()); } - getManager().setSessionTimeout(d.sessionTimeout); + if (d.sessionTimeout > 0 ) + getManager().setSessionTimeout(d.sessionTimeout); for(FilterData fd: d.filters.values()) { addFilter(fd); } for(ServletData sd: d.servlets.values()) { + // jsp-file equivalent to JspProxyServlet + arg + if (sd.servletClass == null) { + if (sd.jspFile == null) { + log.error("Missing servlet class for " + sd.servletName); + continue; + } + sd.servletClass = ServletConfigImpl.JSP_SERVLET_CLASS; + sd.initParams.put(CONTAINER_PREFIX + "jspFile", sd.jspFile); + } + ServletConfigImpl sw = new ServletConfigImpl(this, sd); addServletConfig(sw); } @@ -974,27 +940,27 @@ } } } + + public WebAppData getConfig() { + return webAppData; + } + public void init() throws ServletException { String base = getBasePath(); + Repository ctxRepo = null; // create a class loader - Repository ctxRepo = new Repository(); - ctxRepo.setParentClassLoader(this.getClass().getClassLoader()); + if (getContextPath().startsWith("/__x_classpath")) { + ctxRepo = getEngine().getRepository(); + } else { + ctxRepo = new Repository(); + ctxRepo.setParent(facade.getRepository()); + } ctxRepo.addDir(new File(base + "/WEB-INF/classes")); ctxRepo.addLibs(new File(base + "/WEB-INF/lib")); setRepository(ctxRepo); - // Add default mappings. - ServletData sd = new ServletData(); - sd.serlvetName = "default"; - ServletConfigImpl fileS = new ServletConfigImpl(this, sd); - - Servlet defaultS = new WebdavServlet(); - defaultS.init(fileS); - fileS.setServlet(defaultS); - addMapping("/", fileS); - if (webAppData != null && webAppData.fileName != null) { File f = new File(webAppData.fileName); if (f.exists()) { @@ -1008,6 +974,8 @@ } } if (webAppData == null) { + // Add default mappings. + initDefaults(); readWebXml(base); if (contextConfig != null) { contextConfig.webXml = webAppData; @@ -1042,6 +1010,23 @@ initServlets(); } + private void initDefaults() throws ServletException { + ServletData sd = new ServletData(); + sd.servletName = "default"; + ServletConfigImpl fileS = new ServletConfigImpl(this, sd); + + Servlet defaultS = new WebdavServlet(); + defaultS.init(fileS); + fileS.setServlet(defaultS); + addMapping("/", fileS); + + sd = new ServletData(); + sd.servletName = ServletConfigImpl.JSP_SERVLET_NAME; + fileS = new ServletConfigImpl(this, sd); + sd.servletClass = ServletConfigImpl.JSP_SERVLET_CLASS; + addMapping("*.jsp", fileS); + } + private void readWebXml(String base) throws ServletException { WebXml webXml = new WebXml(); webXml.readWebXml(base); @@ -1074,5 +1059,117 @@ public void setContextConfigData(ContextConfigData ctxD) { this.contextConfig = ctxD; } + + public TomcatLite getEngine() { + return facade; + } + + public String findStatusPage(int status) { + if (getConfig().errorPageCode.size() == 0) { + return null; + } + if (status == 200) { + return null; + } + + return getConfig().errorPageCode.get(Integer.toString(status)); + } + + public void handleStatusPage(ServletRequestImpl req, + ServletResponseImpl res, + int status, + String statusPage) { + String message = RequestUtil.filter(res.getMessage()); + if (message == null) + message = ""; + setErrorAttributes(req, status, message); + dispatchError(req, res, statusPage); + } + + private void setErrorAttributes(ServletRequestImpl req, + int status, + String message) { + req.setAttribute("javax.servlet.error.status_code", + new Integer(status)); + if (req.getWrapper() != null) { + req.setAttribute("javax.servlet.error.servlet_name", + req.getWrapper().data.servletName); + } + req.setAttribute("javax.servlet.error.request_uri", + req.getRequestURI()); + req.setAttribute("javax.servlet.error.message", + message); + + } + + public void handleError(ServletRequestImpl req, + ServletResponseImpl res, + Throwable t) { + Throwable realError = t; + if (realError instanceof ServletException) { + realError = ((ServletException) realError).getRootCause(); + if (realError == null) { + realError = t; + } + } + //if (realError instanceof ClientAbortException ) { + + String errorPage = findErrorPage(t); + if ((errorPage == null) && (realError != t)) { + errorPage = findErrorPage(realError); + } + + if (errorPage != null) { + setErrorAttributes(req, 500, t.getMessage()); + req.setAttribute("javax.servlet.error.exception", realError); + req.setAttribute("javax.servlet.error.exception_type", + realError.getClass()); + dispatchError(req, res, errorPage); + } else { + log("Unhandled error", t); + if (res.getStatus() < 500) { + res.setStatus(500); + } + } + } + + private void dispatchError(ServletRequestImpl req, + ServletResponseImpl res, + String errorPage) { + RequestDispatcher rd = + getRequestDispatcher(errorPage); + try { + // will clean up the buffer + rd.forward(req, res); + return; // handled + } catch (ServletException e) { + // TODO + } catch (IOException e) { + // TODO + } + } + + protected String findErrorPage(Throwable exception) { + if (getConfig().errorPageException.size() == 0) { + return null; + } + if (exception == null) + return (null); + Class clazz = exception.getClass(); + String name = clazz.getName(); + while (!Object.class.equals(clazz)) { + String page = getConfig().errorPageException.get(name); + if (page != null) + return (page); + clazz = clazz.getSuperclass(); + if (clazz == null) + break; + name = clazz.getName(); + } + return (null); + + } + + } Modified: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestImpl.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestImpl.java?rev=439527&r1=439526&r2=439527&view=diff ============================================================================== --- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestImpl.java (original) +++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestImpl.java Fri Sep 1 21:30:15 2006 @@ -1404,7 +1404,11 @@ * Return the scheme used to make this Request. */ public String getScheme() { - return (coyoteRequest.scheme().toString()); + String scheme = coyoteRequest.scheme().toString(); + if (scheme == null) { + scheme = (isSecure() ? "https" : "http"); + } + return scheme; } @@ -2410,7 +2414,7 @@ // Check for a role alias defined in a element if (wrapper != null) { - String realRole = wrapper.findSecurityReference(role); + String realRole = wrapper.getSecurityRoleRef(role); if (realRole != null) { role = realRole; } Modified: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseImpl.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseImpl.java?rev=439527&r1=439526&r2=439527&view=diff ============================================================================== --- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseImpl.java (original) +++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseImpl.java Fri Sep 1 21:30:15 2006 @@ -341,7 +341,9 @@ * * @param suspended The new suspended flag value */ - public void setSuspended(boolean suspended) { + public void setSuspended(boolean suspended) throws IOException { + //coyoteResponse.setCommitted(true); + flushBuffer(); outputBuffer.setSuspended(suspended); } @@ -387,23 +389,6 @@ /** - * Perform whatever actions are required to flush and close the output - * stream or writer, in a single operation. - * - * @exception IOException if an input/output error occurs - */ - public void finishResponse() - throws IOException { - // Writing leftover bytes - try { - outputBuffer.close(); - } catch(Throwable t) { - t.printStackTrace(); - } - } - - - /** * Return the content length that was set or calculated for this Response. */ public int getContentLength() { @@ -606,8 +591,8 @@ /** * Set the content length (in bytes) for this Response. - * - * @param length The new content length + * Ignored for writers if non-ISO-8859-1 encoding ( we could add more + * encodings that are constant. */ public void setContentLength(int length) { @@ -618,9 +603,10 @@ if (included) return; - if (usingWriter) + // writers can use variable-length encoding. + if (usingWriter && !"ISO-8859-1".equals(getCharacterEncoding())) { return; - + } coyoteResponse.setContentLength(length); } @@ -1081,22 +1067,24 @@ if (included) return; -// Wrapper wrapper = getRequest().getWrapper(); -// if (wrapper != null) { -// wrapper.incrementErrorCount(); -// } - setError(); coyoteResponse.setStatus(status); coyoteResponse.setMessage(message); - // Clear any data content that has been buffered - resetBuffer(); - - // Cause the response to be finished (from the application perspective) - setSuspended(true); + // Now go over the error-page handling - + String statusPage = request.getContext().findStatusPage(status); + + if (statusPage != null) { + request.getContext().handleStatusPage(request, + this, status, statusPage); + } else { + // Clear any data content that has been buffered + resetBuffer(); + // Cause the response to be finished (from the application perspective) + setSuspended(true); + } } @@ -1432,11 +1420,6 @@ sb.append(query); return (sb.toString()); - } - - public void finish() { - - setSuspended(true); } Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseIncludeWrapper.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseIncludeWrapper.java?rev=439527&view=auto ============================================================================== --- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseIncludeWrapper.java (added) +++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseIncludeWrapper.java Fri Sep 1 21:30:15 2006 @@ -0,0 +1,120 @@ +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.lite; + + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Locale; + +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; + +import org.apache.tomcat.util.res.StringManager; + + +/** + * Wrapper around the response object received as parameter to + * RequestDispatcher.include(). + * + * @author Costin Manolache + */ +public class ServletResponseIncludeWrapper extends HttpServletResponseWrapper { + public ServletResponseIncludeWrapper(ServletResponse current) { + super((HttpServletResponse) current); + } + + // Not overriden: + /* + public boolean containsHeader(String name) + public String encodeRedirectUrl(String url) + public String encodeRedirectURL(String url) + public String encodeUrl(String url) + public String encodeURL(String url) + public void flushBuffer() throws IOException + public int getBufferSize() + public String getCharacterEncoding() + public String getContentType() + public Locale getLocale() + public ServletOutputStream getOutputStream() throws IOException + public ServletResponse getResponse() + public PrintWriter getWriter() throws IOException + public boolean isCommitted() + public void resetBuffer() + public void setCharacterEncoding(String charset) + public void setResponse(ServletResponse response) + */ + + public void reset() { + if (getResponse().isCommitted()) + getResponse().reset(); + else + throw new IllegalStateException(); + } + + public void setContentLength(int len) { + } + + public void setContentType(String type) { + } + + public void setLocale(Locale loc) { + } + + public void setBufferSize(int size) { + } + + public void addCookie(Cookie cookie) { + } + + public void addDateHeader(String name, long value) { + } + + public void addHeader(String name, String value) { + } + + public void addIntHeader(String name, int value) { + } + + public void sendError(int sc) throws IOException { + } + + public void sendError(int sc, String msg) throws IOException { + } + + public void sendRedirect(String location) throws IOException { + } + + public void setDateHeader(String name, long value) { + } + + public void setHeader(String name, String value) { + } + + public void setIntHeader(String name, int value) { + } + + public void setStatus(int sc) { + } + + public void setStatus(int sc, String msg) { + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org For additional commands, e-mail: dev-help@tomcat.apache.org