remm 02/02/07 11:20:36
Modified: catalina/src/share/org/apache/catalina/loader Tag:
tomcat_40_branch WebappClassLoader.java
WebappLoader.java
Log:
- Port to the 4.0.x branch the modification to the classloader made in the HEAD
branch. This includes fixes for a variety of problems, including:
- 4830: Catalina class loader throws exception while getting
a directory's URL using Class.getResource()
- 6248: Using xerces in webapp causes class cast exception
- Cleanup of source URLs generation
- Add support for external repositories, so that the CL fully emulates the
URLClassLoader
Revision Changes Path
No revision
No revision
1.15.2.9 +229 -67
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/loader/WebappClassLoader.java
Index: WebappClassLoader.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/loader/WebappClassLoader.java,v
retrieving revision 1.15.2.8
retrieving revision 1.15.2.9
diff -u -r1.15.2.8 -r1.15.2.9
--- WebappClassLoader.java 20 Nov 2001 05:06:34 -0000 1.15.2.8
+++ WebappClassLoader.java 7 Feb 2002 19:20:35 -0000 1.15.2.9
@@ -1,7 +1,7 @@
/*
- * $Header:
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/loader/WebappClassLoader.java,v
1.15.2.8 2001/11/20 05:06:34 remm Exp $
- * $Revision: 1.15.2.8 $
- * $Date: 2001/11/20 05:06:34 $
+ * $Header:
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/loader/WebappClassLoader.java,v
1.15.2.9 2002/02/07 19:20:35 remm Exp $
+ * $Revision: 1.15.2.9 $
+ * $Date: 2002/02/07 19:20:35 $
*
* ====================================================================
*
@@ -122,7 +122,7 @@
*
* @author Remy Maucherat
* @author Craig R. McClanahan
- * @version $Revision: 1.15.2.8 $ $Date: 2001/11/20 05:06:34 $
+ * @version $Revision: 1.15.2.9 $ $Date: 2002/02/07 19:20:35 $
*/
public class WebappClassLoader
extends URLClassLoader
@@ -146,6 +146,49 @@
}
+ // ------------------------------------------------------- Static Variables
+
+
+ /**
+ * The set of trigger classes that will cause a proposed repository not
+ * to be added if this class is visible to the class loader that loaded
+ * this factory class. Typically, trigger classes will be listed for
+ * components that have been integrated into the JDK for later versions,
+ * but where the corresponding JAR files are required to run on
+ * earlier versions.
+ */
+ private static final String[] triggers = {
+ "com.sun.jndi.ldap.LdapCtxFactory", // LDAP added in 1.3
+ "com.sun.net.ssl.internal.ssl.Provider", // JSSE added in 1.4
+ "javax.security.auth.Subject", // JAAS added in 1.4
+ //"javax.net.SocketFactory", // JSSE added in 1.4
+ //"javax.security.cert.X509Certificate", // JSSE added in 1.4
+ //"javax.sql.DataSource", // JDBC ext. added in 1.4
+ //"javax.xml.parsers.DocumentBuilder", // JAXP added in 1.4
+ "javax.servlet.Servlet", // Servlet API
+ // "org.apache.crimson.jaxp.DocumentBuilderImpl",
+ // Crimson added in 1.4
+ };
+
+
+ /**
+ * The set of trigger classes that will cause a proposed repository not
+ * to be added if this class is visible to the class loader that loaded
+ * this factory class. Typically, trigger classes will be listed for
+ * components that have been integrated into the JDK for later versions,
+ * but where the corresponding JAR files are required to run on
+ * earlier versions.
+ */
+ private static final String[] classTriggers = {
+ "javax.net.", // JSSE added in 1.4
+ "javax.security.cert.", // JSSE added in 1.4
+ "javax.naming.", // JNDI added in 1.3
+ "javax.xml.", // JAXP added in 1.4
+ "org.xml.sax.",
+ "org.w3c.dom."
+ };
+
+
// ----------------------------------------------------------- Constructors
@@ -340,6 +383,12 @@
/**
+ * Has external repositories.
+ */
+ protected boolean hasExternalRepositories = false;
+
+
+ /**
* All permission.
*/
private Permission allPermission = new java.security.AllPermission();
@@ -398,13 +447,15 @@
*
* @param path file directory path
*/
- public void setPermissions(String path) {
+ public void addPermission(String path) {
if (securityManager != null) {
+ Permission permission = null;
if( path.startsWith("jndi:") || path.startsWith("jar:jndi:") ) {
- permissionList.add(new JndiPermission(path + "*"));
+ permission = new JndiPermission(path + "*");
} else {
- permissionList.add(new FilePermission(path + "-","read"));
+ permission = new FilePermission(path + "-","read");
}
+ addPermission(permission);
}
}
@@ -415,8 +466,20 @@
*
* @param url URL for a file or directory on local system
*/
- public void setPermissions(URL url) {
- setPermissions(url.toString());
+ public void addPermission(URL url) {
+ addPermission(url.toString());
+ }
+
+
+ /**
+ * If there is a Java SecurityManager create a Permission.
+ *
+ * @param url URL for a file or directory on local system
+ */
+ public void addPermission(Permission permission) {
+ if ((securityManager != null) && (permission != null)) {
+ permissionList.add(permission);
+ }
}
@@ -465,6 +528,7 @@
try {
URL url = new URL(repository);
super.addURL(url);
+ hasExternalRepositories = true;
} catch (MalformedURLException e) {
throw new IllegalArgumentException(e.toString());
}
@@ -544,13 +608,6 @@
}
- JarFile[] result2 = new JarFile[jarFiles.length + 1];
- for (i = 0; i < jarFiles.length; i++) {
- result2[i] = jarFiles[i];
- }
- result2[jarFiles.length] = jarFile;
- jarFiles = result2;
-
try {
// Register the JAR for tracking
@@ -574,8 +631,21 @@
lastModifiedDates = result3;
} catch (NamingException e) {
+ // Ignore
}
+ // If the JAR currently contains invalid classes, don't actually use it
+ // for classloading
+ if (!validateJarFile(file))
+ return;
+
+ JarFile[] result2 = new JarFile[jarFiles.length + 1];
+ for (i = 0; i < jarFiles.length; i++) {
+ result2[i] = jarFiles[i];
+ }
+ result2[jarFiles.length] = jarFile;
+ jarFiles = result2;
+
// Add the file to the list
File[] result4 = new File[jarRealFiles.length + 1];
for (i = 0; i < jarRealFiles.length; i++) {
@@ -862,7 +932,7 @@
log(" -->RuntimeException Rethrown", e);
throw e;
}
- if (clazz == null) {
+ if ((clazz == null) && hasExternalRepositories) {
try {
clazz = super.findClass(name);
} catch(AccessControlException ace) {
@@ -922,7 +992,7 @@
url = entry.source;
}
- if (url == null)
+ if ((url == null) && hasExternalRepositories)
url = super.findResource(name);
if (debug >= 3) {
@@ -965,7 +1035,7 @@
// Note : Not getting an exception here means the resource was
// found
try {
- result.addElement(new File(files[i], name).toURL());
+ result.addElement(getURL(new File(files[i], name)));
} catch (MalformedURLException e) {
// Ignore
}
@@ -978,7 +1048,7 @@
JarEntry jarEntry = jarFiles[i].getJarEntry(name);
if (jarEntry != null) {
try {
- String jarFakeUrl = jarRealFiles[i].toURL().toString();
+ String jarFakeUrl = getURL(jarRealFiles[i]).toString();
jarFakeUrl = "jar:" + jarFakeUrl + "!/" + name;
result.addElement(new URL(jarFakeUrl));
} catch (MalformedURLException e) {
@@ -988,10 +1058,14 @@
}
// Adding the results of a call to the superclass
- Enumeration otherResourcePaths = super.findResources(name);
+ if (hasExternalRepositories) {
+
+ Enumeration otherResourcePaths = super.findResources(name);
+
+ while (otherResourcePaths.hasMoreElements()) {
+ result.addElement(otherResourcePaths.nextElement());
+ }
- while (otherResourcePaths.hasMoreElements()) {
- result.addElement(otherResourcePaths.nextElement());
}
return result.elements();
@@ -1122,7 +1196,7 @@
log(" --> Returning stream from local");
stream = findLoadedResource(name);
try {
- if (stream == null)
+ if (hasExternalRepositories && (stream == null))
stream = url.openStream();
} catch (IOException e) {
; // Ignore
@@ -1372,9 +1446,9 @@
URL[] urls = new URL[length];
for (i = 0; i < length; i++) {
if (i < filesLength) {
- urls[i] = files[i].toURL();
+ urls[i] = getURL(files[i]);
} else if (i < filesLength + jarFilesLength) {
- urls[i] = jarRealFiles[i - filesLength].toURL();
+ urls[i] = getURL(jarRealFiles[i - filesLength]);
} else {
urls[i] = external[i - filesLength - jarFilesLength];
}
@@ -1402,6 +1476,15 @@
/**
+ * Get the lifecycle listeners associated with this lifecycle. If this
+ * Lifecycle has no listeners registered, a zero-length array is returned.
+ */
+ public LifecycleListener[] findLifecycleListeners() {
+ return new LifecycleListener[0];
+ }
+
+
+ /**
* Remove a lifecycle event listener from this component.
*
* @param listener The listener to remove
@@ -1451,6 +1534,7 @@
jarNames = new String[0];
lastModifiedDates = new long[0];
paths = new String[0];
+ hasExternalRepositories = false;
required.clear();
permissionList.clear();
@@ -1486,7 +1570,7 @@
entry = findResourceInternal(name, classPath);
}
- if (entry == null)
+ if ((entry == null) || (entry.binaryContent == null))
throw new ClassNotFoundException(name);
Class clazz = entry.loadedClass;
@@ -1592,14 +1676,17 @@
String fullPath = repositories[i] + path;
- resource = (Resource) resources.lookup(fullPath);
+ Object lookupResult = resources.lookup(fullPath);
+ if (lookupResult instanceof Resource) {
+ resource = (Resource) lookupResult;
+ }
// Note : Not getting an exception here means the resource was
// found
entry = new ResourceEntry();
try {
- entry.source = new File(files[i], path).toURL();
+ entry.source = getURL(new File(files[i], path));
} catch (MalformedURLException e) {
return null;
}
@@ -1607,30 +1694,36 @@
(ResourceAttributes) resources.getAttributes(fullPath);
contentLength = (int) attributes.getContentLength();
entry.lastModified = attributes.getLastModified();
- try {
- binaryStream = resource.streamContent();
- } catch (IOException e) {
- return null;
- }
- // Register the full path for modification checking
- synchronized (paths) {
+ if (resource != null) {
- int j;
-
- long[] result2 = new long[lastModifiedDates.length + 1];
- for (j = 0; j < lastModifiedDates.length; j++) {
- result2[j] = lastModifiedDates[j];
+ try {
+ binaryStream = resource.streamContent();
+ } catch (IOException e) {
+ return null;
}
- result2[lastModifiedDates.length] = entry.lastModified;
- lastModifiedDates = result2;
- String[] result = new String[paths.length + 1];
- for (j = 0; j < paths.length; j++) {
- result[j] = paths[j];
+ // Register the full path for modification checking
+ synchronized (paths) {
+
+ int j;
+
+ long[] result2 =
+ new long[lastModifiedDates.length + 1];
+ for (j = 0; j < lastModifiedDates.length; j++) {
+ result2[j] = lastModifiedDates[j];
+ }
+ result2[lastModifiedDates.length] = entry.lastModified;
+ lastModifiedDates = result2;
+
+ String[] result = new String[paths.length + 1];
+ for (j = 0; j < paths.length; j++) {
+ result[j] = paths[j];
+ }
+ result[paths.length] = fullPath;
+ paths = result;
+
}
- result[paths.length] = fullPath;
- paths = result;
}
@@ -1651,7 +1744,7 @@
entry = new ResourceEntry();
try {
- String jarFakeUrl = jarRealFiles[i].toURL().toString();
+ String jarFakeUrl = getURL(jarRealFiles[i]).toString();
jarFakeUrl = "jar:" + jarFakeUrl + "!/" + path;
entry.source = new URL(jarFakeUrl);
} catch (MalformedURLException e) {
@@ -1677,27 +1770,31 @@
return null;
}
- byte[] binaryContent = new byte[contentLength];
+ if (binaryStream != null) {
- try {
- int pos = 0;
- while (true) {
- int n = binaryStream.read(binaryContent, pos,
- binaryContent.length - pos);
- if (n <= 0)
- break;
- pos += n;
+ byte[] binaryContent = new byte[contentLength];
+
+ try {
+ int pos = 0;
+ while (true) {
+ int n = binaryStream.read(binaryContent, pos,
+ binaryContent.length - pos);
+ if (n <= 0)
+ break;
+ pos += n;
+ }
+ binaryStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
}
- binaryStream.close();
- } catch (IOException e) {
- e.printStackTrace();
- return null;
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- entry.binaryContent = binaryContent;
+ entry.binaryContent = binaryContent;
+
+ }
// Add the entry in the local resource repository
synchronized (this) {
@@ -1814,6 +1911,7 @@
return false;
// Looking up the package
+ /*
String packageName = null;
int pos = name.lastIndexOf('.');
if (pos != -1)
@@ -1829,8 +1927,72 @@
return false;
if (packageName.equals("javax.servlet.jsp.tagext"))
return false;
+ */
+ for (int i = 0; i < classTriggers.length; i++) {
+ if (name.startsWith(classTriggers[i]))
+ return false;
+ }
return true;
+
+ }
+
+
+ /**
+ * Check the specified JAR file, and return <code>true</code> if it does
+ * not contain any of the trigger classes.
+ *
+ * @param jarFile The JAR file to be checked
+ *
+ * @exception IOException if an input/output error occurs
+ */
+ private boolean validateJarFile(File jarfile)
+ throws IOException {
+
+ if (triggers == null)
+ return (true);
+ JarFile jarFile = new JarFile(jarfile);
+ for (int i = 0; i < triggers.length; i++) {
+ Class clazz = null;
+ try {
+ if (parent != null) {
+ clazz = parent.loadClass(triggers[i]);
+ } else {
+ clazz = Class.forName(triggers[i]);
+ }
+ } catch (Throwable t) {
+ clazz = null;
+ }
+ if (clazz == null)
+ continue;
+ String name = triggers[i].replace('.', '/') + ".class";
+ if (debug >= 2)
+ log(" Checking for " + name);
+ JarEntry jarEntry = jarFile.getJarEntry(name);
+ if (jarEntry != null) {
+ jarFile.close();
+ return (false);
+ }
+ }
+ jarFile.close();
+ return (true);
+
+ }
+
+
+ /**
+ * Get URL.
+ */
+ protected URL getURL(File file)
+ throws MalformedURLException {
+
+ File realFile = file;
+ try {
+ realFile = realFile.getCanonicalFile();
+ } catch (IOException e) {
+ // Ignore
+ }
+ return new URL("file:" + realFile.getPath());
}
1.12.2.5 +11 -11
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/loader/WebappLoader.java
Index: WebappLoader.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/loader/WebappLoader.java,v
retrieving revision 1.12.2.4
retrieving revision 1.12.2.5
diff -u -r1.12.2.4 -r1.12.2.5
--- WebappLoader.java 12 Dec 2001 20:54:27 -0000 1.12.2.4
+++ WebappLoader.java 7 Feb 2002 19:20:35 -0000 1.12.2.5
@@ -1,7 +1,7 @@
/*
- * $Header:
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/loader/WebappLoader.java,v
1.12.2.4 2001/12/12 20:54:27 craigmcc Exp $
- * $Revision: 1.12.2.4 $
- * $Date: 2001/12/12 20:54:27 $
+ * $Header:
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/loader/WebappLoader.java,v
1.12.2.5 2002/02/07 19:20:35 remm Exp $
+ * $Revision: 1.12.2.5 $
+ * $Date: 2002/02/07 19:20:35 $
*
* ====================================================================
*
@@ -119,7 +119,7 @@
*
* @author Craig R. McClanahan
* @author Remy Maucherat
- * @version $Revision: 1.12.2.4 $ $Date: 2001/12/12 20:54:27 $
+ * @version $Revision: 1.12.2.5 $ $Date: 2002/02/07 19:20:35 $
*/
public class WebappLoader
@@ -805,7 +805,7 @@
try {
URL rootURL = servletContext.getResource("/");
- classLoader.setPermissions(rootURL);
+ classLoader.addPermission(rootURL);
String contextRoot = servletContext.getRealPath("/");
if (contextRoot != null) {
@@ -813,7 +813,7 @@
contextRoot =
(new File(contextRoot)).getCanonicalPath()
+ File.separator;
- classLoader.setPermissions(contextRoot);
+ classLoader.addPermission(contextRoot);
} catch (IOException e) {
// Ignore
}
@@ -822,11 +822,11 @@
URL classesURL =
servletContext.getResource("/WEB-INF/classes/");
if (classesURL != null)
- classLoader.setPermissions(classesURL);
+ classLoader.addPermission(classesURL);
URL libURL = servletContext.getResource("/WEB-INF/lib/");
if (libURL != null) {
- classLoader.setPermissions(libURL);
+ classLoader.addPermission(libURL);
}
if (contextRoot != null) {
@@ -840,7 +840,7 @@
} catch (IOException e) {
}
if (path != null)
- classLoader.setPermissions(path);
+ classLoader.addPermission(path);
}
} else {
@@ -856,7 +856,7 @@
path = libDir.getCanonicalPath() + File.separator;
} catch (IOException e) {
}
- classLoader.setPermissions(path);
+ classLoader.addPermission(path);
}
if (classesURL != null) {
File classesDir =
@@ -867,7 +867,7 @@
+ File.separator;
} catch (IOException e) {
}
- classLoader.setPermissions(path);
+ classLoader.addPermission(path);
}
}
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>