AW Talk is the official development team blog for AribaWeb, the Open Source component-based web application development framework for creating rich, AJAX-enabled applications with the absolute minimum of code (and no hand-coded Javascript).

(Meta UI - JPA) Context Binding Explained !

Hello everyone, 
Almost all of you who have explored AW at any depth will have encountered the ObjectContext and will probably have realized that its function is to bind the persistence-layer session to the AW-layer. The observant amongst you may have noticed that the ObjectContext appears to be per page and that additionally the context is thread-locally bound. When I first saw this I was confused. As I move through the app from page to page, it seems like I would be creating lots of ObjectContexts which may or may not have been committed or flushed and I may lose uncommitted edits; additionally, there's no guarantee that I will rendezvous with the same thread across request potentially causing more memory bloat and / or lost edits. If you are building really enterprise application and you care about a performance the earlier or the later you will want to know more. So what's going on? Read on and I'll tell you.

Class diagram showing relation between the AWPage and ObjectContext

We know that in simple scenario ObjectContext is used to complete your transaction and save the data into the DB, but on the other side do we know what is happening on the background? Is this even so important? 

Yes this is important because this will influence your future performance of the application. I am starting with this because we have decided long time ago to re-implement whole persistence stack with our own API to support our requirements and this week we did some refactoring and discovered several points that we think it should be addressed and clarified by anyone going the same direction as we do.

Here is what's going on: 

1) Every time there is a new request from the Servlet Container and handled by our AWDispatcherServlet it does not have to be the same thread all the time. 

2) When you are playing with AribaWeb you will probably do not notice but from the time you login till the end you logout from the Application you are probably using the same thread. But this is only a coincidence. With big load you might get different thread every time. (But this is common behavior and I am mentioning it just for the completeness). 
So have you even try to understand your hibernate session or ObjectContext? How it is created and how it is destroyed or even propagated over several pages?

3) Every time your page with your content is about to be rendered then new AWPage is created and gets new ObjectContext (or existing is reused from previous thread). All this using ContextBinder and its method pageWillAwake(). ObjectContext is nothing else than in the default implementation the HibernateContext that holds its HibernateSession.

4) If you leave the page or go to the new one the current ObjectContext is removed - unbound. But here might be a problem #1. 
The ObjectContext is removed from ThreadLocal but its not really destroyed meaning your HibernateContext and its HibernateSession is still active. There is no close() called. Now imagine you will have Facebook like application with allots of hits and you are ignoring these facts then you might get into trouble. Of course you might say that Hibernate supports some release strategies which allows you automatically close the database connection when you complete your work but what about session? 
There is even more you need to consider. Especially when dealing with large number of users accessing the website. If you do not have clearly defined your transaction and its demarcation and maybe do not set properly FlushMode you get into trouble. The objects in your session will grow and grow. Of course you can say but we do call flush when we save the object and hibernate specific implementation has defined several rules when the flush should occur. But this might behave differently when you have 100 users using your application or when you have 100k users using your app. If you are planning to implement your own JPA layer please consider all this because hibernate at the end if you configure it correctly might not give you so much trouble compared to your version where you will try to simulate the same behavior but instead of passing around HibernateContext you might be passing your own Context with some state. You need to be lazy meaning you should acquire connection when you really need it and when you are done just get rid of it. 

5) The persistence framework (MetaUI-JPA) allows you to have several active ObjectContext opened and bound to your session id but only one for current thread. (Valid for Nested Session)

Note: Here I want to stress that AribaWeb is mainly unique web framework on first place and then there is rest of its stack (JPA implementation and so on...). So I am showing you these points because you should be aware of it and I want make sure that we understand it and this is not something that AribaWeb (the UI) should handle. If you will have trouble with your session management then all is in your hands. As I mentioned before if you decide to use HibernateSession you need to make sure that your hibernate layer is set correctly

6) We understand now how the session management works and we can go on and focus on the actual flow of the request. So lets say we launched AltIssue Demo application where we have module tabs [Issue,Category,..] and now you simply click on the second tab the Category.

The actual flow can be described like this:

Once you click on the new tab the first phase is executed. Since every click can be from different thread we need to transfer ObjectContext if any to the current thread. 

#1: pageWillAwake() is called on Issue page (the page we are exiting) and current ObjectContext if any is taken from the page context and bound into current thread for the AWPage B. You can see the ThreadLocal does not make any sense anymore for the AWPage A

#2: pageWillAwake() is called again and this time for the new Category page. It will take newly added ObjectContext from current thread and attaches it into the current Page Context that is associated with the AWPage B.

#3, #4: Then content is rendered and pageWillSleep() is called on both AWPages A and B, which releases the ObjectContext from current thread.

Now we get some idea how ObjectContext is transferred between pages and threads. Maybe now you are asking why it is so important to transfer object context from one page to another. The answer is simple. Every time you create a new object this object is associated with current and active EntityManager and this EntityManager is part of your ObjectContext. Typical use case for this might be a Wizard where you are managing a long conversation over several pages for one specific entity. On the picture you can see how the execution is triggered. First is called awake for the model.Issue tab, then the awake for the model.Category and when everything is rendered we remove the ObjectContext from the current thread.

Other areas to investigate:

While we are are still in the persistence layer I think it is worth to check out all classes which are involved in this whole process: 
  • This is your link between persistence layer and the UI layer. This object is responsible for all DAO operation as well is creation of the objects. 
  • Any class using this ObjectContext API might wish to monitor all the changes on a object which happen in the other ObjectContext (for example if a nested context is created) 
  • Use to group ObjectContexts (currently by sessionId). Valid only for the nested context where you need to propagate all the changes to parent context. 
  • This is specific implementation of the ObjectContext based on the java persistence API. 
  • Implements create() method which provides new context in this case HibernateContext when ContextBinder.pageWillAwake() is trying to bind new context to AWPage and ThreadLocal

1 comment: