Repository: deltaspike Updated Branches: refs/heads/master 8e23c8205 -> cf140a98c
DELTASPIKE-1138 ensuring @Futureable works with weld1 - note: we can desire to move the hack in a higher level to benefit to all interceptors Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/cf140a98 Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/cf140a98 Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/cf140a98 Branch: refs/heads/master Commit: cf140a98c4496f976e4a4fea9b84d58f795983a7 Parents: 8e23c82 Author: Romain manni-Bucau <[email protected]> Authored: Fri Apr 29 16:01:11 2016 +0200 Committer: Romain manni-Bucau <[email protected]> Committed: Fri Apr 29 16:01:11 2016 +0200 ---------------------------------------------------------------------- .../impl/future/DefaultFutureableStrategy.java | 113 +++++++++++++++++++ 1 file changed, 113 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/deltaspike/blob/cf140a98/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/future/DefaultFutureableStrategy.java ---------------------------------------------------------------------- diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/future/DefaultFutureableStrategy.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/future/DefaultFutureableStrategy.java index 7a51cc4..70ee7b7 100644 --- a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/future/DefaultFutureableStrategy.java +++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/future/DefaultFutureableStrategy.java @@ -31,6 +31,8 @@ import javax.inject.Inject; import javax.interceptor.InvocationContext; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.LinkedList; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -44,6 +46,17 @@ public class DefaultFutureableStrategy implements FutureableStrategy private static final Class<?> COMPLETABLE_FUTURE; private static final Method COMPLETABLE_STAGE_TO_FUTURE; + // only for weld1 + private static final boolean IS_WELD1; + private static final ThreadLocal<LinkedList<CallKey>> STACK = new ThreadLocal<LinkedList<CallKey>>() + { + @Override + protected LinkedList<CallKey> initialValue() + { + return new LinkedList<CallKey>(); + } + }; + static { Class<?> completionStageClass = null; @@ -63,6 +76,23 @@ public class DefaultFutureableStrategy implements FutureableStrategy COMPLETION_STAGE = completionStageClass; COMPLETABLE_FUTURE = completableFutureClass; COMPLETABLE_STAGE_TO_FUTURE = completionStageClassToCompletableFuture; + + { // workaround for weld -> use a thread local to track the invocations + boolean weld1 = false; + try + { + final Class<?> impl = Thread.currentThread().getContextClassLoader() + .loadClass("org.jboss.weld.manager.BeanManagerImpl"); + final Package pck = impl.getPackage(); + weld1 = "Weld Implementation".equals(pck.getImplementationTitle()) + && pck.getSpecificationVersion() != null && pck.getSpecificationVersion().startsWith("1.1."); + } + catch (final Throwable cnfe) + { + // no-op + } + IS_WELD1 = weld1; + } } @Inject @@ -78,6 +108,33 @@ public class DefaultFutureableStrategy implements FutureableStrategy @Override public Object execute(final InvocationContext ic) throws Exception { + final CallKey invocationKey; + if (IS_WELD1) + { + invocationKey = new CallKey(ic); + { // weld1 workaround + final LinkedList<CallKey> stack = STACK.get(); + if (!stack.isEmpty() && stack.getLast().equals(invocationKey)) + { + try + { + return ic.proceed(); + } + finally + { + if (stack.isEmpty()) + { + STACK.remove(); + } + } + } + } + } + else + { + invocationKey = null; + } + // validate usage final Class<?> returnType = ic.getMethod().getReturnType(); if (!Future.class.isAssignableFrom(returnType) && @@ -104,6 +161,16 @@ public class DefaultFutureableStrategy implements FutureableStrategy @Override public Object call() throws Exception { + final LinkedList<CallKey> callStack; + if (IS_WELD1) + { + callStack = STACK.get(); + callStack.add(invocationKey); + } + else + { + callStack = null; + } try { final Object proceed = ic.proceed(); @@ -120,6 +187,17 @@ public class DefaultFutureableStrategy implements FutureableStrategy { throw ExceptionUtils.throwAsRuntimeException(e); } + finally + { + if (IS_WELD1) + { + callStack.removeLast(); + if (callStack.isEmpty()) + { + STACK.remove(); + } + } + } } }; @@ -152,4 +230,39 @@ public class DefaultFutureableStrategy implements FutureableStrategy } return executorService; } + + private static final class CallKey + { + private final InvocationContext ic; + private final int hash; + + private CallKey(final InvocationContext ic) + { + this.ic = ic; + + final Object[] parameters = ic.getParameters(); + this.hash = ic.getMethod().hashCode() + (parameters == null ? 0 : Arrays.hashCode(parameters)); + } + + @Override + public boolean equals(final Object o) + { + return this == o || !(o == null || getClass() != o.getClass()) && equals(ic, CallKey.class.cast(o).ic); + } + + @Override + public int hashCode() + { + return hash; + } + + private boolean equals(final InvocationContext ic1, final InvocationContext ic2) + { + final Object[] parameters1 = ic1.getParameters(); + final Object[] parameters2 = ic2.getParameters(); + return ic2.getMethod().equals(ic1.getMethod()) && + (parameters1 == parameters2 || + (parameters1 != null && parameters2 != null && Arrays.equals(parameters1, ic2.getParameters()))); + } + } }
