Categories
Java RsBudget

Luna Update: TranslationService not in context

After migrating my Eclipse/E4 application to the latest release Luna, I noticed that the TranslationService is not present anymore within the E4Workbench.getServiceContext(). At least not at the PostContextCreate stage of the application. This is not a big deal, as you can easily create this yourself:

1
2
3
4
5
6
7
8
9
10
11
12
   private static TranslationService TRANSLATIONS = getTopContext().get(TranslationService.class);
 
   public static TranslationService getTranslationService() {
      if (TRANSLATIONS == null) {
         TRANSLATIONS = getTopContext().get(TranslationService.class);
         if (TRANSLATIONS == null) {
            TRANSLATIONS = ContextInjectionFactory.make(BundleTranslationProvider.class, getTopContext());
            getTopContext().set(TranslationService.class, TRANSLATIONS);
         }
      }
      return TRANSLATIONS;
   }
Categories
Upload Maven Plugin

Plugin to Publish Eclipse P2 Repositories

I currently work to publish my first RCP application, based on Eclipse/E4 (Kepler). One of the major topics is to automate the complete build and publish process. Tycho does a good job there already, and in fact it works perfect :). I setup my Bamboo instance to build it without any interaction.

However, Tycho does not offer yet any possibility to finally publish P2 repositories. I understand this as publishing can be a difficult job when it comes to various P2 repository flavours (combined, single etc). The Deploy plugin of Maven 3 is not good for this job as far as I have discovered. So I faced the problem of somehow to publish Snapshots and  final releases automatically. The net didn’t come up with any automated solution. Most folks just recommended to perform that step manually.

So I created the Upload Files Maven Plugin. It’s job is to upload any file(s) to the repository valid for an artifact. Users simply define their repositories as they did previously (in <distributionManagement> section of their POM), and then add the plugin to their lifecycle. Here is an example of how to do this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   <build>
      <plugins>
         <plugin>
            <groupId>eu.ralph-schuster</groupId>
            <artifactId>uploadfiles-maven-plugin</artifactId>
            <version>1.1.0</version>
            <executions>
               <execution>
                  <goals>
                     <goal>upload</goal>
                  </goals>
                  <phase>deploy</phase>
               </execution>
            </executions>
            <configuration>
               <path>target/repository</path>
               <targetPath>.</targetPath>
            </configuration>
         </plugin>
         ...
      </plugins>
      ...
   </build>

This will upload the P2 repository (created by Tycho) to your defined server repository. As the plugin uses Wagon for this task, you can use protocols such as SCP, FTP, WebDAV etc.

You also might also want to disable default install and deploy targets of Maven for your project:

1
2
3
4
   <properties>
      <maven.install.skip>true</maven.install.skip>
      <maven.deploy.skip>true</maven.deploy.skip>
   </properties>

One nice feature is the execution of pre and post commands on your remote server (tested with SCP only, other protocols might not support this). That can be used e.g. to clean your server repository before uploading the new one:

1
2
3
4
5
6
            <configuration>
               ...
               <preCommands>
                  <preCommand>rm -rf /path/to/repository/*</preCommand>
               </preCommands>
            </configuration>

These commands are executed in the user’s home directory, so please be careful :). There exists several possibilities to handle errors of such commands, so just check out the Goal documentation. It also lists other options you might find useful.

Version 1.1.1 will add a small variable substitution for commands, e.g. you can access the user name and base path of your server repository. This would allow a configuration such as:

1
2
3
4
5
6
            <configuration>
               ...
               <preCommands>
                  <preCommand>rm -rf $repository.basepath/*</preCommand>
               </preCommands>
            </configuration>

However, if you want to use that feature by now, you must use the 1.1.1-SNAPSHOT version. It is not officially released yet as I still want to get more experience with publishing P2 repositories before finally releasing it.

Feedback is welcome…

PS: Maven 3.1.1 is required to use this plugin!
PS: Version 1.1.1 was released meanwhile.

Categories
Java

Eclipse/E4: Problem with Key Bindings

I recently updated one of my E4 applications from Juno to Kepler (V4.3) release. Beside a few things (e.g. adding the HandlerProcessingAddOn to e4xmi configuration) I suddenly lost my customized key bindings. Unfortunately, there was not even a slight hint anywhere in the net why this happened. Most of the web sites were just referring to the afore mentioned add-on. But this didn’t bring back the missing key bindings.

So the only solution was to debug the bootstrap of RCP/E4 and find out where the key bindings disappeared. I noticed very early that my Binding Table was read but didn’t contain the correct key bindings. Although, an earlier breakpoint revealed that they have been read correctly. However, somehow they were removed and replaced by other ones.

Debugging in Eclipse/E4 is quite exhausting escpecially when you try to trace a problem in the bootstrap mechanism. But finally I saw an extension point (a “processor” to be precise) as root cause. This extension just threw away my key bindings. It eventually turned out to be the org.eclipse.ui.workbench plugin which I required in my application. This plugin defines a BindingToModelProcessor that simply throws away all key bindings within the org.eclipse.ui.contexts.dialogAndWindow Binding Context except those tagged with type:user.

That’s the solution. Simple as that. I added the tag to all my key bindings and they were not removed and working again. So be aware when adding org.eclipse.ui.workbench as a dependency plugin to your E4 application. 😉

Categories
Java

Eclipse E4: Using the TranslationService

This post demonstrates how the TranslationService from Eclipse/E4 can be used in real world applications. First, you need the translation files, bundle.properties (minimum) and e.g. bundle_de.properties for your special language:

myapp.key1 = A text.
myapp.key2 = Another text.

Store these files in OSGI-INF/l10n folder of your plugin. This way, the Eclipse/E4 translation service will find it.

Next, I recommend to have a static helper class that will retrieve the translation service from Eclipse/E4 and returns the translated keys. It could look like this:

public class E4Utils {
 
	public static final TranslationService TRANSLATIONS = getTopContext().get(TranslationService.class);
 
	/**
	 * Finds the top Eclipse context.
	 * @return the eclipse context.
	 */
	public static IEclipseContext getTopContext() {
		return E4Workbench.getServiceContext();
 
	}
 
	/**
	 * Translate the given key.
	 * @param key key to translate
	 * @param contributorUri the contributor URI of the translation
	 * @param args variable replacements (will replace {0}, {1},... placeholders)
	 */
	public static String translate(String key, String contributorUri, Object... args) {
		if (key == null) return "";
		if (key.charAt(0) != '%') key = '%'+key;
		String rc = TRANSLATIONS.translate(key, contributorUri);
		if ((args == null) || (args.length == 0)) return rc;
		return MessageFormat.format(rc, args);
	}
}

Thie helper class provides a method translate() which you pass in the key, the contributor URI of your plugin and any additional arguments. This method does a few things for me. It first checks whether the key starts with ‘%’ which is a requirement for the TranslationService. If this ‘%’ is missing, it will be added automatically. Also it will apply the MessageFormat pattern after translation so you can use more sophisticated translation patterns.

The key is very obvious the string that you mentioned in the bundle.properties file. The contributor URI is of form platform:/plugin/symbolicPluginName. The symbolic plugin name can be looked up in the MANIFEST file. To ease the usage of your helper class, create a Plugin class that adds all information required:

public class Plugin {
 
	public static final String SYMBOLIC_NAME = "rc.rcpplugins.e4";
	public static final String CONTRIBUTOR_URI = "platform:/plugin/"+SYMBOLIC_NAME;
 
	/**
	 * Translate the given key.
	 * @param key key to translate
	 * @param args variable replacements (will replace {0}, {1},... placeholders)
	 * @return translated value
	 */
	public static String translate(String key, Object... args) {
		return E4Utils.translate(key, CONTRIBUTOR_URI, args);
	}
}

Now we can use the translation service at any class in our Eclipse/E4 project. e.g:

	button.setToolTipText(Plugin.translate("myapp.key1"));

I implemented this scheme in all my E4 plugins now (with E4Utils as a central helper in a base plugin) and rapidly translated a medium-sized Eclipse/E4 application within a few hours.

PS: I will publish the base helpers soon as Open Source Eclipse/E4 plugins so you can just install them in your Eclipse instance.