Granny's Programming Pearls
"inside of every large program is a small program struggling to get out"
JavaRanch.com/granny.jsp
The moose likes JSF and the fly likes What is an efficient way to implement an entirely AJAX based web app using JSF2? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Murach's Java Servlets and JSP this week in the Servlets forum!
JavaRanch » Java Forums » Java » JSF
Bookmark "What is an efficient way to implement an entirely AJAX based web app using JSF2?" Watch "What is an efficient way to implement an entirely AJAX based web app using JSF2?" New topic
Author

What is an efficient way to implement an entirely AJAX based web app using JSF2?

Steve Sims
Greenhorn

Joined: Feb 24, 2009
Posts: 7
I've created a small application that consists of a single Facelets page, with the pages that I want to display all contained within it. Each "page" is really an <h:panelGroup> with its "rendered" attribute set if it is the one to be displayed. The following code example shows the sort of thing that I've done:

That solution works fine, however it looks like a bad design to me; the problem being (as I understand the lifecycle) is that if "rendered" is false, it only prevents the HTML markup from being rendered in the response and in fact, even if #{myViewScopedBean.currentPage} evaluates to "Page2", "page1" and all of its child components are still being created. This seems really wasteful and within an application that has many "pages" and therefore components, it must simply be the wrong way of doing it.

Is there any way that I can programmatically "switch out" the creation of parts of the component tree (for example "page1" and children) when I only want to display "page2"? I've looked within the Facelets templating tags and I couldn't see anything there that might let me do it. Or am I on the wrong track entirely and people use an entirely different method to create large all-AJAX based web apps?

Many thanks in advance for your help.

Steve
Andrea Moehrke
Greenhorn

Joined: Dec 09, 2010
Posts: 2
Hi Steve,

if you want to create "programmatically" create the components when they are needed, you can handle this in your backing bean. Create a backing bean, that handle the call of the pages.

Example:

Backing bean:

public class PageBean
{
String includeFile;

public String getIncludeFile()
{
return includeFile;
}

public void setIncludeFile(String includeFile)
{
this.includeFile = includeFile;
}
...
}

Modify our jsf-File like this.

<h:body>
<h:form id="mainform" prependId="false">
<ui:include src="#{pageBean.includeFile}" />
</h:form>
</h:body>

The includeFile is set to a jsf-file in your worspace, that you want to load.
So you can change your page with an action-event and include the jsf-source you want.

Best regards

Andrea
Steve Sims
Greenhorn

Joined: Feb 24, 2009
Posts: 7
Hi Andrea,

Thank you very much for posting that reply, I'm really close to cracking this now. I've done the following:

index.xhtml:


PageBean.java


page1.xhtml


page2.xhtml


Unfortunately, I've hit a problem with it; the value expression #{pageBean.includeFile} inside index.xhtml's <ui:include /> tag is evaluated before either an ActionSource event or an AjaxBehaviorEvent from the <h:commandButton> or <f:ajax> (page1.xhtml & page2.xhtml) is processed. This means that although I can update PageBean.includeFile to be "page2.xhtml" from the listener, that file won't be included until the next request. I've added a phase listener and can see that includeFile is evaluated before the Apply Request Values phase so even if I set <f:ajax immediate="true"/>, it's still processed after includeFile has been read. Practically speaking, this means that I have to click my button twice in order to navigate to the next page.

Do you by any chance have any ideas how I could work around this at all?

Many thanks for your help - your solution was just what I was looking hoping for!

Steve
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15950
    
  19

I think your original idea was better. Keep it Simple. Only make it complicated if you actually see a problem. Too often what we "know" is either incorrect or out of date and premature optimization can actually hurt you since it can interfere with performance improvement mechanisms in later and smarter versions of JSF (or any other platform, for that matter).


Customer surveys are for companies who didn't pay proper attention to begin with.
Steve Sims
Greenhorn

Joined: Feb 24, 2009
Posts: 7
Hi Tim,

Thanks for your reply. I agree with your advice about keeping it simple, however I felt that my original idea had that "bad design" smell about it, in particular the way in which it was creating components and having to parse a large facelets page, most of which would never be used in any given request. Andrea's method of leveraging the facelets templating functionality feels much better to me, except that I can't fit it into the Faces lifecycle satisfactorily.

I guess my fear is that until a large application using my original technique is finished, I wouldn't see any scalability issues until right at the end when the app was tested under load, at which point they might be a real pain to fix and require a lot of refactoring.

As you say, JSF does an awful lot behind the scenes and wrenching it around just to make work what feels like a good solution is probably asking for a world of pain either now or in the future; however, if there is a method of doing it "nicely" then I'd certainly be interested in hearing it!

Steve
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15950
    
  19

I'm not sure I agree about the "smell". Plus remember, just because an element is in a file doesn't mean that it will get compiled into the finished binary, so you may have an invalid perception of inefficiency.

The biggest reason for avoiding premature optimization is that I've been called on to optimize many systems over the years, and it's pretty much inevitable that the REAL bottleneck is never anywhere NEAR the place where everyone "knew" it was going to be. So if you build an elaborate and delicate optimization framework and then find out in production that your actual problem isn't where you thought it was, you often end up with twice the work as you deconstruct the original "solution" and rebuild a new one. It's easier to make a simple system complicated than to make major changes in an already-complicated system.

Premature optimization costs. You pay for the original solution, you pay for the removal of that solution, you pay for the new solution, and you pay for all the solutions that weren't actually necessary.
Steve Sims
Greenhorn

Joined: Feb 24, 2009
Posts: 7
Hi Tim,

Thanks again for your feedback. It's good to know that you consider the original approach to be the one to continue with in a real system at this stage. I fully agree with your analysis of premature optimisation i.e. it's like shooting in the dark (especially when you know as little about what's going on inside JSF as I do!) - it's just hard to let it lie! In reality, I think that as long as I'm careful about encapsulating the functionality of a "page" inside its own managed bean as much as possible, any refactoring that I decide to do if there is a performance issue later on, should be much easier.

I'm going to mark this topic as resolved on this basis.

Thanks to both you and Andrea for your time and effort on my behalf.

Steve
Steve Sims
Greenhorn

Joined: Feb 24, 2009
Posts: 7
Although I've marked this topic as resolved, on the basis that I was happy with Tim's advice to stick with the original solution on the basis of risk, I was still intrigued to discover whether I could make Andrea's solution work. Referring to my reply to Andrea, I commented that I needed some way to skip back through the JSF lifecycle in order that the view would be rebuilt with index.xhtml's <ui:include> tag pointing to the newly selected content page.

Whilst searching for a number of solutions, I came across this post: http://www.theserverside.com/discussions/thread.tss?thread_id=48227#246767 which describes how to replace the current view with a new one. I've implemented this in the test app detailed previously within this topic and it appears to work fine. The changes that I made are as follows:

PageBean.java


The obvious issue with it is that it's pretty drastic thing to do and I might expect problems with the content around the "included" pages because it completely removes the current view (and therefore any state associated with the components that were in it) and creates a new version of the same one so use it at your own risk.

I don't know enough about JSF to be able to see all of the implications of it but it does answer my previous question which is why I posted it. If anybody has any comments on it, I'd be interested to hear them however as it may be something that I look at again in a future project.

UPDATE:
Instead of creating a new view, I tried calling ViewHandler.restoreView(FacesContext) which appears to work too - I've currently got no idea what ramifications this might have, but the phase listener that I have monitoring the lifecycle isn't really altered. It does however cause the view to be rebuilt - I'm hoping that any component state is therefore preserved as if this had been a normal page navigation?

The updated reloadView() method is below:

PageBean.java

Again, any answers as to whether this is a reasonable thing to do or not are greatly appreciated.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: What is an efficient way to implement an entirely AJAX based web app using JSF2?
 
Similar Threads
ui:repeat + AJAX
JSF 2.0 GlassFish 3.0.1 problem
Ajax render outside of form problem
Ajax listener method is not fire for other(except first) component
Performance issues using ajax