Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'jetty-servlet/src/main')
-rw-r--r--jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java905
-rw-r--r--jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java267
-rw-r--r--jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java194
-rw-r--r--jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterMapping.java280
-rw-r--r--jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java379
-rw-r--r--jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Invoker.java303
-rw-r--r--jetty-servlet/src/main/java/org/eclipse/jetty/servlet/NIOResourceCache.java86
-rw-r--r--jetty-servlet/src/main/java/org/eclipse/jetty/servlet/NoJspServlet.java35
-rw-r--r--jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java502
-rw-r--r--jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java1370
-rw-r--r--jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java685
-rw-r--r--jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletMapping.java80
-rw-r--r--jetty-servlet/src/main/java/org/eclipse/jetty/servlet/StatisticsServlet.java240
13 files changed, 5326 insertions, 0 deletions
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java
new file mode 100644
index 0000000000..a75e1572ee
--- /dev/null
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java
@@ -0,0 +1,905 @@
+// ========================================================================
+// Copyright (c) 1999-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.servlet;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.List;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpContent;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpHeaderValues;
+import org.eclipse.jetty.http.HttpHeaders;
+import org.eclipse.jetty.http.HttpMethods;
+import org.eclipse.jetty.http.MimeTypes;
+import org.eclipse.jetty.io.Buffer;
+import org.eclipse.jetty.io.ByteArrayBuffer;
+import org.eclipse.jetty.io.WriterOutputStream;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.Dispatcher;
+import org.eclipse.jetty.server.HttpConnection;
+import org.eclipse.jetty.server.InclusiveByteRange;
+import org.eclipse.jetty.server.ResourceCache;
+import org.eclipse.jetty.server.Response;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.nio.NIOConnector;
+import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.MultiPartOutputStream;
+import org.eclipse.jetty.util.TypeUtil;
+import org.eclipse.jetty.util.URIUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.util.resource.ResourceFactory;
+
+
+
+/* ------------------------------------------------------------ */
+/** The default servlet.
+ * This servlet, normally mapped to /, provides the handling for static
+ * content, OPTION and TRACE methods for the context.
+ * The following initParameters are supported, these can be set either
+ * on the servlet itself or as ServletContext initParameters with a prefix
+ * of org.eclipse.jetty.servlet.Default. :
+ * <PRE>
+ * acceptRanges If true, range requests and responses are
+ * supported
+ *
+ * dirAllowed If true, directory listings are returned if no
+ * welcome file is found. Else 403 Forbidden.
+ *
+ * redirectWelcome If true, welcome files are redirected rather than
+ * forwarded to.
+ *
+ * gzip If set to true, then static content will be served as
+ * gzip content encoded if a matching resource is
+ * found ending with ".gz"
+ *
+ * resourceBase Set to replace the context resource base
+ *
+ * relativeResourceBase
+ * Set with a pathname relative to the base of the
+ * servlet context root. Useful for only serving static content out
+ * of only specific subdirectories.
+ *
+ * aliases If True, aliases of resources are allowed (eg. symbolic
+ * links and caps variations). May bypass security constraints.
+ *
+ * maxCacheSize The maximum total size of the cache or 0 for no cache.
+ * maxCachedFileSize The maximum size of a file to cache
+ * maxCachedFiles The maximum number of files to cache
+ * cacheType Set to "bio", "nio" or "both" to determine the type resource cache.
+ * A bio cached buffer may be used by nio but is not as efficient as an
+ * nio buffer. An nio cached buffer may not be used by bio.
+ *
+ * useFileMappedBuffer
+ * If set to true, it will use mapped file buffer to serve static content
+ * when using NIO connector. Setting this value to false means that
+ * a direct buffer will be used instead of a mapped file buffer.
+ * By default, this is set to true.
+ *
+ * cacheControl If set, all static content will have this value set as the cache-control
+ * header.
+ *
+ *
+ * </PRE>
+ *
+ *
+ *
+ *
+ */
+public class DefaultServlet extends HttpServlet implements ResourceFactory
+{
+ private ServletContext _servletContext;
+ private ContextHandler _contextHandler;
+
+ private boolean _acceptRanges=true;
+ private boolean _dirAllowed=true;
+ private boolean _redirectWelcome=false;
+ private boolean _gzip=true;
+
+ private Resource _resourceBase;
+ private NIOResourceCache _nioCache;
+ private ResourceCache _bioCache;
+
+ private MimeTypes _mimeTypes;
+ private String[] _welcomes;
+ private boolean _useFileMappedBuffer=false;
+ private ByteArrayBuffer _cacheControl;
+ private String _relativeResourceBase;
+
+
+ /* ------------------------------------------------------------ */
+ public void init()
+ throws UnavailableException
+ {
+ _servletContext=getServletContext();
+ ContextHandler.Context scontext=ContextHandler.getCurrentContext();
+ if (scontext==null)
+ _contextHandler=((ContextHandler.Context)_servletContext).getContextHandler();
+ else
+ _contextHandler = ContextHandler.getCurrentContext().getContextHandler();
+
+ _mimeTypes = _contextHandler.getMimeTypes();
+
+ _welcomes = _contextHandler.getWelcomeFiles();
+ if (_welcomes==null)
+ _welcomes=new String[] {"index.jsp","index.html"};
+
+ _acceptRanges=getInitBoolean("acceptRanges",_acceptRanges);
+ _dirAllowed=getInitBoolean("dirAllowed",_dirAllowed);
+ _redirectWelcome=getInitBoolean("redirectWelcome",_redirectWelcome);
+ _gzip=getInitBoolean("gzip",_gzip);
+
+ String aliases=_servletContext.getInitParameter("aliases");
+ if (aliases!=null)
+ _contextHandler.setAliases(Boolean.parseBoolean(aliases));
+
+ _useFileMappedBuffer=getInitBoolean("useFileMappedBuffer",_useFileMappedBuffer);
+
+ _relativeResourceBase = getInitParameter("relativeResourceBase");
+
+ String rb=getInitParameter("resourceBase");
+ if (rb!=null)
+ {
+ if (_relativeResourceBase!=null)
+ throw new UnavailableException("resourceBase & relativeResourceBase");
+ try{_resourceBase=_contextHandler.newResource(rb);}
+ catch (Exception e)
+ {
+ Log.warn(Log.EXCEPTION,e);
+ throw new UnavailableException(e.toString());
+ }
+ }
+
+ String t=getInitParameter("cacheControl");
+ if (t!=null)
+ _cacheControl=new ByteArrayBuffer(t);
+
+ try
+ {
+ String cache_type =getInitParameter("cacheType");
+ int max_cache_size=getInitInt("maxCacheSize", -2);
+ int max_cached_file_size=getInitInt("maxCachedFileSize", -2);
+ int max_cached_files=getInitInt("maxCachedFiles", -2);
+
+ if (cache_type==null || "nio".equals(cache_type)|| "both".equals(cache_type))
+ {
+ if (max_cache_size==-2 || max_cache_size>0)
+ {
+ _nioCache=new NIOResourceCache(_mimeTypes);
+ _nioCache.setUseFileMappedBuffer(_useFileMappedBuffer);
+ if (max_cache_size>0)
+ _nioCache.setMaxCacheSize(max_cache_size);
+ if (max_cached_file_size>=-1)
+ _nioCache.setMaxCachedFileSize(max_cached_file_size);
+ if (max_cached_files>=-1)
+ _nioCache.setMaxCachedFiles(max_cached_files);
+ _nioCache.start();
+ }
+ }
+ if ("bio".equals(cache_type)|| "both".equals(cache_type))
+ {
+ if (max_cache_size==-2 || max_cache_size>0)
+ {
+ _bioCache=new ResourceCache(_mimeTypes);
+ if (max_cache_size>0)
+ _bioCache.setMaxCacheSize(max_cache_size);
+ if (max_cached_file_size>=-1)
+ _bioCache.setMaxCachedFileSize(max_cached_file_size);
+ if (max_cached_files>=-1)
+ _bioCache.setMaxCachedFiles(max_cached_files);
+ _bioCache.start();
+ }
+ }
+ if (_nioCache==null)
+ _bioCache=null;
+
+ }
+ catch (Exception e)
+ {
+ Log.warn(Log.EXCEPTION,e);
+ throw new UnavailableException(e.toString());
+ }
+
+ if (Log.isDebugEnabled()) Log.debug("resource base = "+_resourceBase);
+ }
+
+ /* ------------------------------------------------------------ */
+ public String getInitParameter(String name)
+ {
+ String value=getServletContext().getInitParameter("org.eclipse.jetty.servlet.Default."+name);
+ if (value==null)
+ value=super.getInitParameter(name);
+ return value;
+ }
+
+ /* ------------------------------------------------------------ */
+ private boolean getInitBoolean(String name, boolean dft)
+ {
+ String value=getInitParameter(name);
+ if (value==null || value.length()==0)
+ return dft;
+ return (value.startsWith("t")||
+ value.startsWith("T")||
+ value.startsWith("y")||
+ value.startsWith("Y")||
+ value.startsWith("1"));
+ }
+
+ /* ------------------------------------------------------------ */
+ private int getInitInt(String name, int dft)
+ {
+ String value=getInitParameter(name);
+ if (value==null)
+ value=getInitParameter(name);
+ if (value!=null && value.length()>0)
+ return Integer.parseInt(value);
+ return dft;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** get Resource to serve.
+ * Map a path to a resource. The default implementation calls
+ * HttpContext.getResource but derived servlets may provide
+ * their own mapping.
+ * @param pathInContext The path to find a resource for.
+ * @return The resource to serve.
+ */
+ public Resource getResource(String pathInContext)
+ {
+ Resource r=null;
+ if (_relativeResourceBase!=null)
+ pathInContext=URIUtil.addPaths(_relativeResourceBase,pathInContext);
+
+ try
+ {
+ if (_resourceBase!=null)
+ r = _resourceBase.addPath(pathInContext);
+ else
+ {
+ URL u = _servletContext.getResource(pathInContext);
+ r = _contextHandler.newResource(u);
+ }
+
+ if (Log.isDebugEnabled()) Log.debug("RESOURCE="+r);
+ }
+ catch (IOException e)
+ {
+ Log.ignore(e);
+ }
+ return r;
+ }
+
+ /* ------------------------------------------------------------ */
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException
+ {
+ String servletPath=null;
+ String pathInfo=null;
+ Enumeration reqRanges = null;
+ Boolean included =request.getAttribute(Dispatcher.__INCLUDE_REQUEST_URI)!=null;
+ if (included!=null && included.booleanValue())
+ {
+ servletPath=(String)request.getAttribute(Dispatcher.__INCLUDE_SERVLET_PATH);
+ pathInfo=(String)request.getAttribute(Dispatcher.__INCLUDE_PATH_INFO);
+ if (servletPath==null)
+ {
+ servletPath=request.getServletPath();
+ pathInfo=request.getPathInfo();
+ }
+ }
+ else
+ {
+ included=Boolean.FALSE;
+ servletPath=request.getServletPath();
+ pathInfo=request.getPathInfo();
+
+ // Is this a range request?
+ reqRanges = request.getHeaders(HttpHeaders.RANGE);
+ if (reqRanges!=null && !reqRanges.hasMoreElements())
+ reqRanges=null;
+ }
+
+ String pathInContext=URIUtil.addPaths(servletPath,pathInfo);
+ boolean endsWithSlash=pathInContext.endsWith(URIUtil.SLASH);
+
+ // Can we gzip this request?
+ String pathInContextGz=null;
+ boolean gzip=false;
+ if (!included.booleanValue() && _gzip && reqRanges==null && !endsWithSlash )
+ {
+ String accept=request.getHeader(HttpHeaders.ACCEPT_ENCODING);
+ if (accept!=null && accept.indexOf("gzip")>=0)
+ gzip=true;
+ }
+
+ // Find the resource and content
+ Resource resource=null;
+ HttpContent content=null;
+
+ Connector connector = HttpConnection.getCurrentConnection().getConnector();
+ ResourceCache cache=(connector instanceof NIOConnector) ?_nioCache:_bioCache;
+ try
+ {
+ // Try gzipped content first
+ if (gzip)
+ {
+ pathInContextGz=pathInContext+".gz";
+
+ if (cache==null)
+ {
+ resource=getResource(pathInContextGz);
+ }
+ else
+ {
+ content=cache.lookup(pathInContextGz,this);
+
+ if (content!=null)
+ resource=content.getResource();
+ else
+ resource=getResource(pathInContextGz);
+ }
+
+ if (resource==null || !resource.exists()|| resource.isDirectory())
+ {
+ if (cache!=null && content==null)
+ {
+ String real_path=_servletContext.getRealPath(pathInContextGz);
+ if (real_path!=null)
+ cache.miss(pathInContextGz,_contextHandler.newResource(real_path));
+ }
+ gzip=false;
+ pathInContextGz=null;
+ }
+ }
+
+ // find resource
+ if (!gzip)
+ {
+ if (cache==null)
+ resource=getResource(pathInContext);
+ else
+ {
+ content=cache.lookup(pathInContext,this);
+
+ if (content!=null)
+ resource=content.getResource();
+ else
+ resource=getResource(pathInContext);
+ }
+ }
+
+ if (Log.isDebugEnabled())
+ Log.debug("resource="+resource+(content!=null?" content":""));
+
+ // Handle resource
+ if (resource==null || !resource.exists())
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ else if (!resource.isDirectory())
+ {
+ // ensure we have content
+ if (content==null)
+ content=new UnCachedContent(resource);
+
+ if (included.booleanValue() || passConditionalHeaders(request,response, resource,content))
+ {
+ if (gzip)
+ {
+ response.setHeader(HttpHeaders.CONTENT_ENCODING,"gzip");
+ String mt=_servletContext.getMimeType(pathInContext);
+ if (mt!=null)
+ response.setContentType(mt);
+ }
+ sendData(request,response,included.booleanValue(),resource,content,reqRanges);
+ }
+ }
+ else
+ {
+ String welcome=null;
+
+ if (!endsWithSlash || (pathInContext.length()==1 && request.getAttribute("org.eclipse.jetty.server.nullPathInfo")!=null))
+ {
+ StringBuffer buf=request.getRequestURL();
+ synchronized(buf)
+ {
+ int param=buf.lastIndexOf(";");
+ if (param<0)
+ buf.append('/');
+ else
+ buf.insert(param,'/');
+ String q=request.getQueryString();
+ if (q!=null&&q.length()!=0)
+ {
+ buf.append('?');
+ buf.append(q);
+ }
+ response.setContentLength(0);
+ response.sendRedirect(response.encodeRedirectURL(buf.toString()));
+ }
+ }
+ // else look for a welcome file
+ else if (null!=(welcome=getWelcomeFile(resource)))
+ {
+ String ipath=URIUtil.addPaths(pathInContext,welcome);
+ if (_redirectWelcome)
+ {
+ // Redirect to the index
+ response.setContentLength(0);
+ String q=request.getQueryString();
+ if (q!=null&&q.length()!=0)
+ response.sendRedirect(URIUtil.addPaths( _servletContext.getContextPath(),ipath)+"?"+q);
+ else
+ response.sendRedirect(URIUtil.addPaths( _servletContext.getContextPath(),ipath));
+ }
+ else
+ {
+ // Forward to the index
+ RequestDispatcher dispatcher=request.getRequestDispatcher(ipath);
+ if (dispatcher!=null)
+ {
+ if (included.booleanValue())
+ dispatcher.include(request,response);
+ else
+ {
+ request.setAttribute("org.eclipse.jetty.server.welcome",ipath);
+ dispatcher.forward(request,response);
+ }
+ }
+ }
+ }
+ else
+ {
+ content=new UnCachedContent(resource);
+ if (included.booleanValue() || passConditionalHeaders(request,response, resource,content))
+ sendDirectory(request,response,resource,pathInContext.length()>1);
+ }
+ }
+ }
+ catch(IllegalArgumentException e)
+ {
+ Log.warn(Log.EXCEPTION,e);
+ if(!response.isCommitted())
+ response.sendError(500, e.getMessage());
+ }
+ finally
+ {
+ if (content!=null)
+ content.release();
+ else if (resource!=null)
+ resource.release();
+ }
+
+ }
+
+ /* ------------------------------------------------------------ */
+ protected void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException
+ {
+ doGet(request,response);
+ }
+
+ /* ------------------------------------------------------------ */
+ /* (non-Javadoc)
+ * @see javax.servlet.http.HttpServlet#doTrace(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Finds a matching welcome file for the supplied {@link Resource}. This will be the first entry in the list of
+ * configured {@link #_welcomes welcome files} that existing within the directory referenced by the <code>Resource</code>.
+ * If the resource is not a directory, or no matching file is found, then <code>null</code> is returned.
+ * The list of welcome files is read from the {@link ContextHandler} for this servlet, or
+ * <code>"index.jsp" , "index.html"</code> if that is <code>null</code>.
+ * @param resource
+ * @return The name of the matching welcome file.
+ * @throws IOException
+ * @throws MalformedURLException
+ */
+ private String getWelcomeFile(Resource resource) throws MalformedURLException, IOException
+ {
+ if (!resource.isDirectory() || _welcomes==null)
+ return null;
+
+ for (int i=0;i<_welcomes.length;i++)
+ {
+ Resource welcome=resource.addPath(_welcomes[i]);
+ if (welcome.exists())
+ return _welcomes[i];
+ }
+
+ return null;
+ }
+
+ /* ------------------------------------------------------------ */
+ /* Check modification date headers.
+ */
+ protected boolean passConditionalHeaders(HttpServletRequest request,HttpServletResponse response, Resource resource, HttpContent content)
+ throws IOException
+ {
+ try
+ {
+ if (!request.getMethod().equals(HttpMethods.HEAD) )
+ {
+ String ifms=request.getHeader(HttpHeaders.IF_MODIFIED_SINCE);
+ if (ifms!=null)
+ {
+ if (content!=null)
+ {
+ Buffer mdlm=content.getLastModified();
+ if (mdlm!=null)
+ {
+ if (ifms.equals(mdlm.toString()))
+ {
+ response.reset();
+ response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+ response.flushBuffer();
+ return false;
+ }
+ }
+ }
+
+ long ifmsl=request.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE);
+ if (ifmsl!=-1)
+ {
+ if (resource.lastModified()/1000 <= ifmsl/1000)
+ {
+ response.reset();
+ response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+ response.flushBuffer();
+ return false;
+ }
+ }
+ }
+
+ // Parse the if[un]modified dates and compare to resource
+ long date=request.getDateHeader(HttpHeaders.IF_UNMODIFIED_SINCE);
+
+ if (date!=-1)
+ {
+ if (resource.lastModified()/1000 > date/1000)
+ {
+ response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
+ return false;
+ }
+ }
+
+ }
+ }
+ catch(IllegalArgumentException iae)
+ {
+ if(!response.isCommitted())
+ response.sendError(400, iae.getMessage());
+ throw iae;
+ }
+ return true;
+ }
+
+
+ /* ------------------------------------------------------------------- */
+ protected void sendDirectory(HttpServletRequest request,
+ HttpServletResponse response,
+ Resource resource,
+ boolean parent)
+ throws IOException
+ {
+ if (!_dirAllowed)
+ {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+
+ byte[] data=null;
+ String base = URIUtil.addPaths(request.getRequestURI(),URIUtil.SLASH);
+ String dir = resource.getListHTML(base,parent);
+ if (dir==null)
+ {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN,
+ "No directory");
+ return;
+ }
+
+ data=dir.getBytes("UTF-8");
+ response.setContentType("text/html; charset=UTF-8");
+ response.setContentLength(data.length);
+ response.getOutputStream().write(data);
+ }
+
+ /* ------------------------------------------------------------ */
+ protected void sendData(HttpServletRequest request,
+ HttpServletResponse response,
+ boolean include,
+ Resource resource,
+ HttpContent content,
+ Enumeration reqRanges)
+ throws IOException
+ {
+ long content_length=resource.length();
+
+ // Get the output stream (or writer)
+ OutputStream out =null;
+ try{out = response.getOutputStream();}
+ catch(IllegalStateException e) {out = new WriterOutputStream(response.getWriter());}
+
+ if ( reqRanges == null || !reqRanges.hasMoreElements())
+ {
+ // if there were no ranges, send entire entity
+ if (include)
+ {
+ resource.writeTo(out,0,content_length);
+ }
+ else
+ {
+ // See if a short direct method can be used?
+ if (out instanceof HttpConnection.Output)
+ {
+ if (_cacheControl!=null)
+ {
+ if (response instanceof Response)
+ ((Response)response).getHttpFields().put(HttpHeaders.CACHE_CONTROL_BUFFER,_cacheControl);
+ else
+ response.setHeader(HttpHeaders.CACHE_CONTROL,_cacheControl.toString());
+ }
+ ((HttpConnection.Output)out).sendContent(content);
+ }
+ else
+ {
+
+ // Write content normally
+ writeHeaders(response,content,content_length);
+ resource.writeTo(out,0,content_length);
+ }
+ }
+ }
+ else
+ {
+ // Parse the satisfiable ranges
+ List ranges =InclusiveByteRange.satisfiableRanges(reqRanges,content_length);
+
+ // if there are no satisfiable ranges, send 416 response
+ if (ranges==null || ranges.size()==0)
+ {
+ writeHeaders(response, content, content_length);
+ response.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
+ response.setHeader(HttpHeaders.CONTENT_RANGE,
+ InclusiveByteRange.to416HeaderRangeString(content_length));
+ resource.writeTo(out,0,content_length);
+ return;
+ }
+
+
+ // if there is only a single valid range (must be satisfiable
+ // since were here now), send that range with a 216 response
+ if ( ranges.size()== 1)
+ {
+ InclusiveByteRange singleSatisfiableRange =
+ (InclusiveByteRange)ranges.get(0);
+ long singleLength = singleSatisfiableRange.getSize(content_length);
+ writeHeaders(response,content,singleLength );
+ response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
+ response.setHeader(HttpHeaders.CONTENT_RANGE,
+ singleSatisfiableRange.toHeaderRangeString(content_length));
+ resource.writeTo(out,singleSatisfiableRange.getFirst(content_length),singleLength);
+ return;
+ }
+
+
+ // multiple non-overlapping valid ranges cause a multipart
+ // 216 response which does not require an overall
+ // content-length header
+ //
+ writeHeaders(response,content,-1);
+ String mimetype=content.getContentType().toString();
+ MultiPartOutputStream multi = new MultiPartOutputStream(out);
+ response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
+
+ // If the request has a "Request-Range" header then we need to
+ // send an old style multipart/x-byteranges Content-Type. This
+ // keeps Netscape and acrobat happy. This is what Apache does.
+ String ctp;
+ if (request.getHeader(HttpHeaders.REQUEST_RANGE)!=null)
+ ctp = "multipart/x-byteranges; boundary=";
+ else
+ ctp = "multipart/byteranges; boundary=";
+ response.setContentType(ctp+multi.getBoundary());
+
+ InputStream in=resource.getInputStream();
+ long pos=0;
+
+ for (int i=0;i<ranges.size();i++)
+ {
+ InclusiveByteRange ibr = (InclusiveByteRange) ranges.get(i);
+ String header=HttpHeaders.CONTENT_RANGE+": "+
+ ibr.toHeaderRangeString(content_length);
+ multi.startPart(mimetype,new String[]{header});
+
+ long start=ibr.getFirst(content_length);
+ long size=ibr.getSize(content_length);
+ if (in!=null)
+ {
+ // Handle non cached resource
+ if (start<pos)
+ {
+ in.close();
+ in=resource.getInputStream();
+ pos=0;
+ }
+ if (pos<start)
+ {
+ in.skip(start-pos);
+ pos=start;
+ }
+ IO.copy(in,multi,size);
+ pos+=size;
+ }
+ else
+ // Handle cached resource
+ (resource).writeTo(multi,start,size);
+
+ }
+ if (in!=null)
+ in.close();
+ multi.close();
+ }
+ return;
+ }
+
+ /* ------------------------------------------------------------ */
+ protected void writeHeaders(HttpServletResponse response,HttpContent content,long count)
+ throws IOException
+ {
+ if (content.getContentType()!=null)
+ response.setContentType(content.getContentType().toString());
+
+ if (response instanceof Response)
+ {
+ Response r=(Response)response;
+ HttpFields fields = r.getHttpFields();
+
+ if (content.getLastModified()!=null)
+ fields.put(HttpHeaders.LAST_MODIFIED_BUFFER,content.getLastModified(),content.getResource().lastModified());
+ else if (content.getResource()!=null)
+ {
+ long lml=content.getResource().lastModified();
+ if (lml!=-1)
+ fields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER,lml);
+ }
+
+ if (count != -1)
+ r.setLongContentLength(count);
+
+ if (_acceptRanges)
+ fields.put(HttpHeaders.ACCEPT_RANGES_BUFFER,HttpHeaderValues.BYTES_BUFFER);
+
+ if (_cacheControl!=null)
+ fields.put(HttpHeaders.CACHE_CONTROL_BUFFER,_cacheControl);
+
+ }
+ else
+ {
+ long lml=content.getResource().lastModified();
+ if (lml>=0)
+ response.setDateHeader(HttpHeaders.LAST_MODIFIED,lml);
+
+ if (count != -1)
+ {
+ if (count<Integer.MAX_VALUE)
+ response.setContentLength((int)count);
+ else
+ response.setHeader(HttpHeaders.CONTENT_LENGTH,TypeUtil.toString(count));
+ }
+
+ if (_acceptRanges)
+ response.setHeader(HttpHeaders.ACCEPT_RANGES,"bytes");
+
+ if (_cacheControl!=null)
+ response.setHeader(HttpHeaders.CACHE_CONTROL,_cacheControl.toString());
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /*
+ * @see javax.servlet.Servlet#destroy()
+ */
+ public void destroy()
+ {
+ try
+ {
+ if (_nioCache!=null)
+ _nioCache.stop();
+ if (_bioCache!=null)
+ _bioCache.stop();
+ }
+ catch(Exception e)
+ {
+ Log.warn(Log.EXCEPTION,e);
+ }
+ finally
+ {
+ super.destroy();
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ private class UnCachedContent implements HttpContent
+ {
+ Resource _resource;
+
+ UnCachedContent(Resource resource)
+ {
+ _resource=resource;
+ }
+
+ /* ------------------------------------------------------------ */
+ public Buffer getContentType()
+ {
+ return _mimeTypes.getMimeByExtension(_resource.toString());
+ }
+
+ /* ------------------------------------------------------------ */
+ public Buffer getLastModified()
+ {
+ return null;
+ }
+
+ /* ------------------------------------------------------------ */
+ public Buffer getBuffer()
+ {
+ return null;
+ }
+
+ /* ------------------------------------------------------------ */
+ public long getContentLength()
+ {
+ return _resource.length();
+ }
+
+ /* ------------------------------------------------------------ */
+ public InputStream getInputStream() throws IOException
+ {
+ return _resource.getInputStream();
+ }
+
+ /* ------------------------------------------------------------ */
+ public Resource getResource()
+ {
+ return _resource;
+ }
+
+ /* ------------------------------------------------------------ */
+ public void release()
+ {
+ _resource.release();
+ _resource=null;
+ }
+
+ }
+}
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java
new file mode 100644
index 0000000000..a40bdab5a8
--- /dev/null
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java
@@ -0,0 +1,267 @@
+// ========================================================================
+// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.servlet;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpMethods;
+import org.eclipse.jetty.server.Dispatcher;
+import org.eclipse.jetty.server.HttpConnection;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.ErrorHandler;
+import org.eclipse.jetty.util.TypeUtil;
+import org.eclipse.jetty.util.log.Log;
+
+/** Error Page Error Handler
+ *
+ * An ErrorHandler that maps exceptions and status codes to URIs for dispatch using
+ * the internal ERROR style of dispatch.
+ *
+ *
+ */
+public class ErrorPageErrorHandler extends ErrorHandler
+{
+ public final static String ERROR_PAGE="org.eclipse.jetty.server.error_page";
+
+ protected ServletContext _servletContext;
+ protected Map _errorPages; // code or exception to URL
+ protected List _errorPageList; // list of ErrorCode by range
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param context
+ */
+ public ErrorPageErrorHandler()
+ {}
+
+ /* ------------------------------------------------------------ */
+ /*
+ * @see org.eclipse.jetty.server.handler.ErrorHandler#handle(java.lang.String, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
+ */
+ public void handle(String target, HttpServletRequest request, HttpServletResponse response) throws IOException
+ {
+ String method = request.getMethod();
+ if(!method.equals(HttpMethods.GET) && !method.equals(HttpMethods.POST))
+ {
+ HttpConnection.getCurrentConnection().getRequest().setHandled(true);
+ return;
+ }
+ if (_errorPages!=null)
+ {
+ String error_page= null;
+ Class exClass= (Class)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE);
+
+ if (ServletException.class.equals(exClass))
+ {
+ error_page= (String)_errorPages.get(exClass.getName());
+ if (error_page == null)
+ {
+ Throwable th= (Throwable)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
+ while (th instanceof ServletException)
+ th= ((ServletException)th).getRootCause();
+ if (th != null)
+ exClass= th.getClass();
+ }
+ }
+
+ while (error_page == null && exClass != null )
+ {
+ error_page= (String)_errorPages.get(exClass.getName());
+ exClass= exClass.getSuperclass();
+ }
+
+ if (error_page == null)
+ {
+ // look for an exact code match
+ Integer code=(Integer)request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
+ if (code!=null)
+ {
+ error_page= (String)_errorPages.get(TypeUtil.toString(code.intValue()));
+
+ // if still not found
+ if ((error_page == null) && (_errorPageList != null))
+ {
+ // look for an error code range match.
+ for (int i = 0; i < _errorPageList.size(); i++)
+ {
+ ErrorCodeRange errCode = (ErrorCodeRange) _errorPageList.get(i);
+ if (errCode.isInRange(code.intValue()))
+ {
+ error_page = errCode.getUri();
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (error_page!=null)
+ {
+ String old_error_page=(String)request.getAttribute(ERROR_PAGE);
+ if (old_error_page==null || !old_error_page.equals(error_page))
+ {
+ request.setAttribute(ERROR_PAGE, error_page);
+
+ Dispatcher dispatcher = (Dispatcher) _servletContext.getRequestDispatcher(error_page);
+ try
+ {
+ if(dispatcher!=null)
+ {
+ dispatcher.error(request, response);
+ return;
+ }
+ else
+ {
+ Log.warn("No error page "+error_page);
+ }
+ }
+ catch (ServletException e)
+ {
+ Log.warn(Log.EXCEPTION, e);
+ return;
+ }
+ }
+ }
+ }
+
+ super.handle(target, request, response);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the errorPages.
+ */
+ public Map getErrorPages()
+ {
+ return _errorPages;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param errorPages The errorPages to set. A map of Exception class name or error code as a string to URI string
+ */
+ public void setErrorPages(Map errorPages)
+ {
+ _errorPages = errorPages;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Add Error Page mapping for an exception class
+ * This method is called as a result of an exception-type element in a web.xml file
+ * or may be called directly
+ * @param code The class (or superclass) of the matching exceptions
+ * @param uri The URI of the error page.
+ */
+ public void addErrorPage(Class exception,String uri)
+ {
+ if (_errorPages==null)
+ _errorPages=new HashMap();
+ _errorPages.put(exception.getName(),uri);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Add Error Page mapping for a status code.
+ * This method is called as a result of an error-code element in a web.xml file
+ * or may be called directly
+ * @param code The HTTP status code to match
+ * @param uri The URI of the error page.
+ */
+ public void addErrorPage(int code,String uri)
+ {
+ if (_errorPages==null)
+ _errorPages=new HashMap();
+ _errorPages.put(TypeUtil.toString(code),uri);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Add Error Page mapping for a status code range.
+ * This method is not available from web.xml and must be called
+ * directly.
+ * @param from The lowest matching status code
+ * @param to The highest matching status code
+ * @param uri The URI of the error page.
+ */
+ public void addErrorPage(int from, int to, String uri)
+ {
+ if (_errorPageList == null)
+ {
+ _errorPageList = new ArrayList();
+ }
+ _errorPageList.add(new ErrorCodeRange(from, to, uri));
+ }
+
+ /* ------------------------------------------------------------ */
+ protected void doStart() throws Exception
+ {
+ super.doStart();
+ _servletContext=ContextHandler.getCurrentContext();
+ }
+
+ /* ------------------------------------------------------------ */
+ protected void doStop() throws Exception
+ {
+ // TODO Auto-generated method stub
+ super.doStop();
+ }
+
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ private class ErrorCodeRange
+ {
+ private int _from;
+ private int _to;
+ private String _uri;
+
+ ErrorCodeRange(int from, int to, String uri)
+ throws IllegalArgumentException
+ {
+ if (from > to)
+ throw new IllegalArgumentException("from>to");
+
+ _from = from;
+ _to = to;
+ _uri = uri;
+ }
+
+ boolean isInRange(int value)
+ {
+ if ((value >= _from) && (value <= _to))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ String getUri()
+ {
+ return _uri;
+ }
+
+ public String toString()
+ {
+ return "from: " + _from + ",to: " + _to + ",uri: " + _uri;
+ }
+ }
+}
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java
new file mode 100644
index 0000000000..b855763410
--- /dev/null
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java
@@ -0,0 +1,194 @@
+// ========================================================================
+// Copyright (c) 1996-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.servlet;
+
+import java.util.EnumSet;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.FilterConfig;
+import javax.servlet.FilterRegistration;
+
+import org.eclipse.jetty.util.log.Log;
+
+/* --------------------------------------------------------------------- */
+/**
+ *
+ */
+public class FilterHolder extends Holder
+{
+ /* ------------------------------------------------------------ */
+ private transient Filter _filter;
+ private transient Config _config;
+
+ /* ---------------------------------------------------------------- */
+ /** Constructor for Serialization.
+ */
+ public FilterHolder()
+ {
+ }
+
+ /* ---------------------------------------------------------------- */
+ /** Constructor for Serialization.
+ */
+ public FilterHolder(Class filter)
+ {
+ super (filter);
+ }
+
+ /* ---------------------------------------------------------------- */
+ /** Constructor for existing filter.
+ */
+ public FilterHolder(Filter filter)
+ {
+ setFilter(filter);
+ }
+
+ /* ------------------------------------------------------------ */
+ public void doStart()
+ throws Exception
+ {
+ super.doStart();
+
+ if (!javax.servlet.Filter.class
+ .isAssignableFrom(_class))
+ {
+ String msg = _class+" is not a javax.servlet.Filter";
+ super.stop();
+ throw new IllegalStateException(msg);
+ }
+
+ if (_filter==null)
+ _filter=(Filter)newInstance();
+
+ _filter = getServletHandler().customizeFilter(_filter);
+
+ _config=new Config();
+ _filter.init(_config);
+ }
+
+ /* ------------------------------------------------------------ */
+ public void doStop()
+ {
+ if (_filter!=null)
+ {
+ try
+ {
+ destroyInstance(_filter);
+ }
+ catch (Exception e)
+ {
+ Log.warn(e);
+ }
+ }
+ if (!_extInstance)
+ _filter=null;
+
+ _config=null;
+ super.doStop();
+ }
+
+ /* ------------------------------------------------------------ */
+ public void destroyInstance (Object o)
+ throws Exception
+ {
+ if (o==null)
+ return;
+ Filter f = (Filter)o;
+ f.destroy();
+ getServletHandler().customizeFilterDestroy(f);
+ }
+
+ /* ------------------------------------------------------------ */
+ public synchronized void setFilter(Filter filter)
+ {
+ _filter=filter;
+ _extInstance=true;
+ setHeldClass(filter.getClass());
+ if (getName()==null)
+ setName(filter.getClass().getName());
+ }
+
+ /* ------------------------------------------------------------ */
+ public Filter getFilter()
+ {
+ return _filter;
+ }
+
+ /* ------------------------------------------------------------ */
+ public String toString()
+ {
+ return getName();
+ }
+
+
+ public FilterRegistration getRegistration()
+ {
+ return new Registration();
+ }
+
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ protected class Registration extends HolderRegistration implements FilterRegistration
+ {
+ /* ------------------------------------------------------------ */
+ public boolean addMappingForServletNames(EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter, String... servletNames)
+ {
+ illegalStateIfContextStarted();
+ FilterMapping mapping = new FilterMapping();
+ mapping.setFilterHolder(FilterHolder.this);
+ mapping.setServletNames(servletNames);
+ mapping.setDispatcherTypes(dispatcherTypes);
+ if (isMatchAfter)
+ _servletHandler.addFilterMapping(mapping);
+ else
+ _servletHandler.prependFilterMapping(mapping);
+
+ return true;
+ }
+
+ public boolean addMappingForUrlPatterns(EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter, String... urlPatterns)
+ {
+ illegalStateIfContextStarted();
+ FilterMapping mapping = new FilterMapping();
+ mapping.setFilterHolder(FilterHolder.this);
+ mapping.setPathSpecs(urlPatterns);
+ mapping.setDispatcherTypes(dispatcherTypes);
+ if (isMatchAfter)
+ _servletHandler.addFilterMapping(mapping);
+ else
+ _servletHandler.prependFilterMapping(mapping);
+ return true;
+ }
+
+ }
+
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ class Config extends HolderConfig implements FilterConfig
+ {
+ /* ------------------------------------------------------------ */
+ public String getFilterName()
+ {
+ return _name;
+ }
+ }
+}
+
+
+
+
+
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterMapping.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterMapping.java
new file mode 100644
index 0000000000..169067353d
--- /dev/null
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterMapping.java
@@ -0,0 +1,280 @@
+// ========================================================================
+// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.servlet;
+
+import java.util.Arrays;
+import java.util.EnumSet;
+
+import javax.servlet.DispatcherType;
+
+import org.eclipse.jetty.http.PathMap;
+import org.eclipse.jetty.server.Handler;
+
+
+public class FilterMapping
+{
+ /** Dispatch types */
+ public static final int DEFAULT=0;
+ public static final int REQUEST=1;
+ public static final int FORWARD=2;
+ public static final int INCLUDE=4;
+ public static final int ERROR=8;
+ public static final int ASYNC=16;
+ public static final int ALL=31;
+
+
+ /* ------------------------------------------------------------ */
+ /** Dispatch type from name
+ */
+ public static int dispatch(String type)
+ {
+ if ("request".equalsIgnoreCase(type))
+ return REQUEST;
+ if ("forward".equalsIgnoreCase(type))
+ return FORWARD;
+ if ("include".equalsIgnoreCase(type))
+ return INCLUDE;
+ if ("error".equalsIgnoreCase(type))
+ return ERROR;
+ if ("async".equalsIgnoreCase(type))
+ return ASYNC;
+ throw new IllegalArgumentException(type);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Dispatch type from name
+ */
+ public static int dispatch(DispatcherType type)
+ {
+ switch(type)
+ {
+ case REQUEST:
+ return REQUEST;
+ case ASYNC:
+ return ASYNC;
+ case FORWARD:
+ return FORWARD;
+ case INCLUDE:
+ return INCLUDE;
+ case ERROR:
+ return ERROR;
+ }
+ throw new IllegalArgumentException(type.toString());
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /** Dispatch type from name
+ */
+ public static DispatcherType dispatch(int type)
+ {
+ switch(type)
+ {
+ case REQUEST:
+ return DispatcherType.REQUEST;
+ case ASYNC:
+ return DispatcherType.ASYNC;
+ case FORWARD:
+ return DispatcherType.FORWARD;
+ case INCLUDE:
+ return DispatcherType.INCLUDE;
+ case ERROR:
+ return DispatcherType.ERROR;
+ }
+ throw new IllegalArgumentException(""+type);
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+
+
+ private int _dispatches=DEFAULT;
+ private String _filterName;
+ private transient FilterHolder _holder;
+ private String[] _pathSpecs;
+ private String[] _servletNames;
+
+ /* ------------------------------------------------------------ */
+ public FilterMapping()
+ {}
+
+ /* ------------------------------------------------------------ */
+ /** Check if this filter applies to a path.
+ * @param path The path to check or null to just check type
+ * @param type The type of request: __REQUEST,__FORWARD,__INCLUDE, __ASYNC or __ERROR.
+ * @return True if this filter applies
+ */
+ boolean appliesTo(String path, int type)
+ {
+ if (appliesTo(type))
+ {
+ for (int i=0;i<_pathSpecs.length;i++)
+ if (_pathSpecs[i]!=null && PathMap.match(_pathSpecs[i], path,true))
+ return true;
+ }
+
+ return false;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Check if this filter applies to a particular dispatch type.
+ * @param type The type of request:
+ * {@link Handler#REQUEST}, {@link Handler#FORWARD}, {@link Handler#INCLUDE} or {@link Handler#ERROR}.
+ * @return <code>true</code> if this filter applies
+ */
+ boolean appliesTo(int type)
+ {
+ if (_dispatches==0)
+ return type==REQUEST || type==ASYNC && _holder.isAsyncSupported();
+ return (_dispatches&type)!=0;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the dispatches.
+ */
+ public int getDispatches()
+ {
+ return _dispatches;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the filterName.
+ */
+ public String getFilterName()
+ {
+ return _filterName;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the holder.
+ */
+ FilterHolder getFilterHolder()
+ {
+ return _holder;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the pathSpec.
+ */
+ public String[] getPathSpecs()
+ {
+ return _pathSpecs;
+ }
+
+ /* ------------------------------------------------------------ */
+ public void setDispatcherTypes(EnumSet<DispatcherType> dispatcherTypes)
+ {
+ _dispatches=DEFAULT;
+ if (dispatcherTypes.contains(DispatcherType.ERROR))
+ _dispatches|=ERROR;
+ if (dispatcherTypes.contains(DispatcherType.FORWARD))
+ _dispatches|=FORWARD;
+ if (dispatcherTypes.contains(DispatcherType.INCLUDE))
+ _dispatches|=INCLUDE;
+ if (dispatcherTypes.contains(DispatcherType.REQUEST))
+ _dispatches|=REQUEST;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param dispatches The dispatches to set.
+ * @see Handler#DEFAULT
+ * @see Handler#REQUEST
+ * @see Handler#ERROR
+ * @see Handler#FORWARD
+ * @see Handler#INCLUDE
+ */
+ public void setDispatches(int dispatches)
+ {
+ _dispatches = dispatches;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param filterName The filterName to set.
+ */
+ public void setFilterName(String filterName)
+ {
+ _filterName = filterName;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param holder The holder to set.
+ */
+ void setFilterHolder(FilterHolder holder)
+ {
+ _holder = holder;
+ setFilterName(holder.getName());
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param pathSpecs The Path specifications to which this filter should be mapped.
+ */
+ public void setPathSpecs(String[] pathSpecs)
+ {
+ _pathSpecs = pathSpecs;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param pathSpec The pathSpec to set.
+ */
+ public void setPathSpec(String pathSpec)
+ {
+ _pathSpecs = new String[]{pathSpec};
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the servletName.
+ */
+ public String[] getServletNames()
+ {
+ return _servletNames;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param servletNames Maps the {@link #setFilterName(String) named filter} to multiple servlets
+ * @see #setServletName
+ */
+ public void setServletNames(String[] servletNames)
+ {
+ _servletNames = servletNames;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param servletName Maps the {@link #setFilterName(String) named filter} to a single servlet
+ * @see #setServletNames
+ */
+ public void setServletName(String servletName)
+ {
+ _servletNames = new String[]{servletName};
+ }
+
+ /* ------------------------------------------------------------ */
+ public String toString()
+ {
+ return "(F="+_filterName+","+(_pathSpecs==null?"[]":Arrays.asList(_pathSpecs).toString())+","+(_servletNames==null?"[]":Arrays.asList(_servletNames).toString())+","+_dispatches+")";
+ }
+
+}
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java
new file mode 100644
index 0000000000..b63267baf8
--- /dev/null
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java
@@ -0,0 +1,379 @@
+// ========================================================================
+// Copyright (c) 1996-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.servlet;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.servlet.UnavailableException;
+
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.util.AttributesMap;
+import org.eclipse.jetty.util.Loader;
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.eclipse.jetty.util.log.Log;
+
+
+/* --------------------------------------------------------------------- */
+/**
+ *
+ */
+public class Holder extends AbstractLifeCycle implements Serializable
+{
+ protected transient Class _class;
+ protected String _className;
+ protected String _displayName;
+ protected Map _initParams;
+ protected boolean _extInstance;
+ protected boolean _asyncSupported;
+ protected AttributesMap _initAttributes;
+
+ /* ---------------------------------------------------------------- */
+ protected String _name;
+ protected ServletHandler _servletHandler;
+
+ protected Holder()
+ {}
+
+ /* ---------------------------------------------------------------- */
+ protected Holder(Class held)
+ {
+ _class=held;
+ if (held!=null)
+ {
+ _className=held.getName();
+ _name=held.getName()+"-"+this.hashCode();
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ public void doStart()
+ throws Exception
+ {
+ //if no class already loaded and no classname, make servlet permanently unavailable
+ if (_class==null && (_className==null || _className.equals("")))
+ throw new UnavailableException("No class for Servlet or Filter", -1);
+
+ //try to load class
+ if (_class==null)
+ {
+ try
+ {
+ _class=Loader.loadClass(Holder.class, _className);
+ if(Log.isDebugEnabled())Log.debug("Holding {}",_class);
+ }
+ catch (Exception e)
+ {
+ Log.warn(e);
+ throw new UnavailableException(e.getMessage(), -1);
+ }
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ public void doStop()
+ {
+ if (!_extInstance)
+ _class=null;
+ }
+
+ /* ------------------------------------------------------------ */
+ public String getClassName()
+ {
+ return _className;
+ }
+
+ /* ------------------------------------------------------------ */
+ public Class getHeldClass()
+ {
+ return _class;
+ }
+
+ /* ------------------------------------------------------------ */
+ public String getDisplayName()
+ {
+ return _displayName;
+ }
+
+ /* ---------------------------------------------------------------- */
+ public String getInitParameter(String param)
+ {
+ if (_initParams==null)
+ return null;
+ return (String)_initParams.get(param);
+ }
+
+ /* ------------------------------------------------------------ */
+ public Enumeration getInitParameterNames()
+ {
+ if (_initParams==null)
+ return Collections.enumeration(Collections.EMPTY_LIST);
+ return Collections.enumeration(_initParams.keySet());
+ }
+
+ /* ---------------------------------------------------------------- */
+ public Map getInitParameters()
+ {
+ return _initParams;
+ }
+
+ /* ------------------------------------------------------------ */
+ public String getName()
+ {
+ return _name;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the servletHandler.
+ */
+ public ServletHandler getServletHandler()
+ {
+ return _servletHandler;
+ }
+
+ /* ------------------------------------------------------------ */
+ public synchronized Object newInstance()
+ throws InstantiationException,
+ IllegalAccessException
+ {
+ if (_class==null)
+ throw new InstantiationException("!"+_className);
+ return _class.newInstance();
+ }
+
+ /* ------------------------------------------------------------ */
+ public void destroyInstance(Object instance)
+ throws Exception
+ {
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param className The className to set.
+ */
+ public void setClassName(String className)
+ {
+ _className = className;
+ _class=null;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param className The className to set.
+ */
+ public void setHeldClass(Class held)
+ {
+ _class=held;
+ _className = held!=null?held.getName():null;
+ }
+
+ /* ------------------------------------------------------------ */
+ public void setDisplayName(String name)
+ {
+ _displayName=name;
+ }
+
+ /* ------------------------------------------------------------ */
+ public void setInitParameter(String param,String value)
+ {
+ if (_initParams==null)
+ _initParams=new HashMap(3);
+ _initParams.put(param,value);
+ }
+
+ /* ---------------------------------------------------------------- */
+ public void setInitParameters(Map map)
+ {
+ _initParams=map;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * The name is a primary key for the held object.
+ * Ensure that the name is set BEFORE adding a Holder
+ * (eg ServletHolder or FilterHolder) to a ServletHandler.
+ * @param name The name to set.
+ */
+ public void setName(String name)
+ {
+ _name = name;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param servletHandler The {@link ServletHandler} that will handle requests dispatched to this servlet.
+ */
+ public void setServletHandler(ServletHandler servletHandler)
+ {
+ _servletHandler = servletHandler;
+ }
+
+ /* ------------------------------------------------------------ */
+ public void setAsyncSupported(boolean suspendable)
+ {
+ _asyncSupported=suspendable;
+ }
+
+ /* ------------------------------------------------------------ */
+ public boolean isAsyncSupported()
+ {
+ return _asyncSupported;
+ }
+
+ /* ------------------------------------------------------------ */
+ public String toString()
+ {
+ return _name;
+ }
+
+ /* ------------------------------------------------------------ */
+ protected void illegalStateIfContextStarted()
+ {
+ if (_servletHandler!=null)
+ {
+ ContextHandler.Context context=(ContextHandler.Context)_servletHandler.getServletContext();
+ if (context!=null && context.getContextHandler().isStarted())
+ throw new IllegalStateException("Started");
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ protected class HolderConfig
+ {
+
+ /* -------------------------------------------------------- */
+ public ServletContext getServletContext()
+ {
+ return _servletHandler.getServletContext();
+ }
+
+ /* -------------------------------------------------------- */
+ public String getInitParameter(String param)
+ {
+ return Holder.this.getInitParameter(param);
+ }
+
+ /* -------------------------------------------------------- */
+ public Enumeration getInitParameterNames()
+ {
+ return Holder.this.getInitParameterNames();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see javax.servlet.ServletConfig#getInitAttribute(java.lang.String)
+ */
+ public Object getInitAttribute(String name)
+ {
+ return (Holder.this._initAttributes==null)?null:Holder.this._initAttributes.getAttribute(name);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see javax.servlet.ServletConfig#getInitAttributeNames()
+ */
+ public Iterable<String> getInitAttributeNames()
+ {
+ if (Holder.this._initAttributes!=null)
+ return Holder.this._initAttributes.keySet();
+ return Collections.emptySet();
+ }
+
+ }
+
+ /* -------------------------------------------------------- */
+ /* -------------------------------------------------------- */
+ /* -------------------------------------------------------- */
+ protected class HolderRegistration
+ {
+ public boolean setAsyncSupported(boolean isAsyncSupported)
+ {
+ illegalStateIfContextStarted();
+ Holder.this.setAsyncSupported(isAsyncSupported);
+ return true;
+ }
+
+ public boolean setDescription(String description)
+ {
+ return true;
+ }
+
+ public boolean setInitParameter(String name, String value)
+ {
+ illegalStateIfContextStarted();
+ if (Holder.this.getInitParameter(name)!=null)
+ return false;
+ Holder.this.setInitParameter(name,value);
+ return true;
+ }
+
+ public boolean setInitParameters(Map<String, String> initParameters)
+ {
+ illegalStateIfContextStarted();
+ for (String name : initParameters.keySet())
+ if (Holder.this.getInitParameter(name)!=null)
+ return false;
+ Holder.this.setInitParameters(initParameters);
+ return true;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see javax.servlet.ServletRegistration#setInitAttribute(java.lang.String, java.lang.Object)
+ */
+ public boolean setInitAttribute(String name, Object value)
+ {
+ illegalStateIfContextStarted();
+ if (_initAttributes==null)
+ _initAttributes=new AttributesMap();
+ else if (_initAttributes.getAttribute(name)!=null)
+ return false;
+ _initAttributes.setAttribute(name,value);
+ return true;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see javax.servlet.ServletRegistration#setInitAttributes(java.util.Map)
+ */
+ public boolean setInitAttributes(Map<String, Object> initAttributes)
+ {
+ illegalStateIfContextStarted();
+ if (_initAttributes==null)
+ _initAttributes=new AttributesMap();
+ else
+ {
+ for (String name : initAttributes.keySet())
+ if (_initAttributes.getAttribute(name)!=null)
+ return false;
+ }
+ for (String name : initAttributes.keySet())
+ _initAttributes.setAttribute(name,initAttributes.get(name));
+
+ return true;
+ };
+ }
+}
+
+
+
+
+
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Invoker.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Invoker.java
new file mode 100644
index 0000000000..2b0175f897
--- /dev/null
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Invoker.java
@@ -0,0 +1,303 @@
+// ========================================================================
+// Copyright (c) 1999-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.servlet;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.server.Dispatcher;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.HttpConnection;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.HandlerWrapper;
+import org.eclipse.jetty.util.LazyList;
+import org.eclipse.jetty.util.URIUtil;
+import org.eclipse.jetty.util.log.Log;
+
+/* ------------------------------------------------------------ */
+/** Dynamic Servlet Invoker.
+ * This servlet invokes anonymous servlets that have not been defined
+ * in the web.xml or by other means. The first element of the pathInfo
+ * of a request passed to the envoker is treated as a servlet name for
+ * an existing servlet, or as a class name of a new servlet.
+ * This servlet is normally mapped to /servlet/*
+ * This servlet support the following initParams:
+ * <PRE>
+ * nonContextServlets If false, the invoker can only load
+ * servlets from the contexts classloader.
+ * This is false by default and setting this
+ * to true may have security implications.
+ *
+ * verbose If true, log dynamic loads
+ *
+ * * All other parameters are copied to the
+ * each dynamic servlet as init parameters
+ * </PRE>
+ * @version $Id: Invoker.java 4780 2009-03-17 15:36:08Z jesse $
+ *
+ */
+public class Invoker extends HttpServlet
+{
+
+ private ContextHandler _contextHandler;
+ private ServletHandler _servletHandler;
+ private Map.Entry _invokerEntry;
+ private Map _parameters;
+ private boolean _nonContextServlets;
+ private boolean _verbose;
+
+ /* ------------------------------------------------------------ */
+ public void init()
+ {
+ ServletContext config=getServletContext();
+ _contextHandler=((ContextHandler.Context)config).getContextHandler();
+
+ Handler handler=_contextHandler.getHandler();
+ while (handler!=null && !(handler instanceof ServletHandler) && (handler instanceof HandlerWrapper))
+ handler=((HandlerWrapper)handler).getHandler();
+ _servletHandler = (ServletHandler)handler;
+ Enumeration e = getInitParameterNames();
+ while(e.hasMoreElements())
+ {
+ String param=(String)e.nextElement();
+ String value=getInitParameter(param);
+ String lvalue=value.toLowerCase();
+ if ("nonContextServlets".equals(param))
+ {
+ _nonContextServlets=value.length()>0 && lvalue.startsWith("t");
+ }
+ if ("verbose".equals(param))
+ {
+ _verbose=value.length()>0 && lvalue.startsWith("t");
+ }
+ else
+ {
+ if (_parameters==null)
+ _parameters=new HashMap();
+ _parameters.put(param,value);
+ }
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ protected void service(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException
+ {
+ // Get the requested path and info
+ boolean included=false;
+ String servlet_path=(String)request.getAttribute(Dispatcher.__INCLUDE_SERVLET_PATH);
+ if (servlet_path==null)
+ servlet_path=request.getServletPath();
+ else
+ included=true;
+ String path_info = (String)request.getAttribute(Dispatcher.__INCLUDE_PATH_INFO);
+ if (path_info==null)
+ path_info=request.getPathInfo();
+
+ // Get the servlet class
+ String servlet = path_info;
+ if (servlet==null || servlet.length()<=1 )
+ {
+ response.sendError(404);
+ return;
+ }
+
+
+ int i0=servlet.charAt(0)=='/'?1:0;
+ int i1=servlet.indexOf('/',i0);
+ servlet=i1<0?servlet.substring(i0):servlet.substring(i0,i1);
+
+ // look for a named holder
+ ServletHolder[] holders = _servletHandler.getServlets();
+ ServletHolder holder = getHolder (holders, servlet);
+
+ if (holder!=null)
+ {
+ // Found a named servlet (from a user's web.xml file) so
+ // now we add a mapping for it
+ Log.debug("Adding servlet mapping for named servlet:"+servlet+":"+URIUtil.addPaths(servlet_path,servlet)+"/*");
+ ServletMapping mapping = new ServletMapping();
+ mapping.setServletName(servlet);
+ mapping.setPathSpec(URIUtil.addPaths(servlet_path,servlet)+"/*");
+ _servletHandler.setServletMappings((ServletMapping[])LazyList.addToArray(_servletHandler.getServletMappings(), mapping, ServletMapping.class));
+ }
+ else
+ {
+ // look for a class mapping
+ if (servlet.endsWith(".class"))
+ servlet=servlet.substring(0,servlet.length()-6);
+ if (servlet==null || servlet.length()==0)
+ {
+ response.sendError(404);
+ return;
+ }
+
+ synchronized(_servletHandler)
+ {
+ // find the entry for the invoker (me)
+ _invokerEntry=_servletHandler.getHolderEntry(servlet_path);
+
+ // Check for existing mapping (avoid threaded race).
+ String path=URIUtil.addPaths(servlet_path,servlet);
+ Map.Entry entry = _servletHandler.getHolderEntry(path);
+
+ if (entry!=null && !entry.equals(_invokerEntry))
+ {
+ // Use the holder
+ holder=(ServletHolder)entry.getValue();
+ }
+ else
+ {
+ // Make a holder
+ Log.debug("Making new servlet="+servlet+" with path="+path+"/*");
+ holder=_servletHandler.addServletWithMapping(servlet, path+"/*");
+
+ if (_parameters!=null)
+ holder.setInitParameters(_parameters);
+
+ try {holder.start();}
+ catch (Exception e)
+ {
+ Log.debug(e);
+ throw new UnavailableException(e.toString());
+ }
+
+ // Check it is from an allowable classloader
+ if (!_nonContextServlets)
+ {
+ Object s=holder.getServlet();
+
+ if (_contextHandler.getClassLoader()!=
+ s.getClass().getClassLoader())
+ {
+ try
+ {
+ holder.stop();
+ }
+ catch (Exception e)
+ {
+ Log.ignore(e);
+ }
+
+ Log.warn("Dynamic servlet "+s+
+ " not loaded from context "+
+ request.getContextPath());
+ throw new UnavailableException("Not in context");
+ }
+ }
+
+ if (_verbose)
+ Log.debug("Dynamic load '"+servlet+"' at "+path);
+ }
+ }
+ }
+
+ if (holder!=null)
+ {
+ final Request base_request=(request instanceof Request)?((Request)request):HttpConnection.getCurrentConnection().getRequest();
+ holder.handle(base_request,
+ new InvokedRequest(request,included,servlet,servlet_path,path_info),
+ response);
+ }
+ else
+ {
+ Log.info("Can't find holder for servlet: "+servlet);
+ response.sendError(404);
+ }
+
+
+ }
+
+ /* ------------------------------------------------------------ */
+ class InvokedRequest extends HttpServletRequestWrapper
+ {
+ String _servletPath;
+ String _pathInfo;
+ boolean _included;
+
+ /* ------------------------------------------------------------ */
+ InvokedRequest(HttpServletRequest request,
+ boolean included,
+ String name,
+ String servletPath,
+ String pathInfo)
+ {
+ super(request);
+ _included=included;
+ _servletPath=URIUtil.addPaths(servletPath,name);
+ _pathInfo=pathInfo.substring(name.length()+1);
+ if (_pathInfo.length()==0)
+ _pathInfo=null;
+ }
+
+ /* ------------------------------------------------------------ */
+ public String getServletPath()
+ {
+ if (_included)
+ return super.getServletPath();
+ return _servletPath;
+ }
+
+ /* ------------------------------------------------------------ */
+ public String getPathInfo()
+ {
+ if (_included)
+ return super.getPathInfo();
+ return _pathInfo;
+ }
+
+ /* ------------------------------------------------------------ */
+ public Object getAttribute(String name)
+ {
+ if (_included)
+ {
+ if (name.equals(Dispatcher.__INCLUDE_REQUEST_URI))
+ return URIUtil.addPaths(URIUtil.addPaths(getContextPath(),_servletPath),_pathInfo);
+ if (name.equals(Dispatcher.__INCLUDE_PATH_INFO))
+ return _pathInfo;
+ if (name.equals(Dispatcher.__INCLUDE_SERVLET_PATH))
+ return _servletPath;
+ }
+ return super.getAttribute(name);
+ }
+ }
+
+
+ private ServletHolder getHolder(ServletHolder[] holders, String servlet)
+ {
+ if (holders == null)
+ return null;
+
+ ServletHolder holder = null;
+ for (int i=0; holder==null && i<holders.length; i++)
+ {
+ if (holders[i].getName().equals(servlet))
+ {
+ holder = holders[i];
+ }
+ }
+ return holder;
+ }
+}
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/NIOResourceCache.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/NIOResourceCache.java
new file mode 100644
index 0000000000..12c900bf26
--- /dev/null
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/NIOResourceCache.java
@@ -0,0 +1,86 @@
+// ========================================================================
+// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+/**
+ *
+ */
+package org.eclipse.jetty.servlet;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.jetty.http.MimeTypes;
+import org.eclipse.jetty.io.Buffer;
+import org.eclipse.jetty.io.nio.DirectNIOBuffer;
+import org.eclipse.jetty.io.nio.IndirectNIOBuffer;
+import org.eclipse.jetty.io.nio.NIOBuffer;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpConnection;
+import org.eclipse.jetty.server.ResourceCache;
+import org.eclipse.jetty.server.nio.NIOConnector;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.resource.Resource;
+
+class NIOResourceCache extends ResourceCache
+{
+ boolean _useFileMappedBuffer;
+
+ /* ------------------------------------------------------------ */
+ public NIOResourceCache(MimeTypes mimeTypes)
+ {
+ super(mimeTypes);
+ }
+
+ /* ------------------------------------------------------------ */
+ protected void fill(Content content) throws IOException
+ {
+ Buffer buffer=null;
+ Resource resource=content.getResource();
+ long length=resource.length();
+
+ if (_useFileMappedBuffer && resource.getFile()!=null)
+ {
+ buffer = new DirectNIOBuffer(resource.getFile());
+ }
+ else
+ {
+ InputStream is = resource.getInputStream();
+ try
+ {
+ Connector connector = HttpConnection.getCurrentConnection().getConnector();
+ buffer = ((NIOConnector)connector).getUseDirectBuffers()?
+ (NIOBuffer)new DirectNIOBuffer((int)length):
+ (NIOBuffer)new IndirectNIOBuffer((int)length);
+ }
+ catch(OutOfMemoryError e)
+ {
+ Log.warn(e.toString());
+ Log.debug(e);
+ buffer = new IndirectNIOBuffer((int) length);
+ }
+ buffer.readFrom(is,(int)length);
+ is.close();
+ }
+ content.setBuffer(buffer);
+ }
+
+ public boolean isUseFileMappedBuffer()
+ {
+ return _useFileMappedBuffer;
+ }
+
+ public void setUseFileMappedBuffer(boolean useFileMappedBuffer)
+ {
+ _useFileMappedBuffer = useFileMappedBuffer;
+ }
+}
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/NoJspServlet.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/NoJspServlet.java
new file mode 100644
index 0000000000..29c5f78247
--- /dev/null
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/NoJspServlet.java
@@ -0,0 +1,35 @@
+// ========================================================================
+// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.servlet;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class NoJspServlet extends HttpServlet
+{
+
+ /* ------------------------------------------------------------ */
+ /*
+ * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException
+ {
+ response.sendError(500,"JSP support not configured");
+ }
+
+}
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java
new file mode 100644
index 0000000000..3b10330cd1
--- /dev/null
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java
@@ -0,0 +1,502 @@
+// ========================================================================
+// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.servlet;
+
+import java.util.EnumSet;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.FilterRegistration;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRegistration;
+import javax.servlet.SessionTrackingMode;
+
+import org.eclipse.jetty.security.SecurityHandler;
+import org.eclipse.jetty.server.Dispatcher;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.HandlerContainer;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.ErrorHandler;
+import org.eclipse.jetty.server.session.SessionHandler;
+import org.eclipse.jetty.util.log.Log;
+
+
+/* ------------------------------------------------------------ */
+/** Servlet Context.
+ * This extension to the ContextHandler allows for
+ * simple construction of a context with ServletHandler and optionally
+ * session and security handlers, et.<pre>
+ * new ServletContext("/context",Context.SESSIONS|Context.NO_SECURITY);
+ * </pre>
+ * <p/>
+ * This class should have been called ServletContext, but this would have
+ * cause confusion with {@link ServletContext}.
+ */
+public class ServletContextHandler extends ContextHandler
+{
+ public final static int SESSIONS=1;
+ public final static int SECURITY=2;
+ public final static int NO_SESSIONS=0;
+ public final static int NO_SECURITY=0;
+
+ protected Class<? extends SecurityHandler> _defaultSecurityHandlerClass=org.eclipse.jetty.security.ConstraintSecurityHandler.class;
+ protected SessionHandler _sessionHandler;
+ protected SecurityHandler _securityHandler;
+ protected ServletHandler _servletHandler;
+ protected int _options;
+
+ /* ------------------------------------------------------------ */
+ public ServletContextHandler()
+ {
+ this(null,null,null,null,null);
+ }
+
+ /* ------------------------------------------------------------ */
+ public ServletContextHandler(int options)
+ {
+ this(null,null,options);
+ }
+
+ /* ------------------------------------------------------------ */
+ public ServletContextHandler(HandlerContainer parent, String contextPath)
+ {
+ this(parent,contextPath,null,null,null,null);
+ }
+
+ /* ------------------------------------------------------------ */
+ public ServletContextHandler(HandlerContainer parent, String contextPath, int options)
+ {
+ this(parent,contextPath,null,null,null,null);
+ _options=options;
+ }
+
+ /* ------------------------------------------------------------ */
+ public ServletContextHandler(HandlerContainer parent, String contextPath, boolean sessions, boolean security)
+ {
+ this(parent,contextPath,(sessions?SESSIONS:0)|(security?SECURITY:0));
+ }
+
+ /* ------------------------------------------------------------ */
+ public ServletContextHandler(HandlerContainer parent, SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler)
+ {
+ this(parent,null,sessionHandler,securityHandler,servletHandler,errorHandler);
+ }
+
+ /* ------------------------------------------------------------ */
+ public ServletContextHandler(HandlerContainer parent, String contextPath, SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler)
+ {
+ super((ContextHandler.Context)null);
+ _scontext = new Context();
+ _sessionHandler = sessionHandler;
+ _securityHandler = securityHandler;
+ _servletHandler = servletHandler;
+
+ if (errorHandler!=null)
+ setErrorHandler(errorHandler);
+
+ if (contextPath!=null)
+ setContextPath(contextPath);
+
+ if (parent!=null)
+ parent.addHandler(this);
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /** Get the defaultSecurityHandlerClass.
+ * @return the defaultSecurityHandlerClass
+ */
+ public Class<? extends SecurityHandler> getDefaultSecurityHandlerClass()
+ {
+ return _defaultSecurityHandlerClass;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set the defaultSecurityHandlerClass.
+ * @param defaultSecurityHandlerClass the defaultSecurityHandlerClass to set
+ */
+ public void setDefaultSecurityHandlerClass(Class<? extends SecurityHandler> defaultSecurityHandlerClass)
+ {
+ _defaultSecurityHandlerClass = defaultSecurityHandlerClass;
+ }
+
+ /* ------------------------------------------------------------ */
+ protected SessionHandler newSessionHandler()
+ {
+ return new SessionHandler();
+ }
+
+ /* ------------------------------------------------------------ */
+ protected SecurityHandler newSecurityHandler()
+ {
+ try
+ {
+ return (SecurityHandler)_defaultSecurityHandlerClass.newInstance();
+ }
+ catch(Exception e)
+ {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ protected ServletHandler newServletHandler()
+ {
+ return new ServletHandler();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Finish constructing handlers and link them together.
+ *
+ * @see org.eclipse.jetty.server.handler.ContextHandler#startContext()
+ */
+ protected void startContext() throws Exception
+ {
+ // force creation of missing handlers.
+ getSessionHandler();
+ getSecurityHandler();
+ getServletHandler();
+
+ Handler handler = _servletHandler;
+ if (_securityHandler!=null)
+ {
+ _securityHandler.setHandler(handler);
+ handler=_securityHandler;
+ }
+
+ if (_sessionHandler!=null)
+ {
+ _sessionHandler.setHandler(handler);
+ handler=_sessionHandler;
+ }
+
+ setHandler(handler);
+
+ super.startContext();
+
+ // OK to Initialize servlet handler now
+ if (_servletHandler != null && _servletHandler.isStarted())
+ _servletHandler.initialize();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the securityHandler.
+ */
+ public SecurityHandler getSecurityHandler()
+ {
+ if (_securityHandler==null && (_options&SECURITY)!=0 && !isStarted())
+ _securityHandler=newSecurityHandler();
+
+ return _securityHandler;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the servletHandler.
+ */
+ public ServletHandler getServletHandler()
+ {
+ if (_servletHandler==null && !isStarted())
+ _servletHandler=newServletHandler();
+ return _servletHandler;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the sessionHandler.
+ */
+ public SessionHandler getSessionHandler()
+ {
+ if (_sessionHandler==null && (_options&SESSIONS)!=0 && !isStarted())
+ _sessionHandler=newSessionHandler();
+ return _sessionHandler;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** conveniance method to add a servlet.
+ */
+ public ServletHolder addServlet(String className,String pathSpec)
+ {
+ return getServletHandler().addServletWithMapping(className, pathSpec);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** conveniance method to add a servlet.
+ */
+ public ServletHolder addServlet(Class<? extends Servlet> servlet,String pathSpec)
+ {
+ return getServletHandler().addServletWithMapping(servlet.getName(), pathSpec);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** conveniance method to add a servlet.
+ */
+ public void addServlet(ServletHolder servlet,String pathSpec)
+ {
+ getServletHandler().addServletWithMapping(servlet, pathSpec);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** conveniance method to add a filter
+ */
+ public void addFilter(FilterHolder holder,String pathSpec,int dispatches)
+ {
+ getServletHandler().addFilterWithMapping(holder,pathSpec,dispatches);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** convenience method to add a filter
+ */
+ public FilterHolder addFilter(Class<? extends Filter> filterClass,String pathSpec,int dispatches)
+ {
+ return getServletHandler().addFilterWithMapping(filterClass,pathSpec,dispatches);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** convenience method to add a filter
+ */
+ public FilterHolder addFilter(String filterClass,String pathSpec,int dispatches)
+ {
+ return getServletHandler().addFilterWithMapping(filterClass,pathSpec,dispatches);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param sessionHandler The sessionHandler to set.
+ */
+ public void setSessionHandler(SessionHandler sessionHandler)
+ {
+ if (isStarted())
+ throw new IllegalStateException("STARTED");
+
+ _sessionHandler = sessionHandler;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param securityHandler The {@link org.eclipse.jetty.server.handler.SecurityHandler} to set on this context.
+ */
+ public void setSecurityHandler(SecurityHandler securityHandler)
+ {
+ if (isStarted())
+ throw new IllegalStateException("STARTED");
+
+ _securityHandler = securityHandler;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param servletHandler The servletHandler to set.
+ */
+ public void setServletHandler(ServletHandler servletHandler)
+ {
+ if (isStarted())
+ throw new IllegalStateException("STARTED");
+
+ _servletHandler = servletHandler;
+ }
+
+ /* ------------------------------------------------------------ */
+ public class Context extends ContextHandler.Context
+ {
+
+ /* ------------------------------------------------------------ */
+ /*
+ * @see javax.servlet.ServletContext#getNamedDispatcher(java.lang.String)
+ */
+ public RequestDispatcher getNamedDispatcher(String name)
+ {
+ ContextHandler context=org.eclipse.jetty.servlet.ServletContextHandler.this;
+ if (_servletHandler==null || _servletHandler.getServlet(name)==null)
+ return null;
+ return new Dispatcher(context, name);
+ }
+
+
+ /* ------------------------------------------------------------ */
+ public void addFilterMappingForServletNames(String filterName, EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter, String... servletNames)
+ {
+ if (isStarted())
+ throw new IllegalStateException();
+ ServletHandler handler = ServletContextHandler.this.getServletHandler();
+ FilterMapping mapping = new FilterMapping();
+ mapping.setFilterName(filterName);
+ mapping.setServletNames(servletNames);
+ mapping.setDispatcherTypes(dispatcherTypes);
+ handler.addFilterMapping(mapping);
+ }
+
+ /* ------------------------------------------------------------ */
+ public void addServletMapping(String servletName, String[] urlPatterns)
+ {
+ if (isStarted())
+ throw new IllegalStateException();
+ ServletHandler handler = ServletContextHandler.this.getServletHandler();
+ ServletHolder holder= handler.newServletHolder();
+ holder.setName(servletName);
+ handler.addServlet(holder);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see javax.servlet.ServletContext#addFilter(java.lang.String, java.lang.Class)
+ */
+ public FilterRegistration addFilter(String filterName, Class<? extends Filter> filterClass)
+ {
+ if (isStarted())
+ throw new IllegalStateException();
+
+ final ServletHandler handler = ServletContextHandler.this.getServletHandler();
+ final FilterHolder holder= handler.newFilterHolder();
+ holder.setName(filterName);
+ holder.setHeldClass(filterClass);
+ handler.addFilter(holder);
+ return holder.getRegistration();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see javax.servlet.ServletContext#addFilter(java.lang.String, java.lang.String)
+ */
+ public FilterRegistration addFilter(String filterName, String className)
+ {
+ if (isStarted())
+ throw new IllegalStateException();
+
+ final ServletHandler handler = ServletContextHandler.this.getServletHandler();
+ final FilterHolder holder= handler.newFilterHolder();
+ holder.setName(filterName);
+ holder.setClassName(className);
+ handler.addFilter(holder);
+ return holder.getRegistration();
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see javax.servlet.ServletContext#addFilter(java.lang.String, javax.servlet.Filter)
+ */
+ public FilterRegistration addFilter(String filterName, Filter filter)
+ {
+ if (isStarted())
+ throw new IllegalStateException();
+
+ final ServletHandler handler = ServletContextHandler.this.getServletHandler();
+ final FilterHolder holder= handler.newFilterHolder();
+ holder.setName(filterName);
+ holder.setFilter(filter);
+ handler.addFilter(holder);
+ return holder.getRegistration();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see javax.servlet.ServletContext#addServlet(java.lang.String, java.lang.Class)
+ */
+ public ServletRegistration addServlet(String servletName, Class<? extends Servlet> servletClass)
+ {
+ if (!isStarting())
+ throw new IllegalStateException();
+
+ final ServletHandler handler = ServletContextHandler.this.getServletHandler();
+ final ServletHolder holder= handler.newServletHolder();
+ holder.setName(servletName);
+ holder.setHeldClass(servletClass);
+ handler.addServlet(holder);
+ return holder.getRegistration();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see javax.servlet.ServletContext#addServlet(java.lang.String, java.lang.String)
+ */
+ public ServletRegistration addServlet(String servletName, String className)
+ {
+ if (!isStarting())
+ throw new IllegalStateException();
+
+ final ServletHandler handler = ServletContextHandler.this.getServletHandler();
+ final ServletHolder holder= handler.newServletHolder();
+ holder.setName(servletName);
+ holder.setClassName(className);
+ handler.addServlet(holder);
+ return holder.getRegistration();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see javax.servlet.ServletContext#addServlet(java.lang.String, javax.servlet.Servlet)
+ */
+ public ServletRegistration addServlet(String servletName, Servlet servlet)
+ {
+ if (!isStarting())
+ throw new IllegalStateException();
+
+ final ServletHandler handler = ServletContextHandler.this.getServletHandler();
+ final ServletHolder holder= handler.newServletHolder();
+ holder.setName(servletName);
+ holder.setServlet(servlet);
+ handler.addServlet(holder);
+ return holder.getRegistration();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see javax.servlet.ServletContext#findFilterRegistration(java.lang.String)
+ */
+ public FilterRegistration findFilterRegistration(String filterName)
+ {
+ final ServletHandler handler = ServletContextHandler.this.getServletHandler();
+ final FilterHolder holder=handler.getFilter(filterName);
+ return (holder==null)?null:holder.getRegistration();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see javax.servlet.ServletContext#findServletRegistration(java.lang.String)
+ */
+ public ServletRegistration findServletRegistration(String servletName)
+ {
+ final ServletHandler handler = ServletContextHandler.this.getServletHandler();
+ final ServletHolder holder=handler.getServlet(servletName);
+ return (holder==null)?null:holder.getRegistration();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see javax.servlet.ServletContext#getDefaultSessionTrackingModes()
+ */
+ public EnumSet<SessionTrackingMode> getDefaultSessionTrackingModes()
+ {
+ return SessionHandler.DEFAULT_TRACKING;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see javax.servlet.ServletContext#getEffectiveSessionTrackingModes()
+ */
+ public EnumSet<SessionTrackingMode> getEffectiveSessionTrackingModes()
+ {
+ Log.warn("Not Implemented");
+ return null;
+ }
+
+
+
+ }
+}
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java
new file mode 100644
index 0000000000..6945e29ada
--- /dev/null
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java
@@ -0,0 +1,1370 @@
+// ========================================================================
+// Copyright (c) 1999-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.servlet;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletRequestEvent;
+import javax.servlet.ServletRequestListener;
+import javax.servlet.ServletResponse;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.PathMap;
+import org.eclipse.jetty.io.EofException;
+import org.eclipse.jetty.io.HttpException;
+import org.eclipse.jetty.security.IdentityService;
+import org.eclipse.jetty.security.SecurityHandler;
+import org.eclipse.jetty.server.Dispatcher;
+import org.eclipse.jetty.server.HttpConnection;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.RetryRequest;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.UserIdentity;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.util.LazyList;
+import org.eclipse.jetty.util.MultiException;
+import org.eclipse.jetty.util.MultiMap;
+import org.eclipse.jetty.util.URIUtil;
+import org.eclipse.jetty.util.log.Log;
+
+
+/* --------------------------------------------------------------------- */
+/** Servlet HttpHandler.
+ * This handler maps requests to servlets that implement the
+ * javax.servlet.http.HttpServlet API.
+ * <P>
+ * This handler does not implement the full J2EE features and is intended to
+ * be used when a full web application is not required. Specifically filters
+ * and request wrapping are not supported.
+ *
+ * Unless run as part of a {@link ServletContextHandler} or derivative, the {@link #initialize()}
+ * method must be called manually after start().
+ *
+ * @see org.eclipse.jetty.webapp.WebAppContext
+ *
+ */
+public class ServletHandler extends AbstractHandler
+{
+ /* ------------------------------------------------------------ */
+ public static final String __DEFAULT_SERVLET="default";
+
+ /* ------------------------------------------------------------ */
+ private ContextHandler _contextHandler;
+ private ContextHandler.Context _servletContext;
+ private FilterHolder[] _filters;
+ private FilterMapping[] _filterMappings;
+ private boolean _filterChainsCached=true;
+ private int _maxFilterChainsCacheSize=1000;
+ private boolean _startWithUnavailable=true;
+ private IdentityService<UserIdentity,?> _identityService;
+
+ private ServletHolder[] _servlets;
+ private ServletMapping[] _servletMappings;
+
+ private transient Map<String,FilterHolder> _filterNameMap= new HashMap<String,FilterHolder>();
+ private transient List<FilterMapping> _filterPathMappings;
+ private transient MultiMap<String> _filterNameMappings;
+
+ private transient Map<String,ServletHolder> _servletNameMap=new HashMap();
+ private transient PathMap _servletPathMap;
+
+ protected transient ConcurrentHashMap _chainCache[];
+
+
+ /* ------------------------------------------------------------ */
+ /** Constructor.
+ */
+ public ServletHandler()
+ {
+ }
+
+ /* ------------------------------------------------------------ */
+ /*
+ * @see org.eclipse.jetty.server.handler.AbstractHandler#setServer(org.eclipse.jetty.server.Server)
+ */
+ public void setServer(Server server)
+ {
+ if (getServer()!=null && getServer()!=server)
+ {
+ getServer().getContainer().update(this, _filters, null, "filter",true);
+ getServer().getContainer().update(this, _filterMappings, null, "filterMapping",true);
+ getServer().getContainer().update(this, _servlets, null, "servlet",true);
+ getServer().getContainer().update(this, _servletMappings, null, "servletMapping",true);
+ }
+ if (server!=null && getServer()!=server)
+ {
+ server.getContainer().update(this, null, _filters, "filter",true);
+ server.getContainer().update(this, null, _filterMappings, "filterMapping",true);
+ server.getContainer().update(this, null, _servlets, "servlet",true);
+ server.getContainer().update(this, null, _servletMappings, "servletMapping",true);
+ }
+ super.setServer(server);
+ }
+
+ /* ----------------------------------------------------------------- */
+ protected synchronized void doStart()
+ throws Exception
+ {
+ _servletContext=ContextHandler.getCurrentContext();
+ _contextHandler=_servletContext==null?null:_servletContext.getContextHandler();
+
+ if (_contextHandler!=null)
+ {
+ SecurityHandler security_handler = (SecurityHandler)_contextHandler.getChildHandlerByClass(SecurityHandler.class);
+ if (security_handler!=null)
+ _identityService=(IdentityService<UserIdentity,?>)security_handler.getIdentityService();
+ }
+
+ updateNameMappings();
+ updateMappings();
+
+ if(_filterChainsCached)
+ _chainCache= new ConcurrentHashMap[]{null,new ConcurrentHashMap(),new ConcurrentHashMap(),null,new ConcurrentHashMap(),null,null,null,new ConcurrentHashMap(),null,null,null,null,null,null,null,new ConcurrentHashMap()};
+
+ super.doStart();
+
+ if (_contextHandler==null || !(_contextHandler instanceof ServletContextHandler))
+ initialize();
+ }
+
+ /* ----------------------------------------------------------------- */
+ protected synchronized void doStop()
+ throws Exception
+ {
+ super.doStop();
+
+ // Stop filters
+ if (_filters!=null)
+ {
+ for (int i=_filters.length; i-->0;)
+ {
+ try { _filters[i].stop(); }catch(Exception e){Log.warn(Log.EXCEPTION,e);}
+ }
+ }
+
+ // Stop servlets
+ if (_servlets!=null)
+ {
+ for (int i=_servlets.length; i-->0;)
+ {
+ try { _servlets[i].stop(); }catch(Exception e){Log.warn(Log.EXCEPTION,e);}
+ }
+ }
+
+ _filterPathMappings=null;
+ _filterNameMappings=null;
+
+ _servletPathMap=null;
+ _chainCache=null;
+ }
+
+ /* ------------------------------------------------------------ */
+ IdentityService getIdentityService()
+ {
+ return _identityService;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the contextLog.
+ */
+ public Object getContextLog()
+ {
+ return null;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the filterMappings.
+ */
+ public FilterMapping[] getFilterMappings()
+ {
+ return _filterMappings;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get Filters.
+ * @return Array of defined servlets
+ */
+ public FilterHolder[] getFilters()
+ {
+ return _filters;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** ServletHolder matching path.
+ * @param pathInContext Path within _context.
+ * @return PathMap Entries pathspec to ServletHolder
+ */
+ public PathMap.Entry getHolderEntry(String pathInContext)
+ {
+ if (_servletPathMap==null)
+ return null;
+ return _servletPathMap.getMatch(pathInContext);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param uriInContext uri to get dispatcher for
+ * @return A {@link RequestDispatcher dispatcher} wrapping the resource at <code>uriInContext</code>,
+ * or <code>null</code> if the specified uri cannot be dispatched to.
+ */
+ public RequestDispatcher getRequestDispatcher(String uriInContext)
+ {
+ if (uriInContext == null)
+ return null;
+
+ if (!uriInContext.startsWith("/"))
+ return null;
+
+ try
+ {
+ String query=null;
+ int q;
+ if ((q=uriInContext.indexOf('?'))>0)
+ {
+ query=uriInContext.substring(q+1);
+ uriInContext=uriInContext.substring(0,q);
+ }
+ if ((q=uriInContext.indexOf(';'))>0)
+ uriInContext=uriInContext.substring(0,q);
+
+ String pathInContext=URIUtil.canonicalPath(URIUtil.decodePath(uriInContext));
+ String uri=URIUtil.addPaths(_contextHandler.getContextPath(), uriInContext);
+ return new Dispatcher(_contextHandler, uri, pathInContext, query);
+ }
+ catch(Exception e)
+ {
+ Log.ignore(e);
+ }
+ return null;
+ }
+
+ /* ------------------------------------------------------------ */
+ public ServletContext getServletContext()
+ {
+ return _servletContext;
+ }
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the servletMappings.
+ */
+ public ServletMapping[] getServletMappings()
+ {
+ return _servletMappings;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get Servlets.
+ * @return Array of defined servlets
+ */
+ public ServletHolder[] getServlets()
+ {
+ return _servlets;
+ }
+
+ /* ------------------------------------------------------------ */
+ public ServletHolder getServlet(String name)
+ {
+ return (ServletHolder)_servletNameMap.get(name);
+ }
+
+ /* ------------------------------------------------------------ */
+ /*
+ * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
+ */
+ public void handle(String target, HttpServletRequest request,HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ if (!isStarted())
+ return;
+
+ // Get the base requests
+ final Request base_request=(request instanceof Request)?((Request)request):HttpConnection.getCurrentConnection().getRequest();
+ final String old_servlet_name=base_request.getServletName();
+ final String old_servlet_path=base_request.getServletPath();
+ final String old_path_info=base_request.getPathInfo();
+ UserIdentity scoped_identity = null;
+
+ DispatcherType type = request.getDispatcherType();
+ Object request_listeners=null;
+ ServletRequestEvent request_event=null;
+ ServletHolder servlet_holder=null;
+ FilterChain chain=null;
+ UserIdentity old_identity=null;
+
+ // find the servlet
+ if (target.startsWith("/"))
+ {
+ // Look for the servlet by path
+ PathMap.Entry entry=getHolderEntry(target);
+ if (entry!=null)
+ {
+ servlet_holder=(ServletHolder)entry.getValue();
+
+ if(Log.isDebugEnabled())Log.debug("servlet="+servlet_holder);
+
+ String servlet_path_spec=(String)entry.getKey();
+ String servlet_path=entry.getMapped()!=null?entry.getMapped():PathMap.pathMatch(servlet_path_spec,target);
+ String path_info=PathMap.pathInfo(servlet_path_spec,target);
+
+ if (DispatcherType.INCLUDE.equals(type))
+ {
+ base_request.setAttribute(Dispatcher.__INCLUDE_SERVLET_PATH,servlet_path);
+ base_request.setAttribute(Dispatcher.__INCLUDE_PATH_INFO, path_info);
+ }
+ else
+ {
+ base_request.setServletPath(servlet_path);
+ base_request.setPathInfo(path_info);
+ }
+
+ if (servlet_holder!=null && _filterMappings!=null && _filterMappings.length>0)
+ chain=getFilterChain(base_request, target, servlet_holder);
+ }
+ }
+ else
+ {
+ // look for a servlet by name!
+ servlet_holder=(ServletHolder)_servletNameMap.get(target);
+ if (servlet_holder!=null)
+ {
+ if (_filterMappings!=null && _filterMappings.length>0)
+ {
+ chain=getFilterChain(base_request, null,servlet_holder);
+ }
+ }
+ }
+
+ if (Log.isDebugEnabled())
+ {
+ Log.debug("chain="+chain);
+ Log.debug("servlet holder="+servlet_holder);
+ }
+
+ try
+ {
+ // Do the filter/handling thang
+ if (servlet_holder==null)
+ {
+ notFound(request, response);
+ }
+ else
+ {
+ base_request.setServletName(servlet_holder.getName());
+ if (_identityService!=null)
+ {
+ old_identity=base_request.getUserIdentity();
+ scoped_identity=_identityService.associate(old_identity,servlet_holder);
+ base_request.setUserIdentity(scoped_identity);
+ }
+
+ // Handle context listeners
+ request_listeners = base_request.takeRequestListeners();
+ if (request_listeners!=null)
+ {
+ request_event = new ServletRequestEvent(getServletContext(),request);
+ final int s=LazyList.size(request_listeners);
+ for(int i=0;i<s;i++)
+ {
+ final ServletRequestListener listener = (ServletRequestListener)LazyList.get(request_listeners,i);
+ listener.requestInitialized(request_event);
+ }
+ }
+
+ base_request.setHandled(true);
+
+ if (chain!=null)
+ chain.doFilter(request, response);
+ else
+ servlet_holder.handle(base_request,request,response);
+ }
+ }
+ catch(RetryRequest e)
+ {
+ throw e;
+ }
+ catch(EofException e)
+ {
+ throw e;
+ }
+ catch(Exception e)
+ {
+ if (!(DispatcherType.REQUEST.equals(type) || DispatcherType.ASYNC.equals(type)))
+ {
+ if (e instanceof IOException)
+ throw (IOException)e;
+ if (e instanceof RuntimeException)
+ throw (RuntimeException)e;
+ if (e instanceof ServletException)
+ throw (ServletException)e;
+ }
+
+
+ // unwrap cause
+ Throwable th=e;
+ if (th instanceof UnavailableException)
+ {
+ Log.debug(th);
+ }
+ else if (th instanceof ServletException)
+ {
+ Log.debug(th);
+ Throwable cause=((ServletException)th).getRootCause();
+ if (cause!=th && cause!=null)
+ th=cause;
+ }
+
+ // handle or log exception
+ if (th instanceof RetryRequest)
+ {
+ base_request.setHandled(false);
+ throw (RetryRequest)th;
+ }
+ else if (th instanceof HttpException)
+ {
+ throw (HttpException)th;
+ }
+ else if (Log.isDebugEnabled())
+ {
+ Log.warn(request.getRequestURI(), th);
+ Log.debug(request.toString());
+ }
+ else if (th instanceof IOException || th instanceof UnavailableException)
+ {
+ Log.warn(request.getRequestURI()+": "+th);
+ }
+ else
+ {
+ Log.warn(request.getRequestURI(),th);
+ }
+
+ // TODO httpResponse.getHttpConnection().forceClose();
+ if (!response.isCommitted())
+ {
+ request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,th.getClass());
+ request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,th);
+ if (th instanceof UnavailableException)
+ {
+ UnavailableException ue = (UnavailableException)th;
+ if (ue.isPermanent())
+ response.sendError(HttpServletResponse.SC_NOT_FOUND,th.getMessage());
+ else
+ response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,th.getMessage());
+ }
+ else
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,th.getMessage());
+ }
+ else
+ if(Log.isDebugEnabled())Log.debug("Response already committed for handling "+th);
+ }
+ catch(Error e)
+ {
+ if (!(DispatcherType.REQUEST.equals(type) || DispatcherType.ASYNC.equals(type)))
+ throw e;
+ Log.warn("Error for "+request.getRequestURI(),e);
+ if(Log.isDebugEnabled())Log.debug(request.toString());
+
+ // TODO httpResponse.getHttpConnection().forceClose();
+ if (!response.isCommitted())
+ {
+ request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,e.getClass());
+ request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,e);
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,e.getMessage());
+ }
+ else
+ if(Log.isDebugEnabled())Log.debug("Response already committed for handling ",e);
+ }
+ finally
+ {
+ if (request_listeners!=null)
+ {
+ for(int i=LazyList.size(request_listeners);i-->0;)
+ {
+ final ServletRequestListener listener = (ServletRequestListener)LazyList.get(request_listeners,i);
+ listener.requestDestroyed(request_event);
+ }
+ }
+
+ if (scoped_identity!=null)
+ {
+ _identityService.disassociate(scoped_identity);
+ base_request.setUserIdentity(old_identity);
+ }
+ base_request.setServletName(old_servlet_name);
+
+ if (!(DispatcherType.INCLUDE.equals(type)))
+ {
+ base_request.setServletPath(old_servlet_path);
+ base_request.setPathInfo(old_path_info);
+ }
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ private FilterChain getFilterChain(Request baseRequest, String pathInContext, ServletHolder servletHolder)
+ {
+ String key=pathInContext==null?servletHolder.getName():pathInContext;
+ int dispatch = FilterMapping.dispatch(baseRequest.getDispatcherType());
+
+ if (_filterChainsCached && _chainCache!=null)
+ {
+ FilterChain chain = (FilterChain)_chainCache[dispatch].get(key);
+ if (chain!=null)
+ return chain;
+ }
+
+ // Build list of filters
+ Object filters= null;
+ // Path filters
+ if (pathInContext!=null && _filterPathMappings!=null)
+ {
+ for (int i= 0; i < _filterPathMappings.size(); i++)
+ {
+ FilterMapping mapping = (FilterMapping)_filterPathMappings.get(i);
+ if (mapping.appliesTo(pathInContext, dispatch))
+ filters= LazyList.add(filters, mapping.getFilterHolder());
+ }
+ }
+
+ // Servlet name filters
+ if (servletHolder != null && _filterNameMappings!=null && _filterNameMappings.size() > 0)
+ {
+ // Servlet name filters
+ if (_filterNameMappings.size() > 0)
+ {
+ Object o= _filterNameMappings.get(servletHolder.getName());
+ for (int i=0; i<LazyList.size(o);i++)
+ {
+ FilterMapping mapping = (FilterMapping)LazyList.get(o,i);
+ if (mapping.appliesTo(dispatch))
+ filters=LazyList.add(filters,mapping.getFilterHolder());
+ }
+
+ o= _filterNameMappings.get("*");
+ for (int i=0; i<LazyList.size(o);i++)
+ {
+ FilterMapping mapping = (FilterMapping)LazyList.get(o,i);
+ if (mapping.appliesTo(dispatch))
+ filters=LazyList.add(filters,mapping.getFilterHolder());
+ }
+ }
+ }
+
+ if (filters==null)
+ return null;
+
+ FilterChain chain = null;
+ if (_filterChainsCached)
+ {
+ if (LazyList.size(filters) > 0)
+ chain= new CachedChain(filters, servletHolder);
+ if (_maxFilterChainsCacheSize>0 && _chainCache[dispatch].size()>_maxFilterChainsCacheSize)
+ _chainCache[dispatch].clear();
+ _chainCache[dispatch].put(key,chain);
+ }
+ else if (LazyList.size(filters) > 0)
+ chain = new Chain(baseRequest,filters, servletHolder);
+
+ return chain;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the initializeAtStart.
+ * @deprecated
+ */
+ public boolean isInitializeAtStart()
+ {
+ return false;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param initializeAtStart The initializeAtStart to set.
+ * @deprecated
+ */
+ public void setInitializeAtStart(boolean initializeAtStart)
+ {
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return true if the handler is started and there are no unavailable servlets
+ */
+ public boolean isAvailable()
+ {
+ if (!isStarted())
+ return false;
+ ServletHolder[] holders = getServlets();
+ for (int i=0;i<holders.length;i++)
+ {
+ ServletHolder holder = holders[i];
+ if (holder!=null && !holder.isAvailable())
+ return false;
+ }
+ return true;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param start True if this handler will start with unavailable servlets
+ */
+ public void setStartWithUnavailable(boolean start)
+ {
+ _startWithUnavailable=start;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return True if this handler will start with unavailable servlets
+ */
+ public boolean isStartWithUnavailable()
+ {
+ return _startWithUnavailable;
+ }
+
+
+
+ /* ------------------------------------------------------------ */
+ /** Initialize filters and load-on-startup servlets.
+ * Called automatically from start if autoInitializeServlet is true.
+ */
+ public void initialize()
+ throws Exception
+ {
+ MultiException mx = new MultiException();
+
+ // Start filters
+ if (_filters!=null)
+ {
+ for (int i=0;i<_filters.length; i++)
+ _filters[i].start();
+ }
+
+ if (_servlets!=null)
+ {
+ // Sort and Initialize servlets
+ ServletHolder[] servlets = (ServletHolder[])_servlets.clone();
+ Arrays.sort(servlets);
+ for (int i=0; i<servlets.length; i++)
+ {
+ try
+ {
+ if (servlets[i].getClassName()==null && servlets[i].getForcedPath()!=null)
+ {
+ ServletHolder forced_holder = (ServletHolder)_servletPathMap.match(servlets[i].getForcedPath());
+ if (forced_holder==null || forced_holder.getClassName()==null)
+ {
+ mx.add(new IllegalStateException("No forced path servlet for "+servlets[i].getForcedPath()));
+ continue;
+ }
+ servlets[i].setClassName(forced_holder.getClassName());
+ }
+
+ servlets[i].start();
+ }
+ catch(Throwable e)
+ {
+ Log.debug(Log.EXCEPTION,e);
+ mx.add(e);
+ }
+ }
+ mx.ifExceptionThrow();
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the filterChainsCached.
+ */
+ public boolean isFilterChainsCached()
+ {
+ return _filterChainsCached;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * see also newServletHolder(Class)
+ */
+ public ServletHolder newServletHolder()
+ {
+ return new ServletHolder();
+ }
+
+ /* ------------------------------------------------------------ */
+ public ServletHolder newServletHolder(Class servlet)
+ {
+ return new ServletHolder(servlet);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** conveniance method to add a servlet.
+ * @return The servlet holder.
+ */
+ public ServletHolder addServletWithMapping (String className,String pathSpec)
+ {
+ ServletHolder holder = newServletHolder(null);
+ holder.setName(className+"-"+holder.hashCode());
+ holder.setClassName(className);
+
+ addServletWithMapping(holder,pathSpec);
+
+ return holder;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** conveniance method to add a servlet.
+ * @return The servlet holder.
+ */
+ public ServletHolder addServletWithMapping (Class<? extends Servlet> servlet,String pathSpec)
+ {
+ ServletHolder holder = newServletHolder(servlet);
+ setServlets((ServletHolder[])LazyList.addToArray(getServlets(), holder, ServletHolder.class));
+
+ addServletWithMapping(holder,pathSpec);
+
+ return holder;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** conveniance method to add a servlet.
+ * @param servlet servlet holder to add
+ * @param pathSpec servlet mappings for the servletHolder
+ */
+ public void addServletWithMapping (ServletHolder servlet,String pathSpec)
+ {
+ ServletHolder[] holders=getServlets();
+ if (holders!=null)
+ holders = holders.clone();
+
+ try
+ {
+ setServlets((ServletHolder[])LazyList.addToArray(holders, servlet, ServletHolder.class));
+
+ ServletMapping mapping = new ServletMapping();
+ mapping.setServletName(servlet.getName());
+ mapping.setPathSpec(pathSpec);
+ setServletMappings((ServletMapping[])LazyList.addToArray(getServletMappings(), mapping, ServletMapping.class));
+ }
+ catch (Exception e)
+ {
+ setServlets(holders);
+ if (e instanceof RuntimeException)
+ throw (RuntimeException)e;
+ throw new RuntimeException(e);
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Convenience method to add a servlet with a servlet mapping.
+ * @param className
+ * @param pathSpec
+ * @return
+ * @deprecated
+ */
+ public ServletHolder addServlet (String className, String pathSpec)
+ {
+ return addServletWithMapping (className, pathSpec);
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /**Convenience method to add a pre-constructed ServletHolder.
+ * @param holder
+ */
+ public void addServlet(ServletHolder holder)
+ {
+ setServlets((ServletHolder[])LazyList.addToArray(getServlets(), holder, ServletHolder.class));
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Convenience method to add a pre-constructed ServletMapping.
+ * @param mapping
+ */
+ public void addServletMapping (ServletMapping mapping)
+ {
+ setServletMappings((ServletMapping[])LazyList.addToArray(getServletMappings(), mapping, ServletMapping.class));
+ }
+
+ /* ------------------------------------------------------------ */
+ public FilterHolder newFilterHolder(Class<? extends Filter> filter)
+ {
+ return new FilterHolder(filter);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see {@link #newFilterHolder(Class)}
+ */
+ public FilterHolder newFilterHolder()
+ {
+ return new FilterHolder();
+ }
+
+ /* ------------------------------------------------------------ */
+ public FilterHolder getFilter(String name)
+ {
+ return (FilterHolder)_filterNameMap.get(name);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** conveniance method to add a filter.
+ * @param filter class of filter to create
+ * @param pathSpec filter mappings for filter
+ * @param dispatches see {@link FilterMapping#setDispatches(int)}
+ * @return The filter holder.
+ */
+ public FilterHolder addFilterWithMapping (Class<? extends Filter> filter,String pathSpec,int dispatches)
+ {
+ FilterHolder holder = newFilterHolder(filter);
+ addFilterWithMapping(holder,pathSpec,dispatches);
+
+ return holder;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** conveniance method to add a filter.
+ * @param className of filter
+ * @param pathSpec filter mappings for filter
+ * @param dispatches see {@link FilterMapping#setDispatches(int)}
+ * @return The filter holder.
+ */
+ public FilterHolder addFilterWithMapping (String className,String pathSpec,int dispatches)
+ {
+ FilterHolder holder = newFilterHolder(null);
+ holder.setName(className+"-"+holder.hashCode());
+ holder.setClassName(className);
+
+ addFilterWithMapping(holder,pathSpec,dispatches);
+ return holder;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** conveniance method to add a filter.
+ * @param holder filter holder to add
+ * @param pathSpec filter mappings for filter
+ * @param dispatches see {@link FilterMapping#setDispatches(int)}
+ */
+ public void addFilterWithMapping (FilterHolder holder,String pathSpec,int dispatches)
+ {
+ FilterHolder[] holders = getFilters();
+ if (holders!=null)
+ holders = (FilterHolder[])holders.clone();
+
+ try
+ {
+ setFilters((FilterHolder[])LazyList.addToArray(holders, holder, FilterHolder.class));
+
+ FilterMapping mapping = new FilterMapping();
+ mapping.setFilterName(holder.getName());
+ mapping.setPathSpec(pathSpec);
+ mapping.setDispatches(dispatches);
+ setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), mapping, FilterMapping.class));
+ }
+ catch (RuntimeException e)
+ {
+ setFilters(holders);
+ throw e;
+ }
+ catch (Error e)
+ {
+ setFilters(holders);
+ throw e;
+ }
+
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Convenience method to add a filter with a mapping
+ * @param className
+ * @param pathSpec
+ * @param dispatches
+ * @return
+ * @deprecated
+ */
+ public FilterHolder addFilter (String className,String pathSpec,int dispatches)
+ {
+ return addFilterWithMapping(className, pathSpec, dispatches);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * convenience method to add a filter and mapping
+ * @param filter
+ * @param filterMapping
+ */
+ public void addFilter (FilterHolder filter, FilterMapping filterMapping)
+ {
+ if (filter != null)
+ setFilters((FilterHolder[])LazyList.addToArray(getFilters(), filter, FilterHolder.class));
+ if (filterMapping != null)
+ setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), filterMapping, FilterMapping.class));
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Convenience method to add a preconstructed FilterHolder
+ * @param filter
+ */
+ public void addFilter (FilterHolder filter)
+ {
+ if (filter != null)
+ setFilters((FilterHolder[])LazyList.addToArray(getFilters(), filter, FilterHolder.class));
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Convenience method to add a preconstructed FilterMapping
+ * @param mapping
+ */
+ public void addFilterMapping (FilterMapping mapping)
+ {
+ if (mapping != null)
+ setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), mapping, FilterMapping.class));
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Convenience method to add a preconstructed FilterMapping
+ * @param mapping
+ */
+ public void prependFilterMapping (FilterMapping mapping)
+ {
+ if (mapping != null)
+ {
+ FilterMapping[] mappings =getFilterMappings();
+ if (mappings==null || mappings.length==0)
+ setFilterMappings(new FilterMapping[] {mapping});
+ else
+ {
+
+ FilterMapping[] new_mappings=new FilterMapping[mappings.length+1];
+ System.arraycopy(mappings,0,new_mappings,1,mappings.length);
+ new_mappings[0]=mapping;
+ setFilterMappings(new_mappings);
+ }
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ protected synchronized void updateNameMappings()
+ {
+ // update filter name map
+ _filterNameMap.clear();
+ if (_filters!=null)
+ {
+ for (int i=0;i<_filters.length;i++)
+ {
+ _filterNameMap.put(_filters[i].getName(),_filters[i]);
+ _filters[i].setServletHandler(this);
+ }
+ }
+
+ // Map servlet names to holders
+ _servletNameMap.clear();
+ if (_servlets!=null)
+ {
+ // update the maps
+ for (int i=0;i<_servlets.length;i++)
+ {
+ _servletNameMap.put(_servlets[i].getName(),_servlets[i]);
+ _servlets[i].setServletHandler(this);
+ }
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ protected synchronized void updateMappings()
+ {
+ // update filter mappings
+ if (_filterMappings==null)
+ {
+ _filterPathMappings=null;
+ _filterNameMappings=null;
+ }
+ else
+ {
+ _filterPathMappings=new ArrayList();
+ _filterNameMappings=new MultiMap();
+ for (int i=0;i<_filterMappings.length;i++)
+ {
+ FilterHolder filter_holder = (FilterHolder)_filterNameMap.get(_filterMappings[i].getFilterName());
+ if (filter_holder==null)
+ throw new IllegalStateException("No filter named "+_filterMappings[i].getFilterName());
+ _filterMappings[i].setFilterHolder(filter_holder);
+ if (_filterMappings[i].getPathSpecs()!=null)
+ _filterPathMappings.add(_filterMappings[i]);
+
+ if (_filterMappings[i].getServletNames()!=null)
+ {
+ String[] names=_filterMappings[i].getServletNames();
+ for (int j=0;j<names.length;j++)
+ {
+ if (names[j]!=null)
+ _filterNameMappings.add(names[j], _filterMappings[i]);
+ }
+ }
+ }
+ }
+
+ // Map servlet paths to holders
+ if (_servletMappings==null || _servletNameMap==null)
+ {
+ _servletPathMap=null;
+ }
+ else
+ {
+ PathMap pm = new PathMap();
+
+ // update the maps
+ for (int i=0;i<_servletMappings.length;i++)
+ {
+ ServletHolder servlet_holder = (ServletHolder)_servletNameMap.get(_servletMappings[i].getServletName());
+ if (servlet_holder==null)
+ throw new IllegalStateException("No such servlet: "+_servletMappings[i].getServletName());
+ else if (_servletMappings[i].getPathSpecs()!=null)
+ {
+ String[] pathSpecs = _servletMappings[i].getPathSpecs();
+ for (int j=0;j<pathSpecs.length;j++)
+ if (pathSpecs[j]!=null)
+ pm.put(pathSpecs[j],servlet_holder);
+ }
+ }
+
+ _servletPathMap=pm;
+ }
+
+
+
+ if (Log.isDebugEnabled())
+ {
+ Log.debug("filterNameMap="+_filterNameMap);
+ Log.debug("pathFilters="+_filterPathMappings);
+ Log.debug("servletFilterMap="+_filterNameMappings);
+ Log.debug("servletPathMap="+_servletPathMap);
+ Log.debug("servletNameMap="+_servletNameMap);
+ }
+
+ try
+ {
+ if (isStarted())
+ initialize();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ protected void notFound(HttpServletRequest request,
+ HttpServletResponse response)
+ throws IOException
+ {
+ if(Log.isDebugEnabled())Log.debug("Not Found "+request.getRequestURI());
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param filterChainsCached The filterChainsCached to set.
+ */
+ public void setFilterChainsCached(boolean filterChainsCached)
+ {
+ _filterChainsCached = filterChainsCached;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param filterMappings The filterMappings to set.
+ */
+ public void setFilterMappings(FilterMapping[] filterMappings)
+ {
+ if (getServer()!=null)
+ getServer().getContainer().update(this,_filterMappings,filterMappings,"filterMapping",true);
+ _filterMappings = filterMappings;
+ updateMappings();
+ }
+
+ /* ------------------------------------------------------------ */
+ public synchronized void setFilters(FilterHolder[] holders)
+ {
+ if (getServer()!=null)
+ getServer().getContainer().update(this,_filters,holders,"filter",true);
+ _filters=holders;
+ updateNameMappings();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param servletMappings The servletMappings to set.
+ */
+ public void setServletMappings(ServletMapping[] servletMappings)
+ {
+ if (getServer()!=null)
+ getServer().getContainer().update(this,_servletMappings,servletMappings,"servletMapping",true);
+ _servletMappings = servletMappings;
+ updateMappings();
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set Servlets.
+ * @param holders Array of servletsto define
+ */
+ public synchronized void setServlets(ServletHolder[] holders)
+ {
+ if (getServer()!=null)
+ getServer().getContainer().update(this,_servlets,holders,"servlet",true);
+ _servlets=holders;
+ updateNameMappings();
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ private class CachedChain implements FilterChain
+ {
+ FilterHolder _filterHolder;
+ CachedChain _next;
+ ServletHolder _servletHolder;
+
+ /* ------------------------------------------------------------ */
+ CachedChain(Object filters, ServletHolder servletHolder)
+ {
+ if (LazyList.size(filters)>0)
+ {
+ _filterHolder=(FilterHolder)LazyList.get(filters, 0);
+ filters=LazyList.remove(filters,0);
+ _next=new CachedChain(filters,servletHolder);
+ }
+ else
+ _servletHolder=servletHolder;
+ }
+
+ /* ------------------------------------------------------------ */
+ public void doFilter(ServletRequest request, ServletResponse response)
+ throws IOException, ServletException
+ {
+ // pass to next filter
+ if (_filterHolder!=null)
+ {
+ if (Log.isDebugEnabled())
+ Log.debug("call filter " + _filterHolder);
+ Filter filter= _filterHolder.getFilter();
+ if (_filterHolder.isAsyncSupported())
+ filter.doFilter(request, response, _next);
+ else
+ {
+ final Request base_request=(request instanceof Request)?((Request)request):HttpConnection.getCurrentConnection().getRequest();
+ final boolean suspendable=base_request.isAsyncSupported();
+ if (suspendable)
+ {
+ try
+ {
+ base_request.setAsyncSupported(false);
+ filter.doFilter(request, response, _next);
+ }
+ finally
+ {
+ base_request.setAsyncSupported(true);
+ }
+ }
+ else
+ filter.doFilter(request, response, _next);
+ }
+ return;
+ }
+
+ // Call servlet
+ if (_servletHolder != null)
+ {
+ if (Log.isDebugEnabled())
+ Log.debug("call servlet " + _servletHolder);
+ final Request base_request=(request instanceof Request)?((Request)request):HttpConnection.getCurrentConnection().getRequest();
+ _servletHolder.handle(base_request,request, response);
+ }
+ else // Not found
+ notFound((HttpServletRequest)request, (HttpServletResponse)response);
+ }
+
+ public String toString()
+ {
+ if (_filterHolder!=null)
+ return _filterHolder+"->"+_next.toString();
+ if (_servletHolder!=null)
+ return _servletHolder.toString();
+ return "null";
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ private class Chain implements FilterChain
+ {
+ final Request _baseRequest;
+ final Object _chain;
+ final ServletHolder _servletHolder;
+ int _filter= 0;
+
+ /* ------------------------------------------------------------ */
+ Chain(Request baseRequest, Object filters, ServletHolder servletHolder)
+ {
+ _baseRequest=baseRequest;
+ _chain= filters;
+ _servletHolder= servletHolder;
+ }
+
+ /* ------------------------------------------------------------ */
+ public void doFilter(ServletRequest request, ServletResponse response)
+ throws IOException, ServletException
+ {
+ if (Log.isDebugEnabled()) Log.debug("doFilter " + _filter);
+
+ // pass to next filter
+ if (_filter < LazyList.size(_chain))
+ {
+ FilterHolder holder= (FilterHolder)LazyList.get(_chain, _filter++);
+ if (Log.isDebugEnabled()) Log.debug("call filter " + holder);
+ Filter filter= holder.getFilter();
+
+ if (holder.isAsyncSupported() || !_baseRequest.isAsyncSupported())
+ {
+ filter.doFilter(request, response, this);
+ }
+ else
+ {
+ try
+ {
+ _baseRequest.setAsyncSupported(false);
+ filter.doFilter(request, response, this);
+ }
+ finally
+ {
+ _baseRequest.setAsyncSupported(true);
+ }
+ }
+
+ return;
+ }
+
+ // Call servlet
+ if (_servletHolder != null)
+ {
+ if (Log.isDebugEnabled()) Log.debug("call servlet " + _servletHolder);
+ _servletHolder.handle(_baseRequest,request, response);
+ }
+ else // Not found
+ notFound((HttpServletRequest)request, (HttpServletResponse)response);
+ }
+
+ /* ------------------------------------------------------------ */
+ public String toString()
+ {
+ StringBuilder b = new StringBuilder();
+ for (int i=0; i<LazyList.size(_chain);i++)
+ {
+ Object o=LazyList.get(_chain, i);
+ b.append(o.toString());
+ b.append("->");
+ }
+ b.append(_servletHolder);
+ return b.toString();
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return The maximum entries in a filter chain cache.
+ */
+ public int getMaxFilterChainsCacheSize()
+ {
+ return _maxFilterChainsCacheSize;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set the maximum filter chain cache size.
+ * Filter chains are cached if {@link #isFilterChainsCached()} is true. If the max cache size
+ * is greater than zero, then the cache is flushed whenever it grows to be this size.
+ *
+ * @param maxFilterChainsCacheSize the maximum number of entries in a filter chain cache.
+ */
+ public void setMaxFilterChainsCacheSize(int maxFilterChainsCacheSize)
+ {
+ _maxFilterChainsCacheSize = maxFilterChainsCacheSize;
+ }
+
+ /**
+ * Customize a servlet.
+ *
+ * Called before the servlet goes into service.
+ * Subclasses of ServletHandler should override
+ * this method.
+ *
+ * @param servlet
+ * @return
+ * @throws Exception
+ */
+ public Servlet customizeServlet (Servlet servlet)
+ throws Exception
+ {
+ return servlet;
+ }
+
+
+ public Servlet customizeServletDestroy (Servlet servlet)
+ throws Exception
+ {
+ return servlet;
+ }
+
+
+ /**
+ * Customize a Filter.
+ *
+ * Called before the Filter goes into service.
+ * Subclasses of ServletHandler should override
+ * this method.
+ *
+ * @param filter
+ * @return
+ * @throws Exception
+ */
+ public Filter customizeFilter (Filter filter)
+ throws Exception
+ {
+ return filter;
+ }
+
+
+ public Filter customizeFilterDestroy (Filter filter)
+ throws Exception
+ {
+ return filter;
+ }
+}
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java
new file mode 100644
index 0000000000..d37504fe4f
--- /dev/null
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java
@@ -0,0 +1,685 @@
+// ========================================================================
+// Copyright (c) 1999-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.servlet;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Stack;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.SingleThreadModel;
+import javax.servlet.UnavailableException;
+
+import org.eclipse.jetty.security.IdentityService;
+import org.eclipse.jetty.security.RunAsToken;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.UserIdentity;
+import org.eclipse.jetty.util.log.Log;
+
+
+
+
+/* --------------------------------------------------------------------- */
+/** Servlet Instance and Context Holder.
+ * Holds the name, params and some state of a javax.servlet.Servlet
+ * instance. It implements the ServletConfig interface.
+ * This class will organise the loading of the servlet when needed or
+ * requested.
+ *
+ *
+ */
+public class ServletHolder extends Holder implements UserIdentity.Scope, Comparable
+{
+ /* ---------------------------------------------------------------- */
+ private int _initOrder;
+ private boolean _initOnStartup=false;
+ private Map<String, String> _roleMap;
+ private String _forcedPath;
+ private String _runAsRole;
+ private RunAsToken _runAsToken;
+ private IdentityService _identityService;
+
+
+ private transient Servlet _servlet;
+ private transient Config _config;
+ private transient long _unavailable;
+ private transient UnavailableException _unavailableEx;
+ public static final Map<String,String> NO_MAPPED_ROLES = Collections.emptyMap();
+
+ /* ---------------------------------------------------------------- */
+ /** Constructor .
+ */
+ public ServletHolder()
+ {}
+
+ /* ---------------------------------------------------------------- */
+ /** Constructor for existing servlet.
+ */
+ public ServletHolder(Servlet servlet)
+ {
+ setServlet(servlet);
+ }
+
+ /* ---------------------------------------------------------------- */
+ /** Constructor for existing servlet.
+ */
+ public ServletHolder(Class servlet)
+ {
+ super(servlet);
+ }
+
+ /* ---------------------------------------------------------------- */
+ /**
+ * @return The unavailable exception or null if not unavailable
+ */
+ public UnavailableException getUnavailableException()
+ {
+ return _unavailableEx;
+ }
+
+ /* ------------------------------------------------------------ */
+ public synchronized void setServlet(Servlet servlet)
+ {
+ if (servlet==null || servlet instanceof SingleThreadModel)
+ throw new IllegalArgumentException();
+
+ _extInstance=true;
+ _servlet=servlet;
+ setHeldClass(servlet.getClass());
+ if (getName()==null)
+ setName(servlet.getClass().getName()+"-"+super.hashCode());
+ }
+
+ /* ------------------------------------------------------------ */
+ public int getInitOrder()
+ {
+ return _initOrder;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set the initialize order.
+ * Holders with order<0, are initialized on use. Those with
+ * order>=0 are initialized in increasing order when the handler
+ * is started.
+ */
+ public void setInitOrder(int order)
+ {
+ _initOnStartup=true;
+ _initOrder = order;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Comparitor by init order.
+ */
+ public int compareTo(Object o)
+ {
+ if (o instanceof ServletHolder)
+ {
+ ServletHolder sh= (ServletHolder)o;
+ if (sh==this)
+ return 0;
+ if (sh._initOrder<_initOrder)
+ return 1;
+ if (sh._initOrder>_initOrder)
+ return -1;
+
+ int c=(_className!=null && sh._className!=null)?_className.compareTo(sh._className):0;
+ if (c==0)
+ c=_name.compareTo(sh._name);
+ if (c==0)
+ c=this.hashCode()>o.hashCode()?1:-1;
+ return c;
+ }
+ return 1;
+ }
+
+ /* ------------------------------------------------------------ */
+ public boolean equals(Object o)
+ {
+ return compareTo(o)==0;
+ }
+
+ /* ------------------------------------------------------------ */
+ public int hashCode()
+ {
+ return _name==null?System.identityHashCode(this):_name.hashCode();
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Link a user role.
+ * Translate the role name used by a servlet, to the link name
+ * used by the container.
+ * @param name The role name as used by the servlet
+ * @param link The role name as used by the container.
+ */
+ public synchronized void setUserRoleLink(String name,String link)
+ {
+ if (_roleMap==null)
+ _roleMap=new HashMap<String, String>();
+ _roleMap.put(name,link);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** get a user role link.
+ * @param name The name of the role
+ * @return The name as translated by the link. If no link exists,
+ * the name is returned.
+ */
+ public String getUserRoleLink(String name)
+ {
+ if (_roleMap==null)
+ return name;
+ String link= _roleMap.get(name);
+ return (link==null)?name:link;
+ }
+
+ /* ------------------------------------------------------------ */
+ public Map<String, String> getRoleMap()
+ {
+ return _roleMap == null? NO_MAPPED_ROLES : _roleMap;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the forcedPath.
+ */
+ public String getForcedPath()
+ {
+ return _forcedPath;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param forcedPath The forcedPath to set.
+ */
+ public void setForcedPath(String forcedPath)
+ {
+ _forcedPath = forcedPath;
+ }
+
+ /* ------------------------------------------------------------ */
+ public void doStart()
+ throws Exception
+ {
+ _unavailable=0;
+ try
+ {
+ super.doStart();
+ checkServletType();
+ }
+ catch (UnavailableException ue)
+ {
+ makeUnavailable(ue);
+ }
+
+ _identityService = _servletHandler.getIdentityService();
+ if (_identityService!=null && _runAsRole!=null)
+ _runAsToken=_identityService.newRunAsToken(_runAsRole);
+
+ _config=new Config();
+
+ if (_class!=null && javax.servlet.SingleThreadModel.class.isAssignableFrom(_class))
+ _servlet = new SingleThreadedWrapper();
+
+ if (_extInstance || _initOnStartup)
+ {
+ try
+ {
+ initServlet();
+ }
+ catch(Exception e)
+ {
+ if (_servletHandler.isStartWithUnavailable())
+ Log.ignore(e);
+ else
+ throw e;
+ }
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ public void doStop()
+ {
+ Object old_run_as = null;
+ if (_servlet!=null)
+ {
+ try
+ {
+ if (_identityService!=null && _runAsToken!=null)
+ old_run_as=_identityService.associateRunAs(_runAsToken);
+
+ destroyInstance(_servlet);
+ }
+ catch (Exception e)
+ {
+ Log.warn(e);
+ }
+ finally
+ {
+ if (_identityService!=null && _runAsToken!=null)
+ _identityService.disassociateRunAs(old_run_as);
+ }
+ }
+
+ if (!_extInstance)
+ _servlet=null;
+
+ _config=null;
+ }
+
+ /* ------------------------------------------------------------ */
+ public void destroyInstance (Object o)
+ throws Exception
+ {
+ if (o==null)
+ return;
+ Servlet servlet = ((Servlet)o);
+ servlet.destroy();
+ getServletHandler().customizeServletDestroy(servlet);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get the servlet.
+ * @return The servlet
+ */
+ public synchronized Servlet getServlet()
+ throws ServletException
+ {
+ // Handle previous unavailability
+ if (_unavailable!=0)
+ {
+ if (_unavailable<0 || _unavailable>0 && System.currentTimeMillis()<_unavailable)
+ throw _unavailableEx;
+ _unavailable=0;
+ _unavailableEx=null;
+ }
+
+ if (_servlet==null)
+ initServlet();
+ return _servlet;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Check to ensure class of servlet is acceptable.
+ * @throws UnavailableException
+ */
+ public void checkServletType ()
+ throws UnavailableException
+ {
+ if (_class==null || !javax.servlet.Servlet.class.isAssignableFrom(_class))
+ {
+ throw new UnavailableException("Servlet "+_class+" is not a javax.servlet.Servlet");
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return true if the holder is started and is not unavailable
+ */
+ public boolean isAvailable()
+ {
+ if (isStarted()&& _unavailable==0)
+ return true;
+ try
+ {
+ getServlet();
+ }
+ catch(Exception e)
+ {
+ Log.ignore(e);
+ }
+
+ return isStarted()&& _unavailable==0;
+ }
+
+ /* ------------------------------------------------------------ */
+ private void makeUnavailable(UnavailableException e)
+ {
+ if (_unavailableEx==e && _unavailable!=0)
+ return;
+
+ _servletHandler.getServletContext().log("unavailable",e);
+
+ _unavailableEx=e;
+ _unavailable=-1;
+ if (e.isPermanent())
+ _unavailable=-1;
+ else
+ {
+ if (_unavailableEx.getUnavailableSeconds()>0)
+ _unavailable=System.currentTimeMillis()+1000*_unavailableEx.getUnavailableSeconds();
+ else
+ _unavailable=System.currentTimeMillis()+5000; // TODO configure
+ }
+ }
+
+
+ /* ------------------------------------------------------------ */
+
+ private void makeUnavailable(Throwable e)
+ {
+ if (e instanceof UnavailableException)
+ makeUnavailable((UnavailableException)e);
+ else
+ {
+ _servletHandler.getServletContext().log("unavailable",e);
+ _unavailableEx=new UnavailableException(e.toString(),-1);
+ _unavailable=-1;
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ private void initServlet()
+ throws ServletException
+ {
+ Object old_run_as = null;
+ try
+ {
+ if (_servlet==null)
+ _servlet=(Servlet)newInstance();
+ if (_config==null)
+ _config=new Config();
+
+ //handle any cusomizations of the servlet, such as @postConstruct
+ if (!(_servlet instanceof SingleThreadedWrapper))
+ _servlet = getServletHandler().customizeServlet(_servlet);
+
+ // Handle run as
+ if (_identityService!=null && _runAsToken!=null)
+ {
+ old_run_as=_identityService.associateRunAs(_runAsToken);
+ }
+
+ _servlet.init(_config);
+ }
+ catch (UnavailableException e)
+ {
+ makeUnavailable(e);
+ _servlet=null;
+ _config=null;
+ throw e;
+ }
+ catch (ServletException e)
+ {
+ makeUnavailable(e.getCause()==null?e:e.getCause());
+ _servlet=null;
+ _config=null;
+ throw e;
+ }
+ catch (Exception e)
+ {
+ makeUnavailable(e);
+ _servlet=null;
+ _config=null;
+ throw new ServletException(this.toString(),e);
+ }
+ finally
+ {
+ // pop run-as role
+ if (_identityService!=null && _runAsToken!=null)
+ _identityService.disassociateRunAs(old_run_as);
+ }
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see org.eclipse.jetty.server.UserIdentity.Scope#getContextPath()
+ */
+ public String getContextPath()
+ {
+ return _config.getServletContext().getContextPath();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see org.eclipse.jetty.server.UserIdentity.Scope#getRoleRefMap()
+ */
+ public Map<String, String> getRoleRefMap()
+ {
+ return _roleMap;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see org.eclipse.jetty.server.UserIdentity.Scope#getRunAsRole()
+ */
+ public String getRunAsRole()
+ {
+ return _runAsRole;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Set the run-as role for this servlet
+ * @param role run-as role for this servlet
+ */
+ public void setRunAsRole(String role)
+ {
+ _runAsRole=role;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Service a request with this servlet.
+ */
+ public void handle(Request baseRequest,
+ ServletRequest request,
+ ServletResponse response)
+ throws ServletException,
+ UnavailableException,
+ IOException
+ {
+ if (_class==null)
+ throw new UnavailableException("Servlet Not Initialized");
+
+ Servlet servlet=_servlet;
+ synchronized(this)
+ {
+ if (_unavailable!=0 || !_initOnStartup)
+ servlet=getServlet();
+ if (servlet==null)
+ throw new UnavailableException("Could not instantiate "+_class);
+ }
+
+ // Service the request
+ boolean servlet_error=true;
+ Object old_run_as = null;
+ boolean suspendable = baseRequest.isAsyncSupported();
+ try
+ {
+ // Handle aliased path
+ if (_forcedPath!=null)
+ // TODO complain about poor naming to the Jasper folks
+ request.setAttribute("org.apache.catalina.jsp_file",_forcedPath);
+
+ // Handle run as
+ if (_identityService!=null && _runAsToken!=null)
+ old_run_as=_identityService.associateRunAs(_runAsToken);
+
+ if (!isAsyncSupported())
+ baseRequest.setAsyncSupported(false);
+
+ servlet.service(request,response);
+ servlet_error=false;
+ }
+ catch(UnavailableException e)
+ {
+ makeUnavailable(e);
+ throw _unavailableEx;
+ }
+ finally
+ {
+ baseRequest.setAsyncSupported(suspendable);
+
+ // pop run-as role
+ if (_identityService!=null && _runAsToken!=null)
+ _identityService.disassociateRunAs(old_run_as);
+
+ // Handle error params.
+ if (servlet_error)
+ request.setAttribute("javax.servlet.error.servlet_name",getName());
+ }
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ protected class Config extends HolderConfig implements ServletConfig
+ {
+ /* -------------------------------------------------------- */
+ public String getServletName()
+ {
+ return getName();
+ }
+
+ }
+
+ /* -------------------------------------------------------- */
+ /* -------------------------------------------------------- */
+ /* -------------------------------------------------------- */
+ protected class Registration extends HolderRegistration implements ServletRegistration
+ {
+ public boolean addMapping(String... urlPatterns)
+ {
+ illegalStateIfContextStarted();
+ ServletMapping mapping = new ServletMapping();
+ mapping.setServletName(ServletHolder.this.getName());
+ mapping.setPathSpecs(urlPatterns);
+ _servletHandler.addServletMapping(mapping);
+ return true;
+ }
+
+ public boolean setLoadOnStartup(int loadOnStartup)
+ {
+ illegalStateIfContextStarted();
+ ServletHolder.this.setInitOrder(loadOnStartup);
+ return false;
+ }
+ }
+
+ public ServletRegistration getRegistration()
+ {
+ return new Registration();
+ }
+
+ /* -------------------------------------------------------- */
+ /* -------------------------------------------------------- */
+ /* -------------------------------------------------------- */
+ private class SingleThreadedWrapper implements Servlet
+ {
+ Stack _stack=new Stack();
+
+ public void destroy()
+ {
+ synchronized(this)
+ {
+ while(_stack.size()>0)
+ try { ((Servlet)_stack.pop()).destroy(); } catch (Exception e) { Log.warn(e); }
+ }
+ }
+
+ public ServletConfig getServletConfig()
+ {
+ return _config;
+ }
+
+ public String getServletInfo()
+ {
+ return null;
+ }
+
+ public void init(ServletConfig config) throws ServletException
+ {
+ synchronized(this)
+ {
+ if(_stack.size()==0)
+ {
+ try
+ {
+ Servlet s = (Servlet) newInstance();
+ s = getServletHandler().customizeServlet(s);
+ s.init(config);
+ _stack.push(s);
+ }
+ catch (ServletException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new ServletException(e);
+ }
+ }
+ }
+ }
+
+ public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
+ {
+ Servlet s;
+ synchronized(this)
+ {
+ if(_stack.size()>0)
+ s=(Servlet)_stack.pop();
+ else
+ {
+ try
+ {
+ s = (Servlet) newInstance();
+ s = getServletHandler().customizeServlet(s);
+ s.init(_config);
+ }
+ catch (ServletException e)
+ {
+ throw e;
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new ServletException(e);
+ }
+ }
+ }
+
+ try
+ {
+ s.service(req,res);
+ }
+ finally
+ {
+ synchronized(this)
+ {
+ _stack.push(s);
+ }
+ }
+ }
+
+ }
+}
+
+
+
+
+
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletMapping.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletMapping.java
new file mode 100644
index 0000000000..88ecb0963a
--- /dev/null
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletMapping.java
@@ -0,0 +1,80 @@
+// ========================================================================
+// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.servlet;
+
+import java.util.Arrays;
+
+
+public class ServletMapping
+{
+ private String[] _pathSpecs;
+ private String _servletName;
+
+ /* ------------------------------------------------------------ */
+ public ServletMapping()
+ {
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the pathSpec.
+ */
+ public String[] getPathSpecs()
+ {
+ return _pathSpecs;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the servletName.
+ */
+ public String getServletName()
+ {
+ return _servletName;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param pathSpec The pathSpec to set.
+ */
+ public void setPathSpecs(String[] pathSpecs)
+ {
+ _pathSpecs = pathSpecs;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param pathSpec The pathSpec to set.
+ */
+ public void setPathSpec(String pathSpec)
+ {
+ _pathSpecs = new String[]{pathSpec};
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param servletName The servletName to set.
+ */
+ public void setServletName(String servletName)
+ {
+ _servletName = servletName;
+ }
+
+
+ /* ------------------------------------------------------------ */
+ public String toString()
+ {
+ return "(S="+_servletName+","+(_pathSpecs==null?"[]":Arrays.asList(_pathSpecs).toString())+")";
+ }
+}
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/StatisticsServlet.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/StatisticsServlet.java
new file mode 100644
index 0000000000..bad7293cb4
--- /dev/null
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/StatisticsServlet.java
@@ -0,0 +1,240 @@
+package org.eclipse.jetty.servlet;
+
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.StatisticsHandler;
+import org.eclipse.jetty.util.log.Log;
+
+public class StatisticsServlet extends HttpServlet
+{
+ boolean _restrictToLocalhost = true; // defaults to true
+ private Server _server = null;
+ private StatisticsHandler _statsHandler;
+ private MemoryMXBean _memoryBean;
+ private Connector[] _connectors;
+
+ public void init() throws ServletException
+ {
+ _memoryBean = ManagementFactory.getMemoryMXBean();
+
+ ServletContext context = getServletContext();
+ ContextHandler.Context scontext = (ContextHandler.Context) context;
+ _server = scontext.getContextHandler().getServer();
+
+ Handler handler = _server.getChildHandlerByClass(StatisticsHandler.class);
+
+ if (handler != null)
+ {
+ _statsHandler = (StatisticsHandler) handler;
+ }
+ else
+ {
+ Log.info("Installing Statistics Handler");
+ _statsHandler = new StatisticsHandler();
+ _server.addHandler(_statsHandler);
+ }
+
+
+ _connectors = _server.getConnectors();
+
+ if (getInitParameter("restrictToLocalhost") != null)
+ {
+ _restrictToLocalhost = "true".equals(getInitParameter("restrictToLocalhost"));
+ }
+
+ }
+
+ public void doPost(HttpServletRequest sreq, HttpServletResponse sres) throws ServletException, IOException
+ {
+ doGet(sreq, sres);
+ }
+
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+
+ if (_restrictToLocalhost)
+ {
+ if (!"127.0.0.1".equals(req.getRemoteAddr()))
+ {
+ resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+ return;
+ }
+ }
+
+ if (req.getParameter("xml") != null && "true".equals(req.getParameter("xml")))
+ {
+ sendXmlResponse(resp);
+ } else
+ {
+ sendTextResponse(resp);
+ }
+
+ }
+
+ private void sendXmlResponse(HttpServletResponse response) throws IOException
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("<statistics>\n");
+
+ sb.append(" <requests>\n");
+ sb.append(" <statsOnMs>").append(_statsHandler.getStatsOnMs()).append("</statsOnMs>\n");
+ sb.append(" <requests>").append(_statsHandler.getRequests()).append("</requests>\n");
+ sb.append(" <requestsTimedout>").append(_statsHandler.getRequestsTimedout()).append("</requestsTimedout>\n");
+ sb.append(" <requestsResumed>").append(_statsHandler.getRequestsResumed()).append("</requestsResumed>\n");
+ sb.append(" <requestsActive>").append(_statsHandler.getRequestsActive()).append("</requestsActive>\n");
+ sb.append(" <requestsActiveMin>").append(_statsHandler.getRequestsActiveMin()).append("</requestsActiveMin>\n");
+ sb.append(" <requestsActiveMax>").append(_statsHandler.getRequestsActiveMax()).append("</requestsActiveMax>\n");
+ sb.append(" <requestsDurationTotal>").append(_statsHandler.getRequestsDurationTotal()).append("</requestsDurationTotal>\n");
+ sb.append(" <requestsDurationAve>").append(_statsHandler.getRequestsDurationAve()).append("</requestsDurationAve>\n");
+ sb.append(" <requestsDurationMin>").append(_statsHandler.getRequestsDurationMin()).append("</requestsDurationMin>\n");
+ sb.append(" <requestsDurationMax>").append(_statsHandler.getRequestsDurationMax()).append("</requestsDurationMax>\n");
+ sb.append(" <requestsActiveDurationAve>").append(_statsHandler.getRequestsActiveDurationAve()).append("</requestsActiveDurationAve>\n");
+ sb.append(" <requestsActiveDurationMin>").append(_statsHandler.getRequestsActiveDurationMin()).append("</requestsActiveDurationMin>\n");
+ sb.append(" <requestsActiveDurationMax>").append(_statsHandler.getRequestsActiveDurationMax()).append("</requestsActiveDurationMax>\n");
+ sb.append(" </requests>\n");
+
+ sb.append(" <responses>\n");
+ sb.append(" <responses1xx>").append(_statsHandler.getResponses1xx()).append("</responses1xx>\n");
+ sb.append(" <responses2xx>").append(_statsHandler.getResponses2xx()).append("</responses2xx>\n");
+ sb.append(" <responses3xx>").append(_statsHandler.getResponses3xx()).append("</responses3xx>\n");
+ sb.append(" <responses4xx>").append(_statsHandler.getResponses4xx()).append("</responses4xx>\n");
+ sb.append(" <responses5xx>").append(_statsHandler.getResponses5xx()).append("</responses5xx>\n");
+ sb.append(" <responsesBytesTotal>").append(_statsHandler.getResponsesBytesTotal()).append("</responsesBytesTotal>\n");
+ sb.append(" </responses>\n");
+
+ sb.append(" <connections>\n");
+ for (Connector connector : _connectors)
+ {
+ sb.append(" <connector>\n");
+ sb.append(" <name>").append(connector.getName()).append("</name>\n");
+ sb.append(" <statsOn>").append(connector.getStatsOn()).append("</statsOn>\n");
+ if (connector.getStatsOn())
+ {
+ sb.append(" <statsOnMs>").append(connector.getStatsOnMs()).append("</statsOnMs>\n");
+ sb.append(" <connections>").append(connector.getConnections()).append("</connections>\n");
+ sb.append(" <connectionsOpen>").append(connector.getConnectionsOpen()).append("</connectionsOpen>\n");
+ sb.append(" <connectionsOpenMin>").append(connector.getConnectionsOpenMin()).append("</connectionsOpenMin>\n");
+ sb.append(" <connectionsOpenMax>").append(connector.getConnectionsOpenMax()).append("</connectionsOpenMax>\n");
+ sb.append(" <connectionsDurationTotal>").append(connector.getConnectionsDurationTotal()).append("</connectionsDurationTotal>\n");
+ sb.append(" <connectionsDurationAve>").append(connector.getConnectionsDurationAve()).append("</connectionsDurationAve>\n");
+ sb.append(" <connectionsDurationMin>").append(connector.getConnectionsDurationMin()).append("</connectionsDurationMin>\n");
+ sb.append(" <connectionsDurationMax>").append(connector.getConnectionsDurationMax()).append("</connectionsDurationMax>\n");
+ sb.append(" <requests>").append(connector.getRequests()).append("</requests>\n");
+ sb.append(" <connectionsRequestsAve>").append(connector.getConnectionsRequestsAve()).append("</connectionsRequestsAve>\n");
+ sb.append(" <connectionsRequestsMin>").append(connector.getConnectionsRequestsMin()).append("</connectionsRequestsMin>\n");
+ sb.append(" <connectionsRequestsMax>").append(connector.getConnectionsRequestsMax()).append("</connectionsRequestsMax>\n");
+ }
+ sb.append(" </connector>\n");
+ }
+ sb.append(" </connections>\n");
+
+ sb.append(" <memory>\n");
+ sb.append(" <heapMemoryUsage>").append(_memoryBean.getHeapMemoryUsage().getUsed()).append("</heapMemoryUsage>\n");
+ sb.append(" <nonHeapMemoryUsage>").append(_memoryBean.getNonHeapMemoryUsage().getUsed()).append("</nonHeapMemoryUsage>\n");
+ sb.append(" </memory>\n");
+
+ sb.append("</statistics>\n");
+
+ response.setContentType("text/xml");
+ PrintWriter pout = null;
+ pout = response.getWriter();
+ pout.write(sb.toString());
+ }
+
+ private void sendTextResponse(HttpServletResponse response) throws IOException
+ {
+
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("<h1>Statistics:</h1>\n");
+
+ sb.append("<h2>Requests:</h2>\n");
+ sb.append("Statistics gathering started " + _statsHandler.getStatsOnMs() + "ms ago").append("<br />\n");
+ sb.append("Total requests: " + _statsHandler.getRequests()).append("<br />\n");
+ sb.append("Total requests timed out: " + _statsHandler.getRequestsTimedout()).append("<br />\n");
+ sb.append("Total requests resumed: " + _statsHandler.getRequestsResumed()).append("<br />\n");
+ sb.append("Current requests active: " + _statsHandler.getRequestsActive()).append("<br />\n");
+ sb.append("Min concurrent requests active: " + _statsHandler.getRequestsActiveMin()).append("<br />\n");
+ sb.append("Max concurrent requests active: " + _statsHandler.getRequestsActiveMax()).append("<br />\n");
+ sb.append("Total requests duration: " + _statsHandler.getRequestsDurationTotal()).append("<br />\n");
+ sb.append("Average request duration: " + _statsHandler.getRequestsDurationAve()).append("<br />\n");
+ sb.append("Min request duration: " + _statsHandler.getRequestsDurationMin()).append("<br />\n");
+ sb.append("Max request duration: " + _statsHandler.getRequestsDurationMax()).append("<br />\n");
+ sb.append("Average request active duration: " + _statsHandler.getRequestsActiveDurationAve()).append("<br />\n");
+ sb.append("Min request active duration: " + _statsHandler.getRequestsActiveDurationMin()).append("<br />\n");
+ sb.append("Max request active duration: " + _statsHandler.getRequestsActiveDurationMax()).append("<br />\n");
+
+ sb.append("<h2>Responses:</h2>\n");
+ sb.append("1xx responses: " + _statsHandler.getResponses1xx()).append("<br />\n");
+ sb.append("2xx responses: " + _statsHandler.getResponses2xx()).append("<br />\n");
+ sb.append("3xx responses: " + _statsHandler.getResponses3xx()).append("<br />\n");
+ sb.append("4xx responses: " + _statsHandler.getResponses4xx()).append("<br />\n");
+ sb.append("5xx responses: " + _statsHandler.getResponses5xx()).append("<br />\n");
+ sb.append("Bytes sent total: " + _statsHandler.getResponsesBytesTotal()).append("<br />\n");
+
+ sb.append("<h2>Connections:</h2>\n");
+ for (Connector connector : _connectors)
+ {
+ sb.append("<h3>" + connector.getName() + "</h3>");
+
+ if (connector.getStatsOn())
+ {
+ sb.append("Statistics gathering started " + connector.getStatsOnMs() + "ms ago").append("<br />\n");
+ sb.append("Total connections: " + connector.getConnections()).append("<br />\n");
+ sb.append("Current connections open: " + connector.getConnectionsOpen());
+ sb.append("Min concurrent connections open: " + connector.getConnectionsOpenMin()).append("<br />\n");
+ sb.append("Max concurrent connections open: " + connector.getConnectionsOpenMax()).append("<br />\n");
+ sb.append("Total connections duration: " + connector.getConnectionsDurationTotal()).append("<br />\n");
+ sb.append("Average connection duration: " + connector.getConnectionsDurationAve()).append("<br />\n");
+ sb.append("Min connection duration: " + connector.getConnectionsDurationMin()).append("<br />\n");
+ sb.append("Max connection duration: " + connector.getConnectionsDurationMax()).append("<br />\n");
+ sb.append("Total requests: " + connector.getRequests()).append("<br />\n");
+ sb.append("Average requests per connection: " + connector.getConnectionsRequestsAve()).append("<br />\n");
+ sb.append("Min requests per connection: " + connector.getConnectionsRequestsMin()).append("<br />\n");
+ sb.append("Max requests per connection: " + connector.getConnectionsRequestsMax()).append("<br />\n");
+ }
+ else
+ {
+ sb.append("Statistics gathering off.\n");
+ }
+
+ }
+
+ sb.append("<h2>Memory:</h2>\n");
+ sb.append("Heap memory usage: " + _memoryBean.getHeapMemoryUsage().getUsed() + " bytes").append("<br />\n");
+ sb.append("Non-heap memory usage: " + _memoryBean.getNonHeapMemoryUsage().getUsed() + " bytes").append("<br />\n");
+
+ response.setContentType("text/html");
+ PrintWriter pout = null;
+ pout = response.getWriter();
+ pout.write(sb.toString());
+
+ }
+}

Back to the top