You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2003/06/15 09:22:16 UTC
cvs commit: jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/loader WebappClassLoader.java WebappLoader.java
remm 2003/06/15 00:22:16
Modified: catalina/src/share/org/apache/catalina/loader
WebappClassLoader.java WebappLoader.java
Log:
- Add a machanism to release JAR objects periodically.
- This should decrease classloading performance because of a big sync block
during JAR access, but lookup of previously loaded class will behave the same as before.
- Add a workaround for JAR locking with XML processing and getResource.
If the resource was loaded from a JAR, it will be extracted as needed to the
work directory.
Revision Changes Path
1.17 +163 -59 jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/loader/WebappClassLoader.java
Index: WebappClassLoader.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/loader/WebappClassLoader.java,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- WebappClassLoader.java 12 Jun 2003 22:02:12 -0000 1.16
+++ WebappClassLoader.java 15 Jun 2003 07:22:16 -0000 1.17
@@ -61,6 +61,7 @@
package org.apache.catalina.loader;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.FilePermission;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
@@ -285,6 +286,12 @@
/**
+ * Last time a JAR was accessed.
+ */
+ protected long lastJarAccessed = 0L;
+
+
+ /**
* The list of local repositories, in the order they should be searched
* for locally loaded classes or resources.
*/
@@ -348,6 +355,12 @@
/**
+ * Path where resources loaded from JARs will be extracted.
+ */
+ private File loaderDir = null;
+
+
+ /**
* The PermissionCollection for each CodeSource for a web
* application context.
*/
@@ -534,6 +547,14 @@
}
+ /**
+ * Change the work directory.
+ */
+ public void setWorkDir(File workDir) {
+ this.loaderDir = new File(workDir, "loader");
+ }
+
+
// ------------------------------------------------------- Reloader Methods
@@ -977,15 +998,18 @@
}
// Looking at the JAR files
- for (i = 0; i < jarFilesLength; i++) {
- JarEntry jarEntry = jarFiles[i].getJarEntry(name);
- if (jarEntry != null) {
- try {
- String jarFakeUrl = getURI(jarRealFiles[i]).toString();
- jarFakeUrl = "jar:" + jarFakeUrl + "!/" + name;
- result.addElement(new URL(jarFakeUrl));
- } catch (MalformedURLException e) {
- // Ignore
+ synchronized (jarFiles) {
+ openJARs();
+ for (i = 0; i < jarFilesLength; i++) {
+ JarEntry jarEntry = jarFiles[i].getJarEntry(name);
+ if (jarEntry != null) {
+ try {
+ String jarFakeUrl = getURI(jarRealFiles[i]).toString();
+ jarFakeUrl = "jar:" + jarFakeUrl + "!/" + name;
+ result.addElement(new URL(jarFakeUrl));
+ } catch (MalformedURLException e) {
+ // Ignore
+ }
}
}
}
@@ -1052,6 +1076,33 @@
// (2) Search local repositories
url = findResource(name);
if (url != null) {
+ // Locating the repository for special handling in the case
+ // of a JAR
+ ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
+ FileOutputStream os = null;
+ try {
+ String repository = entry.codeBase.toString();
+ if (repository.endsWith(".jar")) {
+ // Copy binary content to the work directory if not present
+ File resourceFile = new File(loaderDir, name);
+ if (entry.lastModified > resourceFile.lastModified()) {
+ resourceFile.getParentFile().mkdirs();
+ os = new FileOutputStream(resourceFile);
+ os.write(entry.binaryContent);
+ }
+ url = resourceFile.toURL();
+ }
+ } catch (Exception e) {
+ // Ignore
+ e.printStackTrace();
+ } finally {
+ if (os != null) {
+ try {
+ os.close();
+ } catch (IOException ex) {
+ }
+ }
+ }
if (log.isDebugEnabled())
log.debug(" --> Returning '" + url.toString() + "'");
return (url);
@@ -1454,7 +1505,9 @@
length = jarFiles.length;
for (int i = 0; i < length; i++) {
try {
- jarFiles[i].close();
+ if (jarFiles[i] != null) {
+ jarFiles[i].close();
+ }
} catch (IOException e) {
// Ignore
}
@@ -1479,10 +1532,54 @@
}
+ /**
+ * Used to periodically signal to the classloader to release
+ * JAR resources.
+ */
+ public void closeJARs(boolean force) {
+ if (jarFiles.length > 0) {
+ try {
+ synchronized (jarFiles) {
+ if (force || (System.currentTimeMillis()
+ > (lastJarAccessed + 90000))) {
+ for (int i = 0; i < jarFiles.length; i++) {
+ if (jarFiles[i] != null) {
+ jarFiles[i].close();
+ jarFiles[i] = null;
+ }
+ }
+ }
+ }
+ } catch (IOException e) {
+ log("Failed to close JAR", e);
+ }
+ }
+ }
+
+
// ------------------------------------------------------ Protected Methods
/**
+ * Used to periodically signal to the classloader to release JAR resources.
+ */
+ protected void openJARs() {
+ if (started && (jarFiles.length > 0)) {
+ lastJarAccessed = System.currentTimeMillis();
+ if (jarFiles[0] == null) {
+ try {
+ for (int i = 0; i < jarFiles.length; i++) {
+ jarFiles[i] = new JarFile(jarRealFiles[i]);
+ }
+ } catch (IOException e) {
+ log("Failed to open JAR", e);
+ }
+ }
+ }
+ }
+
+
+ /**
* Find specified class in local repositories.
*
* @return the loaded class, or null if the class isn't found
@@ -1692,67 +1789,74 @@
JarEntry jarEntry = null;
- for (i = 0; (entry == null) && (i < jarFilesLength); i++) {
+ synchronized (jarFiles) {
- jarEntry = jarFiles[i].getJarEntry(path);
+ openJARs();
+ for (i = 0; (entry == null) && (i < jarFilesLength); i++) {
- if (jarEntry != null) {
+ jarEntry = jarFiles[i].getJarEntry(path);
- entry = new ResourceEntry();
- try {
- entry.codeBase = getURL(jarRealFiles[i]);
- String jarFakeUrl = getURI(jarRealFiles[i]).toString();
- jarFakeUrl = "jar:" + jarFakeUrl + "!/" + path;
- entry.source = new URL(jarFakeUrl);
- } catch (MalformedURLException e) {
- return null;
- }
- contentLength = (int) jarEntry.getSize();
- try {
- entry.manifest = jarFiles[i].getManifest();
- binaryStream = jarFiles[i].getInputStream(jarEntry);
- } catch (IOException e) {
- return null;
+ if (jarEntry != null) {
+
+ entry = new ResourceEntry();
+ try {
+ entry.codeBase = getURL(jarRealFiles[i]);
+ String jarFakeUrl = getURI(jarRealFiles[i]).toString();
+ jarFakeUrl = "jar:" + jarFakeUrl + "!/" + path;
+ entry.source = new URL(jarFakeUrl);
+ entry.lastModified = jarRealFiles[i].lastModified();
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ contentLength = (int) jarEntry.getSize();
+ try {
+ entry.manifest = jarFiles[i].getManifest();
+ binaryStream = jarFiles[i].getInputStream(jarEntry);
+ } catch (IOException e) {
+ return null;
+ }
}
- }
- }
+ }
- if (entry == null) {
- synchronized (notFoundResources) {
- notFoundResources.put(name, name);
+ if (entry == null) {
+ synchronized (notFoundResources) {
+ notFoundResources.put(name, name);
+ }
+ return null;
}
- return null;
- }
- if (binaryStream != null) {
+ if (binaryStream != null) {
- byte[] binaryContent = new byte[contentLength];
+ 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;
+ 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;
+
+ // The certificates are only available after the JarEntry
+ // associated input stream has been fully read
+ if (jarEntry != null) {
+ entry.certificates = jarEntry.getCertificates();
+ }
- // The certificates are only available after the JarEntry
- // associated input stream has been fully read
- if (jarEntry != null) {
- entry.certificates = jarEntry.getCertificates();
}
}
1.17 +16 -3 jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/loader/WebappLoader.java
Index: WebappLoader.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/loader/WebappLoader.java,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- WebappLoader.java 22 May 2003 23:04:48 -0000 1.16
+++ WebappLoader.java 15 Jun 2003 07:22:16 -0000 1.17
@@ -530,15 +530,18 @@
return sb.toString();
}
- /** Classpath, as set in org.apache.catalina.jsp_classpath context
+
+ /**
+ * Classpath, as set in org.apache.catalina.jsp_classpath context
* property
*
- * @return
+ * @return The classpath
*/
public String getClasspath() {
return classpath;
}
+
/**
* Has the internal repository associated with this Loader been modified,
* such that the loaded classes should be reloaded?
@@ -551,6 +554,14 @@
/**
+ * Used to periodically signal to the classloader to release JAR resources.
+ */
+ public void closeJARs(boolean force) {
+ classLoader.closeJARs(force);
+ }
+
+
+ /**
* Remove a property change listener from this component.
*
* @param listener The listener to remove
@@ -969,6 +980,8 @@
if( log.isDebugEnabled())
log.debug(sm.getString("webappLoader.deploy", workDir.getAbsolutePath()));
+
+ classLoader.setWorkDir(workDir);
DirContext resources = container.getResources();
---------------------------------------------------------------------
To unsubscribe, e-mail: tomcat-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tomcat-dev-help@jakarta.apache.org