CDI SessionScoped bean access not working in Java 8 parallel thread

I am having trouble understanding why this code is not working. Basically I want to access CDI SessionScoped bean from CDI ViewScoped bean during parallelStream () function, I get this exception:

WELD-001303: No active contexts for scope type javax.enterprise.context.SessionScoped

      

This works in Wildfly 10.1.

ViewScoped bean:

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;

@ViewScoped
@Named
public class TestController implements Serializable {
    private static final long serialVersionUID = 1L;

    @Inject SessionController sessionController;

    public void works() {
        List<Function<String, String>> functions = new ArrayList<>();
        functions.add((String input) -> {
            return sessionController.getSomething();
        });
        functions.add((String input) -> {
            return sessionController.getSomethingElse();
        });
        functions.stream().forEach(f -> f.apply("input"));
    }

    public void doesNotWork() {
        List<Function<String, String>> functions = new ArrayList<>();
        functions.add((String input) -> {
            return sessionController.getSomething();
        });
        functions.add((String input) -> {
            return sessionController.getSomethingElse();
        });
        functions.parallelStream().forEach(f -> f.apply("input"));
    }
}

      

SessionScoped bean:

import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;

@Named
@SessionScoped
public class SessionController implements Serializable {
    private static final long serialVersionUID = 1L;

    public String getSomething() {
        return "something";
    }
    public String getSomethingElse() {
        return "else";
    }
}

      

XHTML:

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://primefaces.org/ui">

    <h:head />

    <h:body>
        <h:form>
            <p:commandButton value="Works" action="#{testController.works}" />
            <br />
            <p:commandButton value="Does Not Work" action="#{testController.doesNotWork}" />
        </h:form>
    </h:body>
</html>

      

StackTrace:

Caused by: org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.SessionScoped
    at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:689)
    at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:90)
    at org.jboss.weld.bean.ContextualInstanceStrategy$CachingContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:165)
    at org.jboss.weld.bean.ContextualInstance.getIfExists(ContextualInstance.java:63)
    at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:83)
    at org.jboss.weld.bean.proxy.ProxyMethodHandler.getInstance(ProxyMethodHandler.java:125)
    at com.SessionController$Proxy$_$$_WeldClientProxy.getSomething(Unknown Source)
    at com.TestController.lambda$3(TestController.java:33)
    at com.TestController.lambda$5(TestController.java:38)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
    at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
    at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:291)
    at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
    at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
    at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
    at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
    at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

      

We have theories that a session can be flow-specific, but without hard evidence.

Also wondering if there is a workaround. The actual code is much more complex, so we cannot preload the results of the SessionController without losing the benefits of parallel streaming.

+3


source to share


2 answers


I think what you are running into is that using parallel threads means you will be working in multiple threads. Now this is a problem with CDI and contexts because you need context propagation - for example, on the main thread that you have (for example) an active session context, but when you create another thread, it is inactive there.

Chapter 6.3 in the spec covers it in more detail, but to give you a story - propagating context to other threads doesn't work by default . And there are good reasons for this - it would be very expensive (synchronization) and you would have to deal with a lot of very strange situations, such as having one of the sessions invalidate threads, hence deactivating the session context while the other threads are running on German And there are many more such situations.



Also, there is no built-in workaround for this. However, you could implement your own scope or extend the existing session scope, but that would be very difficult I think.

+3


source


If you want to parallelize queries in Java EE, I suggest you use ManagedExecutorService. Forked pooled pool used by parallel threads is for parallelizing computations, not IO.

When it comes to propagating CDI context, you may find BoundSessionContext useful, assuming you are using WELD as your CDI implementation. More details at http://john-ament.blogspot.fi/2014/01/bridging-netty-resteasy-and-weld.html



You can probably do without the associated session context. Just grab all the data you need from the session context and feed it to the worker threads.

+1


source







All Articles