You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@apache.org on 2006/09/02 06:30:18 UTC
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...
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 @@
</fileset>
</jar>
+ <jar destfile="webapps/__x_classpath/WEB-INF/lib/jasper.jar"
+ manifest="resources/jasper.MF">
+ <fileset dir="${tc6.classes}" >
+ <include name="org/apache/jasper/*"/>
+ </fileset>
+ </jar>
+
</target>
<target name="all" depends="tomcat-lite.jar,tomcat-runtime.jar" />
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 <code>RequestDispatcher</code> 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
- * <code>javax.servlet.ServletRequestWrapper</code> and
- * <code>javax.servlet.ServletResponseWrapper</code>.
*
- * @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
- * <code>null</code>, 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 <code>null</code>
- */
- 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
- * <code>Servlet.init</code> is invoked.
- */
- private static Class[] classType = new Class[]{ServletConfig.class};
-
- /**
- * Static class array used when the SecurityManager is turned on and
- * <code>Servlet.service</code> 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 <code>true</code> if the servlet class represented by this
- * component implements the <code>SingleThreadModel</code> 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 <code>service()</code> method called. If the servlet class does
- * not implement <code>SingleThreadModel</code>, the (only) initialized
- * instance may be returned immediately. If the servlet class implements
- * <code>SingleThreadModel</code>, the Wrapper implementation must ensure
- * that this instance is not allocated again until it is deallocated by a
- * call to <code>deallocate()</code>.
- *
- * @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 <code>null</code>.
- *
- * @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.
- * <p>
- * <b>IMPLEMENTATION NOTE</b>: Servlets whose classnames begin with
- * <code>org.apache.catalina.</code> (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 <jsp-file> 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 <code>true</code> 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.
* <strong>DO NOT ADD ANY ELEMENTS TO THIS COLLECTION!</strong>
@@ -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 <code>null</code>.
+ *
+ * @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 <code>RequestDispatcher</code> object that acts as a
@@ -443,21 +448,6 @@
/**
- * Return the real path for a given virtual path, if possible; otherwise
- * return <code>null</code>.
- *
- * @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 <code>RequestDispatcher</code> 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<RequestDispatcherImpl> 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<String, String> 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 <security-role-ref> 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