Modified: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestWrapperImpl.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestWrapperImpl.java?view=diff&rev=534293&r1=534292&r2=534293 ============================================================================== --- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestWrapperImpl.java (original) +++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestWrapperImpl.java Tue May 1 19:22:45 2007 @@ -33,8 +33,7 @@ import org.apache.tomcat.servlets.session.HttpSessionImpl; import org.apache.tomcat.servlets.session.SessionManagerServlet; -import org.apache.tomcat.servlets.util.Enumerator; -import org.apache.tomcat.servlets.util.RequestUtil; +import org.apache.tomcat.util.http.RequestUtil; import org.apache.tomcat.util.res.StringManager;
Modified: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseImpl.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseImpl.java?view=diff&rev=534293&r1=534292&r2=534293 ============================================================================== --- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseImpl.java (original) +++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseImpl.java Tue May 1 19:22:45 2007 @@ -33,16 +33,16 @@ import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; - import org.apache.tomcat.lite.util.CharsetMapper; import org.apache.tomcat.lite.util.MessageWriter; import org.apache.tomcat.servlets.session.HttpSessionImpl; +import org.apache.tomcat.util.buf.CBuffer; import org.apache.tomcat.util.buf.CharChunk; import org.apache.tomcat.util.buf.UEncoder; import org.apache.tomcat.util.http.FastHttpDateFormat; import org.apache.tomcat.util.http.MimeHeaders; import org.apache.tomcat.util.http.ServerCookie; -import org.apache.tomcat.util.net.URL; +import java.net.URL; import org.apache.tomcat.util.res.StringManager; /** @@ -65,11 +65,6 @@ // ----------------------------------------------------------- Constructors - static { - // Ensure that URL is loaded for SM - URL.isSchemeChar('c'); - } - public ServletResponseImpl() { urlEncoder.addSafeCharacter('/'); } @@ -110,31 +105,14 @@ */ public void setConnector() { // default size to size of one ajp-packet - outputBuffer = MessageWriter.getWriter( request.getCoyoteRequest(), coyoteResponse, 8196); + outputBuffer = req.con.reqB.messageWriter; outputStream = new ServletOutputStreamImpl(outputBuffer); } /** * Coyote response. */ - protected org.apache.coyote.Response coyoteResponse; - - /** - * Set the Coyote response. - * - * @param coyoteResponse The Coyote response - */ - public void setCoyoteResponse(org.apache.coyote.Response coyoteResponse) { - this.coyoteResponse = coyoteResponse; - outputBuffer.setResponse(coyoteResponse); - } - - /** - * Get the Coyote response. - */ - public org.apache.coyote.Response getCoyoteResponse() { - return (coyoteResponse); - } + //protected org.apache.coyote.Response coyoteResponse; /** @@ -205,7 +183,7 @@ /** * Recyclable buffer to hold the redirect URL. */ - protected CharChunk redirectURLCC = new CharChunk(); + protected CBuffer redirectURLCC = new CBuffer(1024); // --------------------------------------------------------- Public Methods @@ -295,13 +273,13 @@ /** * The request with which this response is associated. */ - protected ServletRequestImpl request = null; + protected ServletRequestImpl req = null; /** * Return the Request with which this Response is associated. */ public ServletRequestImpl getRequest() { - return (this.request); + return (this.req); } /** @@ -310,7 +288,7 @@ * @param request The new associated request */ public void setRequest(ServletRequestImpl request) { - this.request = (ServletRequestImpl) request; + this.req = (ServletRequestImpl) request; setConnector(); } @@ -392,7 +370,7 @@ * Return the content length that was set or calculated for this Response. */ public int getContentLength() { - return (coyoteResponse.getContentLength()); + return req.con.resB.getContentLength(); } @@ -401,7 +379,7 @@ * or <code>null</code> if no content type was set. */ public String getContentType() { - return (coyoteResponse.getContentType()); + return req.con.resB.getContentType(); } @@ -456,7 +434,7 @@ * Return the character encoding used for this Response. */ public String getCharacterEncoding() { - return (coyoteResponse.getCharacterEncoding()); + return (req.con.resB.getCharacterEncoding()); } @@ -487,7 +465,7 @@ * Return the Locale assigned to this response. */ public Locale getLocale() { - return (coyoteResponse.getLocale()); + return (req.con.resB.getLocale()); } @@ -533,7 +511,7 @@ * Has the output of this response already been committed? */ public boolean isCommitted() { - return (coyoteResponse.isCommitted()); + return (req.con.resB.isCommitted()); } @@ -548,7 +526,8 @@ if (included) return; // Ignore any call from an included servlet - coyoteResponse.reset(); + req.con.resB.reset(); + req.con.reset(); outputBuffer.reset(); } @@ -607,7 +586,7 @@ if (usingWriter && !"ISO-8859-1".equals(getCharacterEncoding())) { return; } - coyoteResponse.setContentLength(length); + req.con.resB.setContentLength(length); } @@ -636,7 +615,7 @@ } } - coyoteResponse.setContentType(type); + req.con.resB.setContentType(type); // Check to see if content type contains charset if (type != null) { @@ -684,7 +663,7 @@ if (usingWriter) return; - coyoteResponse.setCharacterEncoding(charset); + req.con.resB.setCharacterEncoding(charset); isCharacterEncodingSet = true; } @@ -705,7 +684,7 @@ if (included) return; - coyoteResponse.setLocale(locale); + req.con.resB.setLocale(locale); // Ignore any call made after the getWriter has been invoked. // The default should be used @@ -716,10 +695,10 @@ return; } - CharsetMapper cm = request.getContext().getCharsetMapper(); + CharsetMapper cm = req.getContext().getCharsetMapper(); String charset = cm.getCharset( locale ); if ( charset != null ){ - coyoteResponse.setCharacterEncoding(charset); + req.con.resB.setCharacterEncoding(charset); } } @@ -746,7 +725,7 @@ * @param name Header name to look up */ public String getHeader(String name) { - return coyoteResponse.getMimeHeaders().getHeader(name); + return req.con.resB.getMimeHeaders().getHeader(name); } @@ -756,7 +735,7 @@ */ public String[] getHeaderNames() { - MimeHeaders headers = coyoteResponse.getMimeHeaders(); + MimeHeaders headers = req.con.resB.getMimeHeaders(); int n = headers.size(); String[] result = new String[n]; for (int i = 0; i < n; i++) { @@ -776,7 +755,7 @@ */ public String[] getHeaderValues(String name) { - Enumeration enumeration = coyoteResponse.getMimeHeaders().values(name); + Enumeration enumeration = req.con.resB.getMimeHeaders().values(name); Vector result = new Vector(); while (enumeration.hasMoreElements()) { result.addElement(enumeration.nextElement()); @@ -793,7 +772,7 @@ * for this Response. */ public String getMessage() { - return coyoteResponse.getMessage(); + return req.con.resB.getMessage(); } @@ -801,7 +780,7 @@ * Return the HTTP status code associated with this Response. */ public int getStatus() { - return coyoteResponse.getStatus(); + return req.con.resB.getStatus(); } @@ -894,7 +873,7 @@ if (included) return; - coyoteResponse.addHeader(name, value); + req.con.resB.addHeader(name, value); } @@ -931,15 +910,15 @@ if(cc=='C' || cc=='c') { if(name.equalsIgnoreCase("Content-Type")) { // Will return null if this has not been set - return (coyoteResponse.getContentType() != null); + return (req.con.resB.getContentType() != null); } if(name.equalsIgnoreCase("Content-Length")) { // -1 means not known and is not sent to client - return (coyoteResponse.getContentLengthLong() != -1); + return (req.con.resB.getContentLengthLong() != -1); } } - return coyoteResponse.containsHeader(name); + return req.con.resB.containsHeader(name); } @@ -952,7 +931,7 @@ public String encodeRedirectURL(String url) { if (isEncodeable(toAbsolute(url))) { - return (toEncoded(url, request.getSessionInternal().getId())); + return (toEncoded(url, req.getSessionInternal().getId())); } else { return (url); } @@ -988,7 +967,7 @@ if (url.equalsIgnoreCase("")){ url = absolute; } - return (toEncoded(url, request.getSessionInternal().getId())); + return (toEncoded(url, req.getSessionInternal().getId())); } else { return (url); } @@ -1025,7 +1004,7 @@ if (included) return; - coyoteResponse.acknowledge(); + req.con.sendAck(); } @@ -1069,14 +1048,14 @@ setError(); - coyoteResponse.setStatus(status); - coyoteResponse.setMessage(message); + req.con.resB.setStatus(status); + req.con.resB.setMessage(message); // Now go over the error-page handling - - String statusPage = request.getContext().findStatusPage(status); + String statusPage = req.getContext().findStatusPage(status); if (statusPage != null) { - request.getContext().handleStatusPage(request, + req.getContext().handleStatusPage(req, this, status, statusPage); } else { // Clear any data content that has been buffered @@ -1168,7 +1147,7 @@ if (included) return; - coyoteResponse.setHeader(name, value); + req.con.resB.setHeader(name, value); } @@ -1222,8 +1201,8 @@ if (included) return; - coyoteResponse.setStatus(status); - coyoteResponse.setMessage(message); + req.con.resB.setStatus(status); + req.con.resB.setMessage(message); } @@ -1254,7 +1233,7 @@ return (false); // Are we in a valid session that is not using cookies? - final ServletRequestImpl hreq = request; + final ServletRequestImpl hreq = req; final HttpSessionImpl session = hreq.getSessionInternal(false); if (session == null) return (false); @@ -1291,7 +1270,7 @@ if (serverPort != urlPort) return (false); - String contextPath = request.getContext().getContextPath(); + String contextPath = req.getContext().getContextPath(); if (contextPath != null) { String file = url.getFile(); if ((file == null) || !file.startsWith(contextPath)) @@ -1327,9 +1306,9 @@ redirectURLCC.recycle(); - String scheme = request.getScheme(); - String name = request.getServerName(); - int port = request.getServerPort(); + String scheme = req.getScheme(); + String name = req.getServerName(); + int port = req.getServerPort(); try { redirectURLCC.append(scheme, 0, scheme.length()); @@ -1342,7 +1321,7 @@ redirectURLCC.append(portS, 0, portS.length()); } if (!leadingSlash) { - String relativePath = request.getDecodedRequestURI(); + String relativePath = req.getDecodedRequestURI(); int pos = relativePath.lastIndexOf('/'); relativePath = relativePath.substring(0, pos); @@ -1379,13 +1358,23 @@ char c = uri.charAt(i); if(c == ':') { return i > 0; - } else if(!URL.isSchemeChar(c)) { + } else if(!isSchemeChar(c)) { return false; } } return false; } + /** + * Determine if the character is allowed in the scheme of a URI. + * See RFC 2396, Section 3.1 + */ + private static boolean isSchemeChar(char c) { + return Character.isLetterOrDigit(c) || + c == '+' || c == '-' || c == '.'; + } + + /** * Return the specified URL with the specified session identifier * suitably encoded. Modified: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseIncludeWrapper.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseIncludeWrapper.java?view=diff&rev=534293&r1=534292&r2=534293 ============================================================================== --- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseIncludeWrapper.java (original) +++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseIncludeWrapper.java Tue May 1 19:22:45 2007 @@ -19,16 +19,12 @@ import java.io.IOException; -import java.io.PrintWriter; import java.util.Locale; -import javax.servlet.ServletOutputStream; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; - -import org.apache.tomcat.util.res.StringManager; /** Modified: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/TomcatLite.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/TomcatLite.java?view=diff&rev=534293&r1=534292&r2=534293 ============================================================================== --- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/TomcatLite.java (original) +++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/TomcatLite.java Tue May 1 19:22:45 2007 @@ -2,16 +2,18 @@ */ package org.apache.tomcat.lite; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import javax.servlet.Filter; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletContext; @@ -19,97 +21,32 @@ import javax.servlet.UnavailableException; import javax.servlet.http.HttpServletResponse; -import org.apache.coyote.Request; -import org.apache.coyote.Response; -import org.apache.tomcat.lite.ctxmap.WebappContextMapper; +import org.apache.tomcat.lite.http11.Http11Connection; import org.apache.tomcat.lite.util.MappingData; -import org.apache.tomcat.lite.webmap.WebappFilterMapper; -import org.apache.tomcat.lite.webmap.WebappServletMapper; import org.apache.tomcat.servlets.config.ServletData; -import org.apache.tomcat.servlets.config.WebAppData; -import org.apache.tomcat.util.loader.Repository; /** - * Frontend for a minimal servlet impl for Tomcat-Lite. + * Simpler, lower footprint serlvet engine. * - * Almost all 'Servlet Container' functionality is implemented using Servlets, - * Filters, Listeners. Most of them are general-purpose, not specific and - * not dependent on Tomcat-Lite. It is possible to replace any of them - * with application-specific ones, or to use some of the general ones on other - * containers. - * - * There are 2 special webapps: - * - __x_engine - defines the context mapper ( host + context path -> context), - * defaults to be used in webapps ( default servlet, session management, - * etc ). - * - * - __x_deploy - optional webapp. If it is missing - a tomcatLite.ser file - * is required, containing all the config info, including processed web.xml - * files. No new apps can be deployed, reload is not allowed. If present - - * it'll provide the above mentioned features. - * - * In addition: - * - any context starting with __x_ will be loaded first - * - context listeners for such apps will receive notifications for all - * contexts - * - in particular, __x_protocol_* webapp should contain the connectors. * - * For each 'module' ( connector, session manager, etc), the implementation - * will be a filter or servlet, defined in __x_engine, with regular init - * parameters in web.xml used to set up. Each webapp can override them - * by defining a servlet with the same name ( names start with __x_ as well ). - * - * - * This is based on catalina classes, with non-essential features removed. It is - * possible to add back some of the flexibility using callbacks/hooks - but this - * package should be a sufficient implementation for a working servlet - * container, with no extra features ( just hooks ). * * @author Costin Manolache */ public class TomcatLite { private static TomcatLite facade = new TomcatLite(); - public static class EngineData implements Serializable { - // Informations about hosts - aliases, etc - public ArrayList<HostData> hosts = new ArrayList(); - - // informations about contexts. - public ArrayList<ContextConfigData> contexts = new ArrayList(); - } - - public static class HostData implements Serializable { - /** Must be lowercase */ - public String hostName; - public ArrayList<String> aliases = new ArrayList(); - } + Filter hostMapper; - /** Data about webapps configured in the system - */ - public static class ContextConfigData implements Serializable { - public ContextConfigData() {}; - public ContextConfigData(String basePath, String path) { - this.basePath = basePath; - this.path = path; - } - public String hostName; // must be a canonical name - public String basePath; // dir - canonical or absolute - String path; // path where it is mapped. ( for multiple - use mapper, - // it is not allowed by spec ) - - public WebAppData webXml; - } + // all contexts - hostMapper knows about hostnames and how they are mapped. + private ArrayList/*<ServletContextImpl>*/ contexts = new ArrayList(); - EngineData data = new EngineData(); + //private Repository engineRepo; - WebappContextMapper hostMapper = new WebappContextMapper(); + URLClassLoader contextParentLoader; - // all contexts - hostMapper knows about hostnames and how they are mapped. - private ArrayList<ServletContextImpl> contexts = new ArrayList(); - - private EngineData engineData; - - private Repository engineRepo; + // The / context + private ServletContextImpl rootContext; + private ServletContextImpl engineContext; private TomcatLite() { } @@ -119,40 +56,51 @@ } // --------------- start/stop --------------- - - public Repository getRepository() { - if (engineRepo == null) { - engineRepo = new Repository(); - engineRepo.setParentClassLoader(this.getClass().getClassLoader()); - } - return engineRepo; + public List/*<ServletContextImpl>*/ getWebapps() { + return contexts; } + public URLClassLoader getContextParentLoader() { + if (contextParentLoader == null) { + + ClassLoader parent = this.getClass().getClassLoader(); + contextParentLoader = new URLClassLoader(new URL[] {}, + parent); + + /*if (engineRepo == null) { + engineRepo = new Repository(); + engineRepo.setParentClassLoader(parent); + } + + contextParentLoader = + engineRepo.getClassLoader(); + */ + } + return contextParentLoader; + } + public void start() throws IOException { long t0 = System.currentTimeMillis(); - Repository ctxRepo = new Repository(); - ctxRepo.setParentClassLoader(this.getClass().getClassLoader()); - // start all contexts // init all contexts - for(ServletContextImpl ctx: contexts) { - try { - ctx.init(); - - } catch (Throwable e) { - e.printStackTrace(); - } + Iterator i1 = contexts.iterator(); + while (i1.hasNext()) { + ServletContextImpl ctx = (ServletContextImpl) i1.next(); + try { + ctx.start(); + } catch (Throwable e) { + e.printStackTrace(); + } } - saveEngineData(engineData); long t1 = System.currentTimeMillis(); System.err.println("Engine.start() " + (t1-t0)); } public void stop() { - // start all contexts - // init all contexts - for(ServletContextImpl ctx: contexts) { + Iterator i1 = contexts.iterator(); + while (i1.hasNext()) { + ServletContextImpl ctx = (ServletContextImpl) i1.next(); try { ctx.destroy(); } catch (Throwable e) { @@ -163,6 +111,8 @@ // -------------- Context add/remove -------------- + public static String[] DEFAULT_WELCOME = { "index.html" }; + /** * * @param hostname - "" @@ -181,34 +131,64 @@ ctx.setBasePath(basePath); contexts.add(ctx); + + boolean isRoot = false; + if (hostname == null || hostname.length() == 0) { + if ("/".equals(path)) { + rootContext = ctx; + isRoot = true; + } + } + // TODO: read web.xml or equivalent // TODO: defaults - // - hostMapper.addContext(hostname, ctx, - new String[] { "index.html" }, - new File(basePath)); - - + + if (isRoot && hostMapper == null) { + // Don't add it just yet - only if we have 2 contexts + return ctx; + } + return ctx; } - public WebappContextMapper getContextMapper() { - return hostMapper; - } - public void removeServletContext(ServletContext sctx) throws ServletException { ServletContextImpl ctx = (ServletContextImpl) sctx; // TODO: destroy all servlets and filters // TODO: clean up any other reference to the context or its loader - - hostMapper.removeContext(ctx); notifyRemove(ctx); } + public void service(Http11Connection connection) throws IOException, Exception { + ServletRequestImpl req = new ServletRequestImpl(); + ServletResponseImpl res = new ServletResponseImpl(); + req.setConnection(connection); + req.setResponse(res); + res.setRequest(req); + + service(req, res); + } + + /** + * Required for ServletContext.getContext(uri); + * @throws ServletException + * @throws IOException + */ + public ServletContextImpl getContext(ServletContextImpl impl, String uri) + throws IOException, ServletException { + if (hostMapper == null) { + return rootContext; + } + + // Create a request - needs to be simplified + ServletRequestImpl req = createMessage(impl, impl.contextPath, uri); + hostMapper.doFilter(req, null, null); + return req.getContext(); + } + public void service(ServletRequestImpl req, ServletResponseImpl res) throws Exception, IOException { // parse the session id from URI @@ -223,7 +203,17 @@ MappingData mapRes = req.getMappingData(); try { - hostMapper.mapContext(req); + if (hostMapper != null) { + // TODO: make hostMapper configurable, implement interface, + // simple to set on ROOT context + hostMapper.doFilter(req, null, null); + } else { + // That's all mapContext() need to do. Host is not actually + // used outside of hostMapper + mapRes.context = rootContext; + mapRes.contextPath.setString("/"); + } + ServletContextImpl ctx = (ServletContextImpl)mapRes.context; if( ctx == null ) { @@ -246,11 +236,12 @@ req.setWrapper((ServletConfigImpl)mapRes.wrapper); serviceServlet(ctx, req, res, h, mapRes ); // send the response... - res.flushBuffer(); + + //res.flushBuffer(); // Recycle the wrapper request and response - req.recycle(); - res.recycle(); + //req.recycle(); + //res.recycle(); } } finally { if(mapRes != null ) @@ -312,6 +303,7 @@ } } catch (Throwable t) { + t.printStackTrace(); ctx.handleError(req, res, t); } finally { if (servlet != null) { @@ -340,72 +332,160 @@ void notifyRemove(Object o) { } + File rootDir; + File workDir; + + public void setRootDir(String rootDir) { + this.rootDir = new File(rootDir); + } + + public File getRoot() { + if (rootDir == null) { + rootDir = new File("."); + } + return rootDir; + } + + public File getWork() { + if (workDir == null) { + workDir = new File(getRoot(), "tomcat-work"); + if (workDir.exists()) { + workDir.mkdirs(); + } + } + return workDir; + } + + + String deployServletName = "org.apache.tomcat.servlets.deploy.InitServlet"; + ServletConfigImpl deployServlet = null; + + public static String A_ENGINE = "__x_tomcatlite"; + + public ServletConfigImpl getDeployServlet(ServletContextImpl deployCtx) + throws ServletException { + if (deployServlet == null) { + deployServlet = new ServletConfigImpl(deployCtx, + new ServletData("engineInit", deployServletName)); + deployCtx.addServletConfig(deployServlet); + deployCtx.init(); + } + return deployServlet; + } + + private static String SERVER_CFG = "tomcat-lite-web.xml"; + + /** + * Load engine config file - a web.xml file from jar or classpath. + * @throws IOException + * + */ + private void engineExtraConfig(ServletContextImpl engineCtx) + throws ServletException, IOException { + File webXmlFile = new File( engineCtx.getBasePath() + "/WEB-INF/" + + SERVER_CFG); + if (webXmlFile.exists()) { + engineCtx.readWebXml(new FileInputStream(webXmlFile)); + return; + } + + InputStream defWebXml = + TomcatLite.class.getClassLoader().getResourceAsStream(SERVER_CFG); + if (defWebXml == null) { + defWebXml = + getClass().getClassLoader().getResourceAsStream("org/apache/tomcat/lite/" + + SERVER_CFG); + } + if (defWebXml == null) { + System.err.println("Default engine web.xml not found"); + } else { + engineCtx.readWebXml(defWebXml); + } + engineCtx.init(); + } + + + /** + * Init using cached tomcatLite.ser + * + * @throws ServletException + * @throws IOException + */ public void init() throws ServletException, IOException { + init("webapps/ROOT", "/", null); + } + + public void init(String rootDir, String path, Servlet deployServlet) + throws ServletException, IOException { + long t0 = System.currentTimeMillis(); - File initFile = new File("tomcatLite.ser"); - if (initFile.exists()) { - try { - ObjectInputStream ois = - new ObjectInputStream(new FileInputStream(initFile)); - engineData = (EngineData)ois.readObject(); - } catch(IOException ex) { - engineData = null; - } catch (ClassNotFoundException e) { - engineData = null; - } - } - if (engineData == null) { - // Ask the deploy app to initialize - ServletContextImpl deployCtx = - (ServletContextImpl)addServletContext("localhost", - "webapps/__x_deploy", - "/__x_deploy"); - ServletConfigImpl initSC = new ServletConfigImpl(deployCtx, - new ServletData("init", - "org.apache.tomcat.servlets.deploy.InitServlet")); - deployCtx.addServletConfig(initSC); - deployCtx.init(); - RequestDispatcher rd = deployCtx.getNamedDispatcher("init"); - Request creq = new Request(); - ServletRequestImpl req = new ServletRequestImpl(); - req.setContextPath("/"); - req.setContext(deployCtx); - req.setCoyoteRequest(creq); - Response cres = new Response(); - ServletResponseImpl res = new ServletResponseImpl(); - res.setRequest(req); - res.setCoyoteResponse(cres); - rd.forward(req, res); - - // end result - a context attribute must be set - engineData = (EngineData)req.getAttribute("engineData"); + + // Use the default - single webapp in rootDir. + File rootDirF = new File(rootDir); + rootDirF = rootDirF.getCanonicalFile(); + ServletContextImpl ctx = + (ServletContextImpl)addServletContext(null, + rootDir, + path); + engineContext = ctx; + ctx.init(); + + // Special 'init' servlet - can add more webapps, context, + // filters, etc. Optional - if not found, only one webapp + // will be used. + ServletConfigImpl initSC = + engineContext.getServletConfig("engineInit"); + // getDeployServlet(engineContext); + if (initSC != null) { + // Create a request - needs to be simplified + ServletRequestImpl req = createMessage(engineContext, "/", "/"); + RequestDispatcher rd = + engineContext.getNamedDispatcher("engineInit"); + rd.forward(req, req.getResponse()); } - // Add the servlets - for (ContextConfigData ctxD: engineData.contexts) { - System.err.println("Loading context: " + ctxD.path + " " + ctxD.basePath); - ServletContextImpl ctx = - (ServletContextImpl)addServletContext(null, - ctxD.basePath, - ctxD.path); - ctx.setContextConfigData(ctxD); - if (ctxD.webXml != null) { - ctx.processWebAppData(ctxD.webXml); - } + // Special case: load engine config from resource + if (rootContext == null) { + rootContext = (ServletContextImpl) + addServletContext(null, rootDir, "/"); + rootContext.init(); // defaults, read web.xml if any + } + + if (engineContext == null) { + engineContext = rootContext; } + // Load exta config file for the engine context ( root or + // single context ) + engineExtraConfig(engineContext); + long t1 = System.currentTimeMillis(); + + // At this point all config is loaded. Contexts are not yet init() + // - this will happen on start. System.err.println("Engine.init() " + (t1-t0)); } - public void saveEngineData(EngineData ed) - throws FileNotFoundException, IOException - { - FileOutputStream fos = new FileOutputStream("tomcatLite.ser"); - ObjectOutputStream oos = new ObjectOutputStream(fos); - oos.writeObject(ed); - oos.close(); + private ServletRequestImpl createMessage(ServletContextImpl deployCtx, + String ctxPath, + String reqPath) { + Http11Connection con = new Http11Connection(this, null, null); + con.setOutputStream(new ByteArrayOutputStream()); + + ServletRequestImpl req = new ServletRequestImpl(); + ServletResponseImpl res = new ServletResponseImpl(); + req.setResponse(res); + res.setRequest(req); + + req.setConnection(con); + + req.setContextPath(ctxPath); + req.setContext(deployCtx); + + req.setRequestURI(ctxPath + reqPath); + + return req; } - + /** Create a dummy request/response object that can be used to invoke */ public ServletRequestImpl dummyRequest() { @@ -417,24 +497,16 @@ ServletRequestImpl req = new ServletRequestImpl(); req.setContext(ctx); req.setQueryString("jsp_precompile=true"); - Request creq = new Request(); - Response cres = new Response(); - cres.setRequest(creq); - creq.setResponse(cres); - req.setCoyoteRequest(creq); ServletResponseImpl res = new ServletResponseImpl(); - res.setCoyoteResponse(cres); res.setRequest(req); req.setResponse(res); return req; } - public static void main(String args[]) - throws ServletException, IOException { - TomcatLite facade = TomcatLite.getServletImpl(); - facade.init(); - facade.start(); + + public void setContextMapper(Filter hostMapper2) { + this.hostMapper = hostMapper2; } } Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/TomcatLiteMain.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/TomcatLiteMain.java?view=auto&rev=534293 ============================================================================== --- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/TomcatLiteMain.java (added) +++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/TomcatLiteMain.java Tue May 1 19:22:45 2007 @@ -0,0 +1,51 @@ +/* + */ +package org.apache.tomcat.lite; + +import org.apache.tomcat.util.IntrospectionUtils; + +/** + * Simpler, lower footprint serlvet engine. + * + * + * + * @author Costin Manolache + */ +public class TomcatLiteMain { + String rootDir = "./webapps/ROOT"; + String ctxPath = "/"; + + public String getPath() { + return ctxPath; + } + + public void setPath(String ctxPath) { + this.ctxPath = ctxPath; + } + + public String getDir() { + return rootDir; + } + + public void setDir(String rootDir) { + this.rootDir = rootDir; + } + + public void execute() throws Exception { + TomcatLite lite = TomcatLite.getServletImpl(); + + lite.init(rootDir, ctxPath, null); + lite.start(); + + } + + public static void main(String args[]) + throws Exception { + + TomcatLiteMain facade = new TomcatLiteMain(); + IntrospectionUtils.processArgs(facade, args); + + facade.execute(); + } + +} Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/WebappFilterMapper.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/WebappFilterMapper.java?view=auto&rev=534293 ============================================================================== --- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/WebappFilterMapper.java (added) +++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/WebappFilterMapper.java Tue May 1 19:22:45 2007 @@ -0,0 +1,529 @@ +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.lite; + + +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; + +import org.apache.tomcat.util.http.RequestUtil; + +/** + * First filter after the context and servlet are mapped. It will add + * web.xml-defined filters. + * + * costin: This is another mapping - done in RequestDispatcher or initial + * mapping. + * Also: StandardHostValve - sets attribute for error pages, + * StandardWrapperValve - mapping per invocation + * + * @author Greg Murray + * @author Remy Maucherat + */ +public class WebappFilterMapper implements Filter { + + + // -------------------------------------------------------------- Constants + + + public static final int ERROR = 1; + public static final Integer ERROR_INTEGER = new Integer(ERROR); + public static final int FORWARD = 2; + public static final Integer FORWARD_INTEGER = new Integer(FORWARD); + public static final int INCLUDE = 4; + public static final Integer INCLUDE_INTEGER = new Integer(INCLUDE); + public static final int REQUEST = 8; + public static final Integer REQUEST_INTEGER = new Integer(REQUEST); + + /** + * Request dispatcher state. + */ + public static final String DISPATCHER_TYPE_ATTR = + "org.apache.catalina.core.DISPATCHER_TYPE"; + + /** + * Request dispatcher path. + */ + public static final String DISPATCHER_REQUEST_PATH_ATTR = + "org.apache.catalina.core.DISPATCHER_REQUEST_PATH"; + + + // ----------------------------------------------------------- Constructors + ServletContextImpl servletContext; + + public WebappFilterMapper() { + } + + public WebappFilterMapper(ServletContextImpl impl) { + servletContext = impl; + } + + public void setServletContext(ServletContextImpl sc) { + servletContext = sc; + } + + // --------------------------------------------------------- Public Methods + + ArrayList filterMaps = new ArrayList(); + + public void addMapping(String filterName, + String url, + String servletName, + String type[]) { + FilterMap map = new FilterMap(); + map.setURLPattern(url); + map.setFilterName(filterName); + map.setServletName(servletName); + filterMaps.add(map); + } + + /** + * Construct and return a FilterChain implementation that will wrap the + * execution of the specified servlet instance. If we should not execute + * a filter chain at all, return <code>null</code>. + * + * @param request The servlet request we are processing + * @param servlet The servlet instance to be wrapped + */ + public FilterChainImpl createFilterChain(ServletRequest request, + ServletConfigImpl wrapper, + Servlet servlet) { + + // If there is no servlet to execute, return null + if (servlet == null) + return (null); + + // get the dispatcher type + int dispatcher = -1; + if (request.getAttribute(DISPATCHER_TYPE_ATTR) != null) { + Integer dispatcherInt = + (Integer) request.getAttribute(DISPATCHER_TYPE_ATTR); + dispatcher = dispatcherInt.intValue(); + } + String requestPath = null; + Object attribute = request.getAttribute(DISPATCHER_REQUEST_PATH_ATTR); + + if (attribute != null){ + requestPath = attribute.toString(); + } + + HttpServletRequest hreq = null; + if (request instanceof HttpServletRequest) + hreq = (HttpServletRequest)request; + + // Create and initialize a filter chain object + FilterChainImpl filterChain = null; + if ((request instanceof ServletRequestImpl)) { + ServletRequestImpl req = (ServletRequestImpl) request; + filterChain = (FilterChainImpl) req.getFilterChain(); + filterChain.release(); + } else { + // Security: Do not recycle + filterChain = new FilterChainImpl(); + } + + filterChain.setServlet(wrapper, servlet); + + // If there are no filter mappings, we are done + if ((filterMaps.size() == 0)) + return (filterChain); + + // Acquire the information we will need to match filter mappings + String servletName = wrapper.getServletName(); + + int n = 0; + + // TODO(costin): optimize: separate in 2 lists, one for url-mapped, one for + // servlet-name. Maybe even separate list for dispatcher and + // non-dispatcher + + // TODO(costin): optimize: set the FilterConfig in the FilterMap, to + // avoid second hash lookup + + // Add the relevant path-mapped filters to this filter chain + for (int i = 0; i < filterMaps.size(); i++) { + FilterMap filterMap = (FilterMap)filterMaps.get(i); + if (!matchDispatcher(filterMap ,dispatcher)) { + continue; + } + if (!matchFiltersURL(filterMap, requestPath)) + continue; + FilterConfigImpl filterConfig = + servletContext.getFilter(filterMap.getFilterName()); + if (filterConfig == null) { + // FIXME - log configuration problem + continue; + } + filterChain.addFilter(filterConfig); + n++; + } + + // Add filters that match on servlet name second + for (int i = 0; i < filterMaps.size(); i++) { + FilterMap filterMap = (FilterMap)filterMaps.get(i); + if (!matchDispatcher(filterMap ,dispatcher)) { + continue; + } + if (!matchFiltersServlet(filterMap, servletName)) + continue; + FilterConfigImpl filterConfig = + servletContext.getFilter(filterMap.getFilterName()); + if (filterConfig == null) { + ; // FIXME - log configuration problem + continue; + } + filterChain.addFilter(filterConfig); + n++; + } + + // Return the completed filter chain + return (filterChain); + + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Return <code>true</code> if the context-relative request path + * matches the requirements of the specified filter mapping; + * otherwise, return <code>null</code>. + * + * @param filterMap Filter mapping being checked + * @param requestPath Context-relative request path of this request + */ + private boolean matchFiltersURL(FilterMap filterMap, String requestPath) { + + if (requestPath == null) + return (false); + + // Match on context relative request path + String testPath = filterMap.getURLPattern(); + if (testPath == null) + return (false); + + // Case 1 - Exact Match + if (testPath.equals(requestPath)) + return (true); + + // Case 2 - Path Match ("/.../*") + if (testPath.equals("/*")) + return (true); + if (testPath.endsWith("/*")) { + if (testPath.regionMatches(0, requestPath, 0, + testPath.length() - 2)) { + if (requestPath.length() == (testPath.length() - 2)) { + return (true); + } else if ('/' == requestPath.charAt(testPath.length() - 2)) { + return (true); + } + } + return (false); + } + + // Case 3 - Extension Match + if (testPath.startsWith("*.")) { + int slash = requestPath.lastIndexOf('/'); + int period = requestPath.lastIndexOf('.'); + if ((slash >= 0) && (period > slash) + && (period != requestPath.length() - 1) + && ((requestPath.length() - period) + == (testPath.length() - 1))) { + return (testPath.regionMatches(2, requestPath, period + 1, + testPath.length() - 2)); + } + } + + // Case 4 - "Default" Match + return (false); // NOTE - Not relevant for selecting filters + + } + + + /** + * Return <code>true</code> if the specified servlet name matches + * the requirements of the specified filter mapping; otherwise + * return <code>false</code>. + * + * @param filterMap Filter mapping being checked + * @param servletName Servlet name being checked + */ + private boolean matchFiltersServlet(FilterMap filterMap, + String servletName) { + + if (servletName == null) { + return (false); + } else { + if (servletName.equals(filterMap.getServletName())) { + return (true); + } else { + return false; + } + } + + } + + + /** + * Convienience method which returns true if the dispatcher type + * matches the dispatcher types specified in the FilterMap + */ + private boolean matchDispatcher(FilterMap filterMap, int dispatcher) { + switch (dispatcher) { + case FORWARD : { + if (filterMap.getDispatcherMapping() == FilterMap.FORWARD || + filterMap.getDispatcherMapping() == FilterMap.FORWARD_ERROR || + filterMap.getDispatcherMapping() == FilterMap.INCLUDE_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE) { + return true; + } + break; + } + case INCLUDE : { + if (filterMap.getDispatcherMapping() == FilterMap.INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR || + filterMap.getDispatcherMapping() == FilterMap.INCLUDE_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE) { + return true; + } + break; + } + case REQUEST : { + if (filterMap.getDispatcherMapping() == FilterMap.REQUEST || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE) { + return true; + } + break; + } + case ERROR : { + if (filterMap.getDispatcherMapping() == FilterMap.ERROR || + filterMap.getDispatcherMapping() == FilterMap.FORWARD_ERROR || + filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR || + filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE) { + return true; + } + break; + } + } + return false; + } + + + // -------------------- Map elements ----------------------- + + public static class FilterMap implements Serializable { + + + // ------------------------------------------------------------- Properties + + + /** + * The name of this filter to be executed when this mapping matches + * a particular request. + */ + + public static final int ERROR = 1; + public static final int FORWARD = 2; + public static final int FORWARD_ERROR =3; + public static final int INCLUDE = 4; + public static final int INCLUDE_ERROR = 5; + public static final int INCLUDE_ERROR_FORWARD =6; + public static final int INCLUDE_FORWARD = 7; + public static final int REQUEST = 8; + public static final int REQUEST_ERROR = 9; + public static final int REQUEST_ERROR_FORWARD = 10; + public static final int REQUEST_ERROR_FORWARD_INCLUDE = 11; + public static final int REQUEST_ERROR_INCLUDE = 12; + public static final int REQUEST_FORWARD = 13; + public static final int REQUEST_INCLUDE = 14; + public static final int REQUEST_FORWARD_INCLUDE= 15; + + // represents nothing having been set. This will be seen + // as equal to a REQUEST + private static final int NOT_SET = -1; + + private int dispatcherMapping=NOT_SET; + + private String filterName = null; + + /** + * The URL pattern this mapping matches. + */ + private String urlPattern = null; + + /** + * The servlet name this mapping matches. + */ + private String servletName = null; + + + + public String getFilterName() { + return (this.filterName); + } + + public void setFilterName(String filterName) { + this.filterName = filterName; + } + + + public String getServletName() { + return (this.servletName); + } + + public void setServletName(String servletName) { + this.servletName = servletName; + } + + + public String getURLPattern() { + return (this.urlPattern); + } + + public void setURLPattern(String urlPattern) { + this.urlPattern = RequestUtil.URLDecode(urlPattern); + } + + /** + * + * This method will be used to set the current state of the FilterMap + * representing the state of when filters should be applied: + * + * ERROR + * FORWARD + * FORWARD_ERROR + * INCLUDE + * INCLUDE_ERROR + * INCLUDE_ERROR_FORWARD + * REQUEST + * REQUEST_ERROR + * REQUEST_ERROR_INCLUDE + * REQUEST_ERROR_FORWARD_INCLUDE + * REQUEST_INCLUDE + * REQUEST_FORWARD, + * REQUEST_FORWARD_INCLUDE + * + */ + public void setDispatcher(String dispatcherString) { + String dispatcher = dispatcherString.toUpperCase(); + + if (dispatcher.equals("FORWARD")) { + + // apply FORWARD to the global dispatcherMapping. + switch (dispatcherMapping) { + case NOT_SET : dispatcherMapping = FORWARD; break; + case ERROR : dispatcherMapping = FORWARD_ERROR; break; + case INCLUDE : dispatcherMapping = INCLUDE_FORWARD; break; + case INCLUDE_ERROR : dispatcherMapping = INCLUDE_ERROR_FORWARD; break; + case REQUEST : dispatcherMapping = REQUEST_FORWARD; break; + case REQUEST_ERROR : dispatcherMapping = REQUEST_ERROR_FORWARD; break; + case REQUEST_ERROR_INCLUDE : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break; + case REQUEST_INCLUDE : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break; + } + } else if (dispatcher.equals("INCLUDE")) { + // apply INCLUDE to the global dispatcherMapping. + switch (dispatcherMapping) { + case NOT_SET : dispatcherMapping = INCLUDE; break; + case ERROR : dispatcherMapping = INCLUDE_ERROR; break; + case FORWARD : dispatcherMapping = INCLUDE_FORWARD; break; + case FORWARD_ERROR : dispatcherMapping = INCLUDE_ERROR_FORWARD; break; + case REQUEST : dispatcherMapping = REQUEST_INCLUDE; break; + case REQUEST_ERROR : dispatcherMapping = REQUEST_ERROR_INCLUDE; break; + case REQUEST_ERROR_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break; + case REQUEST_FORWARD : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break; + } + } else if (dispatcher.equals("REQUEST")) { + // apply REQUEST to the global dispatcherMapping. + switch (dispatcherMapping) { + case NOT_SET : dispatcherMapping = REQUEST; break; + case ERROR : dispatcherMapping = REQUEST_ERROR; break; + case FORWARD : dispatcherMapping = REQUEST_FORWARD; break; + case FORWARD_ERROR : dispatcherMapping = REQUEST_ERROR_FORWARD; break; + case INCLUDE : dispatcherMapping = REQUEST_INCLUDE; break; + case INCLUDE_ERROR : dispatcherMapping = REQUEST_ERROR_INCLUDE; break; + case INCLUDE_FORWARD : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break; + case INCLUDE_ERROR_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break; + } + } else if (dispatcher.equals("ERROR")) { + // apply ERROR to the global dispatcherMapping. + switch (dispatcherMapping) { + case NOT_SET : dispatcherMapping = ERROR; break; + case FORWARD : dispatcherMapping = FORWARD_ERROR; break; + case INCLUDE : dispatcherMapping = INCLUDE_ERROR; break; + case INCLUDE_FORWARD : dispatcherMapping = INCLUDE_ERROR_FORWARD; break; + case REQUEST : dispatcherMapping = REQUEST_ERROR; break; + case REQUEST_INCLUDE : dispatcherMapping = REQUEST_ERROR_INCLUDE; break; + case REQUEST_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD; break; + case REQUEST_FORWARD_INCLUDE : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break; + } + } + } + + public int getDispatcherMapping() { + // per the SRV.6.2.5 absence of any dispatcher elements is + // equivelant to a REQUEST value + if (dispatcherMapping == NOT_SET) return REQUEST; + else return dispatcherMapping; + } + + } + + + public void init(FilterConfig filterConfig) throws ServletException { + } + + + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) + throws IOException, ServletException { + } + + + public void destroy() { + } + +} --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]