Author: costin
Date: Thu Jul 17 10:14:47 2008
New Revision: 677640

URL: http://svn.apache.org/viewvc?rev=677640&view=rev
Log:
Add a non-config starter for tomcat. All you need is the classpath including 
tomcat and the servlets - no config file.
There is a requirement for a temp directory - the spec requires that webapps 
are provided with one I believe. 
It is possible to remove this or do it lazily or have some default in /tmp, if 
anyone wants to.

Also adding a context requires some base dir ( can be an empty one ) - so the 
default servlets points to something.
This can also be eliminated by setting a different default servlet - needs to 
be done if wanted.

It is also pretty fast - the unit tests show startup + first request in ~1 sec. 


Added:
    tomcat/trunk/java/org/apache/catalina/startup/Tomcat.java   (with props)
    tomcat/trunk/test/org/apache/catalina/startup/
    tomcat/trunk/test/org/apache/catalina/startup/TomcatStartupAPITest.java   
(with props)

Added: tomcat/trunk/java/org/apache/catalina/startup/Tomcat.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/Tomcat.java?rev=677640&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/Tomcat.java (added)
+++ tomcat/trunk/java/org/apache/catalina/startup/Tomcat.java Thu Jul 17 
10:14:47 2008
@@ -0,0 +1,791 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.catalina.startup;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Realm;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.core.StandardService;
+import org.apache.catalina.core.StandardWrapper;
+import org.apache.catalina.deploy.LoginConfig;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.apache.catalina.realm.RealmBase;
+import org.apache.catalina.session.StandardManager;
+
+// TODO: lazy init for the temp dir - only when a JSP is compiled or 
+// get temp dir is called we need to create it. This will avoid the 
+// need for the baseDir
+
+// TODO: allow contexts without a base dir - i.e. 
+// only programmatic. This would disable the default servlet.
+
+/**
+ * Minimal tomcat starter for embedding/unit tests.
+ * 
+ * Tomcat supports multiple styles of configuration and 
+ * startup - the most common and stable is server.xml-based,
+ * implemented in org.apache.catalina.startup.Bootstrap.
+ *
+ * This class is for use in apps that embed tomcat. 
+ * Requirements:
+ * 
+ * - all tomcat classes and possibly servlets are in the classpath.
+ * ( for example all is in one big jar, or in eclipse CP, or in any other
+ * combination )
+ * 
+ * - we need one temporary directory for work files
+ * 
+ * - no config file is required. This class provides methods to 
+ * use if you have a webapp with a web.xml file, but it is 
+ * optional - you can use your own servlets.
+ * 
+ * This class provides a main() and few simple CLI arguments,
+ * see setters for doc. It can be used for simple tests and
+ * demo.
+ * 
+ * @see TomcatStartupAPITest for examples on how to use this
+ * @author Costin Manolache
+ */
+public class Tomcat {
+    // Single engine, service, server, connector - few cases need more,
+    // they can use server.xml
+    protected StandardServer server;
+    protected StandardService service;
+    protected StandardEngine engine;
+    protected Connector connector; // for more - customize the classes
+    
+    // To make it a bit easier to config for the common case
+    // ( one host, one context ). 
+    protected StandardHost host;
+
+    // TODO: it's easy to add support for more hosts - but is it 
+    // really needed ?
+
+    // TODO: allow use of in-memory connector
+    
+    protected int port = 8080;
+    protected String hostname = "localhost";
+    protected String basedir;
+    
+    // Default in-memory realm, will be set by default on 
+    // created contexts. Can be replaced with setRealm() on 
+    // the context.
+    protected Realm defaultRealm;
+    private Map<String, String> userPass = new HashMap<String, String>();
+    private Map<String, List<String>> userRoles = 
+            new HashMap<String, List<String>>();
+    private Map<String, Principal> userPrincipals = new HashMap<String, 
Principal>();
+    
+    public Tomcat() {
+    }
+    
+    /**
+     * Tomcat needs a directory for temp files. This should be the 
+     * first method called. 
+     * 
+     * By default, if this method is not called, we use:
+     *  - system properties - catalina.base, catalina.home 
+     *  - $HOME/tomcat.$PORT
+     * ( /tmp doesn't seem a good choice for security ).
+     *   
+     *
+     * TODO: better default ? Maybe current dir ? 
+     * TODO: disable work dir if not needed ( no jsp, etc ).
+     */
+    public void setBaseDir(String basedir) {
+        this.basedir = basedir;
+    }
+
+    /** 
+     * Set the port for the default connector. Must 
+     * be called before start().
+     */
+    public void setPort(int port) {
+        this.port = port;
+    }
+    
+    /** 
+     * The the hostname of the default host, default is 
+     * 'localhost'.
+     */
+    public void setHostname(String s) {
+        hostname = s;
+    }
+
+    /** 
+     * Add a webapp using normal WEB-INF/web.xml if found.
+     * 
+     * @param contextPath
+     * @param baseDir
+     * @return
+     * @throws ServletException 
+     */
+    public StandardContext addWebapp(String contextPath, 
+                                     String baseDir) throws ServletException {
+        
+        return addWebapp(getHost(), contextPath, baseDir);    
+    }
+    
+    
+    /** 
+     * Add a context - programmatic mode, no web.xml used.
+     *
+     * API calls equivalent with web.xml:
+     * 
+     * context-param
+     *  ctx.addParameter("name", "value");
+     *     
+     *
+     * error-page
+     *    ErrorPage ep = new ErrorPage();
+     *    ep.setErrorCode(500);
+     *    ep.setLocation("/error.html");
+     *    ctx.addErrorPage(ep);
+     *   
+     * ctx.addMimeMapping("ext", "type");
+     *  
+     * TODO: add the rest
+     *
+     *  @param host NULL for the 'default' host
+     *  @param contextPath "/" for root context.
+     *  @param dir base dir for the context, for static files. Must exist, 
+     *  relative to the server home
+     */
+    public StandardContext addContext(String contextPath, 
+                                      String baseDir) {
+        return addContext(getHost(), contextPath, baseDir);
+    }
+
+    public StandardWrapper addServlet(String contextPath, 
+                                      String servletName, 
+                                      String servletClass) {
+        Container ctx = getHost().findChild(contextPath);
+        return addServlet((StandardContext) ctx, 
+                servletName, servletClass);
+    }
+    
+    /**
+     * Equivalent with 
+     *  <servlet><servlet-name><servlet-class>.
+     *  
+     * In general it is better/faster to use the method that takes a 
+     * Servlet as param - this one can be used if the servlet is not 
+     * commonly used, and want to avoid loading all deps.
+     * ( for example: jsp servlet )
+     * 
+     * You can customize the returned servlet, ex:
+     * 
+     *    wrapper.addInitParameter("name", "value");
+     */
+    public StandardWrapper addServlet(StandardContext ctx, 
+                                      String servletName, 
+                                      String servletClass) {
+        // will do class for name and set init params
+        StandardWrapper sw = (StandardWrapper)ctx.createWrapper();
+        sw.setServletClass(servletClass);
+        sw.setName(servletName);
+        ctx.addChild(sw);
+        
+        return sw;
+    }
+
+    /** Use an existing servlet, no class.forName or initialization will be 
+     *  performed
+     */
+    public StandardWrapper addServlet(StandardContext ctx,
+                                      String servletName, 
+                                      Servlet servlet) {
+        // will do class for name and set init params
+        StandardWrapper sw = new ExistingStandardWrapper(servlet);
+        sw.setName(servletName);
+        ctx.addChild(sw);
+        
+        return sw;
+    }
+    
+    
+    /**
+     * Initialize and start the server.
+     */
+    public void start() throws Exception {
+        setSilent();
+        getServer();
+        getConnector();
+        server.initialize();
+        server.start();
+    }
+
+    /** 
+     * Stop the server.
+     */
+    public void stop() throws Exception {
+        getServer().stop();
+    }
+
+
+    /** 
+     * Add a user for the in-memory realm. All created apps use this 
+     * by default, can be replaced using setRealm().
+     *  
+     */
+    public void addUser(String user, String pass) {
+        userPass.put(user, pass);
+    }
+    
+    /**
+     * @see addUser 
+     */
+    public void addRole(String user, String role) {
+        List<String> roles = userRoles.get(user);
+        if (roles == null) {
+            roles = new ArrayList<String>();
+            userRoles.put(user, roles);
+        }
+        roles.add(role);
+    }
+
+    // ------- Extra customization -------
+    // You can tune individual tomcat objects, using internal APIs
+    
+    /** 
+     * Get the default http connector. You can set more 
+     * parameters - the port is already initialized.
+     * 
+     * Alternatively, you can construct a Connector and set any params,
+     * then call addConnector(Connector)
+     * 
+     * @return A connector object that can be customized
+     */
+    public Connector getConnector() throws Exception {
+        getServer();
+        if (connector != null) {
+            return connector;
+        }
+        // This will load Apr connector if available,
+        // default to nio. I'm having strange problems with apr
+        // and for the use case the speed benefit wouldn't matter.
+        
+        //connector = new Connector("HTTP/1.1");
+        connector = new Connector("org.apache.coyote.http11.Http11Protocol"); 
+        connector.setPort(port);
+        service.addConnector( connector );
+        return connector;
+    }
+    
+    public void setConnector(Connector connector) {
+        this.connector = connector;
+    }
+    
+    /** 
+     * Get the service object. Can be used to add more 
+     * connectors and few other global settings.
+     */
+    public StandardService getService() {
+        getServer();
+        return service;
+    }
+
+    /** 
+     * Sets the current host - all future webapps will
+     * be added to this host. When tomcat starts, the 
+     * host will be the default host.
+     * 
+     * @param host
+     */
+    public void setHost(StandardHost host) {
+        this.host = host;
+    }
+    
+    public StandardHost getHost() {
+        if (host == null) {
+            host = new StandardHost();
+            host.setName(hostname);
+
+            getEngine().addChild( host );
+        }
+        return host;
+    }
+    
+    /** 
+     * Set a custom realm for auth. If not called, a simple
+     * default will be used, using an internal map.
+     * 
+     * Must be called before adding a context.
+     */
+    public void setDefaultRealm(Realm realm) {
+        defaultRealm = realm;
+    }
+    
+
+    /** 
+     * Access to the engine, for further customization.
+     */
+    public StandardEngine getEngine() {
+        if(engine == null ) {
+            getServer();
+            engine = new StandardEngine();
+            engine.setName( "default" );
+            engine.setDefaultHost(hostname);
+            service.setContainer(engine);
+        }
+        return engine;
+    }
+
+    /**
+     * Get the server object. You can add listeners and 
+     * few more customizations.  
+     */
+    public StandardServer getServer() {
+        
+        if (server != null) {
+            return server;
+        }
+        
+        initBaseDir(); 
+        
+        System.setProperty("catalina.useNaming", "false");
+        
+        server = new StandardServer();
+        server.setPort( -1 );
+        
+        service = new StandardService();
+        service.setName("Tomcat");
+        server.addService( service );
+        return server;
+    }
+
+    public StandardContext addContext(StandardHost host, 
+                                      String contextPath, 
+                                      String dir) {
+        silence(contextPath);
+        StandardContext ctx = new StandardContext();
+        ctx.setPath( contextPath );
+        ctx.setDocBase(dir);
+        ctx.addLifecycleListener(new FixContextListener());
+        
+        if (host == null) {
+            host = getHost();
+        }
+        host.addChild(ctx);
+        return ctx;
+    }
+    
+    public StandardContext addWebapp(StandardHost host, 
+                                     String url, String path) 
+           throws ServletException {
+        silence(url);
+
+        StandardContext ctx = new StandardContext();
+        ctx.setPath( url );
+        ctx.setDocBase(path);
+        if (defaultRealm == null) {
+            initSimpleAuth();
+        }
+        ctx.setRealm(defaultRealm);
+        initWebappDefaults(ctx);
+        
+        ContextConfig ctxCfg = new ContextConfig();
+        ctx.addLifecycleListener( ctxCfg );
+        // prevent it from looking ( if it finds one - it'll have dup error )
+        ctxCfg.setDefaultWebXml("org/apache/catalin/startup/NO_DEFAULT_XML");
+        
+        if (host == null) {
+            host = getHost();
+        }
+        host.addChild(ctx);
+
+        return ctx;
+    }
+
+    
+    
+
+    
+    // ---------- Helper methods and classes -------------------
+    
+    /** 
+     * Initialize an in-memory realm. You can replace it 
+     * for contexts with a real one. 
+     */
+    protected void initSimpleAuth() {
+        defaultRealm = new RealmBase() {
+            @Override
+            protected String getName() {
+                return "Simple";
+            }
+
+            @Override
+            protected String getPassword(String username) {
+                return userPass.get(username);
+            }
+
+            @Override
+            protected Principal getPrincipal(String username) {
+                Principal p = userPrincipals.get(username);
+                if (p == null) {
+                    String pass = userPass.get(username);
+                    if (pass != null) {
+                        p = new GenericPrincipal(this, username, pass, 
+                                userRoles.get(username));
+                        userPrincipals.put(username, p);
+                    }
+                }
+                return p;
+            }
+            
+        };        
+    }
+    
+    protected void initBaseDir() {
+        if (basedir == null) {
+            basedir = System.getProperty("catalina.base");
+        }
+        if (basedir == null) {
+            basedir = System.getProperty("catalina.home");
+        }
+        if (basedir == null) {
+            // Create a temp dir.
+            basedir = System.getProperty("user.dir") + 
+                "/tomcat." + port;
+            File home = new File(basedir);
+            home.mkdir();
+            if (!home.isAbsolute()) {
+                try {
+                    basedir = home.getCanonicalPath();
+                } catch (IOException e) {
+                    basedir = home.getAbsolutePath();
+                }
+            }
+        }
+        System.setProperty("catalina.home", basedir);
+        System.setProperty("catalina.base", basedir);
+    }
+
+    static String[] silences = new String[] {
+        "org.apache.coyote.http11.Http11Protocol",
+        "org.apache.catalina.core.StandardService",
+        "org.apache.catalina.core.StandardEngine",
+        "org.apache.catalina.startup.ContextConfig",
+        "org.apache.catalina.core.ApplicationContext",
+    };
+    
+    public void setSilent() {
+        for (String s : silences) {
+            Logger.getLogger(s).setLevel(Level.WARNING);
+        }
+    }
+    
+    private void silence(String ctx) {
+        String base = "org.apache.catalina.core.ContainerBase.[default].[";
+        base += getHost().getName();
+        base += "].[";
+        base += ctx; 
+        base += "]";
+        Logger.getLogger(base).setLevel(Level.WARNING);
+    }
+    
+    /** Init default servlets for the context. This should be the programmatic
+     * equivalent of the default web.xml. 
+     * 
+     *  TODO: in normal tomcat, if default-web.xml is not found, use this 
+     *  method
+     */
+    protected void initWebappDefaults(StandardContext ctx) {
+        // Default servlet 
+        StandardWrapper servlet = 
+            addServlet(ctx, "default", 
+                    //new DefaultServlet());
+        // Or:
+                    "org.apache.catalina.servlets.DefaultServlet");
+        servlet.addInitParameter("listings", "false");
+        servlet.setLoadOnStartup(1);
+
+        // class name - to avoid loading all deps
+        servlet = addServlet(ctx, "jsp", 
+            "org.apache.jasper.servlet.JspServlet");
+        servlet.addInitParameter("fork", "false");
+        servlet.addInitParameter("xpoweredBy", "false");
+        
+        // in default web.xml - but not here, only needed if you have
+        // jsps.
+        //servlet.setLoadOnStartup(3);
+        
+        ctx.addServletMapping("/", "default");
+        ctx.addServletMapping("*.jsp", "jsp");
+        ctx.addServletMapping("*.jspx", "jsp");
+        // Sessions
+        ctx.setManager( new StandardManager());
+        ctx.setSessionTimeout(30);
+        
+        // TODO: read mime from /etc/mime.types on linux, or some
+        // resource
+        for (int i = 0; i < DEFAULT_MIME_MAPPINGS.length; ) {
+            ctx.addMimeMapping(DEFAULT_MIME_MAPPINGS[i++],
+                    DEFAULT_MIME_MAPPINGS[i++]);
+        }
+        ctx.addWelcomeFile("index.html");
+        ctx.addWelcomeFile("index.htm");
+        ctx.addWelcomeFile("index.jsp");
+        
+        ctx.setLoginConfig( new LoginConfig("NONE", null, null, null));
+        
+        // TODO: set a default realm, add simple API to add users
+    }
+
+    
+    /** Fix startup sequence - required if you don't use web.xml.
+     * 
+     *  The start() method in context will set 'configured' to false - and
+     *  expects a listener to set it back to true.
+     */
+    public static class FixContextListener implements LifecycleListener {
+
+        public void lifecycleEvent(LifecycleEvent event) {
+            try {
+                Context context = (Context) event.getLifecycle();
+                if (event.getType().equals(Lifecycle.START_EVENT)) {
+                    context.setConfigured(true);
+                }
+            } catch (ClassCastException e) {
+                return;
+            }
+        }
+        
+    }
+
+    /** Helper class for wrapping existing servlets. This disables servlet 
+     * lifecycle and normal reloading, but also reduces overhead and provide
+     * more direct control over the servlet.  
+     */
+    public static class ExistingStandardWrapper extends StandardWrapper {
+        private Servlet existing;
+        boolean init = false;
+        
+        public ExistingStandardWrapper( Servlet existing ) {
+            this.existing = existing;
+        }
+        public synchronized Servlet loadServlet() throws ServletException {
+            if (!init) {
+                existing.init(facade);
+                init = true;
+            }
+            return existing;
+
+        }
+        public long getAvailable() {
+            return 0;
+        }
+        public boolean isUnavailable() {
+            return false;       
+        }
+    }
+    
+    /**
+     * TODO: would a properties resource be better ? Or just parsing
+     * /etc/mime.types ?
+     * This is needed because we don't use the default web.xml, where this 
+     * is encoded.
+     */
+    public static final String[] DEFAULT_MIME_MAPPINGS = {
+        "abs", "audio/x-mpeg", 
+        "ai", "application/postscript", 
+        "aif", "audio/x-aiff", 
+        "aifc", "audio/x-aiff", 
+        "aiff", "audio/x-aiff", 
+        "aim", "application/x-aim", 
+        "art", "image/x-jg", 
+        "asf", "video/x-ms-asf", 
+        "asx", "video/x-ms-asf", 
+        "au", "audio/basic", 
+        "avi", "video/x-msvideo", 
+        "avx", "video/x-rad-screenplay", 
+        "bcpio", "application/x-bcpio", 
+        "bin", "application/octet-stream", 
+        "bmp", "image/bmp", 
+        "body", "text/html", 
+        "cdf", "application/x-cdf", 
+        "cer", "application/x-x509-ca-cert", 
+        "class", "application/java", 
+        "cpio", "application/x-cpio", 
+        "csh", "application/x-csh", 
+        "css", "text/css", 
+        "dib", "image/bmp", 
+        "doc", "application/msword", 
+        "dtd", "application/xml-dtd", 
+        "dv", "video/x-dv", 
+        "dvi", "application/x-dvi", 
+        "eps", "application/postscript", 
+        "etx", "text/x-setext", 
+        "exe", "application/octet-stream", 
+        "gif", "image/gif", 
+        "gtar", "application/x-gtar", 
+        "gz", "application/x-gzip", 
+        "hdf", "application/x-hdf", 
+        "hqx", "application/mac-binhex40", 
+        "htc", "text/x-component", 
+        "htm", "text/html", 
+        "html", "text/html", 
+        "hqx", "application/mac-binhex40", 
+        "ief", "image/ief", 
+        "jad", "text/vnd.sun.j2me.app-descriptor", 
+        "jar", "application/java-archive", 
+        "java", "text/plain", 
+        "jnlp", "application/x-java-jnlp-file", 
+        "jpe", "image/jpeg", 
+        "jpeg", "image/jpeg", 
+        "jpg", "image/jpeg", 
+        "js", "text/javascript", 
+        "jsf", "text/plain", 
+        "jspf", "text/plain", 
+        "kar", "audio/x-midi", 
+        "latex", "application/x-latex", 
+        "m3u", "audio/x-mpegurl", 
+        "mac", "image/x-macpaint", 
+        "man", "application/x-troff-man", 
+        "mathml", "application/mathml+xml", 
+        "me", "application/x-troff-me", 
+        "mid", "audio/x-midi", 
+        "midi", "audio/x-midi", 
+        "mif", "application/x-mif", 
+        "mov", "video/quicktime", 
+        "movie", "video/x-sgi-movie", 
+        "mp1", "audio/x-mpeg", 
+        "mp2", "audio/x-mpeg", 
+        "mp3", "audio/x-mpeg", 
+        "mp4", "video/mp4", 
+        "mpa", "audio/x-mpeg", 
+        "mpe", "video/mpeg", 
+        "mpeg", "video/mpeg", 
+        "mpega", "audio/x-mpeg", 
+        "mpg", "video/mpeg", 
+        "mpv2", "video/mpeg2", 
+        "ms", "application/x-wais-source", 
+        "nc", "application/x-netcdf", 
+        "oda", "application/oda", 
+        "odb", "application/vnd.oasis.opendocument.database", 
+        "odc", "application/vnd.oasis.opendocument.chart", 
+        "odf", "application/vnd.oasis.opendocument.formula", 
+        "odg", "application/vnd.oasis.opendocument.graphics", 
+        "odi", "application/vnd.oasis.opendocument.image", 
+        "odm", "application/vnd.oasis.opendocument.text-master", 
+        "odp", "application/vnd.oasis.opendocument.presentation", 
+        "ods", "application/vnd.oasis.opendocument.spreadsheet", 
+        "odt", "application/vnd.oasis.opendocument.text", 
+        "ogg", "application/ogg", 
+        "otg ", "application/vnd.oasis.opendocument.graphics-template", 
+        "oth", "application/vnd.oasis.opendocument.text-web", 
+        "otp", "application/vnd.oasis.opendocument.presentation-template", 
+        "ots", "application/vnd.oasis.opendocument.spreadsheet-template ", 
+        "ott", "application/vnd.oasis.opendocument.text-template", 
+        "pbm", "image/x-portable-bitmap", 
+        "pct", "image/pict", 
+        "pdf", "application/pdf", 
+        "pgm", "image/x-portable-graymap", 
+        "pic", "image/pict", 
+        "pict", "image/pict", 
+        "pls", "audio/x-scpls", 
+        "png", "image/png", 
+        "pnm", "image/x-portable-anymap", 
+        "pnt", "image/x-macpaint", 
+        "ppm", "image/x-portable-pixmap", 
+        "ppt", "application/powerpoint", 
+        "ps", "application/postscript", 
+        "psd", "image/x-photoshop", 
+        "qt", "video/quicktime", 
+        "qti", "image/x-quicktime", 
+        "qtif", "image/x-quicktime", 
+        "ras", "image/x-cmu-raster", 
+        "rdf", "application/rdf+xml", 
+        "rgb", "image/x-rgb", 
+        "rm", "application/vnd.rn-realmedia", 
+        "roff", "application/x-troff", 
+        "rtf", "application/rtf", 
+        "rtx", "text/richtext", 
+        "sh", "application/x-sh", 
+        "shar", "application/x-shar", 
+        /*"shtml", "text/x-server-parsed-html",*/
+        "smf", "audio/x-midi", 
+        "sit", "application/x-stuffit", 
+        "snd", "audio/basic", 
+        "src", "application/x-wais-source", 
+        "sv4cpio", "application/x-sv4cpio", 
+        "sv4crc", "application/x-sv4crc", 
+        "swf", "application/x-shockwave-flash", 
+        "t", "application/x-troff", 
+        "tar", "application/x-tar", 
+        "tcl", "application/x-tcl", 
+        "tex", "application/x-tex", 
+        "texi", "application/x-texinfo", 
+        "texinfo", "application/x-texinfo", 
+        "tif", "image/tiff", 
+        "tiff", "image/tiff", 
+        "tr", "application/x-troff", 
+        "tsv", "text/tab-separated-values", 
+        "txt", "text/plain", 
+        "ulw", "audio/basic", 
+        "ustar", "application/x-ustar", 
+        "vxml", "application/voicexml+xml", 
+        "xbm", "image/x-xbitmap", 
+        "xht", "application/xhtml+xml", 
+        "xhtml", "application/xhtml+xml", 
+        "xml", "application/xml", 
+        "xpm", "image/x-xpixmap", 
+        "xsl", "application/xml", 
+        "xslt", "application/xslt+xml", 
+        "xul", "application/vnd.mozilla.xul+xml", 
+        "xwd", "image/x-xwindowdump", 
+        "wav", "audio/x-wav", 
+        "svg", "image/svg+xml", 
+        "svgz", "image/svg+xml", 
+        "vsd", "application/x-visio", 
+        "wbmp", "image/vnd.wap.wbmp", 
+        "wml", "text/vnd.wap.wml", 
+        "wmlc", "application/vnd.wap.wmlc", 
+        "wmls", "text/vnd.wap.wmlscript", 
+        "wmlscriptc", "application/vnd.wap.wmlscriptc", 
+        "wmv", "video/x-ms-wmv", 
+        "wrl", "x-world/x-vrml", 
+        "wspolicy", "application/wspolicy+xml", 
+        "Z", "application/x-compress", 
+        "z", "application/x-compress", 
+        "zip", "application/zip", 
+        "xls", "application/vnd.ms-excel", 
+        "doc", "application/vnd.ms-word", 
+        "ppt", "application/vnd.ms-powerpoint"
+    };
+}

Propchange: tomcat/trunk/java/org/apache/catalina/startup/Tomcat.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tomcat/trunk/test/org/apache/catalina/startup/TomcatStartupAPITest.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/startup/TomcatStartupAPITest.java?rev=677640&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/startup/TomcatStartupAPITest.java 
(added)
+++ tomcat/trunk/test/org/apache/catalina/startup/TomcatStartupAPITest.java Thu 
Jul 17 10:14:47 2008
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.catalina.startup;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.tomcat.util.buf.ByteChunk;
+
+public class TomcatStartupAPITest extends TestCase {
+    Tomcat tomcat;
+    // if you run in eclipse - or tomcat src dir 
+    String base = "./"; 
+    File tempDir;
+    static int port = 8001;
+    long t0;
+    
+    /**
+     * Simple servlet to test in-line registration 
+     */
+    public static class HelloWorld extends HttpServlet {
+        public void doGet(HttpServletRequest req, HttpServletResponse res) 
+            throws IOException {
+          res.getWriter().write("Hello world");
+        }
+    }
+
+    public void setUp() throws Exception {
+        t0 = System.currentTimeMillis();
+        tempDir = new File("output/tmp");
+        tempDir.mkdir();
+        
+        tomcat = new Tomcat();
+        tomcat.setBaseDir(tempDir.getAbsolutePath());
+          
+        // If each test is running on same port - they
+        // may interfere with each other (on unix at least)
+        port++;
+        tomcat.setPort(port);
+    }
+    
+    public void tearDown() throws Exception {
+        tomcat.stop();
+        System.err.println("Test time: " + 
+                (System.currentTimeMillis() - t0));
+    }
+    
+    /** 
+     * Start tomcat with a single context and one 
+     * servlet - all programmatic, no server.xml or 
+     * web.xml used.
+     * 
+     * @throws Exception 
+     */
+    public void testProgrammatic() throws Exception {
+        
+        StandardContext ctx = 
+            tomcat.addContext("/", 
+                    tempDir.getAbsolutePath());
+        // You can customize the context by calling 
+        // its API
+        
+        tomcat.addServlet(ctx, "myServlet", 
+                new HelloWorld());
+        ctx.addServletMapping("/", "myServlet");
+        
+        tomcat.start();
+        
+        ByteChunk res = getUrl("http://localhost:"; + port + "/");
+        assertEquals(res.toString(), "Hello world");
+    }
+
+    public void testSingleWebapp() throws Exception {
+        // Currently in sandbox/tomcat-lite
+        File appDir = 
+            new File(base + "output/build/webapps/examples");
+        // app dir is relative to server home
+        StandardContext ctx = 
+            tomcat.addWebapp(null, "/examples", 
+                    appDir.getAbsolutePath());
+        
+        ctx.start();
+        tomcat.start();
+
+        ByteChunk res = getUrl("http://localhost:"; + port + 
"/examples/servlets/servlet/HelloWorldExample");
+        assertTrue(res.toString().indexOf("<h1>Hello World!</h1>") > 0);
+    }
+    
+    public void testLaunchTime() throws Exception {
+        tomcat.addContext(null, "/", base);
+        tomcat.start();
+    }
+    
+    /**
+     *  Wrapper for getting the response.
+     */
+    public static ByteChunk getUrl(String path) throws IOException {
+        ByteChunk out = new ByteChunk();
+        getUrl(path, out, null);
+        return out;
+    }
+
+    public static int getUrl(String path, 
+                             ByteChunk out, 
+                             Map<String, List<String>> resHead) throws 
IOException {
+        URL url = new URL(path);
+        HttpURLConnection connection = 
+            (HttpURLConnection) url.openConnection();
+        connection.setReadTimeout(100000);
+        connection.connect();
+        int rc = connection.getResponseCode();
+        if (resHead != null) {
+            Map<String, List<String>> head = connection.getHeaderFields();
+            resHead.putAll(head);
+        }
+        InputStream is = connection.getInputStream();
+        BufferedInputStream bis = new BufferedInputStream(is);
+        byte[] buf = new byte[2048];
+        int rd = 0;
+        while((rd = bis.read(buf)) > 0) {
+            out.append(buf, 0, rd);
+        }
+        return rc;
+    }
+}

Propchange: 
tomcat/trunk/test/org/apache/catalina/startup/TomcatStartupAPITest.java
------------------------------------------------------------------------------
    svn:eol-style = native



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to