views:

271

answers:

4

I've already asked this question on the Icefaces forum, but meanwhile I realized that this is a more generic problem.

I'd like to update parts of a JSF page when I get a message in my MDB.

The problem is, how do I get the FacesContext from the EJB container?

In the message processing function FacesContext.getCurrentInstance() returns null.

I've also tried to make a JSF managed bean be a MDB, but I couldn't (it seems you can't have both in the same class?).

Since I'm a beginner in the JSF world I'm kind of stuck now. Is there a way to make it work?

(Glassfish v3 + Netbeans 6.8, JSF2 + Icefaces 2.0 alpha2)

+1  A: 

I'm no expert but I'd expect that the FacesContext is available only during the processing of a JSF request. I am afraid you can't do exactly what you want but you can certainly work around it. There are actually two issues:

  1. How to get the update via MDB to a JSF page?
  2. How to refresh the page on the client when the event occurs? You cannot normally send data from a server to a client, the client must requst them (though there are some workarounds such as http://en.wikipedia.org/wiki/Comet_(programming))

I'd something like the following:

  1. In the MDB, store the updated data somewhere - such as into a global cache (stateless session bean with @Singleton and a collection or a map for the updates)
  2. Modify the JSF page so that it queries the server for updates in regular interval (preferably in the background using Ajax via some ajax-enabled JSF componet) - if there is an update received via the MDB, the server will return it and the page will re-render itself
Jakub Holý
Hi, thanks for the answer.#2 is easy, because Icefaces 2.0 has its PushRenderer class, which works well. #1 is the question: how do I refer to a class instance managed by the FacesServlet, if I'm outside it? EJBs run in a different container...
Gabor Kulcsar
@egbokul #1 does not deal witl JSF at all, it just stores the data in a @Singleton session bean, which can be then accessed by JSF. So it's JSF -> EJB and not vice versa. But with the PortableRenderer that you mention you can hopefully push the data from the MDB directly to JSF. I'm curious how it works :-) Good luck!
Jakub Holý
A: 

I have a workaround which involves a Timer on the JSF side (luckily it's on the server only, no AJAX and client-server communication is necessary) which checks a Singleton and fires updates when necessary. However I still believe this is not the proper solution and that it could be done without a Timer...

Gabor Kulcsar
A: 

The FacesContext is HTTP request based and thus only available during the HTTP request processing and even then only when the request URL matches the url pattern of the FacesServlet. If you're not inside the thread which is executed by the server to process the HTTP request, then there's also no means of a FacesContext. In an EJB container there's totally no means of HTTP requests.

Technically, the only way to let EJB inform JSF about a new message is to let EJB fire a HTTP request on an URL matching the url pattern of the FacesServlet with the message as request parameter. You can use java.net.URLConnection for this. JSF in turn can then do the Comet/HTTP push like stuff to update the view with the message the IceFaces way as you mentioned.

E.g.

URL url = new URL("http://example.com/context/poll.jsf?msg=" + URLEncoder(msg, "UTF-8"));
URLConenction connection = url.openConnection();
InputStream response = connection.getInputStream();

and a poll.jsf which is attached to a backing bean like this:

@ManagedBean
public class Poll {

    @ManagedProperty(value="#{param.msg}")
    private String msg;

    @PostConstruct
    public void init() {
        // Do something with msg.
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

}

Note: using JSF 2.0 annotations, but they ought to be self-explaining enough.

BalusC
Thank you for the answer. It works, although still not the cleanest solution in my opinion (why doesn't the EE application server have an internal way of doing this, without calling the servlet externally?), but acceptable.
Gabor Kulcsar
A: 

I also got a response on the Icefaces forum:

org.icefaces.application.PortableRenderer provides an object that can be used on non-JSF threads to invoke push. (This is available in the svn trunk and will be provided in the next alpha (= Icefaces 2.0 alpha 3) release.)

Gabor Kulcsar