package org.jboss.modules;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.Collection;
import org.jboss.modules.test.TestClass;
import org.jboss.modules.util.TestModuleLoader;
import org.jboss.modules.util.TestResourceLoader;
import org.junit.Test;
/**
* Verifies the functionality of alias modules in unload/reload scenarios.
*
* @author <a href="mailto:ropalka@redhat.com">Richard Opalka</a>
* @author <a href="https://github.com/ppalaga">Peter Palaga</a>
*/
public class ModuleClassLoaderAliasReloadTest extends AbstractModuleTestCase {
private static final ModuleIdentifier MODULE_ONE_ID = ModuleIdentifier.fromString("test-module-1");
private static final ModuleIdentifier MODULE_TWO_ID = ModuleIdentifier.fromString("test-module-2");
private static final ModuleIdentifier MODULE_TWO_AL = ModuleIdentifier.fromString("test-module-2-alias");
private TestModuleLoader moduleLoader = new TestModuleLoader();
private static final class CloseAwareResourceLoader implements ResourceLoader {
private final ResourceLoader delegate;
private volatile boolean closed;
private CloseAwareResourceLoader(final ResourceLoader delegate) {
this.delegate = delegate;
}
@Override
public String getRootName() {
if (closed) throw new IllegalStateException();
return delegate.getRootName();
}
@Override
public ClassSpec getClassSpec(String fileName) throws IOException {
if (closed) throw new IllegalStateException();
return delegate.getClassSpec(fileName);
}
@Override
public PackageSpec getPackageSpec(String name) throws IOException {
if (closed) throw new IllegalStateException();
return delegate.getPackageSpec(name);
}
@Override
public Resource getResource(String name) {
if (closed) throw new IllegalStateException();
return delegate.getResource(name);
}
@Override
public String getLibrary(String name) {
if (closed) throw new IllegalStateException();
return delegate.getLibrary(name);
}
@Override
public Collection<String> getPaths() {
if (closed) throw new IllegalStateException();
return delegate.getPaths();
}
public void close() {
closed = true;
}
}
public void configureModules() throws Exception {
// first module
final ModuleSpec.Builder moduleOneBuilder = ModuleSpec.build(MODULE_ONE_ID);
moduleOneBuilder.addResourceRoot(ResourceLoaderSpec.createResourceLoaderSpec(
new CloseAwareResourceLoader(
TestResourceLoader.build()
.addClass(TestClass.class)
.addResources(getResource("test/aliasmodule/rootOne"))
.create())
));
moduleOneBuilder.addDependency(DependencySpec.createModuleDependencySpec(MODULE_TWO_AL));
moduleOneBuilder.addDependency(DependencySpec.createLocalDependencySpec());
moduleLoader.addModuleSpec(moduleOneBuilder.create());
// second module
final ModuleSpec.Builder moduleTwoBuilder = ModuleSpec.build(MODULE_TWO_ID);
moduleTwoBuilder.addResourceRoot(ResourceLoaderSpec.createResourceLoaderSpec(
new CloseAwareResourceLoader(
TestResourceLoader.build()
.addClass(TestClass.class)
.addResources(getResource("test/aliasmodule/rootTwo"))
.create()
)
));
moduleTwoBuilder.addDependency(DependencySpec.createModuleDependencySpec(MODULE_ONE_ID));
moduleTwoBuilder.addDependency(DependencySpec.createLocalDependencySpec());
moduleLoader.addModuleSpec(moduleTwoBuilder.create());
// second alias module
final ModuleSpec.AliasBuilder moduleTwoAliasBuilder = ModuleSpec.buildAlias(MODULE_TWO_AL, MODULE_TWO_ID);
moduleLoader.addModuleSpec(moduleTwoAliasBuilder.create());
}
/**
* Ensure the Alias modules do not leak during unload/reload, see https://issues.jboss.org/browse/MODULES-241
*
* @throws Exception
*/
@Test
public void testAliasModuleReload() throws Exception {
// FIRST PHASE
configureModules();
Module testModule1 = moduleLoader.loadModule(MODULE_ONE_ID);
Module testModule2 = moduleLoader.loadModule(MODULE_TWO_ID);
ModuleClassLoader classLoader1 = testModule1.getClassLoader();
ModuleClassLoader classLoader2 = testModule2.getClassLoader();
try {
Class<?> testClass1 = classLoader1.loadClass("org.jboss.modules.test.TestClass");
assertNotNull(testClass1);
Class<?> testClass2 = classLoader2.loadClass("org.jboss.modules.test.TestClass");
assertNotNull(testClass2);
assertNotNull(testClass1.getResource("/test.txt"));
assertNotNull(testClass2.getResource("/test.txt"));
} catch (ClassNotFoundException e) {
fail();
}
// cleanup
for (final ResourceLoader rl : classLoader1.getResourceLoaders()) { ((CloseAwareResourceLoader)rl).close(); }
for (final ResourceLoader rl : classLoader2.getResourceLoaders()) { ((CloseAwareResourceLoader)rl).close(); }
moduleLoader.unloadModuleLocal(testModule1);
moduleLoader.unloadModuleLocal(testModule2);
// SECOND PHASE
configureModules();
testModule1 = moduleLoader.loadModule(MODULE_ONE_ID);
moduleLoader.relink(testModule1);
testModule2 = moduleLoader.loadModule(MODULE_TWO_ID);
moduleLoader.relink(testModule2);
classLoader1 = testModule1.getClassLoader();
classLoader2 = testModule2.getClassLoader();
try {
Class<?> testClass1 = classLoader1.loadClass("org.jboss.modules.test.TestClass");
assertNotNull(testClass1);
Class<?> testClass2 = classLoader2.loadClass("org.jboss.modules.test.TestClass");
assertNotNull(testClass2);
assertNotNull(testClass1.getResource("/test.txt"));
assertNotNull(testClass2.getResource("/test.txt"));
} catch (ClassNotFoundException e) {
fail();
}
// cleanup
for (final ResourceLoader rl : classLoader1.getResourceLoaders()) { ((CloseAwareResourceLoader)rl).close(); }
for (final ResourceLoader rl : classLoader2.getResourceLoaders()) { ((CloseAwareResourceLoader)rl).close(); }
moduleLoader.unloadModuleLocal(testModule1);
moduleLoader.unloadModuleLocal(testModule2);
}
/**
* Ensure the Alias modules do not leak during unload/reload, see https://issues.jboss.org/browse/MODULES-241
*
* @throws Exception
*/
@Test
public void testAliasModuleReload2() throws Exception {
// FIRST PHASE
configureModules();
Module testModule1 = moduleLoader.loadModule(MODULE_ONE_ID);
Module testModule2 = moduleLoader.loadModule(MODULE_TWO_AL);
ModuleClassLoader classLoader1 = testModule1.getClassLoader();
ModuleClassLoader classLoader2 = testModule2.getClassLoader();
try {
Class<?> testClass1 = classLoader1.loadClass("org.jboss.modules.test.TestClass");
assertNotNull(testClass1);
Class<?> testClass2 = classLoader2.loadClass("org.jboss.modules.test.TestClass");
assertNotNull(testClass2);
assertNotNull(testClass1.getResource("/test.txt"));
assertNotNull(testClass2.getResource("/test.txt"));
} catch (ClassNotFoundException e) {
fail();
}
// cleanup
for (final ResourceLoader rl : classLoader1.getResourceLoaders()) { ((CloseAwareResourceLoader)rl).close(); }
for (final ResourceLoader rl : classLoader2.getResourceLoaders()) { ((CloseAwareResourceLoader)rl).close(); }
moduleLoader.unloadModuleLocal(testModule1);
moduleLoader.unloadModuleLocal(testModule2);
// SECOND PHASE
configureModules();
testModule1 = moduleLoader.loadModule(MODULE_ONE_ID);
moduleLoader.relink(testModule1);
testModule2 = moduleLoader.loadModule(MODULE_TWO_AL);
moduleLoader.relink(testModule2);
classLoader1 = testModule1.getClassLoader();
classLoader2 = testModule2.getClassLoader();
try {
Class<?> testClass1 = classLoader1.loadClass("org.jboss.modules.test.TestClass");
assertNotNull(testClass1);
Class<?> testClass2 = classLoader2.loadClass("org.jboss.modules.test.TestClass");
assertNotNull(testClass2);
assertNotNull(testClass1.getResource("/test.txt"));
assertNotNull(testClass2.getResource("/test.txt"));
} catch (ClassNotFoundException e) {
fail();
}
// cleanup
for (final ResourceLoader rl : classLoader1.getResourceLoaders()) { ((CloseAwareResourceLoader)rl).close(); }
for (final ResourceLoader rl : classLoader2.getResourceLoaders()) { ((CloseAwareResourceLoader)rl).close(); }
moduleLoader.unloadModuleLocal(testModule1);
moduleLoader.unloadModuleLocal(testModule2);
}
}