Examples/Eclipse Business Expense Reporting Tool/User State Service
This page is under development
EBERT runs as both a standalone application (RCP, ERCP) and as a multiple-user application (RAP). To support both environments, we have to be careful how we store user state.
EBERT defines an Equinox/OSGi Service of type IUserContextService.java along with two different implementations. Implementations of this type are responsible for one thing: answer, when asked, the user state (an instance of IUserContext) for the current user.
Note that a notion of user state is being explored by the e4 effort.
The notion of "current user" is pretty simple in the standalone case: there is only one user. The StandaloneUserContextService simply returns an instance of StandaloneUserContext that it holds in a field. The activator for the bundle containing these types registers the service on bundle startup and deregisters it on shutdown.
The notion of "current user" is more interesting in the multiple-user case of RAP. RapUserContextService uses the HTTP Session state, accessible through APIs on RAP's RWT type. This returns for us an instance of RapUserContext that is specific to the user tied to the current thread. As is the case with the standalone variant, this service is registered and deregistered by the bundle activator.
The user context provides a view model for the current user along with other useful information such as the user-specific locale. The current implementations are also responsible for managing CRUD operations on the domain model. This will change with the introduction of the notion of a persistence service.
The user context service is obtained by clients using an OSGi ServiceTracker. An example of this can be found in the
startUserContextServiceTracker()<code> method in the AbstractView class (which is the superclass for all the EBERT views). This code will be greatly simplified when we change it to leverage OSGi Declarative Services. The <code>userContextServiceTracker is notified, via the
addingService method whenever a service is added or removed. Our implementation is greedy: it takes the first service that it finds. When this first service presents itself, the instance is notified via the
connectToUserContext(...) method. Likewise, when the service that we greedily obtained is removed, the instance is notified via the
disconnectFromUserContext(...) method. This allows the application to be very dynamic as the state of the services changes; the views dynamically configure themselves based on the availability of a user context service.
syncExec blocks bear some discussion. This ServiceTracker will be invoked by threads other than the UI thread that owns the view instance. Since we may be running in RAP, we need to make sure that when we obtain the user context, we get the right one. By wrapping the call to
getUserContext inside a
syncExec block, we can be sure that the code that obtains the user context is running in the right user's UI thread. The
syncExec method is a convenience method that obtains the receiver's SWT Display and invokes
syncExec on it.