이 글은 http://blog.exadel.com/?p=8 에서 가져왔습니다.
THIS ARTICLE IS COPIED FROM http://blog.exadel.com/?p=8
The copyright of the article is owned by below person. I swear to delete this when the author request to delete the article from my blog.
Author: Igor Shabalov
As you can see from the heading, I’d like to talk a bit about JSF and Hibernate. Both technologies promise us better results with less code. Perfect, this is exactly what I’m looking for. I strongly believe that less coding is better, even if it comes with a price.
To demonstrate this, I will build a realistic example that interacts with both user and database using JSF and Hibernate. Both technologies promise us a truly declarative way of coding, hiding most of the complexity under the hood. This is good, but there is also a price for this that I’ll talk about later.
Use Case
I took a simple example from a developer’s everyday life: A user views or edits a timesheet. TimeSheet is a collection of zero or more Records, usually one per day, with information about Task, Project and hours. I’d like to see and edit the entire TimeSheet (all records for the current week) in a single page.
Here are several UML Diagrams to sketch this example out.
Figure 1: Use Case Model
Figure 2: Class Diagram
Figure 3: Activity DiagramIn fact, if you get already bored going through all of this, you can download the live example application from here, get it into you favorite IDE (my favorite is Exadel Studio Pro, of course), and see what’s in it. It should work “as is” with no database required, I used HSQL’s in-memory configuration, the perfect solution for such a case. You can download example and use Eclipse menu “Import Existing Project” right from zip file. At least on my computer it works I used JDK 1.5 generics in my example, so, you will need JDK 1.5.
Figure 4: MVC unleashed
But if you bother to read more, I’ve put a little bit more theory and commentary below.
Visual Components
To implement something like this, you need a good presentation framework that supports a component-based approach. You need a rich set of standard components, but you also need a good way to create and use special components. JSF is perfect for standard components and user interface controls, but it is not set up as well for custom components. Tiles is a better technology for this, but not all JSF implementations are compatible with Tiles. In my example, I use MyFaces, a complete JSF implementation from the Apache Foundation that also works with Tiles.
Hibernate Session and Database Connection
I assume that you already know a little bit about this problem. You need to pay special attention to the moment when you obtain or free a Hibernate Session (and effectively a Database Connection) in your application. There are two major reasons for that:
A Hibernate Session has a one-to-one relation (OK, almost) to a Database Connection. When you get a Session, you effectively get a Connection. And, we are always told that a connection to database is a valuable resource that needs to be used very carefully. For example, it is not good to keep a Database Connection taken between requests.
A Hibernate Session has a special relationship with objects that are loaded by it. The Hibernate Runtime keeps track of all modifications and generates queries to synchronize the object state with the database. If you keep a persistent object somewhere, but forget about the Session, you cannot do anything with this object (ok, almost).
As a result, we were told to use the “One Session per Request” pattern. You cannot keep persistent objects between requests, you need to store primary key and load objects in every request or use the “detach/attach” technique, which is basically same thing. And, you cannot keep queries open.
Session per Session
Instead of this, what I do is use the “One Session per Session” approach. A Hibernate Session gets created when a Web Session is created, and then kept till the Web Session expires. You can either keep Database Connection or use the “disconnect/reconnect” technique. Personally, I believe, that in many cases, you can keep a Database Connection between requests. Most real business applications are intended to be used by a limited number of users.
Personally, I hate the situation where a developer loads an entire database into memory in order to save database connections. Memory is cheap, but still limited! Keep the data in the database and let database vendors worry about efficient memory use. If database vendors try to ration allowable connections, use an open source product, like MySQL.
Or, you can implement a more middle-of-the-road approach. For example, keep the Database Connection opened when you have something like an opened scrollable query on hand, but otherwise use the “disconnect/reconnect” technique.
In the end, the result is clear code, less code overhead, more effective memory use, and fewer database round-trips.
But, everything has a price. In our case, we need to pay special attention to the Hibernate Session Cache. In our case, if somebody loads TimeSheet from user A into memory, then for user B and then repeats that for 10,000 more users, we get into trouble. At any given moment, we will see just one TimeSheet, the current one kept in Web Session, but the Hibernate Session will have all 10,000 of them. This is wrong.
Here is where Business Transaction becomes our good friend! All we need to do is remove TimeSheet from Hibernate Session either on entering or on leaving Business Transaction. In my example, I’m doing this on entrance, using a session.evict() call. This is why we need Business Transaction and why Page Flow is so important, because Page Flow naturally defines transaction boundaries.
Business Transactions
If you take a look to Activity Diagram, you will see Business Transaction. The User can navigate between “View” and “Edit” forms working with the same data, TimeSheet, which is essentially the Business Transaction Context. This Context is properly initialized at the beginning of the transaction; however, we need to pays some special consideration to the end.
Page Flow
Turning to the Page Flow, I have to admit JSF Page Flow is still “under construction”. I have a dream to eventually present you with the completed Page Flow the JSF gurus will deliver. They were talking about integration with Spring Web Flow, so perhaps I will finally be able to see the point of using Spring!
However, JSF Page Flow does exist now. The default implementation is good enough, and I’m using it in my example. Here is a picture of how it looks:
Figure 5: JSF Page Flow
No Transport Beans, Please
In one my previous projects, I suffered through a painful experience with Transport Objects. I will never ever do that again. I recommend using your persistent Model objects anywhere in screens, and let Hibernate unleash its full power. Keep your Presentation Tier close to the Service and Data Tiers. By close, I mean within the same JVM. If you need to expose some of your services (and data) to the outside world, then use the special Services Externalization interface, basically a wrapper around existing services. From this point, you can use Transport Beans, XML, or whatever you want to move data.
Front Controller, Back Controller
I used Front Controller in my example. It’s very natural for JSF, because it is intended for use with backing beans to implement view-related functions. You can put it anywhere, but I suggest you to keep it separated from “real” controller (Business Service) functions.
Figure 6: Front Controller, Back Controller
Here is a more complicated illustration to show how this works. You can see all this implemented in my example. The Form uses a JSF DataTable component and needs a special DataTableModel. It just display objects from the Model Tier, TimeSheetRecrd. TimeSheetView (it is actually a Front Controller, despite it’s name!) holds all the view-related functions, like saveTimeSheetButton(). TimeSheetService is a typical Business Service implementation, with functions like saveTimeSheet().
Conclusion
I hope you found my example helpful. I didn’t try to make a full blueprint; I just tried to highlight some important issues. And, this isn’t the end at all. I will continue my series of articles about JSF and Hibernate. This time, I didn’t pay too much attention to Database Connection. This is an area that I will revisit soon, when I plan on talking about “scrollable” queries.
Finally, as you can see, my example continues to use the “Injection of Control” pattern that I discussed last time!
Best regards,
Igor Shabalov