- Database connections
- Hibernate sessions or JPA EntityManagers (persistence layer sessions)
- Page state and page objects.
The ConversationContextConversation Context
Many things around a Page need to have some form of life cycle. To manage this each page is associated with a unique ConversationContext. This conversation manages all of the resources related to a page.
The ConversationContext has a life cycle as follows:
- NEW: The ConversationContext has just been created. The NEW state immediately transitions to ATTACHED.
- ATTACHED: A request has entered the server that needs the context. All of the resources of the Context are available for use.
- DETACHED: No request is currently executing for a page related to the Context. The context is valid but connections are released.
- DESTROYED: The context is still known, but all its resources have been released.
The ConversationContext is managed by DomUI. Attaching and detaching a ConversationContext is simply managed by requests entering or exiting the server. Destroying a Context is more complex and is described later (see destroying conversations, later)DomUI destroys a Conversation when it finds out that the page is no longer needed. This process is described later on in "destroying conversations".
The ConversationContext contains setAttribute() and getAttribute() calls with which you can add any object into a context, similar to a HttpSession. When such an object added to the session attributes implements IConversationStateListener the methods on that listener are called as soon as the conversation's state changes. It is this mechanism which implements the state management of the shared QDataContext (see next section): the implementation for that is stored as an attribute in the ConversationContext and implements the above listener. As soon as that listener's "conversationDetached" method is called the connection for the context gets closed.
Let's start Conversation state management is heavily used in the stateful database interface used by DomUI, so let's continue by discussing the needs of the database layers: connection management and the persistence layer, then we'll look how DomUI handles those needs.
Session inside DomUI pages
The QDataContext interface
As DomUI supports multiple persistence frameworks we use parts of the QCriteria framework to represent whatever persistence layer "Session" we use. The wrapper is the QDataContext interface. QCriteria framework "wraps" most of the constructs we need to do database I/O. This includes database session management. A session in QCriteria terms is a QDataContext which is an interface.
This interface has more or less the same set of methods as the EntityManager or Session interfaces, but in a completely framework independent way. The specific interface module of DomUI defines the actual implementation of QDataContext which would be a wrapper around the appropriate Session / EntityManager / Whatever object.
Shared QDataContext for all page fragments and Nodes
A DomUI page can allocate a "default" QDataContext by calling getSharedContext(). This method is available on all DomUI nodes and can be called as soon as the node is attached (added) to some page. The getSharedContext returns a default QDataContext which will be stored with the Page. Subsequent calls to getSharedContext from any node in the page will always return the same QDataContext(). In this way all queries done using the shared data context always return objects related through a single Session/EntityManager.
So far we have talked about DomUI pages. These are classes derived from UrlPage which are uniquely identified by an URL containing a class name and a set of parameters. Changing to another Page means changing the URL, and causing a Browser page change. A DomUI Page, once rendered, is fully AJAX, but changing pages is not AJAX but is closer to a traditional HTML page. This was a good match for the first application DomUI was written for.
DomUI 2.0 has a new concept called SubPages which aims to fix this. This are part of the SPI (Single Page Interface) implementation for DomUI.
This is preliminary info; the implementation can still change quite a bit.
What is a SubPage
A SubPage is a class that extends the class SubPage instead of UrlPage. A SubPage is a DomUI fragment represented as a Div which can be added anywhere in the DomUI DOM. A SubPage is always part of an UrlPage - but an UrlPage can contain multiple SubPage's if so desired.
A SubPage needs SubPage must to be added to an UrlPage, but you can just create a single UrlPage and from then on just replace SubPage's inside that page to create the parts of the UI that are desired.
SubPages also implement state management which is similar to the state management that is done by UrlPages. Like an UrlPage a SubPage has a ConversationContext (called SubConversationContext). These ConversationContexts are children of the main ConversationContext that is attached to the UrlPage.
Like UrlPages subpages are created and destroyed, and this causes their SubConversationContext to be destroyed too. And with that all resources belonging to it are released. In addition all SubConversations will become attached and detached when the Conversation they belong to becomes attached or detached: all SubConversations closely mirror the root conversation state.
A SubPage and its SubConversation are created as soon as an instance of it is added to an UrlPage, either directly or because it is part of some subtree that gets added to a page. As soon as the thing gets added a new SubConversation gets allocated, registered with the UrlPage's Conversation and made Attached.
Calls to getDataContext() on nodes that belong to a SubPage will get their data context from the SubConversation belonging to the closest SubPage parent (remember that SubPages can be nested too!). This means that a SubPage has its own database connection and session. In this way the SubPage acts as a "fence" between different connections and objects.
A SubPage gets destroyed when it is removed from a page. The destruction is not immediate but done when the request finishes. This allows you to temporarily disconnect a SubPage and reconnect it somewhere else within the same request.
Entity (data) objects in SubPages
The normal way for creating SubPages is to have some class with a constructor, passing the data objects into the constructor. This is completely different from UrlPage's: these get their objects from "outside", and because of this these objects are always part of the QDataContext (session) of that UrlPage.
But when you create a SubPage and pass Entity objects in the Constructor those objects belong to the QDataContext of the parent of the SubPage. But the SubPage has its own QDataContext, and using the object as-is would cause trouble as all changes to the object would be done in the parent database context, not in the context inside the SubPage.
DomUI tries to fix this as follows: as soon as your SubPage is added to the page DomUI will scan the SubPage class for (private) fields and getters. All fields and getters that contain an object which is determined to be an Entity object (as detected by MetaManager.findClassInfo) will need to be re-injected in the SubPage. Re-injecting means: a new instance for the object is loaded from the QDataContext that is part of the SubPage. This will always be a new instance. The new instance is then put back into the field or the property. This should mean that all references to those objects now refer to the copy in the SubPage, not to the original.
To indicate that a property or field contains an entity they should be annotated with a @ReInject annotation.