Skip to content

Commit

Permalink
[WFLY-5232] - Naming store is null before CDI lifecycle BeforeShutdow…
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanemerson committed Sep 9, 2015
1 parent a2147d2 commit efdb123
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 19 deletions.
@@ -0,0 +1,66 @@
package org.jboss.as.test.manualmode.weld.extension;

import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.BeforeShutdown;
import javax.enterprise.inject.spi.Extension;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.transaction.TransactionSynchronizationRegistry;
import javax.transaction.UserTransaction;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* @author Ryan Emerson
*/
public class BeforeShutdownExtension implements Extension {

private UserTransaction userTx = null;
private TransactionSynchronizationRegistry txSynchRegistry = null;

void lookupBeforeShutdown(@Observes final BeforeShutdown beforeShutdown) throws Exception {
try {
userTx = lookup("java:jboss/UserTransaction");
userTx.getStatus();

txSynchRegistry = lookup("java:jboss/TransactionSynchronizationRegistry");
txSynchRegistry.getTransactionStatus();
} catch (Exception e) {
writeOutput(e);
throw e;
}
writeOutput(null);
}

private <T> T lookup(String jndiName) {
try {
InitialContext initialContext = new InitialContext();
return (T) initialContext.lookup(jndiName);
} catch (NamingException e) {
throw new IllegalArgumentException(e);
}
}

// Necessary so that BeforeShutdownJNDILookupTestCase can see the outcome of the BeforeShutdown JNDI lookups.
private void writeOutput(Exception exception) throws Exception {
List<String> output = new ArrayList<>();
if (exception != null) {
output.add("Exception");
output.add(exception + "," + Arrays.toString(exception.getStackTrace()));
} else {
output.add("UserTransaction");
output.add(userTx.toString());
output.add("TransactionSynchronizationRegistry");
output.add(txSynchRegistry.toString());
}
File parent = new File(BeforeShutdownJNDILookupTestCase.TEST_URL).getParentFile();
if (!parent.exists())
parent.mkdirs();
Files.write(Paths.get("", BeforeShutdownJNDILookupTestCase.TEST_URL), output, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
}
}
@@ -0,0 +1,78 @@
package org.jboss.as.test.manualmode.weld.extension;

import junit.framework.AssertionFailedError;
import org.jboss.arquillian.container.test.api.ContainerController;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.container.test.api.TargetsContainer;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ArchivePaths;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.AfterClass;
import org.junit.Test;
import org.junit.runner.RunWith;

import javax.enterprise.inject.spi.Extension;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

import static org.junit.Assert.assertEquals;

/**
* A test to ensure that the UserTransaction and TransactionSynchronizationRegistry can be retrieved via JNDI when
* an extensions BeforeShutdown method is invoked.
* <p/>
* See WFLY-5232
*
* @author Ryan Emerson
*/
@RunWith(Arquillian.class)
@RunAsClient
public class BeforeShutdownJNDILookupTestCase {

public static final String TEST_URL = "target" + File.separator + "results.txt";

private static final String CONTAINER = "default-jbossas";
private static final String DEPLOYMENT = "test.war";
private static final Path TEST_PATH = Paths.get("", TEST_URL);

@Deployment(name = DEPLOYMENT, managed = true)
@TargetsContainer(CONTAINER)
public static Archive<?> deploy() throws Exception {
return ShrinkWrap
.create(WebArchive.class, DEPLOYMENT)
.addClasses(BeforeShutdownJNDILookupTestCase.class, BeforeShutdownExtension.class)
.add(EmptyAsset.INSTANCE, ArchivePaths.create("WEB-INF/beans.xml"))
.add(new StringAsset(BeforeShutdownExtension.class.getName()), "META-INF/services/" + Extension.class.getName());
}

@ArquillianResource
ContainerController controller;

@Test
public void testTransactionJNDILookupDuringShutdownEvent() throws Exception {
controller.start(CONTAINER);
controller.kill(CONTAINER);

List<String> output = Files.readAllLines(TEST_PATH);
if (output.get(0).equals("Exception")) {
String stacktrace = output.get(1).replaceAll(",", System.getProperty("line.separator"));
String msg = "An exception was thrown by the deployment %s during shutdown. The server stacktrace is shown below: %n%s";
throw new AssertionFailedError(String.format(msg, DEPLOYMENT, stacktrace));
}
assertEquals("Contents of result.txt is not valid!", "UserTransaction", output.get(0));
}

@AfterClass
public static void cleanup() throws Exception {
Files.delete(TEST_PATH);
}
}
30 changes: 13 additions & 17 deletions weld/src/main/java/org/jboss/as/weld/WeldBootstrapService.java
Expand Up @@ -129,25 +129,9 @@ public synchronized void start(final StartContext context) {
}

/**
* Stops the container
*
* @throws IllegalStateException if the container is not running
* This is a no-op, the actual shutdown is performed in {@link WeldStartService#stop(org.jboss.msc.service.StopContext)}
*/
public synchronized void stop(final StopContext context) {
if (!started) {
throw WeldLogger.ROOT_LOGGER.notStarted("WeldContainer");
}
WeldLogger.DEPLOYMENT_LOGGER.stoppingWeldService(deploymentName);
ClassLoader oldTccl = WildFlySecurityManager.getCurrentContextClassLoaderPrivileged();
try {
WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(deployment.getModule().getClassLoader());
WeldProvider.containerShutDown(Container.instance(deploymentName));
bootstrap.shutdown();
} finally {
WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(oldTccl);
ModuleGroupSingletonProvider.removeClassLoader(deployment.getModule().getClassLoader());
}
started = false;
}

/**
Expand Down Expand Up @@ -198,6 +182,18 @@ public boolean isStarted() {
return started;
}

void setStarted(boolean started) {
this.started = started;
}

WeldDeployment getDeployment() {
return deployment;
}

String getDeploymentName() {
return deploymentName;
}

WeldBootstrap getBootstrap() {
return bootstrap;
}
Expand Down
23 changes: 21 additions & 2 deletions weld/src/main/java/org/jboss/as/weld/WeldStartService.java
Expand Up @@ -26,6 +26,7 @@

import org.jboss.as.server.deployment.SetupAction;
import org.jboss.as.weld.logging.WeldLogger;
import org.jboss.as.weld.services.ModuleGroupSingletonProvider;
import org.jboss.msc.service.AbstractServiceListener;
import org.jboss.msc.service.Service;
import org.jboss.msc.service.ServiceController;
Expand All @@ -35,6 +36,7 @@
import org.jboss.msc.service.StopContext;
import org.jboss.msc.service.ServiceController.Mode;
import org.jboss.msc.value.InjectedValue;
import org.jboss.weld.Container;
import org.wildfly.security.manager.WildFlySecurityManager;

/**
Expand Down Expand Up @@ -107,11 +109,28 @@ public void transition(final ServiceController<?> controller, final ServiceContr
}

/**
* This is a no-op, the actual shutdown is performed in {@link WeldBootstrapService#stop(org.jboss.msc.service.StopContext)}
* Stops the container
* Executed in WeldStartService to shutdown the runtime before NamingService is closed.
*
* @throws IllegalStateException if the container is not running
*/
@Override
public void stop(final StopContext context) {

final WeldBootstrapService bootstrapService = bootstrap.getValue();
if (!bootstrapService.isStarted()) {
throw WeldLogger.ROOT_LOGGER.notStarted("WeldContainer");
}
WeldLogger.DEPLOYMENT_LOGGER.stoppingWeldService(bootstrapService.getDeploymentName());
ClassLoader oldTccl = WildFlySecurityManager.getCurrentContextClassLoaderPrivileged();
try {
WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(bootstrapService.getDeployment().getModule().getClassLoader());
WeldProvider.containerShutDown(Container.instance(bootstrapService.getDeploymentName()));
bootstrapService.getBootstrap().shutdown();
} finally {
WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(oldTccl);
ModuleGroupSingletonProvider.removeClassLoader(bootstrapService.getDeployment().getModule().getClassLoader());
}
bootstrapService.setStarted(false);
}

@Override
Expand Down
Expand Up @@ -43,7 +43,10 @@
import org.jboss.as.jpa.config.Configuration;
import org.jboss.as.jpa.config.PersistenceUnitMetadataHolder;
import org.jboss.as.jpa.service.PersistenceUnitServiceImpl;
import org.jboss.as.naming.deployment.ContextNames;
import org.jboss.as.naming.deployment.JndiNamingDependencyProcessor;
import org.jboss.as.naming.service.DefaultNamespaceContextSelectorService;
import org.jboss.as.naming.service.NamingService;
import org.jboss.as.security.service.SimpleSecurityManager;
import org.jboss.as.security.service.SimpleSecurityManagerService;
import org.jboss.as.server.deployment.Attachments;
Expand Down Expand Up @@ -287,6 +290,10 @@ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitPro

// make sure JNDI bindings are up
startService.addDependency(JndiNamingDependencyProcessor.serviceName(deploymentUnit));

// [WFLY-5232]
startService.addDependencies(getJNDISubsytemDependencies());

final EarMetaData earConfig = deploymentUnit.getAttachment(org.jboss.as.ee.structure.Attachments.EAR_METADATA);
if (earConfig == null || !earConfig.getInitializeInOrder()) {
// in-order install of sub-deployments may result in service dependencies deadlocks if the jndi dependency services of subdeployments are added as dependencies
Expand All @@ -299,6 +306,15 @@ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitPro

}

private List<ServiceName> getJNDISubsytemDependencies() {
List<ServiceName> dependencies = new ArrayList<>();
dependencies.add(ContextNames.JBOSS_CONTEXT_SERVICE_NAME.append(ServiceName.of("UserTransaction")));
dependencies.add(ContextNames.JBOSS_CONTEXT_SERVICE_NAME.append(ServiceName.of("TransactionSynchronizationRegistry")));
dependencies.add(NamingService.SERVICE_NAME);
dependencies.add(DefaultNamespaceContextSelectorService.SERVICE_NAME);
return dependencies;
}

private void getJpaDependencies(final DeploymentUnit deploymentUnit, final Set<ServiceName> jpaServices) {
for (ResourceRoot root : DeploymentUtils.allResourceRoots(deploymentUnit)) {

Expand Down

0 comments on commit efdb123

Please sign in to comment.