Author: remy.maucherat(a)jboss.com
Date: 2009-04-24 22:54:08 -0400 (Fri, 24 Apr 2009)
New Revision: 1029
Modified:
trunk/java/org/apache/catalina/JarRepository.java
trunk/java/org/apache/catalina/core/ContextJarRepository.java
trunk/java/org/apache/catalina/startup/BaseContextScanner.java
Log:
- JarRepository should also hold the class folder, otherwise it's not consistent. This
now takes over all the temping
code from WebappLoader. This could also allow specifying shared JARs of interest rather
than use the great "scan
URL CLs but avoid known JARs" technique.
- ContextConfig, WebappLoader and WebappClassLoader will need updates to use
JarRepository.
Modified: trunk/java/org/apache/catalina/JarRepository.java
===================================================================
--- trunk/java/org/apache/catalina/JarRepository.java 2009-04-24 19:33:12 UTC (rev 1028)
+++ trunk/java/org/apache/catalina/JarRepository.java 2009-04-25 02:54:08 UTC (rev 1029)
@@ -23,11 +23,13 @@
package org.apache.catalina;
+import java.io.File;
+import java.util.Map;
import java.util.jar.JarFile;
/**
- * A JARRepository manages a set of JARs associated with a Context, and
+ * A JarRepository manages a set of Jars associated with a Context, and
* allows efficient access to them.
*
* @author Remy Maucherat
@@ -73,15 +75,22 @@
/**
- * Get a JarFile with the specified name.
+ * Get the JarFile map.
*
- * @param name
- * @return
+ * @return the JarFile map, associating logical name with JarFile
*/
- public JarFile getJar(String name);
+ public Map<String, JarFile> getJars();
/**
+ * Find the JarFile corresponding to the path.
+ *
+ * @return the JarFile, or null if not found
+ */
+ public JarFile findJar(String path);
+
+
+ /**
* Find all JarFile managed by the JARRepository.
*
* @return All JarFile
@@ -89,4 +98,20 @@
public JarFile[] findJars();
+ /**
+ * Find all exploded Jars managed by the JARRepository.
+ *
+ * @return All exploded File
+ */
+ public File[] findExplodedJars();
+
+
+ /**
+ * Get the exploded Jar map.
+ *
+ * @return the Jar map, associating logical name with File
+ */
+ public Map<String, File> getExplodedJars();
+
+
}
Modified: trunk/java/org/apache/catalina/core/ContextJarRepository.java
===================================================================
--- trunk/java/org/apache/catalina/core/ContextJarRepository.java 2009-04-24 19:33:12 UTC
(rev 1028)
+++ trunk/java/org/apache/catalina/core/ContextJarRepository.java 2009-04-25 02:54:08 UTC
(rev 1029)
@@ -53,11 +53,11 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.Map;
import java.util.jar.JarFile;
import javax.naming.Binding;
+import javax.naming.NameClassPair;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
@@ -151,6 +151,12 @@
/**
+ * Classes path, which is essentially an exploded Jar.
+ */
+ protected String classesPath = "/WEB-INF/classes";
+
+
+ /**
* Library path.
*/
protected String libPath = "/WEB-INF/lib";
@@ -168,6 +174,30 @@
protected JarFile[] jarFilesArray = new JarFile[0];
+ /**
+ * Map for the File instances.
+ */
+ protected Map<String, File> explodedJars = new HashMap<String, File>();
+
+
+ /**
+ * Array of the exploded Jars, as convenience.
+ */
+ protected File[] explodedJarsArray = new File[0];
+
+
+ /**
+ * Delete temp Jars.
+ */
+ protected boolean tempJars = false;
+
+
+ /**
+ * Delete temp exploded Jars.
+ */
+ protected boolean tempExplodedJars = false;
+
+
// --------------------------------------------------------- Public Methods
@@ -270,37 +300,34 @@
if (servletContext == null)
return;
- // Check JARs from Context
- File workDir =
- (File) servletContext.getAttribute(Globals.WORK_DIR_ATTR);
+ // Access work directory
+ File workDir = (File) servletContext.getAttribute(Globals.WORK_DIR_ATTR);
if (workDir == null) {
+ // FIXME: this is actually an error
log.info("No work dir for " + servletContext);
}
+ // Looking up directory /WEB-INF/lib in the context
NamingEnumeration<Binding> libPathListing = null;
- // Looking up directory /WEB-INF/lib in the context
try {
libPathListing = resources.listBindings(libPath);
} catch (NamingException e) {
- // Silent catch: it's valid that no /WEB-INF/lib collection
- // exists
+ // Silent catch: it's valid that no /WEB-INF/lib collection exists
}
-
if (libPathListing != null) {
- boolean copyJars = false;
String absoluteLibPath = servletContext.getRealPath(libPath);
File destDir = null;
if (absoluteLibPath != null) {
destDir = new File(absoluteLibPath);
} else {
- copyJars = true;
+ tempJars = true;
destDir = new File(workDir, libPath);
destDir.mkdirs();
}
while (libPathListing.hasMoreElements()) {
Binding binding = libPathListing.nextElement();
- String filename = libPath + "/" + binding.getName();
- if (!filename.endsWith(".jar"))
+ String logicalName = libPath + "/" + binding.getName();
+ if (!logicalName.endsWith(".jar"))
continue;
// Copy JAR in the work directory, always (the JAR file
// would get locked otherwise, which would make it
@@ -311,7 +338,7 @@
continue;
Resource jarResource = (Resource) obj;
try {
- if (copyJars) {
+ if (tempJars) {
InputStream is = null;
OutputStream os = null;
try {
@@ -333,17 +360,54 @@
}
}
JarFile jarFile = new JarFile(destFile);
- jarFiles.put(destFile.getAbsolutePath(), jarFile);
+ jarFiles.put(logicalName, jarFile);
} catch (IOException ex) {
// Catch the exception if there is an empty jar file,
// or if the JAR cannot be copied to temp
- // FIXME: throw an error, as webapp will not run
+ // FIXME: throw an error, as the webapp will not run
}
}
}
jarFilesArray = jarFiles.values().toArray(jarFilesArray);
+ // Setting up the class repository (/WEB-INF/classes), if it exists
+ DirContext classes = null;
+ try {
+ Object object = resources.lookup(classesPath);
+ if (object instanceof DirContext) {
+ classes = (DirContext) object;
+ }
+ } catch(NamingException e) {
+ // Silent catch: it's valid that no /WEB-INF/classes collection
+ // exists
+ }
+ if (classes != null) {
+ File classRepository = null;
+ String absoluteClassesPath = servletContext.getRealPath(classesPath);
+ if (absoluteClassesPath != null) {
+ classRepository = new File(absoluteClassesPath);
+ } else {
+ classRepository = new File(workDir, classesPath);
+ classRepository.mkdirs();
+ tempExplodedJars = true;
+ try {
+ copyDirContext(classes, classRepository);
+ } catch (NamingException ex) {
+ // Catch the exception if there is an empty jar file,
+ // or if the JAR cannot be copied to temp
+ // FIXME: throw an error, as the webapp will not run
+ } catch (IOException ex) {
+ // Catch the exception if there is an empty jar file,
+ // or if the JAR cannot be copied to temp
+ // FIXME: throw an error, as the webapp will not run
+ }
+ }
+ // Adding the repository to the class loader
+ explodedJarsArray = new File[] { classRepository };
+ explodedJars.put(classesPath + "/", classRepository);
+ }
+
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(START_EVENT, null);
@@ -364,7 +428,7 @@
// Validate and update our current component state
if (!started) {
if(log.isDebugEnabled())
- log.debug(sm.getString("standardPipeline.notStarted"));
+ log.debug(sm.getString("contextJarRepository.notStarted"));
return;
}
@@ -379,12 +443,10 @@
try {
for (int i = 0; i < jarFilesArray.length; i++) {
jarFilesArray[i].close();
+ if (tempJars) {
+ (new File(jarFilesArray[i].getName())).delete();
+ }
}
- Iterator<String> jarFilesNames = jarFiles.keySet().iterator();
- while (jarFilesNames.hasNext()) {
- File jarFile = new File(jarFilesNames.next());
- jarFile.delete();
- }
} catch (IOException ex) {
// Catch the exception if there is an empty jar file,
// or if the JAR cannot be copied to temp
@@ -392,6 +454,11 @@
}
jarFiles.clear();
jarFilesArray = new JarFile[0];
+ tempJars = false;
+ explodedJars.clear();
+ explodedJarsArray = new File[0];
+ // FIXME: delete exploded copy
+ tempExplodedJars = false;
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
@@ -412,17 +479,31 @@
/**
- * Get a JarFile with the specified name.
+ * Get the JarFile map.
*
- * @param name
- * @return
+ * @return the JarFile map, associating logical name with JarFile
*/
- public JarFile getJar(String name) {
- return jarFiles.get(name);
+ public Map<String, JarFile> getJars() {
+ return jarFiles;
}
/**
+ * Find the JarFile corresponding to the path.
+ *
+ * @return the JarFile, or null if not found
+ */
+ public JarFile findJar(String path) {
+ for (int i = 0; i < jarFilesArray.length; i++) {
+ if (jarFilesArray[i].getName().equals(path)) {
+ return jarFilesArray[i];
+ }
+ }
+ return null;
+ }
+
+
+ /**
* Find all JarFile managed by the JARRepository.
*
* @return All JarFile
@@ -432,4 +513,81 @@
}
+ /**
+ * Get the exploded Jar map.
+ *
+ * @return the Jar map, associating logical name with File
+ */
+ public Map<String, File> getExplodedJars() {
+ return explodedJars;
+ }
+
+
+ /**
+ * Find all exploded Jars managed by the JARRepository.
+ *
+ * @return All exploded File
+ */
+ public File[] findExplodedJars() {
+ return explodedJarsArray;
+ }
+
+
+ /**
+ * Copy directory.
+ */
+ protected void copyDirContext(DirContext srcDir, File destDir)
+ throws IOException, NamingException {
+ InputStream is = null;
+ OutputStream os = null;
+ NamingEnumeration<NameClassPair> enumeration = srcDir.list("");
+ while (enumeration.hasMoreElements()) {
+ NameClassPair ncPair = enumeration.nextElement();
+ String name = ncPair.getName();
+ Object object = srcDir.lookup(name);
+ File currentFile = new File(destDir, name);
+ if (object instanceof Resource) {
+ try {
+ is = ((Resource) object).streamContent();
+ os = new FileOutputStream(currentFile);
+ IOTools.flow(is, os);
+ // Don't catch IOE - let the outer try/catch handle it
+ } finally {
+ try {
+ if (is != null) is.close();
+ } catch (IOException e){
+ // Ignore
+ }
+ try {
+ if (os != null) os.close();
+ } catch (IOException e){
+ // Ignore
+ }
+ }
+ } else if (object instanceof InputStream) {
+ try {
+ is = (InputStream) object;
+ os = new FileOutputStream(currentFile);
+ IOTools.flow(is, os);
+ // Don't catch IOE - let the outer try/catch handle it
+ } finally {
+ try {
+ if (is != null) is.close();
+ } catch (IOException e){
+ // Ignore
+ }
+ try {
+ if (os != null) os.close();
+ } catch (IOException e){
+ // Ignore
+ }
+ }
+ } else if (object instanceof DirContext) {
+ currentFile.mkdir();
+ copyDirContext((DirContext) object, currentFile);
+ }
+ }
+ }
+
+
}
Modified: trunk/java/org/apache/catalina/startup/BaseContextScanner.java
===================================================================
--- trunk/java/org/apache/catalina/startup/BaseContextScanner.java 2009-04-24 19:33:12 UTC
(rev 1028)
+++ trunk/java/org/apache/catalina/startup/BaseContextScanner.java 2009-04-25 02:54:08 UTC
(rev 1029)
@@ -24,9 +24,6 @@
package org.apache.catalina.startup;
import java.io.File;
-import java.io.IOException;
-import java.net.URL;
-import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
@@ -45,6 +42,7 @@
import org.apache.catalina.Context;
import org.apache.catalina.ContextScanner;
import org.apache.catalina.Globals;
+import org.apache.catalina.JarRepository;
public abstract class BaseContextScanner
implements ContextScanner {
@@ -137,21 +135,30 @@
* @param context
*/
public void scan(Context context) {
-
- if (context.getLoader().findLoaderRepositories() != null) {
- String[] repositories = context.getLoader().findLoaderRepositories();
- for (int i = 0; i < repositories.length; i++) {
- if (repositories[i].endsWith(".jar")) {
- try {
- scanJar(context, new JarFile(repositories[i]));
- } catch (IOException e) {
- // Ignore
- }
- } else {
- scanClasses(context, new File(repositories[i]), "");
- }
+ JarRepository jarRepository = context.getJarRepository();
+ if (jarRepository != null) {
+ JarFile[] jars = jarRepository.findJars();
+ for (int i = 0; i < jars.length; i++) {
+ scanJar(context, jars[i]);
}
+ File[] explodedJars = jarRepository.findExplodedJars();
+ for (int i = 0; i < explodedJars.length; i++) {
+ scanClasses(context, explodedJars[i], "");
+ }
}
+ // Do the same for the context parent
+ jarRepository = context.getParent().getJarRepository();
+ if (jarRepository != null) {
+ JarFile[] jars = jarRepository.findJars();
+ for (int i = 0; i < jars.length; i++) {
+ scanJar(context, jars[i]);
+ }
+ File[] explodedJars = jarRepository.findExplodedJars();
+ for (int i = 0; i < explodedJars.length; i++) {
+ scanClasses(context, explodedJars[i], "");
+ }
+ }
+ /*
ClassLoader loader = context.getLoader().getClassLoader().getParent();
while (loader != null) {
if (loader instanceof URLClassLoader) {
@@ -182,10 +189,8 @@
if (!path.endsWith(".jar")) {
continue;
}
- /*
- * Scan all JARs from WEB-INF/lib, plus any shared JARs
- * that are not known not to contain any TLDs
- */
+ // Scan all JARs from WEB-INF/lib, plus any shared JARs
+ // that are not known not to contain any TLDs
if (skipJars == null
|| !skipJars.contains(file.getName())) {
try {
@@ -198,6 +203,7 @@
}
loader = loader.getParent();
}
+ */
HashSet<String> warTLDs = new HashSet<String>();
@@ -391,11 +397,6 @@
if (jarTLDs.size() > 0) {
TLDs.put(file.getName(), jarTLDs);
}
- try {
- file.close();
- } catch (IOException e) {
- // Ignore
- }
}