/*
* Copyright (C) 2015 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.errai.bus.server.websocket.test.jsr356.cdi.adapter;
import java.io.File;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import javax.enterprise.context.Conversation;
import javax.enterprise.inject.spi.Bean;
import javax.inject.Inject;
import javax.servlet.http.HttpSession;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.errai.bus.server.websocket.jsr356.weld.conversation.ConversationState;
import org.jboss.errai.bus.server.websocket.jsr356.weld.conversation.WeldConversationScopeAdapter;
import org.jboss.errai.bus.server.websocket.jsr356.weld.request.WeldRequestScopeAdapter;
import org.jboss.errai.bus.server.websocket.jsr356.weld.session.WeldSessionScopeAdapter;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.jboss.shrinkwrap.resolver.api.maven.Maven;
import org.jboss.weld.context.bound.BoundConversationContext;
import org.jboss.weld.context.bound.BoundRequestContext;
import org.jboss.weld.manager.BeanManagerImpl;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Tests the contexts and scopes.
*
* @author Michel Werren
*/
@RunWith(Arquillian.class)
public class ContainerOnlyTest {
private static final Logger LOGGER = LoggerFactory.getLogger(ContainerOnlyTest.class.getName());
@SuppressWarnings("rawtypes")
@Deployment
public static Archive getDeployment() {
final WebArchive war = ShrinkWrap.create(WebArchive.class, "containertest.war");
war.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
war.addClasses(RequestScopedBean.class, SessionScopedBean.class, FakeHttpSession.class, ConversationScopeBean.class);
war.addPackages(true, "org.jboss.errai.bus.server.websocket.jsr356");
final File[] files = Maven.resolver().loadPomFromFile("./pom.xml", "test-dependency-override")
.resolve("org.jboss.errai:errai-bus:?", "com.google.guava:guava:?")
.withTransitivity()
.asFile();
for (final File file : files) {
war.addAsLibrary(file);
}
return war;
}
@Inject
private BoundRequestContext boundRequestContext;
@Inject
private BoundConversationContext boundConversationContext;
@Inject
private BeanManagerImpl beanManager;
@Inject
private Conversation conversation;
@Before
public void setUp() throws Exception {
WeldRequestScopeAdapter.init(boundRequestContext);
WeldSessionScopeAdapter.init(beanManager);
WeldConversationScopeAdapter.init(boundConversationContext);
}
/**
* Test for 6 concurrent {@link javax.enterprise.context.RequestScoped} beans.
* Each one has its own {@link Thread}.
*
* @throws Exception
*/
@Test
public void testRequestScope() throws Exception {
final AtomicInteger doneRunnerCount = new AtomicInteger(0);
final Runnable requestScopeTask = new Runnable() {
@Override
public void run() {
final long timestamp = System.currentTimeMillis();
WeldRequestScopeAdapter.getInstance().activateContext();
final RequestScopedBean requestScopedBean = getInstance(RequestScopedBean.class);
requestScopedBean.setTimestamp(timestamp);
try {
Thread.sleep(500);
} catch (final InterruptedException e) {
Assert.fail();
}
Assert.assertEquals(timestamp, requestScopedBean.getTimestamp());
WeldRequestScopeAdapter.getInstance().invalidateContext();
doneRunnerCount.incrementAndGet();
}
};
final Thread one = new Thread(requestScopeTask);
final Thread two = new Thread(requestScopeTask);
final Thread three = new Thread(requestScopeTask);
final Thread four = new Thread(requestScopeTask);
final Thread five = new Thread(requestScopeTask);
final Thread six = new Thread(requestScopeTask);
one.start();
two.start();
three.start();
four.start();
five.start();
six.start();
/* Avoid hanging */
final long startTime = System.currentTimeMillis();
while (doneRunnerCount.get() < 6 && System.currentTimeMillis() - startTime < 2000) {
Thread.sleep(10);
}
if (doneRunnerCount.get() < 6) {
LOGGER.error("not all runners done.");
Assert.fail();
}
}
/**
* Test 2 concurrent sessions in each 3 {@link Thread}. That's each
* {@link Thread} obtain the correct
* {@link javax.enterprise.context.SessionScoped} bean and its value.
*
* @throws Exception
*/
@Test
public void testSessionScope() throws Exception {
final AtomicInteger doneRunnerCount = new AtomicInteger(0);
final Short idFirstSession = 1;
final Short idSecondSession = 2;
final FakeHttpSession firstSession = new FakeHttpSession();
final FakeHttpSession secondSession = new FakeHttpSession();
final AtomicBoolean done = new AtomicBoolean(false);
final Runnable firstSessionActivator = new Runnable() {
@Override
public void run() {
WeldSessionScopeAdapter.getInstance().activateContext(firstSession);
final SessionScopedBean sessionScopedBean = getInstance(SessionScopedBean.class);
sessionScopedBean.setId(idFirstSession);
WeldSessionScopeAdapter.getInstance().deactivateContext();
done.set(true);
}
};
new Thread(firstSessionActivator).start();
while (!done.get()) {
Thread.sleep(10);
}
done.set(false);
final Runnable secondSessionActivator = new Runnable() {
@Override
public void run() {
WeldSessionScopeAdapter.getInstance().activateContext(secondSession);
final SessionScopedBean sessionScopedBean = getInstance(SessionScopedBean.class);
sessionScopedBean.setId(idSecondSession);
WeldSessionScopeAdapter.getInstance().deactivateContext();
done.set(true);
}
};
new Thread(secondSessionActivator).start();
while (!done.get()) {
Thread.sleep(10);
}
class SessionRunner implements Runnable {
private final HttpSession httpSession;
private final Short id;
SessionRunner(final HttpSession httpSession, final Short id) {
this.httpSession = httpSession;
this.id = id;
}
@Override
public void run() {
WeldSessionScopeAdapter.getInstance().activateContext(httpSession);
final SessionScopedBean sessionScopedBean = getInstance(SessionScopedBean.class);
Assert.assertEquals("not same session in different thread", id, sessionScopedBean.getId());
WeldSessionScopeAdapter.getInstance().deactivateContext();
doneRunnerCount.incrementAndGet();
}
}
final Thread one = new Thread(new SessionRunner(firstSession, idFirstSession));
final Thread two = new Thread(new SessionRunner(secondSession, idSecondSession));
final Thread three = new Thread(new SessionRunner(firstSession, idFirstSession));
final Thread four = new Thread(new SessionRunner(secondSession, idSecondSession));
final Thread five = new Thread(new SessionRunner(firstSession, idFirstSession));
final Thread six = new Thread(new SessionRunner(secondSession, idSecondSession));
one.start();
two.start();
three.start();
four.start();
five.start();
six.start();
/* Avoid hanging */
final long startTime = System.currentTimeMillis();
while (doneRunnerCount.get() < 6 && System.currentTimeMillis() - startTime < 2000) {
Thread.sleep(10);
}
if (doneRunnerCount.get() < 6) {
LOGGER.error("not all runners done.");
Assert.fail();
}
}
/**
* Test for 2 concurrent active {@link Conversation} in one
* {@link HttpSession} {@link ConversationScopeBean} must anytime have the
* same id as the {@link ConversationState}. Runs with 4 concurrent
* {@link Thread} per {@link Conversation}.
*
* @throws Exception
*/
@Test
public void testConversationScope() throws Exception {
final FakeHttpSession httpSession = new FakeHttpSession();
final ConversationState firstCS = new ConversationState();
final ConversationState secondCS = new ConversationState();
final AtomicInteger doneRunnerCount = new AtomicInteger(0);
final AtomicBoolean done = new AtomicBoolean(false);
final Runnable firstConversationActivator = new Runnable() {
@Override
public void run() {
/* Like begin of message processing */
WeldRequestScopeAdapter.getInstance().activateContext();
WeldSessionScopeAdapter.getInstance().activateContext(httpSession);
WeldConversationScopeAdapter.getInstance().activateContext(firstCS);
conversation.begin();
final ConversationScopeBean conversationScopeBean = getInstance(ConversationScopeBean.class);
conversationScopeBean.setId(conversation.getId());
WeldConversationScopeAdapter.getInstance().deactivateContext();
WeldSessionScopeAdapter.getInstance().deactivateContext();
WeldRequestScopeAdapter.getInstance().deactivateContext();
done.set(true);
}
};
new Thread(firstConversationActivator).start();
/* wait until conversation has begun */
while (!done.get()) {
Thread.sleep(10);
}
done.set(false);
final Runnable secondConversationActivator = new Runnable() {
@Override
public void run() {
/* Like begin of message processing */
WeldRequestScopeAdapter.getInstance().activateContext();
WeldSessionScopeAdapter.getInstance().activateContext(httpSession);
WeldConversationScopeAdapter.getInstance().activateContext(secondCS);
conversation.begin();
final ConversationScopeBean conversationScopeBean = getInstance(ConversationScopeBean.class);
conversationScopeBean.setId(conversation.getId());
WeldConversationScopeAdapter.getInstance().deactivateContext();
WeldSessionScopeAdapter.getInstance().deactivateContext();
WeldRequestScopeAdapter.getInstance().deactivateContext();
WeldRequestScopeAdapter.getInstance().activateContext();
WeldSessionScopeAdapter.getInstance().activateContext(httpSession);
WeldConversationScopeAdapter.getInstance().activateContext(secondCS);
WeldConversationScopeAdapter.getInstance().deactivateContext();
WeldSessionScopeAdapter.getInstance().deactivateContext();
WeldRequestScopeAdapter.getInstance().deactivateContext();
done.set(true);
}
};
new Thread(secondConversationActivator).start();
/* wait until conversation has begun */
while (!done.get()) {
Thread.sleep(10);
}
class ConversationRunner implements Runnable {
private final ConversationState conversationState;
private final Conversation conversation;
ConversationRunner(final ConversationState conversationState, final Conversation conversation) {
this.conversationState = conversationState;
this.conversation = conversation;
}
@Override
public void run() {
WeldRequestScopeAdapter.getInstance().activateContext();
WeldSessionScopeAdapter.getInstance().activateContext(httpSession);
WeldConversationScopeAdapter.getInstance().activateContext(conversationState);
Assert.assertFalse(conversation.isTransient());
Assert.assertTrue(conversationState.isLongRunning());
final ConversationScopeBean conversationScopeBean = getInstance(ConversationScopeBean.class);
Assert.assertEquals("wrong state", conversationState.getConversationId(), conversationScopeBean.getId());
WeldConversationScopeAdapter.getInstance().deactivateContext();
WeldSessionScopeAdapter.getInstance().deactivateContext();
WeldRequestScopeAdapter.getInstance().deactivateContext();
final int runner = doneRunnerCount.incrementAndGet();
LOGGER.info("conversation {} runner: {} done", conversationState.getConversationId(), runner);
}
}
LOGGER.info("first conversation id: {}", firstCS.getConversationId());
LOGGER.info("second conversation id: {}", secondCS.getConversationId());
final Thread firstFirst = new Thread(new ConversationRunner(firstCS, conversation));
final Thread firstSecond = new Thread(new ConversationRunner(firstCS, conversation));
final Thread firstThird = new Thread(new ConversationRunner(firstCS, conversation));
final Thread firstFourth = new Thread(new ConversationRunner(firstCS, conversation));
final Thread secondFirst = new Thread(new ConversationRunner(secondCS, conversation));
final Thread secondSecond = new Thread(new ConversationRunner(secondCS, conversation));
final Thread secondThird = new Thread(new ConversationRunner(secondCS, conversation));
final Thread secondFourth = new Thread(new ConversationRunner(secondCS, conversation));
firstFirst.start();
secondFirst.start();
firstSecond.start();
secondSecond.start();
firstThird.start();
secondThird.start();
firstFourth.start();
secondFourth.start();
/* Avoid hanging */
final long startTime = System.currentTimeMillis();
while (doneRunnerCount.get() < 8 && System.currentTimeMillis() - startTime < 2000) {
Thread.sleep(10);
}
if (doneRunnerCount.get() < 8) {
LOGGER.error("not all runners done.");
Assert.fail();
}
}
@SuppressWarnings("unchecked")
public <T> T getInstance(final Class<T> clazz) {
final Set<Bean<?>> beans = beanManager.getBeans(clazz);
final Bean<?> bean = beans.iterator().next();
final Object reference = beanManager.getReference(bean, bean.getBeanClass(),
beanManager.createCreationalContext(bean));
return (T) reference;
}
}