}
@Override
public Interceptor create(final InterceptorFactoryContext context) {
final SessionBeanComponent component = (SessionBeanComponent) context.getContextData().get(Component.class);
return new Interceptor() {
@Override
public Object processInvocation(final InterceptorContext context) throws Exception {
final InterceptorContext asyncInterceptorContext = context.clone();
asyncInterceptorContext.putPrivateData(InvocationType.class, InvocationType.ASYNC);
final CancellationFlag flag = new CancellationFlag();
final SecurityContext securityContext;
if(WildFlySecurityManager.isChecking()) {
securityContext = AccessController.doPrivileged(new PrivilegedAction<SecurityContext>() {
@Override
public SecurityContext run() {
return SecurityContextAssociation.getSecurityContext();
}
});
} else {
securityContext = SecurityContextAssociation.getSecurityContext();
}
// clone the original security context so that changes to the original security context in a separate (caller/unrelated) thread doesn't affect
// the security context associated with the async invocation thread
final SecurityContext clonedSecurityContext;
if (securityContext instanceof JBossSecurityContext) {
clonedSecurityContext = (SecurityContext) ((JBossSecurityContext) securityContext).clone();
} else {
// we can't do anything if it isn't a JBossSecurityContext so just use the original one
clonedSecurityContext = securityContext;
}
final AsyncInvocationTask task = new AsyncInvocationTask(flag) {
@Override
protected Object runInvocation() throws Exception {
setSecurityContextOnAssociation(clonedSecurityContext);
try {
return asyncInterceptorContext.proceed();
} finally {
clearSecurityContextOnAssociation();
}
}
};
asyncInterceptorContext.putPrivateData(CancellationFlag.class, flag);
// This interceptor runs in user application's context classloader. Triggering an execute via an executor service from here can potentially lead to
// new thread creation which will assign themselves the context classloader of the parent thread (i.e. this thread). This effectively can lead to
// deployment's classloader leak. See https://issues.jboss.org/browse/WFLY-1375
// To prevent this, we set the TCCL of this thread to null and then trigger the "execute" before "finally" setting the TCCL back to the original one.
final ClassLoader oldClassLoader = WildFlySecurityManager.setCurrentContextClassLoaderPrivileged((ClassLoader) null);
try {
component.getAsynchronousExecutor().execute(task);
} finally {
// reset to the original TCCL
WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(oldClassLoader);
}
return task;