Win a copy of Kotlin in Action this week in the Kotlin forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

Call variables instead of methods from a xhtml page  RSS feed

 
Jorge Martinez
Ranch Hand
Posts: 41
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hy,

If I had this code:



And in the server getCustomerList() accessed to database, how many times getCustomerList() would be called from I request the xhtml page?. I have read this would be called several times because of JSF internals and It would be better to store it in a variable and access this variable.

1. Is this true this would be called several times? why?

2. If the previous statement was true, how to avoid it, I mean not call the method from a service?



Thanks
 
Tim Holloway
Bartender
Posts: 18705
71
Android Eclipse IDE Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You don't "call" variables (properties), you reference them.

And the number of times that the get/set methods of a referenced property are invoked (and in what order) are essentially unpredictable. Meaning that while I probably could predict them, it wouldn't be wise to try and do so.

The "get" methods for backing bean properties are supposed to be idempotent. Which simply means that they should have no side-effects and that if you invoke it 50 times, you should get the same answer 50 times and no other parts of the system should be affected.

Often there's a need for a backing bean property to obtain "expensive" information, such as rows pulled from a database table. Like in your example. Obviously, pulling those same rows 5 or 6 times every time the page was rendered would be slow and a waste of resources. In such instances, I often make the first call do the dirty work, then cache the results:


The loadCustomerList method can be any sort of database finder method you prefer, JDBC, JPA, Hibernate, or whatever. Or a non-database method for that matter.

The nice thing about this technique is that if you need to refresh the model, you can simply set the customerList datamode to null and a new list will be fetched and a new model constructed next time they are needed.
 
Jorge Martinez
Ranch Hand
Posts: 41
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, nice example!

1.But if this datamodel is in a session backing bean, and if the session of the user lasts 1 hour or more, you will have all this time cached results and the rows in the ddbb could have changed a lot.

2. What you mean is that in the example I posted, in one only jsf request, the method getCustomerList() could be called more than one time in a normal operation?

Thanks

 
Tim Holloway
Bartender
Posts: 18705
71
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
2. Yes, it wouldn't be unusual for getCustomerList() to be invoked 5 or 6 times during a single JSF request processing cycle. More often than not.

1. It really doesn't matter what's in the backing bean an hour later or a day later as long as the session is still alive. HTTP doesn't update the client unless the client asks for an update anyway. HTTP cannot update a client unless a client asks for an update. Either via a page request or AJAX request.

If you want updated results, then you'll have to discard the stale list and replace it with a fresh one. How you determine when to discard an old model and get a new one is really up to you. If you wanted something that provided a periodic update, such as a incoming flights display at an airport, then you'd probably have the client do a periodic AJAX refresh request and make the AJAX listener method null out the stale model so that the getCustomerList method would know to build a fresh one.
 
Jorge Martinez
Ranch Hand
Posts: 41
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, good to know

1 . So in any jsf application when you get values from database, its almost mandatory to cache the results, right? I think this causes to add extra code or cache the results just because you are using JSF

2. Why jsf would need to call getCustomerList() more than once in a jsf request?

3. So the example from http://www.mkyong.com/jsf2/jsf-2-0-spring-hibernate-integration-example/, is not a good design because he doesnt cache at all the results, right?

4. Is important to know in what phases of a jsf cycle request the same method can be called more than one? Could you refer me to some documentation to talk about it?

Thanks
 
Tim Holloway
Bartender
Posts: 18705
71
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
1. No, this isn't because it's JSF, it's because JSF makes multiple references to the data that in other systems would be done by application code instead. Caching is simply a way to avoid making those references more expensive than they need to be.

2. Relating to that, the backing bean is the authoritative repository for the data that will be read and rendered. Remember what I said earlier about the UIComponent being only temporary storage. As such, the data needs to be available for any purpose that the framework requires. For example, a valueChangeListener only fires if the value of the listened-for property of the backing bean is being actually changed. If the incoming value is the same as the existing value, the event doesn't fire and the listener isn't invoked. And the way that JSF determines whether the value has changed is by querying its current property using the backing bean's "get" method, since JSF doesn't do "magic" in order to see inside the beans, it uses the same ordinary access methods that normal user code would.

3. True. It's a horrible design. And the larger the list, the slower the database connection, the worse the penalty will be.

4. It is not documented, and for good reason. You should code as though it can happen at any time. That is why these methods must be idempotent. Because it can happen at any time, and what happens today may not be what happens in a future release. The only guarantee you get is what's documented in the JSF lifecycle flowchart and that's basically just going to tell you at what point a "set" method will be invoked to actually do the property update. Assuming that the the update phase isn't short-circuited.

Again, very little of this is really specific to JSF. It's how JavaBeans are supposed to work.
 
Jorge Martinez
Ranch Hand
Posts: 41
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hy,

I think this user happens what we are talking about : http://osdir.com/ml/java.facelets.user/2007-05/msg00174.html.

1. In any part of the JSF documentation, doesnt appear the recomendation to cache the results of the database in backed beans or some official example about it?

Thanks
 
Tim Holloway
Bartender
Posts: 18705
71
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That is correct. I do this all the time.

JSF says nothing about databases. Or caching. It's simply a technique that I have found to be effective. And, as I said, works on JavaBeans in general, J2EE, JSF, oe otherwise.
 
Jorge Martinez
Ranch Hand
Posts: 41
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Just for finishing:

what you said "It really doesn't matter what's in the backing bean an hour later or a day later as long as the session is still alive. HTTP doesn't update the client unless the client asks for an update anyway. HTTP cannot update a client unless a client asks for an update. Either via a page request or AJAX request. ".

1. Do something like a command button that said "update results in datable", this should go to the server and set the property to null, would be a good approach to refresh the results in a datatable?

2. Its not enough for a user in order to get new results from database to request an xhtml file more than once, I mean, becuase if the backed bean is in session the property with the cached results would be not null so in order to get it its needed to do something similar like in the previous approach, right?

Thanks
 
Tim Holloway
Bartender
Posts: 18705
71
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes, you could have a "refresh" button. You could also use the traditional HTML meta-tag that causes a re-submit at intervals. Or you could have a timer that invokes an AJAX refresh request.

AJAX allows a displayed page to do partial form submits and/or receive partial page updates. So if you had something like this:



And server code like this:


Then the listener would null out the old copy of the DataModel, which means that the next time getCustomerList() was invoked, a fresh database request would be made and a new DataModel would be constructed and cached. The "render" attribute on the f:ajax tag will ensure that that happens as soon as the refreshTable event method has executed and the render-response phase of the JSF lifecycle is processed.
 
Jorge Martinez
Ranch Hand
Posts: 41
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Reviewing all the answers rigth now, I got a doubt about caching results from database. The example about caching results from a database is a good one but in many cases you cant do it because you cant get all the customers from database because they are so big so there will be some pagination.

1. Due to the pagination, caching the results from database with pagination parameters from the client is not possible, right?

2. getCustomerList() should be in a application scoped bean?

Thanks
 
Tim Holloway
Bartender
Posts: 18705
71
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
As a general rule, a webapp shouldn't be trying to work its way through an entire database. That's what batch processes are for. Webapps are better suited for more focussed views of the data.

So application scope would not usually be a good way to "cache" a customer table. If it's that large, loading the entire table into RAM would be expensive or impossible regardless of what scope you used.

ORM systems do provide various levels of caching - as do add-on caches. But a cache isn't just a dump of data from the database into RAM, it's a selective retention of frequently-used data. Normally, a cache has a fixed size limit, and after that point, it starts discarding stuff that it doesn't think need to be in RAM. Oracle's "cache" notwithstanding.

There are limits to what one server can do, of course, which is by the Big Data systems have become so popular. But they work in large part because they distributed the workload over many systems.
 
Jorge Martinez
Ranch Hand
Posts: 41
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, thanks. So if we have pagination from the client because there is some grid, is not possible to cache the results in the next way, right? My question would be how to avoid the repeated calls to getCustomerList() in the same request if we had pagination parameters



Thanks
 
Tim Holloway
Bartender
Posts: 18705
71
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You have no control over when or how many times a property get method will be invoked by JSF.

However, I was talking about database caching. The code you illustrated is GUI Model caching. Normally your GUI Model is going to be only a small subset of the database data, since putting large quantities of data on a single web page will both retard performance and make the users' eyes water.

There are dataTable models where you can page within the Model, but the larger the model is, the more memory it's going to consume, so if you really want to page over very large sequences of data, it's best to not use the dataTable's view model paginator, but to instead paginate the model itself.

In other words, the view paginator displays subsets of data from within the view model, and that's a good option for fairly small sets of data, but for large sets of data, the view model should be only a window into the larger set of potential rows, and the view model itself should be paginated.
 
Jorge Martinez
Ranch Hand
Posts: 41
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok. In this example I found http://www.javacodegeeks.com/2012/04/lazy-jsf-primefaces-datatable_11.html the guy is doing real pagination from database but the method load from PlayerLazyList class can be called several times in the same request when the users does some pagination and is not caching at all, right?; this is what I mean; in this kind of case we cannot do any caching at all

Thanks
 
Tim Holloway
Bartender
Posts: 18705
71
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
He's paging the View Model, not the Data Model.

He is actually not caching as such, but doing just-in-time (on-demand) view model construction. And, as I mentioned in another post, not doing it very well.
 
Jorge Martinez
Ranch Hand
Posts: 41
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, but I havent found an example doing caching with pagination. How can you do that?

Thanks
 
Tim Holloway
Bartender
Posts: 18705
71
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
There's no one single fits-everything solution.

In general, I'd attempt to find a cache that works automatically for my database (ORM) system and tune it to fit the demand.

The actual datatable UI model object, I would usually reduce to just the number of rows actually being displayed on the page, replacing the wrapped data collection in the DataModel by doing fetches from the ORM, which in turn would (hopefully) be able to resolve the request from its cache. The pagination buttons would thus not page through the UI model, but would trigger the wrapped data changes.

But depending on the size of the dataset, the back-end caching effectiveness, and how the users typically viewed the data, I might adopt variations on that concept or even employ a different strategy. Whatever worked best for the users.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!