Question

I've just updated a SessionScoped bean to OmniFaces (1.6.1) ViewScoped. Everything seems to work except for the fact that I get the following Exception when my backing bean is injected into a Servlet that I'm using for the processing of an ajax request:

org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type org.omnifaces.cdi.ViewScoped

Some things to consider:

1) The reason I have to inject a backing bean into a servlet is because I'm using jQuery's DataTables plugin, which (for server-side processing tables) requires an ajax request to retrieve table data. So basically I can't use Primefaces' <p:remoteCommand..> or anything like that.

2) From what I can tell, there aren't any extra GET requests to the view that would destroy and recreate the backing bean.

Is there anything else that could cause this Exception? Also, if this can't be done, is there another way to achieve what I'm doing?

Was it helpful?

Solution

The @ViewScoped annotation ties the bean to a specific JSF view which in turn relies on the presence of FacesContext#getViewRoot() and subsequently UIViewRoot#getViewMap(). None of both are available in a "plain vanilla" servlet. There's no means of a JSF view inside a plain servlet request, let alone a JSF context. So, unfortunately, this behavior is "by design".

You've basically 2 options:

  1. Store the desired shared information in the session scope which is keyed by an unique key which is passed around as HTTP request parameter so that both the JSF managed bean and the servlet can grab it from the session scope.

    E.g. in JSF backing bean:

    dataId = UUID.randomUUID().toString();
    externalContext.getSessionMap().put(dataId, data);
    

    In JSF view:

    <h:outputScript>var dataId = "#{bean.dataId}";</h:outputScript>
    

    In JavaScript:

    function loadData() {
        $.get("servletURL", { dataId: dataId }, function(response) {
            // ...
        });
    }
    

    In servlet:

    String dataId = request.getParameter("dataId");
    Data data = (Data) session.getAttribute(dataId);
    

  2. Use a true JSF backing bean instead of a plain vanilla servlet. You can definitely use <p:remoteCommand> for that. You can use RequestContext#addCallbackParam() in action(listener) method to "pass" ("print" is technically more correct) a JSON object from Java to JS and finally use oncomplete attribute to process it. Given that you're using OmniFaces, the <o:commandScript> and Ajax#data() offers the same functionality. The Ajax#data() has the additional advantage that it automatically converts from Java to JSON so that you don't need to do it yourself.

    E.g. in JSF view:

    <o:commandScript name="loadData" action="#{bean.loadData}" oncomplete="processData()" />
    

    In JSF backing bean:

    public void loadData() {
        Ajax.data(data);
    }
    

    In JavaScript:

    function processData() {
        var data = OmniFaces.Ajax.data;
        // ...
    }
    
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top