sylvain     2003/12/11 10:22:14

  Added:       src/blocks/paranoid/java/org/apache/cocoon/servlet
                        BootstrapServlet.java ParanoidClassLoader.java
                        ParanoidCocoonServlet.java
  Log:
  Move the paranoid servlet to a block to have a separate jar
  
  Revision  Changes    Path
  1.1                  
cocoon-2.1/src/blocks/paranoid/java/org/apache/cocoon/servlet/BootstrapServlet.java
  
  Index: BootstrapServlet.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      [EMAIL PROTECTED]
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.servlet;
  
  import java.io.File;
  import java.io.InputStream;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.util.Enumeration;
  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.
   * <p>
   * This servlet adds a mandatory "context-dir" parameter to those accepted by 
[EMAIL PROTECTED] CocoonServlet},
   * which should point to Cocoon's context directory (e.g. 
"<code>/path-to-webapp/cocoon</code>").
   * This directory is used to :
   * <ul>
   * <li>build a classloader with the correct class path with the contents of
   *     <code>WEB-INF/classes</code> and <code>WEB-INF/lib</code> (see
   *     [EMAIL PROTECTED] ParanoidClassLoader}),</li>
   * <li>resolve paths for context resources.
   * </ul>
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Sylvain Wallez</a>
   * @version CVS $Id: BootstrapServlet.java,v 1.1 2003/12/11 18:22:14 sylvain 
Exp $
   */
  
  public class BootstrapServlet extends ParanoidCocoonServlet {
      
      protected File contextDir;
      
        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;
        }
  
  
      protected void initServlet() throws ServletException {
          
          ServletContext newContext = new ContextWrapper(getServletContext(), 
this.contextDir);
          ServletConfig newConfig = new ConfigWrapper(getServletConfig(), 
newContext);
          
          this.servlet.init(newConfig);        
      }
  
      
//-------------------------------------------------------------------------
      /**
       * Implementation of <code>ServletConfig</code> passed to the actual 
servlet.
       * It wraps the original config object and returns the new context.
       */
      public static class ConfigWrapper implements ServletConfig {
          ServletConfig config;
          ServletContext context;
          
          /**
           * Builds a <code>ServletConfig</code> using a servlet name and
           * a <code>ServletContext</code>.
           */
          public ConfigWrapper(ServletConfig config, ServletContext context) {
              this.config = config;
              this.context = context;
          }
          public String getServletName() {
              return config.getServletName();
          }
          
          public Enumeration getInitParameterNames() {
              return this.config.getInitParameterNames();
          }
          
          public ServletContext getServletContext() {
              return this.context;
          }
          
          public String getInitParameter(String name) {
              return config.getInitParameter(name);
          }
      }
  
      
//-------------------------------------------------------------------------
      /**
       * Wrapper for the <code>ServletContext</code> passed to the actual 
servlet.
       * It implements all resource-related methods using the provided context
       * root directory. Other calls are delegated to the wrapped context.
       */
      public static class ContextWrapper implements ServletContext {
          ServletContext context;
          File contextRoot;
          
          /**
           * Builds a wrapper around an existing context, and handle all
           * resource resolution relatively to <code>contextRoot</code>
           */
          public ContextWrapper(ServletContext context, File contextRoot) {
              this.context = context;
              this.contextRoot = contextRoot;
          }
          
          public ServletContext getContext(String param) {
              return this.context.getContext(param);
          }
      
          public int getMajorVersion() {
              return this.context.getMajorVersion();
          }
      
          public int getMinorVersion() {
              return this.context.getMinorVersion();
          }
      
          public String getMimeType(String param) {
              return this.context.getMimeType(param);
          }
  
          /**
           * Returns the resource URL by appending <code>path</code> to the 
context
           * root. If this doesn't point to an existing file, <code>null</code> 
is
           * returned.
           */
          public URL getResource(String path) throws MalformedURLException {
              File file = new File(this.contextRoot, path);
              if (file.exists()) {
                  URL result = file.toURL();
                  //this.context.log("getResource(" + path + ") = " + result);
                  return result;
              } else {
                  //this.context.log("getResource(" + path + ") = null");
                  return null;
              }
          }
      
          /**
           * Returns the stream for the result of <code>getResource()</code>, or
           * <code>null</code> if the resource doesn't exist.
           */
          public InputStream getResourceAsStream(String path) {
              try {
                  URL url = getResource(path);
                  return (url == null) ? null : url.openStream();
              } catch(Exception e) {
                  this.context.log("getResourceAsStream(" + path + ") failed", 
e);
                  return null;
              }
          }
      
          public RequestDispatcher getRequestDispatcher(String param) {
              return this.context.getRequestDispatcher(param);
          }
      
          public RequestDispatcher getNamedDispatcher(String param) {
              return this.context.getNamedDispatcher(param);
          }
  
          /**
           * @deprecated The method 
BootstrapServlet.ContextWrapper.getServlet(String)
           *             overrides a deprecated method from ServletContext.
           * @see <a 
href="http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/ServletContext.html#getServlet(java.lang.String)">ServletContext#getServlet(java.lang.String)</a>
           */
          public Servlet getServlet(String param) throws ServletException {
              return this.context.getServlet(param);
          }
  
          /**
           * @deprecated The method 
BootstrapServlet.ContextWrapper.getServlets()
           *             overrides a deprecated method from ServletContext.
           * @see <a 
href="http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/ServletContext.html#getServlets()">ServletContext#getServlets()</a>
           */
          public Enumeration getServlets() {
              return this.context.getServlets();
          }
  
          /**
           * @deprecated The method 
BootstrapServlet.ContextWrapper.getServletNames()
           *             overrides a deprecated method from ServletContext.
           * @see <a 
href="http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/ServletContext.html#getServletNames()">ServletContext#getServletNames()</a>
           */
          public Enumeration getServletNames() {
              return this.context.getServletNames();
          }
      
          public void log(String msg) {
              this.context.log(msg);
          }
  
          /** @deprecated use [EMAIL PROTECTED] #log(String message, Throwable 
throwable)} instead. */
          public void log(Exception ex, String msg) {
              this.context.log(ex, msg);
          }
      
          public void log(String msg, Throwable thr) {
              this.context.log(msg, thr);
          }
  
          /**
           * Appends <code>path</code> to the context root.
           */
          public String getRealPath(String path) {
              String result = this.contextRoot + path;
              //this.context.log("getRealPath(" + path + ") = " + result);
              return result;
          }
      
          public String getServerInfo() {
              return this.context.getServerInfo();
          }
      
          public String getInitParameter(String param) {
              return this.context.getInitParameter(param);
          }
      
          public Enumeration getInitParameterNames() {
              return this.context.getInitParameterNames();
          }
      
          public Object getAttribute(String param) {
              Object result = this.context.getAttribute(param);
              //this.context.log("getAttribute(" + param + ") = " + result);
              return result;
          }
      
          public Enumeration getAttributeNames() {
              return this.context.getAttributeNames();
          }
      
          public void setAttribute(String name, Object value) {
              this.context.setAttribute(name, value);
          }
      
          public void removeAttribute(String name) {
              this.context.removeAttribute(name);
          }
          
          // Implementation of Servlet 2.3 methods. This is not absolutely 
required
          // for real usage since this servlet is targeted at 2.2, but is needed
          // for successful compilation
          public Set getResourcePaths(String param) {
              return null;
          }
          
          public String getServletContextName() {
              return "Cocoon context";
          }
      }
  }
  
  
  
  
  1.1                  
cocoon-2.1/src/blocks/paranoid/java/org/apache/cocoon/servlet/ParanoidClassLoader.java
  
  Index: ParanoidClassLoader.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      [EMAIL PROTECTED]
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.servlet;
  
  import java.io.File;
  import java.io.IOException;
  import java.net.URL;
  import java.net.URLClassLoader;
  import java.net.URLStreamHandlerFactory;
  
  /**
   * The <code>ParanoidClassLoader</code> reverses the search order for
   * classes.  It checks this classloader before it checks its parent.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
   * @author <a href="http://www.apache.org/~sylvain/";>Sylvain Wallez</a>
   * @version CVS $Id: ParanoidClassLoader.java,v 1.1 2003/12/11 18:22:14 
sylvain Exp $
   */
  
  public class ParanoidClassLoader extends URLClassLoader {
  
      /**
       * Default constructor has no parents or initial <code>URL</code>s.
       */
      public ParanoidClassLoader() {
          this(null, null, null);
      }
  
      /**
       * Alternate constructor to define a parent.
       */
      public ParanoidClassLoader(final ClassLoader parent) {
          this(new URL[0], parent, null);
      }
  
      /**
       * Alternate constructor to define initial <code>URL</code>s.
       */
      public ParanoidClassLoader(final URL[] urls) {
          this(urls, null, null);
      }
  
      /**
       * Alternate constructor to define a parent and initial
       * <code>URL</code>s.
       */
      public ParanoidClassLoader(final URL[] urls, final ClassLoader parent) {
          this(urls, parent, null);
      }
  
      /**
       * Alternate constructor to define a parent, initial
       * <code>URL</code>s, and a default
       * <code>URLStreamHandlerFactory</code>.
       */
      public ParanoidClassLoader(final URL[] urls, final ClassLoader parent, 
final URLStreamHandlerFactory factory) {
          super(urls, parent, factory);
      }
  
      /**
       * Extends <code>URLClassLoader</code>'s initialization methods so
       * we return a <code>ParanoidClassLoad</code> instead.
       */
      public static final URLClassLoader newInstance(final URL[] urls) {
          return new ParanoidClassLoader(urls);
      }
  
      /**
       * Extends <code>URLClassLoader</code>'s initialization methods so
       * we return a <code>ParanoidClassLoad</code> instead.
       */
      public static final URLClassLoader newInstance(final URL[] urls, final 
ClassLoader parent) {
          return new ParanoidClassLoader(urls, parent);
      }
  
      /**
       * Loads the class from this <code>ClassLoader</class>.  If the
       * class does not exist in this one, we check the parent.  Please
       * note that this is the exact opposite of the
       * <code>ClassLoader</code> spec.  We use it to work around
       * inconsistent class loaders from third party vendors.
       *
       * @param     name the name of the class
       * @param     resolve if <code>true</code> then resolve the class
       * @return    the resulting <code>Class</code> object
       * @exception ClassNotFoundException if the class could not be found
       */
      public final Class loadClass(String name, boolean resolve)
        throws ClassNotFoundException
      {
          // First check if it's already loaded
          Class clazz = findLoadedClass(name);
          
          if (clazz == null) {
              
              try {
                  clazz = findClass(name);
                  //System.err.println("Paranoid load : " + name);
              } catch (ClassNotFoundException cnfe) {
                  ClassLoader parent = getParent();
                  if (parent != null) {
                       // Ask to parent ClassLoader (can also throw a CNFE).
                      clazz = parent.loadClass(name);
                  } else {
                      // Propagate exception
                      throw cnfe;
                  }
              }
          }
          
          if (resolve) {
              resolveClass(clazz);
          }
          
          return clazz;
      }
      
      /**
       * Gets a resource from this <code>ClassLoader</class>.  If the
       * resource does not exist in this one, we check the parent.
       * Please note that this is the exact opposite of the
       * <code>ClassLoader</code> spec.  We use it to work around
       * inconsistent class loaders from third party vendors.
       *
       * @param name of resource
       */
      public final URL getResource(final String name) {
  
          URL resource = findResource(name);
          ClassLoader parent = this.getParent();
          if (resource == null && parent != null) {
              resource = parent.getResource(name);
          }
  
          return resource;
      }
  
      /**
       * Adds a new directory of class files.
       *
       * @param file for jar or directory
       * @throws IOException
       */
      public final void addDirectory(File file) throws IOException {
          this.addURL(file.getCanonicalFile().toURL());
      }
      
      /**
       * Adds a new URL
       */
      
      public void addURL(URL url) {
        super.addURL(url);
      }
  }
  
  
  
  1.1                  
cocoon-2.1/src/blocks/paranoid/java/org/apache/cocoon/servlet/ParanoidCocoonServlet.java
  
  Index: ParanoidCocoonServlet.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      [EMAIL PROTECTED]
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.servlet;
  
  import java.io.File;
  import java.io.FileReader;
  import java.io.FilenameFilter;
  import java.io.IOException;
  import java.io.LineNumberReader;
  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 servlet builds a classloading sandbox and runs another servlet inside 
that
   * sandbox. The purpose is to shield the libraries and classes shipped with 
the web
   * application from any other classes with the same name that may exist in 
the system,
   * such as Xerces and Xalan versions included in JDK 1.4.
   * <p>
   * This servlet propagates all initialisation parameters to the sandboxed 
servlet, and
   * accept only one additional parameter, <code>servlet-class</code>, which 
defined the
   * sandboxed servlet class. The default is [EMAIL PROTECTED] CocoonServlet}.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
   * @author <a href="http://www.apache.org/~sylvain/";>Sylvain Wallez</a>
   * @version CVS $Id: ParanoidCocoonServlet.java,v 1.1 2003/12/11 18:22:14 
sylvain Exp $
   */
  
  public class ParanoidCocoonServlet extends HttpServlet {
  
        /**
         * The name of the actual servlet class.
         */
        public static final String DEFAULT_SERVLET_CLASS = 
"org.apache.cocoon.servlet.CocoonServlet";
      
        protected Servlet servlet;
      
      protected ClassLoader classloader;
      
        public void init(ServletConfig config) throws ServletException {
                
                super.init(config);
  
                // Create the classloader in which we will load the servlet
          // this can either be specified by an external file configured
          // as a parameter in web.xml or (the default) all jars and 
          // classes from WEB-INF/lib and WEB-INF/classes are used.
          final String externalClasspath = 
config.getInitParameter("paranoid-classpath");
          if ( externalClasspath == null ) {
              this.classloader = this.getClassLoader(this.getContextDir());
          } else {
              this.classloader = this.getClassLoader(externalClasspath);
          }
          
          String servletName = config.getInitParameter("servlet-class");
          if (servletName == null) {
              servletName = DEFAULT_SERVLET_CLASS;
          }
          
          // Create the servlet
                try {
                        Class servletClass = 
this.classloader.loadClass(servletName);
              
                        this.servlet = (Servlet)servletClass.newInstance();
  
                } catch(Exception e) {
                        throw new ServletException("Cannot load servlet " + 
servletName, 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.
          final ClassLoader old = 
Thread.currentThread().getContextClassLoader();
          try {
              Thread.currentThread().setContextClassLoader(this.classloader);
          
              // Inlitialize the actual servlet
              this.initServlet();
          } finally {
              Thread.currentThread().setContextClassLoader(old);
          }
          
        }
        
        /**
         * Initialize the wrapped servlet. Subclasses (see [EMAIL PROTECTED] 
BootstrapServlet} change the
         * <code>ServletConfig</code> given to the servlet.
         * 
         * @throws ServletException
         */
        protected void initServlet() throws ServletException {
                this.servlet.init(this.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.
         */
        protected 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 
JarFileFilter());
  
                        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());
        }
      
      /**
       * Get the classloader that will be used to create the actual servlet. 
Its classpath is defined
       * by an external file.
       */
      protected ClassLoader getClassLoader(String externalClasspath) 
      throws ServletException {
          final List urlList = new ArrayList();
  
          log("Adding classpath from " + externalClasspath);
          try {
              FileReader fileReader = new FileReader(externalClasspath);
              LineNumberReader lineReader = new LineNumberReader(fileReader);
          
              String line;
              do {
                  line = lineReader.readLine();
                  if ( line != null ) {
                      if (line.startsWith("class-dir:")) {
                          line = line.substring("class-dir:".length()).trim();
                          URL url = new File(line).toURL();
                          log("Adding class directory " + url);
                          urlList.add(url);
                          
                      } else if (line.startsWith("lib-dir:")) {
                          line = line.substring("lib-dir:".length()).trim();
                          File dir = new File(line);
                          File[] libraries = dir.listFiles(new JarFileFilter());
                          log("Adding " + libraries.length + " libraries from " 
+ dir.toURL());
                          for (int i = 0; i < libraries.length; i++) {
                              URL url = libraries[i].toURL();
                              urlList.add(url);
                          }
                      } else {
                          // Consider it as a URL
                          final URL lib;
                          if ( line.indexOf(':') == -1) {
                              File entry = new File(line);        
                              lib = entry.toURL();
                          } else {
                              lib = new URL(line);
                          }
                          log("Adding class URL " + lib);
                          urlList.add(lib);
                      }
                  }
              } while ( line != null );
              lineReader.close();
          } catch (IOException io) {
              throw new ServletException(io);
          }
                
          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 {
  
          final ClassLoader old = 
Thread.currentThread().getContextClassLoader();
          try {
                    
Thread.currentThread().setContextClassLoader(this.classloader);
                    this.servlet.service(request, response);
          } finally {
              Thread.currentThread().setContextClassLoader(old);    
          }
        }
      
        /**
         * Destroy the actual servlet
         */
        public void destroy() {
  
          if ( this.servlet != null ) {
              final ClassLoader old = 
Thread.currentThread().getContextClassLoader();
              try {
                  
Thread.currentThread().setContextClassLoader(this.classloader);
                  this.servlet.destroy();
              } finally {
                  Thread.currentThread().setContextClassLoader(old);    
              }
          }
  
                super.destroy();
        }
      
      private class JarFileFilter implements FilenameFilter {
          public boolean accept(File dir, String name) {
              return name.endsWith(".zip") || name.endsWith(".jar");
          }
      }
  }
  
  
  
  

Reply via email to