I've been developing software for over 15 years working in Delphi and now Java. This site is a home for my open source projects, writings, articles and tutorials mainly focusing on Java and Java EE. Andy is a DZone MVB and is not an employee of DZone and has posted 34 posts at DZone. You can read more from them at their website. View Full User Profile

CDI Conversations Part 1

08.17.2010
| 6629 views |
  • submit to reddit

This is the first in a series of articles looking at the conversation scope introduced in CDI as part of Java EE 6. We’ll start by looking at existing scopes and how they introduce limitations for developers and how CDI conversations get around these limitations.

Why we need a CDI Conversation scope

Scopes limit the lifespan of a piece of data and the ability for different users to access that data. Most of us are familiar with the 3 common scopes available in web applications.

Original Web Application Scopes
Application
Data is available to all users of an application for the duration of the application
Session
Data is only available to the current user for the duration of the users session.
Request
Data is only available to the current user for the duration of the current request

The application scope was intended to contain data that was shared among all users of an application, Session was intended for holding data belonging to the individual users, and Request scoped data was limited to the current web request for the user and was not available from one request to the next.

Regarding statefulness, these scopes are either all or nothing with respect to requests. If you put an object in the request scope, it will not exist in the next request. If you put an object in the session scope it will be available in every single request that user makes until they leave the application. An object placed in Application scope will be available in every request made by every user until the application is restarted.

As developers, this puts us in a very tricky place since we don’t have a lot of options. While there are clear cases of when we should use Application or Session scoped data, 80% of our application will probably be using objects of a much shorter lifespan than the user session and application, but longer than a single request. Take for example a situation where we need to collect a lot of information over 3 pages and at the end save the data. What if we are editing an entity which allows us to click an AJAX button and modify the server side state that does not have any client side representation? How do we hold that state for when we want to save our objects later?

The fact is that most applications have a lot of state that needs carrying around from request to request and the 3 scopes we’ve been using for years are not a great solution for dealing with it.

Hold state in the session

We can hold the state in the session under a specific key name and fetch it during each request, but that leads to the following problems :

  1. Huge sessions if you never clear out the session objects when you are done with them
  2. Overwriting session objects if you have two windows/tabs open at the same time
  3. In a replicated environment this can have problems if you modify the object and forget to call setAttribute on the session for the bean. This can lead to out of date objects on some servers and bugs that are difficult to track down.

Hold state in the database

We could use the database to store the state in between requests so we have a stateless system without having to ferry data between the client and server and without having to hold it on the server. Again, this has a set of problems :

  1. It is slower than an in-memory fetch
  2. The database scales the least of all the tiers and will soon become a bottleneck
  3. You still need to do some work for optimistic transactions
  4. Our bottleneck multiplies when you bring Ajax into the mix as then we have dozens of requests per page each needing to hit the database
  5. If you have partially created objects in the database, you need to keep excluding those from queries which while not impossible is prone to being missed off queries and either breaking the application or skewing reporting results.
  6. If you save as a partially created object, you have to overcome (i.e. remove) database constraints that might not be met by a partially constructed object
  7. If you don’t save state as a partial object, it will require additional code to read and write the object to the database or other store.

Hold state in the client

Sending the state to the client means we generate the state in the initial request and ship it off to the user as part of the page. When they post back, the state is read back in and re-constructed server side. While this delivers a truly stateless application and is very scalable, it has the following problems :

  1. You have to make sure you get all the state on the client which can be difficult with more complex models (i.e. a Teacher with a set of students). Otherwise you need to go back to the database for the information.
  2. You can’t use GET urls unless you attach everything to the url as a parameter and keep up with the maintenance of the values included. Bundling everything in a POST is easier.
  3. You have to validate everything that is sent back to the server from a client that could be malicious

The validation issue is particularly interesting because in many cases, you would need to go and re-load the data again just to validate it to ensure the user hasn’t modified it. In some ways, this can be the worst of both worlds since you have to code for client side state handling, but still have to go to the database to validate your model.

Improving the current options

There are two possible modifications to the above examples that make them more palatable.

One is to use a key that is unique to the page to store objects in the session so objects can’t be over written in the session. The key is then passed from server to client and back again but you have to manage the propagation of the key from one page to the next.

We can also use a cache with the database to hold recent copies of data based on the notion that since this object was just used, it will be used again soon. In essence this is adding a stateful component to the stateless system in order to relieve the database.

If these two options sound like good ideas then you are going to love Conversations because fundamentally, that is what they are.

Enter Conversations

A conversation is a scope that isolates data in the session from different requests and holds state from one request to another for a duration that is shorter than the session. This is exactly what we want for our data, we want to use it across multiple requests, but we don’t want it to last forever, and we don’t want the data from one page overwriting the data in another in the session.

Conversations are like numbered buckets that are held by a conversation manager in the session. Objects can be put into a conversation bucket where it stays for a fixed duration since once the conversation times out, the bucket is removed from the manager and the objects in the bucket are freed up. This is like a smart stateful cache that knows how long each conversation needs to be held for (you can even change conversation durations on a per-conversation basis). An object cache just removes objects on a most recently used basis with no context of what the object is actually used for or how long it is needed. A Conversation ‘cache’ has context and knows what data it has and how long it is needed for.

We can enjoy the benefits of state on the server side without the worry of the user session growing too large, and as part of java EE 6, our other frameworks will be able to deal with conversations by default, such as the ability to propagate the conversation key from one page to the next as needed in JSF.

Since conversations ids are unique to the specific activity the user is performing, the user can carry out two similar activities such as editing two separate Person entities in different browser windows without worrying about the data being overwritten in the session since the data is isolated in their own conversation instance. This means we get properly functioning web applications that can deal with multiple windows/tabs at once…for free!

Furthermore, if you consider that EJBs can be put in a conversation, then you have a conversation cache containing objects that when needed, can passivate themselves to save resources which lets you stretch your server resources even further.

Next time, we’ll start using CDI conversations and see how they work and the third part will look at dealing with Persistence and conversations.

From http://www.andygibson.net/blog/article/cdi-conversations-part-1/

Published at DZone with permission of Andy Gibson, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Jose Maria Arranz replied on Wed, 2010/08/18 - 7:15am

Since conversations ids are unique to the specific activity the user is performing, the user can carry out two similar activities such as editing two separate Person entities in different browser windows without worrying about the data being overwritten in the session since the data is isolated in their own conversation instance. This means we get properly functioning web applications that can deal with multiple windows/tabs at once…for free!

<begin ironic>

WOW!! 2010 and not there yet? Yeah is a technological revolution!!

<end ironic>

Fortunatelly this kind of stuff is already working years ago on independent web frameworks.

 

Andy Gibson replied on Wed, 2010/08/18 - 1:44pm

What primary frameworks have had first degree, native, codeless conversation handling that allows for data isolation across different requests in the users session ?

 

Jose Maria Arranz replied on Wed, 2010/08/18 - 2:39pm in response to: Andy Gibson

For instance GWT, ZK and ItsNat since day one.

I the case of ItsNat there is no public use of sessions (fully optional), the framework itself of course uses internally sessions just for browser identity, applications are event based and developers do not care about page navigation it frees developers of tons of headaches (such as back/forward/reload problems and multiple windows open).

In my opinion is crazy that JSF (JavaEE) continues building artifacts for page navigation, page navigation is becoming more and more an anti-pattern for web applications.

 

Andy Gibson replied on Wed, 2010/08/18 - 3:39pm

That's a fair point, but these are fairly untypical frameworks, more like abstractions of web applications that are more about producing web pages (or a single web page) rather than being made up of pages. 

The single page interface is a bit of a misnomer, there are still multiple pages, they just exist in code as opposed to files in the application. Personally I feel the abstraction is a little too high (mind you, I think the abstraction of JSF is too high).

Cheers,

Andy Gibson

 

 

Jose Maria Arranz replied on Thu, 2010/08/19 - 1:15am

"there are still multiple pages, they just exist in code as opposed to files in the application"

I don't understand you, previous frameworks generate true single page interface applications, no reload, no page shift, is not a simulation like Wicket when no using AJAX.

"more like abstractions of web applications"

Form submitting was a hack defined many years ago to provide some kind of client to server data submitting, it has worked "fine" more or less but these days with AJAX out there many years ago form submitting is anachronism even for many kind of web sites. The Single Page Interface Manifesto summarizes my thinking about this subject.

 

 

King Sam replied on Fri, 2012/02/24 - 10:22am

Good intro, looking forward to part 2. One question: shouldn’t you include Page in the list of Original Web Application Scopes?

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.