• Post Reply Bookmark Topic Watch Topic
  • New Topic

Updating component parameters before end of JSF lifecycle

 
Brian Stock
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
from: http://stackoverflow.com/questions/10883133/how-can-a-jsf-icefaces-components-parameters-be-updated-immediately
I have an ICEfaces web app which contains a component with a property linked to a backing bean variable. In theory, variable value is programitcally modified, and the component sees the change and updates its appearance/properties accordingly.

However, it seems that the change in variable isn't "noticed" by the component until the end of the JSF cycle (which, from my basic understanding, is the render response phase).

The problem is, I have a long file-copy operation to perform, and I would like the the inputText component to show a periodic status update. However, since the component is only updated at the render response phase, it doesn't show any output until the Java methods have finished executing, and it shows it all changes accumulated at once.

I have tried using FacesContext.getCurrentInstance().renderResponse() and other fucntions, such as PushRenderer.render(String ID) to force XmlHttpRequest to initialize early, but no matter what, the appearance of the component does not change until the Java code finishes executing.

One possible solution that comes to mind is to have an invisible button somewhere that is automatically "pressed" by the bean when step 1 of the long operation completes, and by clicking it, it calls step 2, and so on and so forth. It seems like it would work, but I don't want to spend time hacking together such an inelegant solution when I would hope that there is a more elegant solution built into JSF/ICEfaces.

Am I missing something, or is resorting to ugly hacks the only way to acheive the desired behavior?
 
Tim Holloway
Bartender
Posts: 18413
58
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You are missing an fundamental issue that underlies, not just IceFace, not just JSF, but all HTTP, whether it's in Java, .Net or even assembly language.

HTTP is not a conversational protocol and it does not support asynchronous "status report" updates to the client. Never mind the JSF lifecyle, the HTTP lifecycle is what's important here, and the HTTP lifecycle says that the client bundles up a Request as a single atomic batch, sends it to the server, which processes that request and generates the Response as a single atomic batch. There is no overlay between processing and sending the response back, so there's no way that a long-running operation can post back intermediate status. There is no intermediate status, since none of the output comes back until all processing is done, and that's not JSF, that's essential HTTP.

HTTP is expected to operate in a quick in-and-out mode. Http server components do not and cannot operate as asynchronous processes, only as sequential handlers for a single process threading the pipeline. That processing should take the absolute minimum amount of time possible because not only does it annoy the end user when responses are delayed, but the longer a request takes to process, the longer the request processing thread is unavailable to handle other requests and therefore the overall workload capacity of the server is dragged down.

If a process takes more than a few seconds, it should hand off the work to an out-of-band processor that isn't subject to these constraints, return a "working..." status and let the client poll the out-of-band processor periodically to see if the long-running process has completed (and how far it has gotten). You can achieve the simulation of a true conversational process by using AJAX so that the request page remains displayed but periodic AJAX polls to the server retrieve the progress information.

Because the normal HttpServlet process() method is forbidden from spawning threads suitable for the out-of-band processor, the OOB processor is commonly spawned by a ServletContextListener. A popular architecture is to feed/interrogate this "engine" process via a synchronize queue mechanism.
 
Brian Stock
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the insightful post.

Please correct me if I am mistaken, but if I understand you correctly, ICEfaces, or specifically ICEpush (http://www.icesoft.org/projects/ICEfaces/ajax-push.jsf) abstracts the client polling so that it gives the illusion of a server "pushing" DOM objects to the client browser, while it is in fact the client browser periodically polling the server for new DOM objects. The problem I am experiencingi s an artifact of this illusion. If the PushRenderer.render("someGroup"); is called from an existing HTTP request, it has to wait for it to complete to update the browser, and it won't complete until the long processing is done.

What I need to do is spawn the long processing task in a seperate thread, and call PushRenderer.render("someGrounp); from that thread, after somehow passing it the correct PushRenderer context.
 
Tim Holloway
Bartender
Posts: 18413
58
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You don't really want "push", you want "poll". I need to refresh my memory on IceFaces, but RichFaces actually has 2 different tag types that can help with polling. One, in fact, is a progress indicator.

As I often say, though, Rule #1 in JSF is that if your solution is complex, it's probably wrong. You don't need to muck around with internal request parameters or the JSF lifecycle or internal component tree to do this.

When a page is first displayed, its DOM is rendered. Thereafter, if you want to do something like update a status indicator, you leave the DOM essentially intact except that you modify/re-render the part of the page that contains the status information.

If you're using an extension tagset that supports a polling-style control, that control will periodically send down an HTTP request and consume the HTTP response. The original page request has long since completed its lifecycle, so this is an entirely new request. So modifying the original page rendering lifecycle doesn't apply. The new request also goes through the JSF lifecycle, although some (fairly minor) tweaks are usually made to the process since you'll often be submitting only part of a form and/or updating only part of the page and the response comes back to JavaScript AJAX code rather than directly to the browser's rendering engine.

Or, to put it simply, forget about all the JSF-specific coding. It can all be done POJO. If you have an actual progress control, it will typically contain a "value=" attribute that references a backing bean property. Instead of simply returning a static value, however, the property "get" method can obtain the current progress percentage (or whatever) from the back-end engine and return that.

All of the UI component work is handled automatically by the page reRender functionality, so that's all you need is the actual data value/
 
Brian Stock
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I believe I understand what you're saying. If you read my post carefully, I tried to only refer to "pushing" as the illusion provided by the ICEfaces (ICEpush) abstraction layer. ICEfaces is still polling under the hood (which you can see by inspecting in Firebug), but PushRenderer/PortableRenderer allow the developer to perceive the illusion of "pushing" from the server by setting a flag for the poller to pick up.

Now that I understand the inner workings, I can see why you need to spawn a new thread in order to do what I want. Thank you very much for helping me understand.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!