Bug 418306 - [enterprise] Update of web application fails
diff --git a/org.eclipse.virgo.web.enterprise.appdeployer/.classpath b/org.eclipse.virgo.web.enterprise.appdeployer/.classpath
index db963f3..591e67d 100755
--- a/org.eclipse.virgo.web.enterprise.appdeployer/.classpath
+++ b/org.eclipse.virgo.web.enterprise.appdeployer/.classpath
@@ -6,15 +6,16 @@
 	<classpathentry kind="src" path="src/main/java"/>

 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>

 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>

-	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/org.apache.openejb.core/4.0.0.beta-2_v201205260545-virgo-2/org.apache.openejb.core-4.0.0.beta-2_v201205260545-virgo-2.jar" sourcepath="/IVY_CACHE/org.eclipse.virgo.mirrored/org.apache.openejb.core/4.0.0.beta-2_v201205260545-virgo-2/org.apache.openejb.core.source-4.0.0.beta-2_v201205260545-virgo-2.jar"/>

-	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/org.apache.openejb.loader/4.0.0.beta-2_v201205041336/org.apache.openejb.loader-4.0.0.beta-2_v201205041336.jar"/>

+	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/org.apache.openejb.core/4.5.2.virgo-1/org.apache.openejb.core-4.5.2.virgo-1.jar" sourcepath="/IVY_CACHE/org.eclipse.virgo.mirrored/org.apache.openejb.core/4.0.0.beta-2_v201205260545-virgo-2/org.apache.openejb.core.source-4.0.0.beta-2_v201205260545-virgo-2.jar"/>

+	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/org.apache.openejb.loader/4.5.2/org.apache.openejb.loader-4.5.2.jar"/>

 	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/javax.ejb/3.1.1.v201204261316/javax.ejb-3.1.1.v201204261316.jar"/>

 	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/org.apache.catalina/7.0.35.v201302131125/org.apache.catalina-7.0.35.v201302131125.jar" sourcepath="/IVY_CACHE/org.eclipse.virgo.mirrored/org.apache.catalina/7.0.35.v201302131125/org.apache.catalina.source-7.0.35.v201302131125.jar"/>

 	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.medic/org.eclipse.virgo.medic/3.7.0.D-20130521041335/org.eclipse.virgo.medic-3.7.0.D-20130521041335.jar" sourcepath="/IVY_CACHE/org.eclipse.virgo.medic/org.eclipse.virgo.medic/3.1.0.M01/org.eclipse.virgo.medic-sources-3.1.0.M01.jar"/>

 	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/org.slf4j.api/1.7.2.v20121108-1250/org.slf4j.api-1.7.2.v20121108-1250.jar" sourcepath="/IVY_CACHE/org.eclipse.virgo.mirrored/org.slf4j.api/1.7.2.v20121108-1250/org.slf4j.api.source-1.7.2.v20121108-1250.jar"/>

-	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/org.apache.openejb.jee/4.0.0.beta-2_v201205041336/org.apache.openejb.jee-4.0.0.beta-2_v201205041336.jar"/>

+	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/org.apache.openejb.jee/4.5.2/org.apache.openejb.jee-4.5.2.jar"/>

 	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/javax.validation/1.0.0.GA_v201205091237/javax.validation-1.0.0.GA_v201205091237.jar"/>

 	<classpathentry kind="var" path="IVY_CACHE/javax.servlet/javax.servlet/3.0.0.v201103241009/javax.servlet-3.0.0.v201103241009.jar" sourcepath="/IVY_CACHE/javax.servlet/javax.servlet/3.0.0.v201103241009/javax.servlet-sources-3.0.0.v201103241009.jar"/>

 	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/org.eclipse.osgi/3.8.1.v20120830-144521/org.eclipse.osgi-3.8.1.v20120830-144521.jar" sourcepath="/IVY_CACHE/org.eclipse.osgi/org.eclipse.osgi/3.7.1.R37x_v20110808-1106/org.eclipse.osgi-sources-3.7.1.R37x_v20110808-1106.jar"/>

+	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/org.apache.xbean.finder/3.9.0.v201205031350-virgo-1/org.apache.xbean.finder-3.9.0.v201205031350-virgo-1.jar"/>

 	<classpathentry kind="output" path="bin"/>

 </classpath>

diff --git a/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoDeployerEjb.java b/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoDeployerEjb.java
index 5805ff7..d4d1329 100755
--- a/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoDeployerEjb.java
+++ b/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoDeployerEjb.java
@@ -14,6 +14,8 @@
 import static javax.ejb.TransactionManagementType.BEAN;

 

 import java.io.File;

+import java.io.IOException;

+import java.lang.reflect.Field;

 import java.net.MalformedURLException;

 import java.net.URI;

 import java.net.URISyntaxException;

@@ -25,6 +27,7 @@
 import java.util.List;

 import java.util.Map;

 import java.util.Map.Entry;

+import java.util.jar.JarFile;

 import java.util.Properties;

 import java.util.TreeMap;

 

@@ -61,11 +64,20 @@
 import org.apache.openejb.config.DeploymentLoader;

 import org.apache.openejb.config.DeploymentModule;

 import org.apache.openejb.config.DynamicDeployer;

+import org.apache.openejb.config.FinderFactory;

 import org.apache.openejb.config.ServiceUtils;

+import org.apache.openejb.config.WebModule;

+import org.apache.openejb.config.WebappAggregatedArchive;

 import org.apache.openejb.config.sys.Resource;

 import org.apache.openejb.config.sys.ServiceProvider;

 import org.apache.openejb.loader.SystemInstance;

 import org.apache.openejb.util.Contexts;

+import org.apache.xbean.finder.AnnotationFinder;

+import org.apache.xbean.finder.IAnnotationFinder;

+import org.apache.xbean.finder.archive.Archive;

+import org.apache.xbean.finder.archive.CompositeArchive;

+import org.apache.xbean.finder.archive.FilteredArchive;

+import org.apache.xbean.finder.archive.JarArchive;

 import org.eclipse.virgo.medic.eventlog.LogEvent;

 import org.eclipse.virgo.web.enterprise.openejb.deployer.log.OpenEjbDeployerLogEvents;

 import org.osgi.framework.Bundle;

@@ -206,12 +218,97 @@
 			}

 			throw new OpenEJBException("Error while deploying application with real path '" + loc + "' and web context path '" + this.webContextPath + "'.", e);

 		} finally {

+			if (appModule != null) {

+				try {

+					closeOpenJars(appModule);

+				} catch (Exception e) {

+					logger.warn("Could not close open application jars");

+				}

+			}

+

 			if(webAppClassLoader != null) {

 				Thread.currentThread().setContextClassLoader(webAppClassLoader);

 			}

 		}

 

 	}

+	

+	private void closeOpenJars(AppModule appModule) throws Exception {

+		List<WebModule> webModules = appModule.getWebModules();

+		for (WebModule webModule : webModules) {

+			closeWebModuleOpenJars(webModule);

+		}

+	}

+	

+	private void closeWebModuleOpenJars(WebModule webModule) throws Exception {

+		IAnnotationFinder finder = webModule.getFinder();

+		if (finder == null) {

+			logger.debug("The IAnnotationFinder in WebModule [" + webModule + "] is null; no jar closing will be performed");

+			return;

+		}

+		AnnotationFinder annotationFinder = null;

+		if (finder instanceof FinderFactory.ModuleLimitedFinder) {

+			annotationFinder = (AnnotationFinder)((FinderFactory.ModuleLimitedFinder)finder).getDelegate();

+		} else if (finder instanceof AnnotationFinder) {

+			annotationFinder = (AnnotationFinder) finder;

+		}

+		

+		if (annotationFinder != null) {

+			WebappAggregatedArchive aggregateArchive = (WebappAggregatedArchive) annotationFinder.getArchive();

+			

+			// get internal CompositeArchive

+			Field archive = WebappAggregatedArchive.class.getDeclaredField("archive");

+			archive.setAccessible(true);

+			CompositeArchive compositeArchive = (CompositeArchive)archive.get(aggregateArchive);

+			archive.setAccessible(false);

+			

+			// get internal list of FilteredArchives

+			handleCompositeArchive(compositeArchive);

+		}

+	}

+	

+	private void handleArchivesList(List<Archive> archives) throws Exception {

+		for (Archive arch : archives) {

+			handleArchive(arch);

+		}

+	}

+	

+	private void handleCompositeArchive(CompositeArchive compositeArchive) throws Exception {

+		Field archives = CompositeArchive.class.getDeclaredField("archives");

+		archives.setAccessible(true);

+		List<Archive> internalArchives = (List<Archive>)archives.get(compositeArchive);

+		archives.setAccessible(false);

+		handleArchivesList(internalArchives);

+	}

+	

+	private void handleFilteredArchive(FilteredArchive filteredArchive) throws Exception {

+		Field internalArchiveField = FilteredArchive.class.getDeclaredField("archive");

+		internalArchiveField.setAccessible(true);

+		Archive internalArchive = (Archive)internalArchiveField.get(filteredArchive);

+		internalArchiveField.setAccessible(false);

+		handleArchive(internalArchive);

+	}

+	

+	private void handleArchive(Archive arch) throws Exception {

+		if (arch instanceof FilteredArchive) {

+			FilteredArchive filteredArchive = (FilteredArchive) arch;

+			handleFilteredArchive(filteredArchive);

+		} else if (arch instanceof CompositeArchive) {

+			CompositeArchive compositeArchive = (CompositeArchive) arch;

+			handleCompositeArchive(compositeArchive);

+		} else if (arch instanceof JarArchive) {

+			JarArchive jarArchive = (JarArchive) arch;

+			Field jarField = JarArchive.class.getDeclaredField("jar");

+			jarField.setAccessible(true);

+			JarFile jar = (JarFile)jarField.get(jarArchive);

+			jarField.setAccessible(false);

+			try {

+				jar.close();

+			} catch(IOException e) {

+				// do nothing

+			}

+		}

+	}

 

 	private boolean isAppBringingOwnPersistence(StandardContext standardContext) {

 		ServletContext servletContext = standardContext.getServletContext();

diff --git a/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoDeploymentLoader.java b/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoDeploymentLoader.java
index 215054e..521d03d 100755
--- a/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoDeploymentLoader.java
+++ b/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoDeploymentLoader.java
@@ -295,6 +295,8 @@
         } catch (IOException e) {
 
             return;
+        } finally {
+        	ClassLoaderUtil.destroyClassLoader(loader);
         }
 
         Beans complete = null;
diff --git a/org.eclipse.virgo.web.enterprise.appdeployer/template.mf b/org.eclipse.virgo.web.enterprise.appdeployer/template.mf
index 974bced..fc4b020 100644
--- a/org.eclipse.virgo.web.enterprise.appdeployer/template.mf
+++ b/org.eclipse.virgo.web.enterprise.appdeployer/template.mf
@@ -14,7 +14,7 @@
  org.apache.naming.*;version="${org.apache.catalina:[=.=.=, +1)}",
  org.apache.openejb.*;version="0",
  org.apache.webbeans.*;version="0",
- org.apache.xbean.finder;version="0",
+ org.apache.xbean.finder.*;version="0",
  org.osgi.framework;version="0",
  org.eclipse.virgo.medic.*;version="${org.eclipse.virgo.medic:[=.=.=, +1)}",
  org.slf4j;version="0"