sylvain 2003/06/03 06:25:43
Modified: src/java/org/apache/cocoon/servlet BootstrapServlet.java CocoonServlet.java ParanoidClassLoader.java ParanoidCocoonServlet.java Log: ParanoidCocoonServlet is now really paranoid Revision Changes Path 1.2 +53 -139 cocoon-2.1/src/java/org/apache/cocoon/servlet/BootstrapServlet.java Index: BootstrapServlet.java =================================================================== RCS file: /home/cvs/cocoon-2.1/src/java/org/apache/cocoon/servlet/BootstrapServlet.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- BootstrapServlet.java 9 Mar 2003 00:09:37 -0000 1.1 +++ BootstrapServlet.java 3 Jun 2003 13:25:42 -0000 1.2 @@ -50,19 +50,19 @@ */ package org.apache.cocoon.servlet; -import javax.servlet.*; -import javax.servlet.http.HttpServlet; - import java.io.File; -import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; -import java.util.ArrayList; import java.util.Enumeration; -import java.util.List; import java.util.Set; +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + /** * A bootstrap servlet to allow Cocoon to run in servlet engines that aren't fully * compliant with the servlet 2.2 spec. @@ -81,141 +81,55 @@ * @version CVS $Id$ */ -public class BootstrapServlet extends HttpServlet { - - /** - * The name of the actual servlet class. - */ - public static final String SERVLET_CLASS = "org.apache.cocoon.servlet.CocoonServlet"; +public class BootstrapServlet extends ParanoidCocoonServlet { - protected Servlet servlet; + private File contextDir; - protected ClassLoader classloader; - - protected ServletContext context; - - public void init(ServletConfig config) throws ServletException { - this.context = config.getServletContext(); - - this.context.log("getRealPath(\"/\") = " + context.getRealPath("/")); - - String contextDirParam = config.getInitParameter("context-directory"); - if (contextDirParam == null) { - // Check old form, not consistent with other parameter names - contextDirParam = config.getInitParameter("context-dir"); - if (contextDirParam == null) { - String msg = "The 'context-directory' parameter must be set to the root of the servlet context"; - this.context.log(msg); - throw new ServletException(msg); - } else { - this.context.log("Parameter 'context-dir' is deprecated - use 'context-directory'"); - } - } - - // Ensure context dir doesn't end with a "/" (servlet spec says that paths for - // getResource() should start by a "/") - if (contextDirParam.endsWith("/")) { - contextDirParam = contextDirParam.substring(0, contextDirParam.length() - 1); - } - - // Ensure context dir exists and is a directory - File contextDir = new File(contextDirParam); - if (!contextDir.exists()) { - String msg = "Context dir '" + contextDir + "' doesn't exist"; - this.context.log(msg); - throw new ServletException(msg); - } + protected File getContextDir() throws ServletException { + + ServletContext context = getServletContext(); + ServletConfig config = getServletConfig(); + + log("getRealPath(\"/\") = " + context.getRealPath("/")); + + String contextDirParam = config.getInitParameter("context-directory"); + + if (contextDirParam == null) { + throw new ServletException("The 'context-directory' parameter must be set to the root of the servlet context"); + } + + // Ensure context dir doesn't end with a "/" (servlet spec says that paths for + // getResource() should start by a "/") + if (contextDirParam.endsWith("/")) { + contextDirParam = contextDirParam.substring(0, contextDirParam.length() - 1); + } + + // Ensure context dir exists and is a directory + this.contextDir = new File(contextDirParam); + if (!this.contextDir.exists()) { + String msg = "Context dir '" + this.contextDir + "' doesn't exist"; + log(msg); + throw new ServletException(msg); + } + + if (!this.contextDir.isDirectory()) { + String msg = "Context dir '" + this.contextDir + "' should be a directory"; + log(msg); + throw new ServletException(msg); + } + + context.log("Context dir set to " + this.contextDir); + + return this.contextDir; + } - if (!contextDir.isDirectory()) { - String msg = "Context dir '" + contextDir + "' should be a directory"; - this.context.log(msg); - throw new ServletException(msg); - } - - context.log("Context dir set to " + contextDir); - this.classloader = getClassLoader(contextDirParam); - - try { - Class servletClass = this.classloader.loadClass(SERVLET_CLASS); - - this.servlet = (Servlet)servletClass.newInstance(); - } catch(Exception e) { - context.log("Cannot load servlet", e); - throw new ServletException(e); - } - - // Always set the context classloader. JAXP uses it to find a ParserFactory, - // and thus fails if it's not set to the webapp classloader. - Thread.currentThread().setContextClassLoader(this.classloader); - - ServletContext newContext = new ContextWrapper(context, contextDirParam); - ServletConfig newConfig = new ConfigWrapper(config, newContext); + protected void initServlet(Servlet servlet) throws ServletException { - super.init(newConfig); + ServletContext newContext = new ContextWrapper(getServletContext(), this.contextDir); + ServletConfig newConfig = new ConfigWrapper(getServletConfig(), newContext); - // Inlitialize the actual servlet - this.servlet.init(newConfig); - - } - - /** - * Get the classloader that will be used to create the actual servlet. - */ - protected ClassLoader getClassLoader(String contextDirParam) throws ServletException { - List urlList = new ArrayList(); - - try { - File classDir = new File(contextDirParam + "/WEB-INF/classes"); - if (classDir.exists()) { - if (!classDir.isDirectory()) { - String msg = classDir + " exists but is not a directory"; - this.context.log(msg); - throw new ServletException(msg); - } - - URL classURL = classDir.toURL(); - context.log("Adding class directory " + classURL); - urlList.add(classURL); - - } - - File libDir = new File(contextDirParam + "/WEB-INF/lib"); - File[] libraries = libDir.listFiles(); - - for (int i = 0; i < libraries.length; i++) { - URL lib = libraries[i].toURL(); - context.log("Adding class library " + lib); - urlList.add(lib); - } - } catch (MalformedURLException mue) { - context.log("Malformed url", mue); - throw new ServletException(mue); - } - - URL[] urls = (URL[])urlList.toArray(new URL[urlList.size()]); - - return ParanoidClassLoader.newInstance(urls, this.getClass().getClassLoader()); - } - - /** - * Service the request by delegating the call to the real servlet - */ - public void service(ServletRequest request, ServletResponse response) - throws ServletException, IOException { - - Thread.currentThread().setContextClassLoader(this.classloader); - this.servlet.service(request, response); - } - - /** - * Destroy the actual servlet - */ - public void destroy() { - - super.destroy(); - Thread.currentThread().setContextClassLoader(this.classloader); - this.servlet.destroy(); + servlet.init(newConfig); } //------------------------------------------------------------------------- @@ -260,13 +174,13 @@ */ public static class ContextWrapper implements ServletContext { ServletContext context; - String contextRoot; + File contextRoot; /** * Builds a wrapper around an existing context, and handle all * resource resolution relatively to <code>contextRoot</code> */ - public ContextWrapper(ServletContext context, String contextRoot) { + public ContextWrapper(ServletContext context, File contextRoot) { this.context = context; this.contextRoot = contextRoot; } @@ -293,7 +207,7 @@ * returned. */ public URL getResource(String path) throws MalformedURLException { - File file = new File(this.contextRoot + path); + File file = new File(this.contextRoot, path); if (file.exists()) { URL result = file.toURL(); //this.context.log("getResource(" + path + ") = " + result); 1.8 +83 -100 cocoon-2.1/src/java/org/apache/cocoon/servlet/CocoonServlet.java Index: CocoonServlet.java =================================================================== RCS file: /home/cvs/cocoon-2.1/src/java/org/apache/cocoon/servlet/CocoonServlet.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- CocoonServlet.java 20 May 2003 12:38:27 -0000 1.7 +++ CocoonServlet.java 3 Jun 2003 13:25:42 -0000 1.8 @@ -269,9 +269,12 @@ super.init(conf); - final String initClassLoaderParam = conf.getInitParameter("init-classloader"); - this.initClassLoader = "true".equalsIgnoreCase(initClassLoaderParam) || - "yes".equalsIgnoreCase(initClassLoaderParam); + // Check the init-classloader parameter only if it's not already true. + // This is useful for subclasses of this servlet that override the value + // initially set by this class (i.e. false). + if (!this.initClassLoader) { + this.initClassLoader = getInitParameterAsBoolean("init-classloader", false); + } if (this.initClassLoader) { // Force context classloader so that JAXP can work correctly @@ -298,8 +301,8 @@ // first init the work-directory for the logger. // this is required if we are running inside a war file! - final String workDirParam = conf.getInitParameter("work-directory"); - if ((workDirParam != null) && (!workDirParam.trim().equals(""))) { + final String workDirParam = getInitParameter("work-directory"); + if (workDirParam != null) { if (this.servletContextPath == null) { // No context path : consider work-directory as absolute this.workDir = new File(workDirParam); @@ -361,17 +364,12 @@ log.debug("URL for Root: " + this.servletContextURL); } - this.forceLoadParameter = conf.getInitParameter("load-class"); - if (conf.getInitParameter("load-class") == null) { - if (log.isDebugEnabled()) { - log.debug("load-class was not set - defaulting to false?"); - } - } + this.forceLoadParameter = getInitParameter("load-class", null); - this.forceSystemProperty = conf.getInitParameter("force-property"); + this.forceSystemProperty = getInitParameter("force-property", null); // add work directory - if ((workDirParam != null) && (!workDirParam.trim().equals(""))) { + if (workDirParam != null) { if (log.isDebugEnabled()) { log.debug("Using work-directory " + this.workDir); } @@ -383,7 +381,7 @@ this.appContext.put(Constants.CONTEXT_WORK_DIR, workDir); final String uploadDirParam = conf.getInitParameter("upload-directory"); - if ((uploadDirParam != null) && (!uploadDirParam.trim().equals(""))) { + if (uploadDirParam != null) { if (this.servletContextPath == null) { this.uploadDir = new File(uploadDirParam); } else { @@ -409,33 +407,12 @@ this.uploadDir.mkdirs(); this.appContext.put(Constants.CONTEXT_UPLOAD_DIR, this.uploadDir); - value = conf.getInitParameter("enable-uploads"); - if (value != null) { - this.enableUploads = ("yes".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value)); - } else { - this.enableUploads = ENABLE_UPLOADS; - if (log.isDebugEnabled()) { - log.debug("enable-uploads was not set - defaulting to " + this.enableUploads); - } - } + this.enableUploads = getInitParameterAsBoolean("enable-uploads", ENABLE_UPLOADS); - value = conf.getInitParameter("autosave-uploads"); - if (value != null) { - this.autoSaveUploads = ("yes".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value)); - } else { - this.autoSaveUploads = SAVE_UPLOADS_TO_DISK; - if (log.isDebugEnabled()) { - log.debug("autosave-uploads was not set - defaulting to " + this.autoSaveUploads); - } - } + this.autoSaveUploads = getInitParameterAsBoolean("autosave-uploads", SAVE_UPLOADS_TO_DISK); - String overwriteParam = conf.getInitParameter("overwrite-uploads"); + String overwriteParam = getInitParameter("overwrite-uploads", "rename"); // accepted values are deny|allow|rename - rename is default. - if (overwriteParam == null) { - if (log.isDebugEnabled()) { - log.debug("overwrite-uploads was not set - defaulting to rename"); - } - } if ("deny".equalsIgnoreCase(overwriteParam)) { this.allowOverwrite = false; this.silentlyRename = false; @@ -448,14 +425,10 @@ this.silentlyRename = true; } - this.maxUploadSize = MAX_UPLOAD_SIZE; - String maxSizeParam = conf.getInitParameter("upload-max-size"); - if ((maxSizeParam != null) && (!maxSizeParam.trim().equals(""))) { - this.maxUploadSize = Integer.parseInt(maxSizeParam); - } + this.maxUploadSize = getInitParameterAsInteger("upload-max-size", MAX_UPLOAD_SIZE); String cacheDirParam = conf.getInitParameter("cache-directory"); - if ((cacheDirParam != null) && (!cacheDirParam.trim().equals(""))) { + if (cacheDirParam != null) { if (this.servletContextPath == null) { this.cacheDir = new File(cacheDirParam); } else { @@ -490,15 +463,7 @@ } // get allow reload parameter, default is true - value = conf.getInitParameter("allow-reload"); - if (value != null) { - this.allowReload = value.equalsIgnoreCase("yes") || value.equalsIgnoreCase("true"); - } else { - this.allowReload = ALLOW_RELOAD; - if (log.isDebugEnabled()) { - log.debug("allow-reload was not set - defaulting to " + ALLOW_RELOAD); - } - } + this.allowReload = getInitParameterAsBoolean("allow-reload", ALLOW_RELOAD); value = conf.getInitParameter("show-time"); this.showTime = "yes".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value) @@ -509,12 +474,8 @@ } } - parentComponentManagerClass = conf.getInitParameter("parent-component-manager"); - if (parentComponentManagerClass == null) { - if (log.isDebugEnabled()) { - log.debug("parent-component-manager was not set - defaulting to null."); - } - } else { + parentComponentManagerClass = getInitParameter("parent-component-manager", null); + if (parentComponentManagerClass != null) { int dividerPos = parentComponentManagerClass.indexOf('/'); if (dividerPos != -1) { parentComponentManagerInitParam = parentComponentManagerClass.substring(dividerPos + 1); @@ -522,38 +483,12 @@ } } - this.containerEncoding = conf.getInitParameter("container-encoding"); - if (containerEncoding == null) { - this.containerEncoding = "ISO-8859-1"; - if (log.isDebugEnabled()) { - log.debug("container-encoding was not set - defaulting to ISO-8859-1."); - } - } - - this.defaultFormEncoding = conf.getInitParameter("form-encoding"); - if (defaultFormEncoding == null) { - this.defaultFormEncoding = "ISO-8859-1"; - if (log.isDebugEnabled()) { - log.debug("form-encoding was not set - defaulting to ISO-8859-1."); - } - } + this.containerEncoding = getInitParameter("container-encoding", "ISO-8859-1"); + this.defaultFormEncoding = getInitParameter("form-encoding","ISO-8859-1"); - value = conf.getInitParameter("manage-exceptions"); - this.manageExceptions = (value == null || value.equalsIgnoreCase("yes") || value.equalsIgnoreCase("true")); - if (value == null) { - if (log.isDebugEnabled()) { - log.debug("Parameter manageExceptions was not set - defaulting to true."); - } - } + this.manageExceptions = getInitParameterAsBoolean("manage-exceptions", true); - value = conf.getInitParameter("enable-instrumentation"); - this.enableInstrumentation = - "yes".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value); - if (value == null) { - if (log.isDebugEnabled()) { - log.debug("enable-instrumentation was not set - defaulting to false."); - } - } + this.enableInstrumentation = getInitParameterAsBoolean("enable-instrumentation", false); this.requestFactory = new RequestFactory(this.autoSaveUploads, this.uploadDir, @@ -790,7 +725,7 @@ protected String getExtraClassPath() throws ServletException { String extraClassPath = this.getInitParameter("extra-classpath"); - if ((extraClassPath != null) && !extraClassPath.trim().equals("")) { + if (extraClassPath != null) { StringBuffer sb = new StringBuffer(); StringTokenizer st = new StringTokenizer(extraClassPath, System.getProperty("path.separator"), false); int i = 0; @@ -849,14 +784,11 @@ * file. */ private void initLogger() { - String logLevel = getInitParameter("log-level"); - if (logLevel == null) { - logLevel = "INFO"; - } + String logLevel = getInitParameter("log-level", "INFO"); final String accesslogger = getInitParameter("servlet-logger"); - final Priority logPriority = Priority.getPriorityForName(logLevel.trim()); + final Priority logPriority = Priority.getPriorityForName(logLevel); final ServletOutputLogTarget servTarget = new ServletOutputLogTarget(this.servletContext); @@ -888,10 +820,7 @@ this.logKitManager = logKitManager; //Configure the logkit management - String logkitConfig = getInitParameter("logkit-config"); - if (logkitConfig == null) { - logkitConfig = "/WEB-INF/logkit.xconf"; - } + String logkitConfig = getInitParameter("logkit-config", "/WEB-INF/logkit.xconf"); InputStream is = this.servletContext.getResourceAsStream(logkitConfig); if (is == null) is = new FileInputStream(logkitConfig); @@ -1511,5 +1440,59 @@ this.cocoon.dispose(); this.cocoon = null; } + } + + /** + * Get an initialisation parameter. The value is trimmed, and null is returned if the trimmed value + * is empty. + */ + public String getInitParameter(String name) { + String result = super.getInitParameter(name); + if (result != null) { + result = result.trim(); + if (result.length() == 0) { + result = null; + } + } + + return result; + } + + /** Convenience method to access servlet parameters */ + protected String getInitParameter(String name, String defaultValue) { + String result = getInitParameter(name); + if (result == null) { + if (log != null && log.isDebugEnabled()) { + log.debug(name + " was not set - defaulting to '" + defaultValue + "'"); + } + return defaultValue; + } else { + return result; + } + } + + /** Convenience method to access boolean servlet parameters */ + protected boolean getInitParameterAsBoolean(String name, boolean defaultValue) { + String value = getInitParameter(name); + if (value == null) { + if (log != null && log.isDebugEnabled()) { + log.debug(name + " was not set - defaulting to '" + defaultValue + "'"); + } + return defaultValue; + } else { + return value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes"); + } + } + + protected int getInitParameterAsInteger(String name, int defaultValue) { + String value = getInitParameter(name); + if (value == null) { + if (log != null && log.isDebugEnabled()) { + log.debug(name + " was not set - defaulting to '" + defaultValue + "'"); + } + return defaultValue; + } else { + return Integer.parseInt(value); + } } } 1.2 +12 -3 cocoon-2.1/src/java/org/apache/cocoon/servlet/ParanoidClassLoader.java Index: ParanoidClassLoader.java =================================================================== RCS file: /home/cvs/cocoon-2.1/src/java/org/apache/cocoon/servlet/ParanoidClassLoader.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- ParanoidClassLoader.java 9 Mar 2003 00:09:37 -0000 1.1 +++ ParanoidClassLoader.java 3 Jun 2003 13:25:42 -0000 1.2 @@ -64,7 +64,7 @@ * classes. It checks this classloader before it checks its parent. * * @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a> - * @author <a href="mailto:[EMAIL PROTECTED]">Sylvain Wallez</a> + * @author <a href="http://www.apache.org/~sylvain/">Sylvain Wallez</a> * @version CVS $Id$ */ @@ -85,7 +85,7 @@ * Alternate constructor to define a parent. */ public ParanoidClassLoader(final ClassLoader parent) { - this(null, parent, null); + this(new URL[0], parent, null); } /** @@ -151,6 +151,7 @@ try { clazz = findClass(name); + //System.err.println("Paranoid load : " + name); } catch (ClassNotFoundException cnfe) { if (this.parent != null) { // Ask to parent ClassLoader (can also throw a CNFE). @@ -201,5 +202,13 @@ } catch (MalformedURLException mue) { throw new CascadingIOException("Could not add repository", mue); } + } + + /** + * Adds a new URL + */ + + public void addURL(URL url) { + super.addURL(url); } } 1.2 +138 -100 cocoon-2.1/src/java/org/apache/cocoon/servlet/ParanoidCocoonServlet.java Index: ParanoidCocoonServlet.java =================================================================== RCS file: /home/cvs/cocoon-2.1/src/java/org/apache/cocoon/servlet/ParanoidCocoonServlet.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- ParanoidCocoonServlet.java 9 Mar 2003 00:09:37 -0000 1.1 +++ ParanoidCocoonServlet.java 3 Jun 2003 13:25:42 -0000 1.2 @@ -50,12 +50,20 @@ */ package org.apache.cocoon.servlet; -import org.apache.cocoon.components.classloader.RepositoryClassLoader; -import org.apache.cocoon.util.IOUtils; - -import javax.servlet.ServletException; import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.net.MalformedURLException; import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServlet; /** * This is the entry point for Cocoon execution as an HTTP Servlet. @@ -66,105 +74,135 @@ * of it. * * @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a> + * @author <a href="http://www.apache.org/~sylvain/">Sylvain Wallez</a> * @version CVS $Id$ */ -public class ParanoidCocoonServlet extends CocoonServlet { +public class ParanoidCocoonServlet extends HttpServlet { - protected RepositoryClassLoader repositoryLoader; + /** + * The name of the actual servlet class. + */ + public static final String SERVLET_CLASS = "org.apache.cocoon.servlet.CocoonServlet"; + + private Servlet servlet; + + private ClassLoader classloader; - public ParanoidCocoonServlet() { - super(); - // Override the parent class classloader - this.repositoryLoader = new RepositoryClassLoader(new URL[] {}, this.getClass().getClassLoader()); - super.classLoader = this.repositoryLoader; - } - - /** - * This builds the important ClassPath used by this Servlet. It - * does so in a Servlet Engine neutral way. It uses the - * <code>ServletContext</code>'s <code>getRealPath</code> method - * to get the Servlet 2.2 identified classes and lib directories. - * It iterates through every file in the lib directory and adds - * it to the classpath. - * - * Also, we add the files to the ClassLoader for the Cocoon system. - * In order to protect ourselves from skitzofrantic classloaders, - * we need to work with a known one. - * - * @param context The ServletContext to perform the lookup. - * - * @throws ServletException - */ - protected String getClassPath() - throws ServletException { - - StringBuffer buildClassPath = new StringBuffer(); - String classDirPath = getInitParameter("class-dir"); - String libDirPath = getInitParameter("lib-dir"); - String classDir; - File root; - - if ((classDirPath != null) && !classDirPath.trim().equals("")) { - classDir = classDirPath; - } else { - classDir = this.servletContext.getRealPath("/WEB-INF/classes"); - } - - if ((libDirPath != null) && !libDirPath.trim().equals("")) { - root = new File(libDirPath); - } else { - root = new File(this.servletContext.getRealPath("/WEB-INF/lib")); - } - - addClassLoaderDirectory(classDir); - - buildClassPath.append(classDir); - - if (root.isDirectory()) { - File[] libraries = root.listFiles(); - - for (int i = 0; i < libraries.length; i++) { - String fullName = IOUtils.getFullFilename(libraries[i]); - buildClassPath.append(File.pathSeparatorChar).append(fullName); - - addClassLoaderDirectory(fullName); - } - } - - buildClassPath.append(File.pathSeparatorChar) - .append(System.getProperty("java.class.path")); - - buildClassPath.append(File.pathSeparatorChar) - .append(getExtraClassPath()); - - return buildClassPath.toString(); - } - - /** - * Adds an URL to the classloader. - */ - protected void addClassLoaderURL(URL url) { - try { - this.repositoryLoader.addURL(url); - } catch (Exception e) { - if (log.isDebugEnabled()) { - log.debug("Could not add URL" + url, e); - } - } - } - - /** - * Adds a directory to the classloader. - */ - protected void addClassLoaderDirectory(String dir) { - try { - this.repositoryLoader.addDirectory(new File(dir)); - } catch (Exception e) { - if (log.isDebugEnabled()) { - log.debug("Could not add directory" + dir, e); - } - } - } + public void init(ServletConfig config) throws ServletException { + + super.init(config); + + // Create the classloader in which we will load the servlet + this.classloader = getClassLoader(this.getContextDir()); + + // Create the servlet + try { + Class servletClass = this.classloader.loadClass(SERVLET_CLASS); + + this.servlet = (Servlet)servletClass.newInstance(); + + } catch(Exception e) { + throw new ServletException("Cannot load servlet " + SERVLET_CLASS, e); + } + + // Always set the context classloader. JAXP uses it to find a ParserFactory, + // and thus fails if it's not set to the webapp classloader. + Thread.currentThread().setContextClassLoader(this.classloader); + + // Inlitialize the actual servlet + initServlet(servlet); + + } + + /** + * Initialize the wrapped servlet. Subclasses (see [EMAIL PROTECTED] BootstrapServlet} change the + * <code>ServletConfig</code> given to the servlet. + * + * @param servlet the servlet to initialize + * @throws ServletException + */ + protected void initServlet(Servlet servlet) throws ServletException { + this.servlet.init(getServletConfig()); + } + + /** + * Get the web application context directory. + * + * @return the context dir + * @throws ServletException + */ + protected File getContextDir() throws ServletException { + String result = getServletContext().getRealPath("/"); + if (result == null) { + throw new ServletException(this.getClass().getName() + " cannot run in an undeployed WAR file"); + } + return new File(result); + } + + /** + * Get the classloader that will be used to create the actual servlet. Its classpath is defined + * by the WEB-INF/classes and WEB-INF/lib directories in the context dir. + */ + private ClassLoader getClassLoader(File contextDir) throws ServletException { + List urlList = new ArrayList(); + + try { + File classDir = new File(contextDir + "/WEB-INF/classes"); + if (classDir.exists()) { + if (!classDir.isDirectory()) { + throw new ServletException(classDir + " exists but is not a directory"); + } + + URL classURL = classDir.toURL(); + log("Adding class directory " + classURL); + urlList.add(classURL); + + } + + // List all .jar and .zip + File libDir = new File(contextDir + "/WEB-INF/lib"); + File[] libraries = libDir.listFiles( + new FilenameFilter() { + public boolean accept(File dir, String name) { + return name.endsWith(".zip") || name.endsWith(".jar"); + } + } + ); + + for (int i = 0; i < libraries.length; i++) { + URL lib = libraries[i].toURL(); + log("Adding class library " + lib); + urlList.add(lib); + } + } catch (MalformedURLException mue) { + throw new ServletException(mue); + } + + URL[] urls = (URL[])urlList.toArray(new URL[urlList.size()]); + + return ParanoidClassLoader.newInstance(urls, this.getClass().getClassLoader()); + } + + /** + * Service the request by delegating the call to the real servlet + */ + public void service(ServletRequest request, ServletResponse response) + throws ServletException, IOException { + + Thread.currentThread().setContextClassLoader(this.classloader); + this.servlet.service(request, response); + } + + /** + * Destroy the actual servlet + */ + public void destroy() { + + Thread.currentThread().setContextClassLoader(this.classloader); + this.servlet.destroy(); + + super.destroy(); + } }