forked from quarkusio/quarkus
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request quarkusio#45170 from mkouba/issue-45146
ArC: introduce CurrentManagedContext, built-in session context, `@ActivateSessionContext`
- Loading branch information
Showing
22 changed files
with
613 additions
and
390 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcTestSteps.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package io.quarkus.arc.deployment; | ||
|
||
import java.util.HashSet; | ||
import java.util.Set; | ||
import java.util.function.Predicate; | ||
|
||
import org.jboss.jandex.AnnotationInstance; | ||
import org.jboss.jandex.AnnotationTransformation; | ||
import org.jboss.jandex.DotName; | ||
|
||
import io.quarkus.arc.processor.BeanInfo; | ||
import io.quarkus.arc.runtime.ArcRecorder; | ||
import io.quarkus.arc.runtime.test.ActivateSessionContextInterceptor; | ||
import io.quarkus.arc.runtime.test.PreloadedTestApplicationClassPredicate; | ||
import io.quarkus.deployment.IsTest; | ||
import io.quarkus.deployment.annotations.BuildProducer; | ||
import io.quarkus.deployment.annotations.BuildStep; | ||
import io.quarkus.deployment.annotations.BuildSteps; | ||
import io.quarkus.deployment.annotations.ExecutionTime; | ||
import io.quarkus.deployment.annotations.Record; | ||
import io.quarkus.deployment.builditem.ApplicationClassPredicateBuildItem; | ||
|
||
@BuildSteps(onlyIf = IsTest.class) | ||
public class ArcTestSteps { | ||
|
||
@BuildStep | ||
public void additionalBeans(BuildProducer<AdditionalBeanBuildItem> additionalBeans) { | ||
// We need to register the bean implementation for TestApplicationClassPredicate | ||
// TestApplicationClassPredicate is used programmatically in the ArC recorder when StartupEvent is fired | ||
additionalBeans.produce(AdditionalBeanBuildItem.unremovableOf(PreloadedTestApplicationClassPredicate.class)); | ||
// In tests, register the ActivateSessionContextInterceptor and ActivateSessionContext interceptor binding | ||
additionalBeans.produce(new AdditionalBeanBuildItem(ActivateSessionContextInterceptor.class)); | ||
additionalBeans.produce(new AdditionalBeanBuildItem("io.quarkus.test.ActivateSessionContext")); | ||
} | ||
|
||
@BuildStep | ||
AnnotationsTransformerBuildItem addInterceptorBinding() { | ||
return new AnnotationsTransformerBuildItem( | ||
AnnotationTransformation.forClasses().whenClass(ActivateSessionContextInterceptor.class).transform(tc -> tc.add( | ||
AnnotationInstance.builder(DotName.createSimple("io.quarkus.test.ActivateSessionContext")).build()))); | ||
} | ||
|
||
// For some reason the annotation literal generated for io.quarkus.test.ActivateSessionContext lives in app class loader. | ||
// This predicates ensures that the generated bean is considered an app class too. | ||
// As a consequence, the type and all methods of ActivateSessionContextInterceptor must be public. | ||
@BuildStep | ||
ApplicationClassPredicateBuildItem appClassPredicate() { | ||
return new ApplicationClassPredicateBuildItem(new Predicate<String>() { | ||
|
||
@Override | ||
public boolean test(String name) { | ||
return name.startsWith(ActivateSessionContextInterceptor.class.getName()); | ||
} | ||
}); | ||
} | ||
|
||
@BuildStep | ||
@Record(ExecutionTime.STATIC_INIT) | ||
void initTestApplicationClassPredicateBean(ArcRecorder recorder, BeanContainerBuildItem beanContainer, | ||
BeanDiscoveryFinishedBuildItem beanDiscoveryFinished, | ||
CompletedApplicationClassPredicateBuildItem predicate) { | ||
Set<String> applicationBeanClasses = new HashSet<>(); | ||
for (BeanInfo bean : beanDiscoveryFinished.beanStream().classBeans()) { | ||
if (predicate.test(bean.getBeanClass())) { | ||
applicationBeanClasses.add(bean.getBeanClass().toString()); | ||
} | ||
} | ||
recorder.initTestApplicationClassPredicate(applicationBeanClasses); | ||
} | ||
|
||
} |
32 changes: 32 additions & 0 deletions
32
extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/session/Client.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package io.quarkus.arc.test.context.session; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
import static org.junit.jupiter.api.Assertions.fail; | ||
|
||
import jakarta.enterprise.context.Dependent; | ||
import jakarta.enterprise.context.SessionScoped; | ||
import jakarta.inject.Inject; | ||
|
||
import io.quarkus.arc.Arc; | ||
import io.quarkus.arc.ClientProxy; | ||
import io.quarkus.test.ActivateSessionContext; | ||
|
||
@Dependent | ||
class Client { | ||
|
||
@Inject | ||
SimpleBean bean; | ||
|
||
@ActivateSessionContext | ||
public String ping() { | ||
assertTrue(Arc.container().sessionContext().isActive()); | ||
if (bean instanceof ClientProxy proxy) { | ||
assertEquals(SessionScoped.class, proxy.arc_bean().getScope()); | ||
} else { | ||
fail("Not a client proxy"); | ||
} | ||
return bean.ping(); | ||
} | ||
|
||
} |
49 changes: 49 additions & 0 deletions
49
.../arc/deployment/src/test/java/io/quarkus/arc/test/context/session/SessionContextTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package io.quarkus.arc.test.context.session; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertFalse; | ||
import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
import jakarta.inject.Inject; | ||
|
||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.RegisterExtension; | ||
|
||
import io.quarkus.arc.Arc; | ||
import io.quarkus.arc.ManagedContext; | ||
import io.quarkus.test.QuarkusUnitTest; | ||
|
||
public class SessionContextTest { | ||
|
||
@RegisterExtension | ||
static final QuarkusUnitTest config = new QuarkusUnitTest() | ||
.withApplicationRoot(root -> root | ||
.addClasses(SimpleBean.class, Client.class)); | ||
|
||
@Inject | ||
Client client; | ||
|
||
@Inject | ||
SimpleBean simpleBean; | ||
|
||
@Test | ||
public void testContexts() { | ||
assertFalse(Arc.container().sessionContext().isActive()); | ||
assertNotNull(client.ping()); | ||
assertTrue(SimpleBean.DESTROYED.get()); | ||
assertFalse(Arc.container().sessionContext().isActive()); | ||
SimpleBean.DESTROYED.set(false); | ||
|
||
ManagedContext sessionContext = Arc.container().sessionContext(); | ||
try { | ||
sessionContext.activate(); | ||
String id = simpleBean.ping(); | ||
assertEquals(id, client.ping()); | ||
assertFalse(SimpleBean.DESTROYED.get()); | ||
} finally { | ||
sessionContext.terminate(); | ||
} | ||
assertTrue(SimpleBean.DESTROYED.get()); | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/session/SimpleBean.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package io.quarkus.arc.test.context.session; | ||
|
||
import java.util.UUID; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
|
||
import jakarta.annotation.PostConstruct; | ||
import jakarta.annotation.PreDestroy; | ||
import jakarta.enterprise.context.SessionScoped; | ||
|
||
@SessionScoped | ||
class SimpleBean { | ||
|
||
static final AtomicBoolean DESTROYED = new AtomicBoolean(); | ||
|
||
private String id; | ||
|
||
@PostConstruct | ||
void init() { | ||
id = UUID.randomUUID().toString(); | ||
} | ||
|
||
public String ping() { | ||
return id; | ||
} | ||
|
||
@PreDestroy | ||
void destroy() { | ||
DESTROYED.set(true); | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
.../runtime/src/main/java/io/quarkus/arc/runtime/test/ActivateSessionContextInterceptor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package io.quarkus.arc.runtime.test; | ||
|
||
import jakarta.annotation.Priority; | ||
import jakarta.interceptor.AroundInvoke; | ||
import jakarta.interceptor.Interceptor; | ||
import jakarta.interceptor.InvocationContext; | ||
|
||
import io.quarkus.arc.Arc; | ||
import io.quarkus.arc.ManagedContext; | ||
|
||
// The @ActivateSessionContext interceptor binding is added by the extension | ||
@Interceptor | ||
@Priority(Interceptor.Priority.PLATFORM_BEFORE + 100) | ||
public class ActivateSessionContextInterceptor { | ||
|
||
@AroundInvoke | ||
public Object aroundInvoke(InvocationContext ctx) throws Exception { | ||
ManagedContext sessionContext = Arc.container().sessionContext(); | ||
if (sessionContext.isActive()) { | ||
return ctx.proceed(); | ||
} | ||
try { | ||
sessionContext.activate(); | ||
return ctx.proceed(); | ||
} finally { | ||
sessionContext.terminate(); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.