Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "Examples/Eclipse Business Expense Reporting Tool/User State Service"

Line 10: Line 10:
 
The notion of "current user" is more interesting in the multiple-user case of RAP. [http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.examples/ebert/org.eclipse.examples.expenses.application.rap/src/org/eclipse/examples/expenses/context/rap/RapUserContextService.java?root=Technology_Project&view=markup RapUserContextService] uses the HTTP Session state, accessible through APIs on RAP's RWT type. This returns for us an instance of [http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.examples/ebert/org.eclipse.examples.expenses.application.rap/src/org/eclipse/examples/expenses/context/rap/RapUserContext.java?root=Technology_Project&view=markup 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 notion of "current user" is more interesting in the multiple-user case of RAP. [http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.examples/ebert/org.eclipse.examples.expenses.application.rap/src/org/eclipse/examples/expenses/context/rap/RapUserContextService.java?root=Technology_Project&view=markup RapUserContextService] uses the HTTP Session state, accessible through APIs on RAP's RWT type. This returns for us an instance of [http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.examples/ebert/org.eclipse.examples.expenses.application.rap/src/org/eclipse/examples/expenses/context/rap/RapUserContext.java?root=Technology_Project&view=markup 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 service is obtained by clients using an OSGi ServiceTracker. An example of this can be found in the AbstractView class (which is the superclass for all the EBERT views.
+
The user context service is obtained by clients using an OSGi ServiceTracker. An example of this can be found in the [http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.examples/ebert/org.eclipse.examples.expenses.views/src/org/eclipse/examples/expenses/views/AbstractView.java?root=Technology_Project&view=markup AbstractView] class (which is the superclass for all the EBERT views) as follows:
 +
 
 +
<source lang="java">
 +
protected void startUserContextServiceTracker() {
 +
userContextServiceTracker = new ServiceTracker(ExpenseReportingUI.getDefault().getContext(), IUserContextService.class.getName(), null) {
 +
/**
 +
* We keep track of the first service we find and ignore the
 +
* rest. This is a great example of where declarative services
 +
* would be helpful: you can declare that you want exactly one
 +
* instance of a service and that's what you get.
 +
*/
 +
protected IUserContextService userContextService;
 +
 +
/**
 +
* This method is called when a matching service is found or
 +
* added. This finds both pre-existing and new instances of the
 +
* service.
 +
*/
 +
public Object addingService(ServiceReference reference) {
 +
Object service = super.addingService(reference);
 +
if (userContextService == null) {
 +
userContextService = (IUserContextService)service;
 +
/*
 +
* Do the part where we get the user context in a
 +
* syncExec block. This will make sure that it runs
 +
* in the user interface thread for the current user.
 +
* This doesn't matter too much on RCP/eRCP, but the
 +
* thread that we're running in is pretty critical
 +
* in RAP.
 +
*/
 +
syncExec(new Runnable() {
 +
public void run() {
 +
userContext = userContextService.getUserContext();
 +
connectToUserContext(userContext);
 +
}
 +
});
 +
}
 +
return service;
 +
}
 +
 +
/**
 +
* This method is called when the service is being removed, or the
 +
* tracker is being closed.
 +
*/
 +
public void removedService(ServiceReference reference, Object service) {
 +
if (service == userContextService) {
 +
disconnectFromUserContext(userContext);
 +
userContext = null;
 +
userContextService = null;
 +
// TODO Do we try to match up with a hypothetical second service in this case?
 +
}
 +
super.removedService(reference, service);
 +
};
 +
 +
 +
};
 +
userContextServiceTracker.open();
 +
}
 +
</source>

Revision as of 15:54, 26 February 2009

This page is under development

Managing the user state in a standalone application is relatively easy. 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 service is obtained by clients using an OSGi ServiceTracker. An example of this can be found in the AbstractView class (which is the superclass for all the EBERT views) as follows:

	protected void startUserContextServiceTracker() {
		userContextServiceTracker = new ServiceTracker(ExpenseReportingUI.getDefault().getContext(), IUserContextService.class.getName(), null) {
			/**
			 * We keep track of the first service we find and ignore the
			 * rest. This is a great example of where declarative services
			 * would be helpful: you can declare that you want exactly one
			 * instance of a service and that's what you get. 
			 */
			protected IUserContextService userContextService;
 
			/**
			 * This method is called when a matching service is found or
			 * added. This finds both pre-existing and new instances of the
			 * service.
			 */
			public Object addingService(ServiceReference reference) {
				Object service = super.addingService(reference);
				if (userContextService == null) {
					userContextService = (IUserContextService)service;
					/*
					 * Do the part where we get the user context in a
					 * syncExec block. This will make sure that it runs
					 * in the user interface thread for the current user.
					 * This doesn't matter too much on RCP/eRCP, but the
					 * thread that we're running in is pretty critical
					 * in RAP.
					 */
					syncExec(new Runnable() {
						public void run() {
							userContext = userContextService.getUserContext();
							connectToUserContext(userContext);
						}
					});
				}
				return service;
			}
 
			/**
			 * This method is called when the service is being removed, or the 
			 * tracker is being closed.
			 */
			public void removedService(ServiceReference reference, Object service) {
				if (service == userContextService) {
					disconnectFromUserContext(userContext);
					userContext = null;
					userContextService = null;
					// TODO Do we try to match up with a hypothetical second service in this case?
				}
				super.removedService(reference, service);
			};
 
 
		};
		userContextServiceTracker.open();
	}

Back to the top