STATEFUL SCOPE-CONVERSATON IN SEAM
Posted On February 28, 2012 by Sneha Philipose filed under Enterprise
State management facilities in Seam are very highly. Author explains scope conversation in Seam with an example.
State management facilities in Seam are spoken of very highly by Michael Juntao Yuan &ors in their book on Seam in the following words: “The real jewel of Seam is its support for sophisticated application state management that is not available in any other web application framework today. That is what we mean when we call Seam the next generation web application framework.”
Advantages: The advantages of the above state management listed by them are: 1) Correct usage of ORM 2) reduced roundtrips to database (we saw about these in the earlier article on Persistence context) 3) better browser navigation support 4) fewer memory leaks 5) higher granularity components 6) reduction in boiler-plate code–we will see about these in this article.
Better browser navigation support & higher granularity components HTTP session is the only stateful scope available in other frameworks. Seam supports several stateful contexts of finer granularity. They are: 1) stateless 2) event 3) page 4) conversation 5) session 6) business process :This context holds stateful components associated with a long-running business process managed in the JBoss jBPM (Business Process Manager). While all the previously mentioned contexts manage stateful components for a single web user, the business process components can span across several users. 7) application: This is a global context that holds static information. There is no concept of web users in this context. You can see about them in any book on Seam, we will concentrate on Conversation, the most important and widely used scope of Seam
Fewer memory leaks
The symptom of memory leak is that the application uses more and more memory, as more users access the site but it does not free the memory as the users leave. Eventually, the site crashes due to insufficient memory. Earlier, web application developers had to monitor objects in the HTTP session very closely and remove any objects that are no longer needed. This involves extra work for the developer and programming errors tend to creep in when developers have to track complex state objects. Seam does away with this manual memory management in HTTP sessions. Since a stateful Seam component by default is stored in a conversation, it is automatically removed from the session and garbage collected once the user completes the conversation. Since defining a Seam conversation is very easy (as we are going to see) and can be incorporated into the business logic Seam greatly cuts down memory leaks in complex applications.
Reduces boiler-plate code In stateless frameworks, there is an artificial gap between the web presentation layer and the business logic layer of the application. The web presentation layer is always stateful due to the HTTP session object. The business layer, however, is stateless and has to wipe the slate clean after each service request. Hence “wrapper objects” are required to move data from one layer to the next. For example we require them in the following occasions:
• To transport complex database query results-DTOs
• To embed data objects into display components (i.e., to build JSF DataModel components)
• To propagate exceptions (e.g., data validation errors, transaction errors, etc.) from the business layer to the presentation layer.
These wrapper objects are requirements of stateless frameworks and hence they are boiler-plate code. Seam dispenses with them. The objects from the data layer set in their default context and the view files in the web layer can access them.
What is the problem in storing state in session?
The HTTP session is well suited for data that you want to retain across all requests made by a given user, such as the user’s identity. It works fine when the user is accessing the application from a single window—but when the user spawns multiple tabs or windows problem starts. The session identifier is stored as a cookie in the user’s browser, and the same is shared between tabs and windows in browser. The result is that the multiple tabs share the same session data.
The objects in an HTTP session are not managed, and, as mentioned earlier, we must write a lot of code to manually shuffle objects into and out of the session. If we forget to save a modified state object back into the session, the application will exhibit hard-to-debug behavior errors at runtime. A single timeout parameter controls the HTTP session. Objects in a session have no notion of a lifecycle. As a result, the HTTP session is a major source of memory leaks in web applications when developers forget to manually clean out objects from a long-running session.
Conversation context: As mentioned earlier, it is the most important of the contexts defined in Seam. A conversation refers to any user action—a unit of work—that takes several pages to complete. Conversations are subsets of a user’s session, as illustrated in the following Figure-1.
The conversation context is carved out of the HTTP session to form an isolated and managed memory segment. A unique identifier, known as the conversation id, is generated and associated with this region of the session. A conversation has its own distinct life cycle as shown in Figure 2. Seam manages them and the concurrent conversations are kept isolated, unlike session attributes, which just get jammed together in a single map. Seam’s conversation model supports multiple concurrent conversations, and each conversation is not only contained inside its own browser window or tab but also within its workspace. Thus workspace management that support multi-tasking, known to desktop applications, is brought to web applications through conversations. This enables Seam to avoid Back button problem and allow users to interact with the application through multiple windows/tabs. It is this workspace management that puts Seam into a separate category among web frameworks.
Types of Conversations
There are two types of conversations. To be exact we should say there are two primary stages to a conversation.1) temporary 2) long running. A temporary conversation is started on every request unless Seam detects a previous long-running conversation and resumes it. The lifespan of a temporary conversation is a single request; it is destroyed when the response is rendered; however, a temporary conversation is promoted to long-running if you tell Seam to begin a long-running conversation. A simple way to do this is by annotating an action method with @Begin. By promoting a conversation to long-running, you are telling Seam that you want the conversation to be maintained between requests as shown in Figure 3. Thus, our conversation and all variables maintained in its state container will be stored by Seam once the request completes. This conversation will then be resumed by Seam upon subsequent requests instead of starting a new temporary conversation. A conversation is resumed based on the conversation ID that is sent along with the request. The conversation ID is either sent with the form or through a query parameter in the URL string. You need not bother about passing the ID, Seam does it for you when you use JSF post backs or Seam command links(<s:link>).It is this long running conversation which enables seam managed persistence context and application scoped transaction and simplifies multi-page wizards and shopping cart applications.
How conversation is destroyed and memory reclaimed One of ways in which a long-running conversation is destroyed is by annotating an action method with @End. When Seam is told to end the conversation, it demotes the conversation back to a temporary conversation. This means that Seam will destroy the conversation once the request completes. The other way is by timeout; either conversation time out or session time out. Conversation can have its own timeout period but the session timeout must exceed all conversation timeouts put together. Figure 2 shows the various stages of a conversation ie how it is created, promoted, demoted and destroyed.
The conversation is not only created with ease, but also destroyed transparently and memory is reclaimed by Seam and thus memory leaks are minimized.
Other ways to start and end a long-running conversation
A temporary conversation is always present across JSF requests and redirects. As we saw earlier we can promote it to a long running conversation through @Begin annotation in the code. We can also do the same through <begin-conversation> tag in the page.xml file. Likewise we can demote long running conversation to a temporary conversation through @End annotation or <end-conversation>tag. If you want to know more about the ways you can begin and end long running conversations you can refer to Dan Allen’s Seam in Action. Now let us look at the samples available in Seam distribution. You can have a look at the code for HotelBookingAction.java in booking application available in examples folder of the Seam distribution.
1) A temporary conversation is created earlier is promoted to a long running conversation with @Begin annotation when the selectHotel() method is executed.
2) The boundaries of conversation above are extended, to include within it the methods bookHotel(), setBookingDetails(), isBookingValid(), and it is demoted/converted to a temporary conversation when the confirm() or cancel() method is executed. The temporary conversation is destroyed when the confirm.xhtml is rendered.
The other way to begin a long running conversation can be understood by looking at the code generated with seam-gen for any of the earlier projects. The extract from the code for editBook.xhtml is given under:
<begin-conversation join="true" flush-mode="MANUAL"/> //-----------------1)
1)The long running conversation begins when the bookEdit page is rendered.
2) It is demoted for any of the outcomes “persisted” or “updated” or “removed”.
We can see conversation at work by looking at the booking application in examples folder of Seam distribution. They can be built with Apache Ant as they contain build.xml files. The requisites are:
1) You should have “ Apache Ant” installed in your System.
2) Set ANT_HOME variable to your Ant installation.
3) Edit path variable and add %ANT_HOME%/bin to it.
4) The “jboss.home” variable in the files “default.build.properties” and “sample.build.properties” in /jbosss-seam/build folder have to be changed for your JBoss version and installation directory.
Now change to jboss-seam-2.1.2/examples/booking directory in the command prompt and type “ant deploy”. In the exploded-archives folder under /examples/booking you can see jboss-seem-booking.ear, jar and war sub-folders. The ear folder will be deployed /copied to jboss/server/default/deploy and jar and war sub-folders under ear folder. The file “jboss-seam-booking-ds.xml” will be copied from examples/booking/resources to/server/default/deploy folder. In case, the above command did not deploy the above files, you can manually copy the above file and folders from exploded-archives folder to server/default/deploy as narrated above. Start JBoss server. Go to your Browser and type http://localhost:8080/seam-booking. After registering and logging in the browser may look as in Figure 4.You can select View Hotel link of the Marriott Courtyard and choose Open Link in a New Tab. Likewise select View Hotel link of the Doubletree and choose Open Link in a New Tab. You can see Figure 5 and Figure 6.You can see that for each tab a conversation /workspace is opened and in the second workspace you can see the list of all workspaces used and current workspace is also indicated. You can book Marriot hotel from tab1 and Doubletree from tab2. If the application were based on an older-generation web framework which saves state in the HTTP session, you would ended up booking only the Doubletree hotel, since the Doubletree hotel in tab 2 was most recently put into the HTTP session, and the button action in either tab 1 or tab 2 would therefore perform the booking operation on that hotel. An HTTP session-based web application does not support multiple browser windows or tabs; those workspaces interfere with each other via the shared application state. Seam was designed to support stateful application contexts. Seam web applications support workspaces by default. The conversations in each window are completely independent, although all conversations are tied to the same user.. Open several browser windows or tabs .Use the Back button in any of it. There will be no problem. You can then book different hotels in parallel in all windows. Seam always injects the appropriate hotel and booking instances based on the current workspace.
Figure 4 main.xhtml: Click on View Hotel to load the hotel information for any item in the results list.
Figure 6(lists all long-running conversations and indicates the current-foreground conversation)
Figure 7 confirm.xhtml: Click on the Confirm button to end the conversation
Figure 8 After second hotel is booked.