sylvain     2003/06/05 09:33:11

  Modified:    src/java/org/apache/cocoon/servlet BootstrapServlet.java
                        ParanoidClassLoader.java ParanoidCocoonServlet.java
  Log:
  Backported the ParanoidCocoon servlet, which is now really paranoid
  
  Revision  Changes    Path
  1.2       +52 -138   
cocoon-2.0/src/java/org/apache/cocoon/servlet/BootstrapServlet.java
  
  Index: BootstrapServlet.java
  ===================================================================
  RCS file: 
/home/cvs/cocoon-2.0/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:03:16 -0000       1.1
  +++ BootstrapServlet.java     5 Jun 2003 16:33:10 -0000       1.2
  @@ -51,17 +51,17 @@
   package org.apache.cocoon.servlet;
   
   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.*;
  -import javax.servlet.http.HttpServlet;
  +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
  @@ -81,141 +81,55 @@
    * @version CVS $Id$
    */
   
  -public class BootstrapServlet extends HttpServlet {
  +public class BootstrapServlet extends ParanoidCocoonServlet {
       
  -    /**
  -     * The name of the actual servlet class.
  -     */
  -    public static final String SERVLET_CLASS = 
"org.apache.cocoon.servlet.CocoonServlet";
  -    
  -    protected Servlet servlet;
  -    
  -    protected ClassLoader classloader;
  -    
  -    protected ServletContext context;
  +    private File contextDir;
       
  -    public void init(ServletConfig config) throws ServletException {
  -        this.context = config.getServletContext();
  -        
  -        this.context.log("getRealPath(\"/\") = " + context.getRealPath("/"));
  +     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;
  +     }
   
  -        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);
  -        }
   
  -        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);
  -        
  -        super.init(newConfig);
  +    protected void initServlet(Servlet servlet) throws ServletException {
           
  -        // Inlitialize the actual servlet
  -        this.servlet.init(newConfig);
  +        ServletContext newContext = new ContextWrapper(getServletContext(), 
this.contextDir);
  +        ServletConfig newConfig = new ConfigWrapper(getServletConfig(), newContext);
           
  -    }
  -    
  -    /**
  -     * 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.2       +15 -4     
cocoon-2.0/src/java/org/apache/cocoon/servlet/ParanoidClassLoader.java
  
  Index: ParanoidClassLoader.java
  ===================================================================
  RCS file: 
/home/cvs/cocoon-2.0/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:03:16 -0000       1.1
  +++ ParanoidClassLoader.java  5 Jun 2003 16:33:10 -0000       1.2
  @@ -50,6 +50,8 @@
   */
   package org.apache.cocoon.servlet;
   
  +import org.apache.cocoon.CascadingIOException;
  +
   import java.io.File;
   import java.io.IOException;
   import java.net.MalformedURLException;
  @@ -62,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$
    */
   
  @@ -83,7 +85,7 @@
        * Alternate constructor to define a parent.
        */
       public ParanoidClassLoader(final ClassLoader parent) {
  -        this(null, parent, null);
  +        this(new URL[0], parent, null);
       }
   
       /**
  @@ -149,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).
  @@ -197,7 +200,15 @@
           try {
               this.addURL(file.getCanonicalFile().toURL());
           } catch (MalformedURLException mue) {
  -            throw new IOException("Could not add repository");
  +            throw new CascadingIOException("Could not add repository", mue);
           }
  +    }
  +    
  +    /**
  +     * Adds a new URL
  +     */
  +    
  +    public void addURL(URL url) {
  +     super.addURL(url);
       }
   }
  
  
  
  1.2       +148 -103  
cocoon-2.0/src/java/org/apache/cocoon/servlet/ParanoidCocoonServlet.java
  
  Index: ParanoidCocoonServlet.java
  ===================================================================
  RCS file: 
/home/cvs/cocoon-2.0/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:03:16 -0000       1.1
  +++ ParanoidCocoonServlet.java        5 Jun 2003 16:33:10 -0000       1.2
  @@ -50,121 +50,166 @@
   */
   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.
  - * It also creates a buffer by loading the whole servlet inside a ClassLoader.
  - * It has been changed to extend <code>CocoonServlet</code> so that it is
  - * easier to add and change functionality between the two servlets.
  - * The only real differences are the ClassLoader and instantiating Cocoon inside
  - * of it.
  + * 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$
    */
   
  -public class ParanoidCocoonServlet extends CocoonServlet {
  +public class ParanoidCocoonServlet extends HttpServlet {
   
  -    protected RepositoryClassLoader repositoryLoader;
  +     /**
  +      * The name of the actual servlet class.
  +      */
  +     public static final String DEFAULT_SERVLET_CLASS = 
"org.apache.cocoon.servlet.CocoonServlet";
       
  -    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);
  -            }
  +     private Servlet servlet;
  +    
  +     private ClassLoader classloader;
  +    
  +     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());
  +        
  +        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.
  +             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() {
   
  -        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);
  -            }
  -        }
  -    }
  +             Thread.currentThread().setContextClassLoader(this.classloader);
  +             this.servlet.destroy();
   
  -    /**
  -     * 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);
  -            }
  -        }
  -    }
  +             super.destroy();
  +     }
   }
   
  
  
  

Reply via email to