voyent
How to immediately update component parameters.  XML
Forum Index -> Components
Author Message
stockb

Joined: 01/May/2012 10:39:41
Messages: 26
Offline


Originally posted: http://jforum.icesoft.org/JForum/posts/list/20918.page

Basically, I have a compopnent with a parameter linked to a backing bean's variable. I have a method which modifies this variable, and calls other methods. From stepping through the program and using Firebug, I was able to determine that the component's parameter does not get updated until after the Java methods finish executing. I would like the change in variable to be reflected in the component's parameter concurrently with the Java methods.

I have tried using PushRenderer.render() to force updating of the components, but this does not change the behaviour.

This seems like a severe limitation in JSF/ICEfaces, so I feel I must be missing some basic concept here. What am I doing wrong?
ted.goddard

Joined: 26/Oct/2004 00:00:00
Messages: 874
Offline


It's not clear what you are trying to do (for instance your use of input was not included), but the behaviour you are seeing with ICEfaces is prescribed by the JSF standard. Could you explain the end result that you hope to see with the popup panel?
[Email]
stockb

Joined: 01/May/2012 10:39:41
Messages: 26
Offline


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?
 


To briefly summarize: I would like to render the component multiple times within the backing-beans method, before it finishes executing. I would like to manually trigger XmlHttpResonse. I thought that's what

Code:
FacesContext.getCurrentInstance().renderResponse()
was supposed to do, but it doesn't give the desired behavior.
ted.goddard

Joined: 26/Oct/2004 00:00:00
Messages: 874
Offline


Is the file copy running in a separately spawned thread? That would be necessary to not block the servlet thread used by JSF.

[Email]
stockb

Joined: 01/May/2012 10:39:41
Messages: 26
Offline


I am new to threading in Java, but I did try that last week. Much to my surprise, the main thread still hung. I'm not sure if it was due to a mistake in my noobish attempt at multithreading, or wheter JSF/ICEfaces detected a dependency and acted on it. I decided not to investigate further as that solution seemed overly complex for such a simple problem.
I'm surprised that the render() one-liners aren't sufficient.

To be honest, the hidden button triggering the next step is starting to seem like the simplest option.

I'm looking for some method, maybe something like, updateComponent() i.e.
Code:
 componentParam = "step 1 executing...";
 updateComponent();
 stepOne();
 
 componentParam = "step 2 executing...";
 updateComponent();
 stepTwo();
 
 componentParam = "step 3 executing...";
 updateComponent();
 stepOne();
 


Is there such a method like updateComponent() that will do what it sounds like?

EDIT: I reread your post. Are you suggesting that in addition to multithreading, I also need to call the FacesContext.getCurrentInstance().renderResponse()?
ted.goddard

Joined: 26/Oct/2004 00:00:00
Messages: 874
Offline


Once the file copy is running in a separate thread, you would need to periodically obtain progress on the copy and call PushRenderer.render() to update the page where your outputText displays the current number of bytes copied.
[Email]
stockb

Joined: 01/May/2012 10:39:41
Messages: 26
Offline


I have nowhere to call PushRenderer.render() from. If I call it from the main thread after spawning a file copy thread, then when/how will the component get updated? As it is, it doesn't get updated until the end of the main thread, regardless of whether PushRenderer.render() is called, or whether file copy is in a seperate thread or not.

I apologize if I misinterpreted your post, but it seems apparent to me that spawning a new thread will still require the main thread to run to process the updates, and as long as the main thread is running, the updates won't be rendered on the component/DOM side of things.

Is there no such thing as a simple updateComponent() function?

I'm feeling cramped by the apparent limitation of one UI update per JSF cycle, or rather, one JSF cycle per user action (e.g. clicking a button).

On a side note, I'm currently looking at binding properties. Would using a binded object allow me to programmatically modify the component's properties immediately?
ted.goddard

Joined: 26/Oct/2004 00:00:00
Messages: 874
Offline


Component bindings can introduce other problems since it can lead the JSF component being in multiple component trees at once. It's also slightly less pure in MVC terms since the model acquires a reference to parts of the view.

Depending on the API used for file copying, three threads may actually be needed: a thread to invoke the copy method, a thread to check the number of bytes copied on the destination and invoke PushRenderer.push() and the JSF servlet thread to handle the browser requests. So, a lot of this depends on how you are able to determine the current progress of the copied file.
[Email]
stockb

Joined: 01/May/2012 10:39:41
Messages: 26
Offline


Ok, so here's what I'm about to try and implement (please stop me if I'm on the wrong track):

I have a "main" thread called by the user clicking a button, which spawns a "copy" thread. After the copy thread is spawned, the main thread closes and the JSF cycle completes.

Now, this copy thread has PushRenderer.push() lines in it, which can initiate new JSF cycles and update the components. Each time PushRenderer.push() is called, a new JSF cycle is started, and ended

The part I'm most unsure about is that last part. If I'm calling PushRenderer.push() from the copy thread multiple times, will it create a new JSF cycle each time it is called?

Just so I'm making myself clear, here's what's in my head:

Main Thread:
Code:
 runInNewThread(copy);
 


Copy Thread:
Code:
 while (!done)
 {
     doThings();
     if (progressPropertyChanged) 
     {
         progressProperty ++;
         pushRenderer.render();
     }
 }
 
ted.goddard

Joined: 26/Oct/2004 00:00:00
Messages: 874
Offline


That looks like the right approach (the key point being that the push initiates new JSF lifecycles to update the page) but there is still the concern that File.copy() will not return until the entire file is copied, thereby giving you only one progress update at the end.
[Email]
stockb

Joined: 01/May/2012 10:39:41
Messages: 26
Offline


What I have called a file copy operation is not a File.copy(), but rather a series of executed shell scripts, of which the primary task is to copy some files. So, splitting this task into seperate calls is relatively trivial.

My concern now is that, in my spawned thread, will a new request cycle occur every time I call PushRenderer.render()? I need some way of accessing the correct PushRenderer context, but assuming I can pass in an instance of it, since it is not associated with any existing request, I should be able to spawn multiple new requests, correct?

EDIT/UPDATE:

I was able to get it working perfectly! Thanks Ted!

I do in fact have three threads running off of a single class- one for running the long operation, one for polling for status updates, and one (my "main" thread) for kicking everything off and returning the UI control to the browser.

To those of you possibly reading this in the future, check out these links:
http://wiki.icesoft.org/display/ICE/Ajax+Push+-+APIs
http://www.tutorialspoint.com/java/java_multithreading.htm
http://stackoverflow.com/questions/2081747/how-to-deal-with-multiple-threads-in-one-class
and finally, if you are having trouble grasping JSF/HTTP lifecycles: http://www.coderanch.com/t/583103/JSF/java/Updating-component-parameters-before-end
 
Forum Index -> Components
Go to:   
Powered by JForum 2.1.7ice © JForum Team