Author: andygumbrecht
Date: Tue Jan 29 12:13:18 2013
New Revision: 1439849
URL: http://svn.apache.org/viewvc?rev=1439849&view=rev
Log:
Fixed ClassLoaderUtil use on destroy - Uses potentially both appId and path as
keys.
Improved test - Checks for clean undeployment.
Modified:
tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/ClassLoaderUtil.java
tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/assembler/DeployerEjb.java
tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
tomee/tomee/trunk/container/openejb-core/src/test/java/org/apache/openejb/config/AutoDeployerTest.java
Modified:
tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/ClassLoaderUtil.java
URL:
http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/ClassLoaderUtil.java?rev=1439849&r1=1439848&r2=1439849&view=diff
==============================================================================
---
tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/ClassLoaderUtil.java
(original)
+++
tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/ClassLoaderUtil.java
Tue Jan 29 12:13:18 2013
@@ -16,6 +16,7 @@
*/
package org.apache.openejb;
+import org.apache.openejb.assembler.classic.AppInfo;
import org.apache.openejb.classloader.ClassLoaderConfigurer;
import org.apache.openejb.classloader.CompositeClassLoaderConfigurer;
import org.apache.openejb.core.TempClassLoader;
@@ -60,6 +61,11 @@ public class ClassLoaderUtil {
private static final Map<ClassLoader, Set<String>> appsByClassLoader = new
HashMap<ClassLoader, Set<String>>();
private static final UrlCache localUrlCache = new UrlCache();
+ public static void destroyClassLoader(final AppInfo info) {
+ destroyClassLoader(info.appId);
+ destroyClassLoader(info.path);
+ }
+
public static ClassLoader getContextClassLoader() {
return AccessController.doPrivileged(new
PrivilegedAction<ClassLoader>() {
@@ -114,11 +120,12 @@ public class ClassLoaderUtil {
* @param classLoader ClassLoader to destroy.
*/
public static void destroyClassLoader(final ClassLoader classLoader) {
- logger.debug("Destroying classLoader " + toString(classLoader));
// remove from the indexes
final Set<String> apps = appsByClassLoader.remove(classLoader);
+ logger.debug("Destroying classLoader '" + toString(classLoader) + "'
for apps: " + apps);
+
if (apps != null) {
List<ClassLoader> classLoaders;
@@ -192,6 +199,7 @@ public class ClassLoaderUtil {
return files;
}
+ @SuppressWarnings("UseOfObsoleteCollectionType")
public boolean finalizeNativeLibs(final ClassLoader cl) {
boolean res = false;
@@ -477,15 +485,14 @@ public class ClassLoaderUtil {
* @param fieldName the name of the cache field
*/
public static void clearSunSoftCache(final Class clazz, final String
fieldName) {
- synchronized (clazz) {
- try {
- final Field field = clazz.getDeclaredField(fieldName);
- field.setAccessible(true);
- final Map cache = (Map) field.get(null);
- cache.clear();
- } catch (Throwable ignored) {
- // there is nothing a user could do about this anyway
- }
+
+ try {
+ final Field field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ final Map cache = (Map) field.get(null);
+ cache.clear();
+ } catch (Throwable ignored) {
+ // there is nothing a user could do about this anyway
}
}
Modified:
tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/assembler/DeployerEjb.java
URL:
http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/assembler/DeployerEjb.java?rev=1439849&r1=1439848&r2=1439849&view=diff
==============================================================================
---
tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/assembler/DeployerEjb.java
(original)
+++
tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/assembler/DeployerEjb.java
Tue Jan 29 12:13:18 2013
@@ -16,10 +16,18 @@
*/
package org.apache.openejb.assembler;
-import org.apache.openejb.*;
+import org.apache.openejb.ClassLoaderUtil;
+import org.apache.openejb.NoSuchApplicationException;
+import org.apache.openejb.OpenEJBException;
+import org.apache.openejb.OpenEJBRuntimeException;
+import org.apache.openejb.UndeployException;
import org.apache.openejb.assembler.classic.AppInfo;
import org.apache.openejb.assembler.classic.Assembler;
-import org.apache.openejb.config.*;
+import org.apache.openejb.config.AppModule;
+import org.apache.openejb.config.ConfigurationFactory;
+import org.apache.openejb.config.DeploymentLoader;
+import org.apache.openejb.config.DeploymentModule;
+import org.apache.openejb.config.WebModule;
import org.apache.openejb.config.sys.AdditionalDeployments;
import org.apache.openejb.config.sys.Deployments;
import org.apache.openejb.config.sys.JaxbOpenejb;
@@ -38,17 +46,23 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.SecureRandom;
-import java.util.*;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TreeMap;
import static javax.ejb.TransactionManagementType.BEAN;
import static
org.apache.openejb.config.ConfigurationFactory.ADDITIONAL_DEPLOYMENTS;
import static org.apache.openejb.loader.ProvisioningUtil.realLocation;
+@SuppressWarnings("EjbProhibitedPackageUsageInspection")
@Stateless(name = "openejb/Deployer")
@Remote(Deployer.class)
@TransactionManagement(BEAN)
@Alternative
public class DeployerEjb implements Deployer {
+
public static final String OPENEJB_DEPLOYER_FORCED_APP_ID_PROP =
"openejb.deployer.forced.appId";
public static final Logger LOGGER =
Logger.getInstance(LogCategory.OPENEJB, DeployerEjb.class);
@@ -58,19 +72,23 @@ public class DeployerEjb implements Depl
private final static boolean oldWarDeployer =
"old".equalsIgnoreCase(SystemInstance.get().getOptions().get("openejb.deployer.war",
"new"));
static {
- String uniqueName = "OpenEJB-" + new BigInteger(128, new
SecureRandom()).toString(Character.MAX_RADIX);
- String tempDir = System.getProperty("java.io.tmpdir");
+ final String uniqueName = "OpenEJB-" + new BigInteger(128, new
SecureRandom()).toString(Character.MAX_RADIX);
+ final String tempDir = System.getProperty("java.io.tmpdir");
File unique;
try {
unique = new File(tempDir, uniqueName).getCanonicalFile();
- unique.createNewFile();
+ if (!unique.createNewFile()) {
+ throw new IOException("Failed to create file in temp: " +
unique);
+ }
} catch (IOException e) {
// same trying in work directory
unique = new File(SystemInstance.get().getBase().getDirectory(),
"work");
if (unique.exists()) {
try {
unique = new File(unique, uniqueName).getCanonicalFile();
- unique.createNewFile();
+ if (!unique.createNewFile()) {
+ throw new IOException("Failed to create file in work:
" + unique);
+ }
} catch (IOException e1) {
throw new OpenEJBRuntimeException(e);
}
@@ -92,23 +110,28 @@ public class DeployerEjb implements Depl
assembler = (Assembler)
SystemInstance.get().getComponent(org.apache.openejb.spi.Assembler.class);
}
+ @Override
public String getUniqueFile() {
return uniqueFile.getAbsolutePath();
}
+ @Override
public Collection<AppInfo> getDeployedApps() {
return assembler.getDeployedApplications();
}
- public AppInfo deploy(String location) throws OpenEJBException {
+ @Override
+ public AppInfo deploy(final String location) throws OpenEJBException {
return deploy(location, null);
}
- public AppInfo deploy(Properties properties) throws OpenEJBException {
+ @Override
+ public AppInfo deploy(final Properties properties) throws OpenEJBException
{
return deploy(null, properties);
}
- public AppInfo deploy(String inLocation, Properties properties) throws
OpenEJBException {
+ @Override
+ public AppInfo deploy(final String inLocation, Properties properties)
throws OpenEJBException {
String rawLocation = inLocation;
if (rawLocation == null && properties == null) {
throw new NullPointerException("location and properties are null");
@@ -129,45 +152,45 @@ public class DeployerEjb implements Depl
AUTO_DEPLOY.set(autoDeploy);
try {
return SystemInstance.get().getComponent(WebAppDeployer.class)
- .deploy(contextRoot(properties,
file.getAbsolutePath()), file);
+ .deploy(contextRoot(properties,
file.getAbsolutePath()), file);
} finally {
AUTO_DEPLOY.remove();
}
}
- AppInfo appInfo;
+ AppInfo appInfo = null;
try {
appModule = deploymentLoader.load(file);
// Add any alternate deployment descriptors to the modules
- Map<String, DeploymentModule> modules = new TreeMap<String,
DeploymentModule>();
- for (DeploymentModule module : appModule.getEjbModules()) {
+ final Map<String, DeploymentModule> modules = new TreeMap<String,
DeploymentModule>();
+ for (final DeploymentModule module : appModule.getEjbModules()) {
modules.put(module.getModuleId(), module);
}
- for (DeploymentModule module : appModule.getClientModules()) {
+ for (final DeploymentModule module : appModule.getClientModules())
{
modules.put(module.getModuleId(), module);
}
- for (WebModule module : appModule.getWebModules()) {
+ for (final WebModule module : appModule.getWebModules()) {
final String contextRoot = contextRoot(properties,
module.getJarLocation());
if (contextRoot != null) {
module.setContextRoot(contextRoot);
}
modules.put(module.getModuleId(), module);
}
- for (DeploymentModule module : appModule.getConnectorModules()) {
+ for (final DeploymentModule module :
appModule.getConnectorModules()) {
modules.put(module.getModuleId(), module);
}
- for (Map.Entry<Object, Object> entry : properties.entrySet()) {
+ for (final Map.Entry<Object, Object> entry :
properties.entrySet()) {
String name = (String) entry.getKey();
if (name.startsWith(ALT_DD + "/")) {
name = name.substring(ALT_DD.length() + 1);
- DeploymentModule module;
- int slash = name.indexOf('/');
+ final DeploymentModule module;
+ final int slash = name.indexOf('/');
if (slash > 0) {
- String moduleId = name.substring(0, slash);
+ final String moduleId = name.substring(0, slash);
name = name.substring(slash + 1);
module = modules.get(moduleId);
} else {
@@ -175,8 +198,8 @@ public class DeployerEjb implements Depl
}
if (module != null) {
- String value = (String) entry.getValue();
- File dd = new File(value);
+ final String value = (String) entry.getValue();
+ final File dd = new File(value);
if (dd.canRead()) {
module.getAltDDs().put(name, dd.toURI().toURL());
} else {
@@ -192,17 +215,22 @@ public class DeployerEjb implements Depl
if (properties != null &&
properties.containsKey(OPENEJB_DEPLOYER_FORCED_APP_ID_PROP)) {
appInfo.appId =
properties.getProperty(OPENEJB_DEPLOYER_FORCED_APP_ID_PROP);
}
- assembler.createApplication(appInfo);
+ assembler.createApplication(appInfo);
saveDeployment(file, true);
return appInfo;
+
} catch (Throwable e) {
// destroy the class loader for the failed application
if (appModule != null) {
ClassLoaderUtil.destroyClassLoader(appModule.getJarLocation());
}
+ if (null != appInfo) {
+ ClassLoaderUtil.destroyClassLoader(appInfo);
+ }
+
LOGGER.error("Can't deploy " + inLocation, e);
if (e instanceof javax.validation.ValidationException) {
@@ -219,7 +247,7 @@ public class DeployerEjb implements Depl
}
}
- private synchronized void saveDeployment(final File file, boolean add) {
+ private synchronized void saveDeployment(final File file, final boolean
add) {
final Deployments deps = new Deployments();
if (file.isDirectory()) {
deps.setDir(file.getAbsolutePath());
@@ -258,7 +286,7 @@ public class DeployerEjb implements Depl
additionalDeployments.getDeployments().add(deps);
}
} else {
- Iterator<Deployments> it =
additionalDeployments.getDeployments().iterator();
+ final Iterator<Deployments> it =
additionalDeployments.getDeployments().iterator();
while (it.hasNext()) {
final Deployments current = it.next();
if (deps.getDir() != null &&
deps.getDir().equals(current.getDir())) {
@@ -268,7 +296,7 @@ public class DeployerEjb implements Depl
it.remove();
break;
} else { // exploded dirs
- String jar = deps.getFile();
+ final String jar = deps.getFile();
if (jar != null && jar.length() > 3 &&
jar.substring(0, jar.length() - 4).equals(deps.getDir())) {
it.remove();
break;
@@ -285,7 +313,8 @@ public class DeployerEjb implements Depl
}
}
- public void undeploy(String moduleId) throws UndeployException,
NoSuchApplicationException {
+ @Override
+ public void undeploy(final String moduleId) throws UndeployException,
NoSuchApplicationException {
try {
assembler.destroyApplication(moduleId);
} catch (NoSuchApplicationException nsae) {
@@ -306,12 +335,13 @@ public class DeployerEjb implements Depl
saveDeployment(new File(moduleId), false);
}
- private static String contextRoot(final Properties properties, final
String jarPath) {
+ private String contextRoot(final Properties properties, final String
jarPath) {
return properties.getProperty("webapp." + jarPath + ".context-root");
}
+ @Override
public void reload(final String moduleId) {
- for (AppInfo info : assembler.getDeployedApplications()) {
+ for (final AppInfo info : assembler.getDeployedApplications()) {
if (info.path.equals(moduleId)) {
reload(info);
break;
Modified:
tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
URL:
http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java?rev=1439849&r1=1439848&r2=1439849&view=diff
==============================================================================
---
tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
(original)
+++
tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
Tue Jan 29 12:13:18 2013
@@ -1527,7 +1527,7 @@ public class Assembler extends Assembler
containerSystem.removeAppContext(appInfo.appId);
- ClassLoaderUtil.destroyClassLoader(appInfo.path);
+ ClassLoaderUtil.destroyClassLoader(appInfo);
if (undeployException.getCauses().size() > 0) {
throw undeployException;
Modified:
tomee/tomee/trunk/container/openejb-core/src/test/java/org/apache/openejb/config/AutoDeployerTest.java
URL:
http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-core/src/test/java/org/apache/openejb/config/AutoDeployerTest.java?rev=1439849&r1=1439848&r2=1439849&view=diff
==============================================================================
---
tomee/tomee/trunk/container/openejb-core/src/test/java/org/apache/openejb/config/AutoDeployerTest.java
(original)
+++
tomee/tomee/trunk/container/openejb-core/src/test/java/org/apache/openejb/config/AutoDeployerTest.java
Tue Jan 29 12:13:18 2013
@@ -23,8 +23,9 @@ import org.apache.openejb.loader.IO;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.util.Archives;
import org.junit.After;
-import org.junit.Assert;
+import org.junit.AfterClass;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import javax.annotation.PostConstruct;
@@ -34,22 +35,55 @@ import javax.ejb.Startup;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
/**
* @version $Rev$ $Date$
*/
-public class AutoDeployerTest extends Assert {
+public class AutoDeployerTest {
+
+ private static final Set<File> files = new HashSet<File>();
+
+ @BeforeClass
+ public static void beforeClass() {
+ files.clear();
+ }
+
+ @AfterClass
+ public static void afterClass() throws InterruptedException {
+
+ //Give async IO a reasonable chance to catch up.
+ SystemInstance.reset();
+ Thread.sleep(3000);
+
+ //Make sure files have been deleted.
+ for (final File file : files) {
+ if (file.exists()) {
+ final File[] exists = file.listFiles();
+ assertTrue("Application files still exist in: " +
file.getAbsolutePath(), (null == exists || exists.length == 0));
+ }
+ }
+ }
@Before
@After
- public void beforeAndAfter() {
+ public void beforeAndAfter() throws InterruptedException {
+
+ //Allow AutoDeployer scanning to complete
+ Thread.sleep(3000);
+
final AutoDeployer autoDeployer =
SystemInstance.get().getComponent(AutoDeployer.class);
if (autoDeployer != null) {
autoDeployer.stop();
@@ -64,6 +98,8 @@ public class AutoDeployerTest extends As
final File apps = Files.mkdir(tmpdir, "myapps");
final File conf = Files.mkdir(tmpdir, "conf");
+ files.add(apps);
+
final Properties properties = new Properties();
properties.setProperty("openejb.deployments.classpath", "false");
properties.setProperty("openejb.deployment.unpack.location", "false");
@@ -122,6 +158,8 @@ public class AutoDeployerTest extends As
final File apps = Files.mkdir(tmpdir, "my apps");
final File conf = Files.mkdir(tmpdir, "conf");
+ files.add(apps);
+
final Properties properties = new Properties();
properties.setProperty("openejb.deployments.classpath", "false");
properties.setProperty("openejb.deployment.unpack.location", "false");
@@ -180,6 +218,8 @@ public class AutoDeployerTest extends As
final File apps = Files.mkdir(tmpdir, "myapps");
final File conf = Files.mkdir(tmpdir, "conf");
+ files.add(apps);
+
final Properties properties = new Properties();
properties.setProperty("openejb.deployments.classpath", "false");
properties.setProperty("tomee.unpack.dir", "work");