You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by sy...@apache.org on 2003/06/05 18:33:11 UTC
cvs commit: cocoon-2.0/src/java/org/apache/cocoon/servlet BootstrapServlet.java ParanoidClassLoader.java ParanoidCocoonServlet.java
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:bloritsch@apache.org">Berin Loritsch</a>
- * @author <a href="mailto:sylvain@apache.org">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 {@link CocoonServlet}.
*
* @author <a href="mailto:bloritsch@apache.org">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 {@link 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();
+ }
}