Skip to content

Commit

Permalink
WELD-1412 Introduce proper SPI for constructor interception of EE com…
Browse files Browse the repository at this point in the history
…ponents
  • Loading branch information
jharting committed Jun 27, 2013
1 parent d745e9a commit c248f8c
Show file tree
Hide file tree
Showing 29 changed files with 616 additions and 65 deletions.
2 changes: 1 addition & 1 deletion impl/src/main/java/org/jboss/weld/bean/SessionBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ protected void specialize() {
* @return The instance
*/
public T create(final CreationalContext<T> creationalContext) {
return proxyInstantiator.newInstance(creationalContext, beanManager, null);
return proxyInstantiator.newInstance(creationalContext, beanManager);
}

public void destroy(T instance, CreationalContext<T> creationalContext) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

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

import org.jboss.weld.construction.api.AroundConstructCallback;
import org.jboss.weld.context.api.ContextualInstance;
import org.jboss.weld.injection.spi.ResourceReference;
import org.jboss.weld.util.reflection.Reflections;
Expand All @@ -52,22 +54,27 @@ public class CreationalContextImpl<T> implements CreationalContext<T>, WeldCreat

private final List<ContextualInstance<?>> parentDependentInstances;

private final WeldCreationalContext<?> parentCreationalContext;
private final CreationalContextImpl<?> parentCreationalContext;

private transient List<ResourceReference<?>> resourceReferences;

private boolean constructorInterceptionSuppressed;

private transient List<AroundConstructCallback<T>> aroundConstructCallbacks;

public CreationalContextImpl(Contextual<T> contextual) {
this(contextual, null, Collections.synchronizedList(new ArrayList<ContextualInstance<?>>()), null);
}

private CreationalContextImpl(Contextual<T> contextual, Map<Contextual<?>, Object> incompleteInstances,
List<ContextualInstance<?>> parentDependentInstancesStore, WeldCreationalContext<?> parentCreationalContext) {
List<ContextualInstance<?>> parentDependentInstancesStore, CreationalContextImpl<?> parentCreationalContext) {
this.incompleteInstances = incompleteInstances;
this.contextual = contextual;
// this is direct ref by intention - to track dependencies hierarchy
this.dependentInstances = Collections.synchronizedList(new ArrayList<ContextualInstance<?>>());
this.parentDependentInstances = parentDependentInstancesStore;
this.parentCreationalContext = parentCreationalContext;
this.constructorInterceptionSuppressed = false;
}

public void push(T incompleteInstance) {
Expand All @@ -77,7 +84,8 @@ public void push(T incompleteInstance) {
incompleteInstances.put(contextual, incompleteInstance);
}

public <S> WeldCreationalContext<S> getCreationalContext(Contextual<S> contextual) {

public <S> CreationalContextImpl<S> getCreationalContext(Contextual<S> contextual) {
return new CreationalContextImpl<S>(contextual, incompleteInstances, dependentInstances, this);
}

Expand All @@ -93,13 +101,11 @@ public void addDependentInstance(ContextualInstance<?> contextualInstance) {
parentDependentInstances.add(contextualInstance);
}

@java.lang.SuppressWarnings({"NullableProblems"})
public void release() {
release(null, null);
}

// should not be public
@java.lang.SuppressWarnings({"UnusedParameters"})
public void release(Contextual<T> contextual, T instance) {
for (ContextualInstance<?> dependentInstance : dependentInstances) {
// do not destroy contextual again, since it's just being destroyed
Expand All @@ -118,10 +124,16 @@ private static <T> void destroy(ContextualInstance<T> beanInstance) {
beanInstance.getContextual().destroy(beanInstance.getInstance(), beanInstance.getCreationalContext());
}

public WeldCreationalContext<?> getParentCreationalContext() {
/**
* @return the parent {@link CreationalContext} or null if there isn't any parent.
*/
public CreationalContextImpl<?> getParentCreationalContext() {
return parentCreationalContext;
}

/**
* Returns an unmodifiable list of dependent instances.
*/
public List<ContextualInstance<?>> getDependentInstances() {
return Collections.unmodifiableList(dependentInstances);
}
Expand Down Expand Up @@ -156,15 +168,22 @@ protected Object writeReplace() throws ObjectStreamException {
return this;
}

@Override
/**
* Register a {@link ResourceReference} as a dependency. {@link ResourceReference#release()} will be called on every {@link ResourceReference} once this
* {@link CreationalContext} instance is released.
*/
public void addDependentResourceReference(ResourceReference<?> resoruceReference) {
if (resourceReferences == null) {
this.resourceReferences = new ArrayList<ResourceReference<?>>();
}
this.resourceReferences.add(resoruceReference);
}

@Override
/**
* Destroys dependent instance
* @param instance
* @return true if the instance was destroyed, false otherwise
*/
public boolean destroyDependentInstance(T instance) {
for (Iterator<ContextualInstance<?>> iterator = dependentInstances.iterator(); iterator.hasNext();) {
ContextualInstance<?> contextualInstance = iterator.next();
Expand All @@ -177,8 +196,35 @@ public boolean destroyDependentInstance(T instance) {
return false;
}

@Override
/**
* @return the {@link Contextual} for which this {@link CreationalContext} is created.
*/
public Contextual<T> getContextual() {
return contextual;
}

public List<AroundConstructCallback<T>> getAroundConstructCallbacks() {
if (aroundConstructCallbacks == null) {
return Collections.emptyList();
}
return aroundConstructCallbacks;
}

@Override
public void setConstructorInterceptionSuppressed(boolean value) {
this.constructorInterceptionSuppressed = value;
}

@Override
public boolean isConstructorInterceptionSuppressed() {
return this.constructorInterceptionSuppressed;
}

@Override
public void registerAroundConstructCallback(AroundConstructCallback<T> callback) {
if (aroundConstructCallbacks == null) {
this.aroundConstructCallbacks = new LinkedList<AroundConstructCallback<T>>();
}
this.aroundConstructCallbacks.add(callback);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
* @param <T>
* @author pmuir
*/
public interface WeldCreationalContext<T> extends CreationalContext<T> {
public interface WeldCreationalContext<T> extends org.jboss.weld.construction.api.WeldCreationalContext<T> {

<S> WeldCreationalContext<S> getCreationalContext(Contextual<S> Contextual);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.security.AccessController;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.TransientReference;
Expand All @@ -30,9 +33,13 @@

import org.jboss.weld.annotated.enhanced.ConstructorSignature;
import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedConstructor;
import org.jboss.weld.injection.AroundConstructCallback.ConstructionHandle;
import org.jboss.weld.construction.api.AroundConstructCallback;
import org.jboss.weld.construction.api.ConstructionHandle;
import org.jboss.weld.context.CreationalContextImpl;
import org.jboss.weld.exceptions.WeldException;
import org.jboss.weld.manager.BeanManagerImpl;
import org.jboss.weld.security.GetAccessibleCopyOfMember;
import org.jboss.weld.util.reflection.Reflections;

/**
* High-level representation of an injected constructor. This class does not need to be serializable because it is never injected.
Expand All @@ -55,25 +62,49 @@ protected ConstructorInjectionPoint(EnhancedAnnotatedConstructor<T> constructor,
this.accessibleConstructor = AccessController.doPrivileged(new GetAccessibleCopyOfMember<Constructor<T>>(constructor.getJavaMember()));
}

public T newInstance(BeanManagerImpl manager, CreationalContext<?> ctx, AroundConstructCallback<T> callback) {
public T newInstance(BeanManagerImpl manager, CreationalContext<?> ctx) {
CreationalContext<?> invocationContext = manager.createCreationalContext(null);
try {
Object[] parameterValues = getParameterValues(manager, ctx, invocationContext);
if (callback == null) {
return newInstance(parameterValues);
if (ctx instanceof CreationalContextImpl<?>) {
CreationalContextImpl<T> weldCtx = Reflections.cast(ctx);
return invokeAroundConstructCallbacks(parameterValues, weldCtx);
} else {
return callback.aroundConstruct(parameterValues, new ConstructionHandle<T>() {
@Override
public T construct(Object[] parameters) {
return newInstance(parameters);
}
});
return newInstance(parameterValues);
}
} finally {
invocationContext.release();
}
}

private T invokeAroundConstructCallbacks(Object[] parameters, CreationalContextImpl<T> ctx) {
final List<AroundConstructCallback<T>> callbacks = ctx.getAroundConstructCallbacks();
final Iterator<AroundConstructCallback<T>> iterator = callbacks.iterator();
if (!iterator.hasNext()) {
return newInstance(parameters);
}
return invokeAroundConstructCallback(iterator.next(), new ConstructionHandle<T>() {
@Override
public T proceed(Object[] parameters, Map<String, Object> data) {
if (iterator.hasNext()) {
return invokeAroundConstructCallback(iterator.next(), this, getComponentConstructor(), parameters, data);
} else {
return newInstance(parameters);
}
}
}, getComponentConstructor(), parameters, new HashMap<String, Object>());
}

private T invokeAroundConstructCallback(AroundConstructCallback<T> callback, ConstructionHandle<T> ctx, AnnotatedConstructor<T> constructor, Object[] parameters, Map<String, Object> data) {
try {
return callback.aroundConstruct(ctx, constructor, parameters, data);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new WeldException(e);
}
}

protected T newInstance(Object[] parameterValues) {
try {
return accessibleConstructor.newInstance(parameterValues);
Expand Down Expand Up @@ -117,4 +148,8 @@ public AnnotatedConstructor<T> getAnnotated() {
public ConstructorSignature getSignature() {
return signature;
}

public AnnotatedConstructor<T> getComponentConstructor() {
return constructor;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import java.util.List;

import javax.enterprise.inject.spi.AnnotatedConstructor;
import javax.enterprise.inject.spi.Bean;

import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedConstructor;
Expand Down Expand Up @@ -93,4 +94,9 @@ protected T newInstance(Object[] parameterValues) {
}
return instance;
}

@Override
public AnnotatedConstructor<T> getComponentConstructor() {
return originalConstructorInjectionPoint.getAnnotated();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import org.jboss.weld.bean.proxy.ProxyObject;
import org.jboss.weld.bean.proxy.TargetBeanInstance;
import org.jboss.weld.exceptions.WeldException;
import org.jboss.weld.injection.AroundConstructCallback;
import org.jboss.weld.injection.CurrentInjectionPoint;
import org.jboss.weld.manager.BeanManagerImpl;
import org.jboss.weld.serialization.spi.ContextualStore;
Expand Down Expand Up @@ -60,9 +59,9 @@ public AbstractDecoratorApplyingInstantiator(Instantiator<T> delegate, Bean<T> b
}

@Override
public T newInstance(CreationalContext<T> ctx, BeanManagerImpl manager, AroundConstructCallback<T> callback) {
public T newInstance(CreationalContext<T> ctx, BeanManagerImpl manager) {
InjectionPoint originalInjectionPoint = manager.getServices().get(CurrentInjectionPoint.class).peek();
return applyDecorators(delegate().newInstance(ctx, manager, callback), ctx, originalInjectionPoint, manager);
return applyDecorators(delegate().newInstance(ctx, manager), ctx, originalInjectionPoint, manager);
}

protected abstract T applyDecorators(T instance, CreationalContext<T> creationalContext, InjectionPoint originalInjectionPoint, BeanManagerImpl manager);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,14 @@

import javax.enterprise.context.spi.CreationalContext;

import org.jboss.weld.injection.AroundConstructCallback;
import org.jboss.weld.injection.ConstructorInjectionPoint;
import org.jboss.weld.manager.BeanManagerImpl;

public abstract class AbstractInstantiator<T> implements Instantiator<T> {

@Override
public T newInstance(CreationalContext<T> ctx, BeanManagerImpl manager, AroundConstructCallback<T> callback) {
return getConstructorInjectionPoint().newInstance(manager, ctx, callback);
public T newInstance(CreationalContext<T> ctx, BeanManagerImpl manager) {
return getConstructorInjectionPoint().newInstance(manager, ctx);
}

protected abstract ConstructorInjectionPoint<T> getConstructorInjectionPoint();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ protected void checkType(EnhancedAnnotatedType<T> type) {
}

public T produce(CreationalContext<T> ctx) {
return instantiator.newInstance(ctx, beanManager, null);
return instantiator.newInstance(ctx, beanManager);
}

@Override
Expand Down
Loading

0 comments on commit c248f8c

Please sign in to comment.