问题
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:
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.
回答2:
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:
- How to get the update via MDB to a JSF page?
- 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:
- 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)
- 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
回答3:
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...
回答4:
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.)
来源:https://stackoverflow.com/questions/2673716/server-initiated-rendering-ejb-facescontext