Tag Archives: Eclipse RCP

Executing commands programmatically

Executing commands (e.g. from a SWT listener) is a pretty handy thing. You don’t have to care about, where the handler is registered, you simply execute the command via the ICommandService, the delegation is provided by the framework.


...
ICommandService commandService = (ICommandService)getViewSite().getService(ICommandService.class);
try {
commandService.getCommand("com.foo.the.command").executeWithChecks(new ExecutionEvent());
}
catch (Exception exception) {
logger.error(exception.getMessage(), exception);
}
...

There is just one thing about the snippet above that is bad: The way the ExecutionEvent is created. Using the default constructor results in hard time for a handler, as the HandlerUtil class cannot be used due to the missing context information. A better way is to pass on some parameters to the ExecutionEvent to be created. The most important one is the last parameter, the application context object. It can be obtained via the IEvaluationService.


...
ICommandService commandService = (ICommandService)getViewSite().getService(ICommandService.class);
IEvaluationService evaluationService = (IEvaluationService)getViewSite().getService(IEvaluationService.class);
try {
Command theCommand = commandService.getCommand("com.foo.the.command");
theCommand.executeWithChecks(new ExecutionEvent(theCommand, new HashMap(), control, evaluationService.getCurrentState()));
}
catch (Exception exception) {
logger.error(exception.getMessage(), exception);
}
...

This command invokation can be processed by any handler using the HandlerUtil class.

Eclipse RCP and language selection

Eclipse RCP Clients are usually shipped with language bundles providing the translations of the application’s labels. Depending on the locale (either the system’s default locale or the locale set with the -nl program argument), the client appears with the labels in the defined language. But what about letting the user choose his language, e.g. in a login dialog or during runtime?
Well, simply modifying the default locale using Locale.setDefault() has no effect as the underlaying workbench has been already configured with the startup language. You actually need to restart the client and reset the default locale. Eclipse provides a special exit code IApplication.EXIT_RELAUNCH in order to relaunch a client and use programmatically defined startup parameters. To do so, simply set the system property eclipse.exitdata with the required startup parameters with System.setProperty(). The prefix of the property’s value should be {eclipse.vm}\n, the rest is to be structured like the common .ini file, that is usually used to set the client’s startup configuration. In order to reset the locale, the property’s value needs to contain the -nl program argument set to the language selected by the user. When exiting the Workbench using the IApplication.EXIT_RELAUNCH exit code, the client will then be relaunched using the configuration defined with the eclipse.exitdata property’s value and appear in the requested language.

Building Source Features with the PDE Build

The PDE Build provides a pretty convenient way of automatically creating a source feature. The additional feature contains all source files and artefacts listed in the containing bundles’ build.properties files for a source build. There are only a few settings necessary.

Assume we have a feature com.foo.feature containing some bundles with binaries only.

First, we need to configure a source feature include for the feature. Simply add a line to the com.foo.feature feature’s feature.xml:
<includes id="com.foo.feature.source" />

The linked feature com.foo.feature.source does not exist yet, it will be created by the PDE Build later on.

To get the PDE Build actually creating the source feature, we have to edit the com.foo.feature features’s build.properties by adding another line to it:
generate.feature@com.foo.feature.source = com.foo.feature

The PDE Build will now build the linked source feature com.foo.feature.source including a bundle containing all sources of all binary bundles included in the com.foo.feature feature. Since Eclipse 3.4, we can tell the PDE Build to create an individual source bundle for each bundle by setting a PDE Build property individualSourceBundles to true.

Fragments vs. Buddy Classloading

Classloading is a serious issue when creating OSGi based applications. As each bundle is bound to it’s own classpath, sometimes the reflection mechanism will not work as expected. So, there are basicly two ways of solving the problem of extending a bundle’s classpath (when using Equinox…), either create a feature or use Buddy Classloading. But which solutions fits best for what problem?

Fragments

A fragment is an OSGi mechanism to allow a dynamic extension of a bundle at runtime. The fragment itself is not a true component as other bundles may not define a dependency on the fragment. It is used for different purposes such as testing, internationalisation or logging configuration. You can add system dependent code or configuration files to a generic implementation. The good thing is, that the extended code has no dependency on the fragment i.e. does not necessarily require the fragment for running (for example testing fragments).

How to
A fragment is structured as a common bundle. It may be created using a wizard (in Eclipse) or by adding a line to the manifest.mf of a common bundle defining the so called fragment host:
Fragment-Host: bundleSymbolic-Name
This advises the runtime to merge the fragment’s content with it’s host at runtime.

What’s good
Fragments are pure OSGi and provide the flexibility of extending a component dynamicly at runtime without breaking the component architecture. Some third party classpath requirements can be solved this way, for example providing a logging configuration.

What’s bad
Some third party classpath requirements cannot be matched using fragments.

Buddy Classloading

Buddy Cassloading is somewhat a hack (in my opinion), as it adds a bundle’s classpath to another’s – you could call it ‘reverse-dependency’. In OSGi terms, this is explicitly not wanted as a bundle should be treated as a component. But since many Java libraries got used to a single classloader environment, they still expect an exclusive access to any class of the application using reflection. So, in some situations, you can’t really avoid using Buddy Classloading in an Equinox environment.

How to
The manifest.mf of the bundle to be extended receives an additional line to define a Buddy Policy:
Eclipse-BuddyPolicy: registered
This defines the bundle to be aware of registered bundles which entend the classpath.

The manifest.mf of the bundle to extend receives two additional lines:
Eclipse-RegisterBuddy: bundleSymbolic-Name
Require-Bundle: bundleSymbolic-Name

This defines the bundle to extend the classpath of the listed bundles. Additionally, the registered Buddy Policy requires the extending bundle to have a dependency on the extended bundle.

What’s good
Buddy Classloading easily enables using common reliable libraries without any problems. Additionally, the extending bundle can still be treated as a ‘normal’ bundle, other bundles may have a dependency on the bundle and use the exported packages as provided.

What’s bad
Buddy Classloading is not ‘the OSGi way’ as it corrupts the idea of having a component based application with clearly separated bundles defining an interface and dependencies. Buddy Classloading is an answer to a technical problem and should not be used for application design.

Programmatic command contributions

Have you ever faced the task of programmatically adding commands to a given menu? It is not that difficult – when you finally found out ;).
First of all, you need a target menu, whether it is declared or programmatically created does not matter. What you actually need is the menu’s location URI. You may the create an AbstractContributionFactory with the menu’s location URI:

...
AbstractContributionFactory contribFactory = new AbstractContributionFactory ("menu:com.foo.targetmenu?after=targetGroup", null) {
@Override
public void createContributionItems(IServiceLocator locator, IContributionRoot additions) {
// add the contribution using it's source
additions.addContributionItem(createContributionItem(contribSource), null);
}
IMenuService menuService = (IMenuService)getViewSite().getService(IMenuService.class);
menuService.addContributionFactory(locator, contribFactory);
...

The items are added to the IContributionRoot within the factory’s createContributionItems() method. The factory is then registered at the IMenuService and your contributions show up.
For creating an IContributionItem for a given command, you may use the CommandContributionItem class, which takes an CommandContributionItemParameter as constructor parameter. A CommandContributionItemParameter basicly contains all the required data for a command contribution known from the org.eclipse.ui.menus extension point.


private IContributionItem createContributionItem(IServiceLocator locator, Object contribSource) {
CommandContributionItemParameter contributionItemParameter = new CommandContributionItemParameter(locator, null, "com.foo.the.command.id", SWT.PUSH);
// pimp the item using the contribSource
...
return new CommandContributionItem(contributionItemParameter);
}

There you go.

Bundles & Libraries

I heard a talk about VIB – Very Important Bundles – today at the W-JAX here in Munich. The speaker pointed out some key features and services (and available solutions) necessary for developing applications in an enterprise context. He also discussed the way bundles should be designed in general. There were two mentioned aspects that made me wonder.

  • Bundles represent a deployment artefact only.
  • Bundles may contain libraries they need, if it is applicable.

For me, a bundle is explicitly not only a deployment artefact. Bundles represent a software component and are therefor an architectual element of the software. They are essential to be able to use public and private API, as Java Packages simply do not serve this need. No need to say that I prefer ‘Required Bundles’ instead of ‘Imported Packages’ :). And turning to libraries, they should be encapsulated in a separate bundle and definetly not included in any bundle containing business code. A big advantage is the reusability of these individual so called ‘library bundles’, for instance logging frameworks or apache commons components. From my point of view, intergrating libraries in a bundle and even exporting them makes their management difficulter than necessary, at least within an enterprise context.

Eclipse Commands: Cut, Copy and Paste

I came around the requirement to enable the default cut, copy and paste function as menu entries within the main menubar. When adding the commands org.eclipse.ui.edit.cut, org.eclipse.ui.edit.copy and org.eclipse.ui.edit.paste to my menubar using the org.eclipse.ui.menus extension point. Unfortunately, these menu entries where disabled all the time. This was pretty comprehensible, as there was no active handler available. So I did register an appropriate handler (working like the Eclipse WidgetMethodHandler) using the IHandlerService. It takes the currently focussed element and checks whether this Control has the necessary cut(), copy() or paste() method to invoke and calls the required method on execution. So far, so good, my menu entries were now enabled – at least sometimes?!? The reason for that was the isHandled() method of my handler which returns true only if the method is available on the currently focussed element.

/** {@inheritDoc} */
@Override
public boolean isHandled() {
return isTargetMethodAvailable(Display.getCurrent().getFocusControl());
}

As the enablement state is determined only on the context part’s (IWorkbenchPart) activation, the state is only requested once for the default focus Control of the part. So the state of the commands stays the same for the whole part activation. Additionally, a ‘no active handler available’ exception is thrown, if the menu entry is selected with a focussed Control not supporting the method. Bad luck.

So, what to do now? I ended up registering a focus Listener for all elements of the part to keep the command state in sync with the handler state.


// create a listener for tracking the focus
final Listener listener = new Listener() {
/** {@inheritDoc} */
@Override
public void handleEvent(Event event) {
ICommandService commandService = (ICommandService)workbenchPart.getSite().getService(ICommandService.class);
commandService.refreshElements(commandId, null);
}
};

The refreshElements() method calls the updateElement() method of active handlers for the given command ID implementing the IElementUpdater interface. So I let my handler implement that interface, the interface method simply fired an HandlerEvent stating that the enabled state changed.

/** {@inheritDoc} */
@Override
public void updateElement(UIElement element, Map parameters) {
fireHandlerChanged(new HandlerEvent(this, true, false));
}

The only thing left to do was to implement the isEnabled() method which is used to determine the commands enablement state.

/** {@inheritDoc} */
@Override
public boolean isEnabled() {
return isTargetMethodAvailable(Display.getCurrent().getFocusControl());
}

There you are, it works!

Model View Presenter, Passive View & DI

After three days of interesting conversations I’m off to my November holidays. This is a very calm and silent time which leaves a lot time for interesting thoughts.

Denmark

Denmark

I heard a talk about testing RCP Applications on Wednesday shortly before I left Munich which was pretty interesting. Ralf Ebert outlined a way of designing GUIs to ease testing by applying the Model View Presenter pattern in combination with the Passiv View pattern. Basicly it introduces a presenter which mediates between the ‘Model’ and the ‘View’. The model includes all data and logic, e.g. adding two numbers. The view simply displays everything. The presenter connects input and widgets and delegates calls from the UI to the model’s logic. This allows mocking the view’s behaviour and simply test the logic within the model.

The testing aspect sounds interesting, but something else comes a long with that design. In distributed systems, the view usually calls some logic from serverside services. That means, the view has to somehow access a service instance by using some context holding component. Now, what about making the view part of this service structure and provide the service via DI. Usually (in Spring terms ūüėČ ) this means hooking the view into the service container, which is pretty bad (if even possible) as they are controlled by the platform. But using a so called view model (at least I tend to call it like that) solves that. The model (and even the presenter) may be hooked easily to the container, which makes interaction quite easy.

Nice idea, what do you think?

Eclipse RCP & Logging

Logging within an Eclipse RCP application is pretty easy, every Activator provides an¬†ILog using it’s getLog() method. Though it’s a little annoying wrapping the log statements with an IStatus, using some convenience methods solves that. But what about using another logging framework, e.g. Log4J?

Nearly everybody who tried to use Log4J accross Eclipse bundles faced the context classloader problem. Usually, the Log4J binaries should be placed within a library bundle. The configuration, the log4j.properties file, though is supposed to be somewhere else within a project specific bundle. Creating a Logger instance then runs into a problem: the configuration is not visible from the library bundle. So what to do now?

A pretty elegant solution is to use a fragment containing the configuration tied to the library bundle. So the project specific configuration is separated from the framework and can be managed individually.