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]