Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arc - request context propagation #44

Merged
merged 1 commit into from
Oct 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.jboss.protean.arc.Arc;
import org.jboss.protean.arc.ArcContainer;
import org.jboss.protean.arc.InstanceHandle;
import org.jboss.protean.arc.ManagedContext;
import org.jboss.shamrock.runtime.BeanContainer;
import org.jboss.shamrock.runtime.ContextObject;
import org.jboss.shamrock.runtime.InjectionFactory;
Expand Down Expand Up @@ -65,11 +66,12 @@ public <T, C> Action<T, C> create(Action<T, C> action) {
return new Action<T, C>() {
@Override
public T call(HttpServerExchange exchange, C context) throws Exception {
arcContainer.requestContext().activate();
ManagedContext requestContext = arcContainer.requestContext();
requestContext.activate();
try {
return action.call(exchange, context);
} finally {
arcContainer.requestContext().deactivate();
requestContext.terminate();
}
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,17 @@
import org.junit.Test;

public class InjectionTest {

@BeforeClass
public static void init() {
Arc.initialize();
}

@AfterClass
public static void shutdown() {
Arc.shutdown();
}

@SuppressWarnings("serial")
@Test
public void testInjection() {
ArcContainer arc = Arc.container();
Expand All @@ -41,7 +40,7 @@ public void testInjection() {
assertEquals("Lu Foo", foo.get().ping());
assertEquals("Lu Foo", foo.get().lazyPing());
assertEquals(foo.get(), arc.instance(Foo.class, new MyQualifier.OneLiteral()).get());
foo.release();
foo.destroy();
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -997,8 +997,7 @@ protected void implementGet(BeanInfo bean, ClassCreator beanCreator, String prov
MethodDescriptor.ofMethod(beanCreator.getClassName(), "create", providerTypeName, CreationalContext.class), get.getThis(),
get.getMethodParam(0));
// CreationalContextImpl.addDependencyToParent(this,instance,ctx)
get.invokeStaticMethod(MethodDescriptor.ofMethod(CreationalContextImpl.class, "addDependencyToParent", void.class, InjectableBean.class,
Object.class, CreationalContext.class), get.getThis(), instance, get.getMethodParam(0));
get.invokeStaticMethod(MethodDescriptors.CREATIONAL_CTX_ADD_DEP_TO_PARENT, get.getThis(), instance, get.getMethodParam(0));
// return instance
get.returnValue(instance);
} else if (ScopeInfo.SINGLETON.equals(bean.getScope())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ final class MethodDescriptors {
static final MethodDescriptor INVOCATION_CONTEXT_PRE_DESTROY = MethodDescriptor.ofMethod(InvocationContextImpl.class, "preDestroy",
InvocationContextImpl.class, Object.class, List.class, Set.class);

static final MethodDescriptor CREATIONAL_CTX_ADD_DEP_TO_PARENT = MethodDescriptor.ofMethod(CreationalContextImpl.class, "addDependencyToParent", void.class, InjectableBean.class,
Object.class, CreationalContext.class);

private MethodDescriptors() {
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package org.jboss.protean.arc;

import javax.enterprise.context.spi.AlterableContext;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.enterprise.context.spi.Contextual;
import javax.enterprise.context.spi.CreationalContext;

abstract class AbstractSharedContext implements AlterableContext {
abstract class AbstractSharedContext implements InjectableContext {

private final ComputingCache<Key<?>, InstanceHandleImpl<?>> instances;

Expand All @@ -24,6 +27,13 @@ public <T> T get(Contextual<T> contextual) {
return get(contextual, null);
}

@Override
public Collection<InstanceHandle<?>> getAll() {
List<InstanceHandle<?>> all = new ArrayList<>();
instances.forEachValue(v -> all.add(v));
return all;
}

@Override
public boolean isActive() {
return true;
Expand All @@ -33,15 +43,13 @@ public boolean isActive() {
public void destroy(Contextual<?> contextual) {
InstanceHandleImpl<?> handle = instances.remove(new Key<>(contextual, null));
if (handle != null) {
handle.destroy();
handle.destroyInternal();
}
}

public void destroy() {
synchronized (this) {
instances.forEachValue(instance -> instance.destroy());
instances.clear();
}
public synchronized void destroy() {
instances.forEachValue(instance -> instance.destroyInternal());
instances.clear();
}

@SuppressWarnings({ "unchecked", "rawtypes" })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public interface ArcContainer {
*
* @return the context for {@link javax.enterprise.context.RequestScoped}
*/
RequestContext requestContext();
ManagedContext requestContext();

void withinRequest(Runnable action);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.util.concurrent.CopyOnWriteArrayList;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.Initialized;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.spi.Context;
Expand Down Expand Up @@ -77,17 +78,19 @@ public <T> InstanceHandle<T> instance(TypeLiteral<T> type, Annotation... qualifi
}

@Override
public RequestContext requestContext() {
return (RequestContext) getContext(RequestScoped.class);
public ManagedContext requestContext() {
return (ManagedContext) getContext(RequestScoped.class);
}

@Override
public void withinRequest(Runnable action) {
ManagedContext requestContext = requestContext();
try {
requestContext().activate();
requestContext.activate();
action.run();
} finally {
requestContext().deactivate();
requestContext.destroy();
requestContext.deactivate();
}
}

Expand All @@ -105,11 +108,14 @@ private <T> InstanceHandle<T> instanceHandle(Type type, Annotation... qualifiers

private <T> InstanceHandle<T> instance(InjectableBean<T> bean) {
if (bean != null) {
CreationalContextImpl<T> parentContext = new CreationalContextImpl<>();
CreationalContextImpl<T> parentContext = null;
if (Dependent.class.equals(bean.getScope())) {
parentContext = new CreationalContextImpl<>();
}
CreationalContextImpl<T> creationalContext = parentContext != null ? parentContext.child() : new CreationalContextImpl<>();
InjectionPoint prev = InjectionPointProvider.CURRENT.get();
InjectionPointProvider.CURRENT.set(CurrentInjectionPointProvider.EMPTY);
try {
CreationalContextImpl<T> creationalContext = parentContext.child();
return new InstanceHandleImpl<T>(bean, bean.get(creationalContext), creationalContext, parentContext);
} finally {
if (prev != null) {
Expand All @@ -119,7 +125,7 @@ private <T> InstanceHandle<T> instance(InjectableBean<T> bean) {
}
}
} else {
return InstanceHandleImpl.unresolvable();
return InstanceHandleImpl.unavailable();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ void destroyDependentInstance(Object dependentInstance) {
synchronized (dependentInstances) {
for (InstanceHandle<?> instanceHandle : dependentInstances) {
if (instanceHandle.get() == dependentInstance) {
instanceHandle.release();
instanceHandle.destroy();
dependentInstances.remove(instanceHandle);
break;
}
Expand All @@ -51,7 +51,7 @@ public void push(T incompleteInstance) {
public void release() {
synchronized (dependentInstances) {
for (InstanceHandle<?> instance : dependentInstances) {
instance.release();
instance.destroy();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.jboss.protean.arc;

import java.util.Collection;

import javax.enterprise.context.spi.AlterableContext;

/**
*
* @author Martin Kouba
*/
public interface InjectableContext extends AlterableContext {

/**
* Note that we cannot actually return just a map of contextuals to contextual instances because we need to preserve the
* {@link javax.enterprise.context.spi.CreationalContext} too so that we're able to destroy the dependent objects correctly.
*
* @return all existing contextual instances
*/
Collection<InstanceHandle<?>> getAll();

/**
* Destroy all existing contextual instances.
*/
void destroy();
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,27 @@ public interface InstanceHandle<T> extends AutoCloseable {

/**
*
* @return an injected instance of {@code T}
* @return an injected instance of {@code T} or {@code null}
*/
T get();

/**
* Destroys the underlying injected instance.
* Destroys the instance and removes the instance from the underlying context.
*
* @see javax.enterprise.context.spi.Contextual#destroy(Object, javax.enterprise.context.spi.CreationalContext)
*/
void release();
void destroy();

/**
*
* @return the injectable bean
*/
InjectableBean<T> getBean();

/**
* Delegates to {@link #destroy()}.
*/
default void close() {
release();
destroy();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
class InstanceHandleImpl<T> implements InstanceHandle<T> {

@SuppressWarnings("unchecked")
public static final <T> InstanceHandle<T> unresolvable() {
return (InstanceHandle<T>) UNRESOLVABLE;
public static final <T> InstanceHandle<T> unavailable() {
return (InstanceHandle<T>) UNAVAILABLE;
}

static final InstanceHandleImpl<Object> UNRESOLVABLE = new InstanceHandleImpl<Object>(null, null, null, null);
static final InstanceHandleImpl<Object> UNAVAILABLE = new InstanceHandleImpl<Object>(null, null, null, null);

private final InjectableBean<T> bean;

Expand Down Expand Up @@ -51,22 +51,35 @@ public T get() {
}

@Override
public void release() {
public InjectableBean<T> getBean() {
return bean;
}

@Override
public void destroy() {
if (isAvailable()) {
if (bean.getScope().equals(ApplicationScoped.class) || bean.getScope().equals(RequestScoped.class) || bean.getScope().equals(Singleton.class)) {
((AlterableContext) Arc.container().getContext(bean.getScope())).destroy(bean);
} else {
destroy();
destroyInternal();
}
}
}

void destroy() {
public void destroyInternal() {
if (parentCreationalContext != null) {
parentCreationalContext.release();
} else {
bean.destroy(instance, creationalContext);
}
}

static <T> InstanceHandleImpl<T> unwrap(InstanceHandle<T> handle) {
if (handle instanceof InstanceHandleImpl) {
return (InstanceHandleImpl<T>) handle;
} else {
throw new IllegalArgumentException("Failed to unwrap InstanceHandleImpl: " + handle);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.jboss.protean.arc;

import java.util.Collection;

/**
*
* @author Martin Kouba
*/
public interface ManagedContext extends InjectableContext {

/**
* Activate the context with no initial state.
*/
default void activate() {
activate(null);
}

/**
* Activate the context. All instance handles from the initial state must have the same scope as the context, otherwise an {@link IllegalArgumentException}
* is thrown.
*
* @param initialState The initial state, may be {@code null}
*/
void activate(Collection<InstanceHandle<?>> initialState);

/**
* Deactivate the context - do not destoy existing contextual instances.
*/
void deactivate();

/**
* Destroy and deactivate the context.
*/
default void terminate() {
destroy();
deactivate();
}
}
Loading