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");
}
}
}