May 24, 2013

Quick’n'dirty Apache Felix webconsole on (recent) Equinox

Below you find a instructions to install Apache Felix webconsole on a running Equinox. Just paste this into the console and start bundle “org.apache.felix.webconsole” and “org.eclipse.equinox.http.jetty” afterwards.

# On the OSGi console install the following bundles
# (optionally set -Dorg.osgi.service.http.port=9980 to change the default http port)
# “services org.osgi.service.http.HttpService” to check for correctly installed server and port

# common http server deps
install ftp://ftp.osuosl.org/pub/eclipse/tools/orbit/downloads/drops/R20130517111416/repository/plugins/org.apache.commons.io_1.4.0.v20081110-1000.jar
install ftp://ftp.osuosl.org/pub/eclipse/tools/orbit/downloads/drops/R20130517111416/repository/plugins/org.apache.commons.fileupload_1.2.2.v20111214-1400.jar

# equinox.http <= http servlet 2.1
#install ftp://ftp.osuosl.org/pub/eclipse/equinox/drops/R-3.7.2-201202080800/org.eclipse.equinox.http_1.0.500.v20110413.jar
#install ftp://ftp.osuosl.org/pub/eclipse/tools/orbit/downloads/drops/R20130517111416/repository/plugins/javax.servlet_2.4.0.v200806031604.jar

# equinox.jetty <= http server 2.4
install ftp://ftp.osuosl.org/pub/eclipse/releases/kepler/201305100900/plugins/org.eclipse.equinox.http.jetty_3.0.100.v20130327-1442.jar
install ftp://ftp.osuosl.org/pub/eclipse/releases/kepler/201305100900/plugins/org.eclipse.equinox.http.servlet_1.1.400.v20130418-1354.jar
install ftp://ftp.osuosl.org/pub/eclipse/releases/kepler/201305100900/plugins/org.eclipse.equinox.http.registry_1.1.300.v20130402-1529.jar
install ftp://ftp.osuosl.org/pub/eclipse/releases/kepler/201305100900/plugins/javax.servlet_3.0.0.v201112011016.jar
install ftp://ftp.osuosl.org/pub/eclipse/releases/kepler/201305100900/plugins/org.eclipse.jetty.servlet_8.1.10.v20130312.jar
install ftp://ftp.osuosl.org/pub/eclipse/releases/kepler/201305100900/plugins/org.eclipse.jetty.continuation_8.1.10.v20130312.jar
install ftp://ftp.osuosl.org/pub/eclipse/releases/kepler/201305100900/plugins/org.eclipse.jetty.util_8.1.10.v20130312.jar
install ftp://ftp.osuosl.org/pub/eclipse/releases/kepler/201305100900/plugins/org.eclipse.jetty.io_8.1.10.v20130312.jar
install ftp://ftp.osuosl.org/pub/eclipse/releases/kepler/201305100900/plugins/org.eclipse.jetty.http_8.1.10.v20130312.jar
install ftp://ftp.osuosl.org/pub/eclipse/releases/kepler/201305100900/plugins/org.eclipse.jetty.security_8.1.10.v20130312.jar
install ftp://ftp.osuosl.org/pub/eclipse/releases/kepler/201305100900/plugins/org.eclipse.jetty.server_8.1.10.v20130312.jar

# webconsole
install ftp://ftp.osuosl.org/pub/apache/felix/org.apache.felix.webconsole-4.0.0.jar

# Optionally
install ftp://ftp.osuosl.org/pub/apache/felix/org.apache.felix.webconsole.plugins.ds-1.0.0.jar
install ftp://ftp.osuosl.org/pub/apache/felix/org.apache.felix.webconsole.plugins.memoryusage-1.0.4.jar
install ftp://ftp.osuosl.org/pub/apache/felix/org.apache.felix.webconsole.plugins.event-1.0.2.jar

# Go to: http://admin:admin@localhost:9980/system/console/bundles

May 23, 2013
May 22, 2013

Custom touchpoints in p2

For most people, p2 is simply the Install  Software Dialog  in Eclipse. While this is certainly true (or at least the Install Software Dialog is built with p2), p2 is much more than this. The Eclipse Provisioning Platform (p2) is a general purpose platform for provisioning everything and nothing in particular.

Most of the out-of-the-box p2 tools are related to provisioning OSGi bundles (or Eclipse plug-ins, if you prefer), but there is nothing in the core that limits us to Eclipse or OSGi. In fact, you can extend p2 to install whatever you want. In this example I’ll show you how to create a custom Install Action (touchpoint) that executes an arbitrary binary during installation.

Background

When you use p2 to install software it goes through a number of steps.

  1. A provisioning plan is computed. Based on what you already have installed and the install action you’re taking, p2 computes a plan. The plan includes operands such as: remove foo, upgrade bar, install baz, etc..
  2. Artifacts are fetched and checked. Once a plan is constructed, the plan is executed on the p2 engine. The first step is fetching all the artifacts and the trust checking (checksum validation)
  3. Unconfigure / Uninstall. If there are any units being removed, they are given a chance to ‘unconfigure’ themsevles. Once this is done, they are uninstalled.
  4. Install / Configure. If there are any units being added, they are first installed and then they are given a chance to configure themselves.

For installable units being upgraded, this is essentially an unconfigure / uninstall followed by an instal / configure.

The Problem

p2 has a number of actions you can invoke when an installable unit (IU) is installed, configured, unconfigured or uninstalled. For example, artifacts can be unzippedcopied or the permissions can be set. These actions are called touchpoint actions. Eclipse has two sets of touchpoint actions, native and OSGi. Native ones are general (such as move, copy, mkdir) while the OSGi ones are Eclipse or OSGi specific (install bundle, set VM Args, etc…).

While these are a good start (and enough to provision an Eclipse system), often you need custom actions if you are provisioning a highly specific system. Also, not only do you need custom actions, you need them to be installed before they can be used.

Let’s consider the case where we want to ship and run an arbitrary executable during the installation of a plugin.

Touchpoint Actions

Custom touchpoint actions can be specified using the org.eclipse.equinox.p2.engine.action extension point. Touchpoint Actions are tied to a touchpoint, the controller responsible for executing the action. You can either write your own custom touchpoint, or simply tie your action to an existing one. In our case, we will tie our touchpoint action to the OSGi touchpoint.

Screen Shot 2013 05 22 at 3.43.23 PM Custom touchpoints in p2All touchpoint actions extend ProvisioningAction and provide two methods execute and undo. Execute is used whenever the provisioning action is invoked. Undo is used if the action needs to be rolled back. In our case we will implement execute to read a parameter and call Runtime#exec on the value of that parameter.

public IStatus execute(Map&lt;String, Object&gt; parameters) {
  String artifact = null;
  if ( parameters.containsKey(ARTIFACT) ) {
    // If an artifact is specified, look it up
  }
  String program = (String)parameters.get(PROGRAM);
  String fullPath = computeProgramPath(artifact, program);
  try {
    Runtime.getRuntime().exec(fullPath);
  } catch (IOException e) {
    e.printStackTrace();
    return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Cannot execute " + fullPath);
  }
  return Status.OK_STATUS;
}

The undo method (that is, the inverse of Runtime#exec) has been left as an exercise to the reader icon wink Custom touchpoints in p2 .

MetaRequirements

In order to ensure that  your touchpoints get installed before the components that need them, you can either invoke two updates (update the installer and then update the application) or you can use MetaRequirements. MetaRequirements invoke a two stage plan, ensuring that the touchpoints are fetched and installed before they are invoked.

MetaRequirements can be declared in a p2.inf file as follows.

metaRequirements.0.namespace=org.eclipse.equinox.p2.iu
metaRequirements.0.name=com.ianbull.p2.touchpoint.exec
metaRequirements.0.range=[1,2)

In this case we’ve specified a metaRequirement on the Installable Unit com.ianbull.p2.touchpoint.exec version [1.0,2.0). This Installable Unit must exist before our IU can be installed. For OSGi bundles, the p2.inf file should be placed next to the MANIFEST.MF file. In our case, it’s placed in a bundle called com.ianbull.p2.touchpoint.payload.

To summarize, before ‘payload’ can be installed, the touchpoint ‘exec’ must be installed and available. Since it’s declared as a metaRequirement, p2 will handle this by using a two-stage plan.

Invoking the Touchpoint

Now that we’ve created the touchpoint, all we need to do is invoke it. This is done by the Installable Unit which declares the metaRequirement. In our case, we will ship the executable as part of our ‘payload’ plugin.

We will use two touchpoints, one to set the permission (755) and then our custom touchpoint to launch the application.

instructions.install = \
chmod(targetDir:@artifact,targetFile:payload/someProgram,permissions:755);


instructions.install.import= \
org.eclipse.equinox.p2.touchpoint.eclipse.chmod

instructions.configure = com.ianbull.p2.touchpoint.exec.Execute(artifact:@artifact, program:payload/someProgram);

Putting it all Together

Once we have these two plugins (the ‘exec’ touchpoint and the ‘payload’) we create a repository that contains them both.

With the repository in place, we simply invoke the director, or better yet, the p2 Install Software Dialog to install the payload.

Screen Shot 2013 05 22 at 3.12.34 PM Custom touchpoints in p2

The payload doesn’t actually have any dependency on the ‘exec’ touchpoint, except for the MetaRequirement. This MetaRequirement will cause the ‘exec’ touchpoint to first be installed, and then the touchpoint can be invoked.

And now during installation, our custom application is started. While this particular application doesn’t do anything useful, it could be an installer for another tool, or it may simply invoke an existing service such as Apache HTTPD.

Screen Shot 2013 05 22 at 3.13.54 PM Custom touchpoints in p2

If you’re interested in the code examples I’ve used here, I’ve pushed them all to GitHub.


TwitterGoogle+LinkedInFacebook

Leave a Comment. Tagged with eclipse, p2, eclipse, p2

Testing Web Apps with Selenium and Jnario

As you might know Jnario is a new language for testing Java applications. Jnario takes the ideas of Cucumber and RSpec from the Ruby world to the Java world. At the same time, Jnario preserves the things we Java developers like so much: type safety and great tool support!

In this post I demonstrate how easy it is to write Cucumber style acceptance tests in Jnario. Jnario has some unique features, which makes writing given, when, then style scenarios a lot easier than in Cucumber or JBehave. I will show how to use Jnario by implementing a simple acceptance test for a web app using the browser automation tool Selenium. We will also cover more advanced topics such as how to encapsulate setup and teardown logic for scenarios and how to generate reports from your scenarios.

Jnario is a language specifically designed for testing based on Xtend. Xtend is a new language for the JVM featuring lambda expressions, type-inference, multi-line strings and more. The good thing about Xtend is that it uses the same type system as Java and compiles to readable Java code. This means when writing specs with Jnario, you can use all the goodness of Xtend resulting in less boilerplate code in your specs. Furthermore, Jnario is easy to integrate into existing Java projects, as specifications compile to plain Java JUnit tests.

Getting Started

First you need to install the Jnario tooling for Eclipse (if you haven’t already), the easiest way to do this is via the update site or the Eclipse Marketplace. Eclipse is not strictly required for this tutorial, but its going to be a lot more convenient.

We will be using Maven to manage our dependencies and to compile our specs. The easiest way to set up a new Jnario project using maven to use the Jnario Maven Archetype. If your are using the Maven tooling for Eclipse just create a new maven project and select the jnario-archetype:

Otherwise enter the following on the command line to create a new maven project:

$ mvn archetype:generate                                  \
  -DarchetypeGroupId=org.jnario                           \
  -DarchetypeArtifactId=jnario-archetype                  \
  -DarchetypeVersion=0.4.2                                \
  -DgroupId=org.jnario                                    \
  -DartifactId=selenium

Afterwards we have to add the selenium dependencies to our pom file:

   ...
   <dependencies>
    ...
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>2.32.0</version>
        </dependency>
        <dependency>
            <groupId>com.opera</groupId>
            <artifactId>operadriver</artifactId>
        </dependency>
    </dependencies>
  <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.opera</groupId>
                <artifactId>operadriver</artifactId>
                <version>0.18</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.seleniumhq.selenium</groupId>
                        <artifactId>selenium-remote-driver</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    </dependencyManagement>

That is all we need to do for setting up Jnario. You can verify whether everything works by running:

$ mvn clean install

This will compile and run the example specs in the new project. If the build is successful, we can safely delete the example files “src/main/org/jnario/selenium/HelloWorld.xtend” and “src/test/org/jnario/selenium/HelloWorld.spec” and get started.

Our first Scenario

To demonstrate how to use Jnario with Selenium, we will test a web app most of us should be familiar with: the Google Search. Our goal is to test, when we search for a certain keyword that the search result contains matching websites.

Jnario features two different languages for writing tests, one for unit tests and one for high-level acceptance tests similar to Cucumber. As the feature we are going to test is pretty high-level and can easily be understood by a non-technical stakeholder, we will be using the acceptance spec language. To create a new feature definition use the wizard via New File->Jnario->Jnario Feature:

Jnario feature files use a format similar to Cucumber with some small differences, which we will look into later. The basic idea is the same, to use Given, When, Then steps to describe simple scenarios. In our example, we establish the precondition in the Given step that we open Google search in a browser. In the following When step we search for the “Jnario” keyword. Afterwards, we describe in the Then step the expected outcome, namely, to find the Jnario slogan “Executable Specifications for Java” in our search results:

package org.jnario.selenium

Feature: Searching for web pages via Google

  In order to safe time
  As a developer
  I want to find web sites faster

  Scenario: Searching for Jnario

   Given I opened "http://www.google.com" in a browser
   When I search for "Jnario"
   Then the result should contain "Jnario - Executable Specifications for Java"

Note that we use quotes to define step parameters, such as "http://www.google.com". We will use this later, when we make our specification executable.

Executable Specification FTW

So far we have defined a simple acceptance criterion for our feature. We can already execute it as a JUnit test by right-clicking our feature file and selecting Run as->JUnit Test. It might be surprising, but our scenario passes already. The reason is that our scenario will be ignored by JUnit as we haven’t provided an implementation for our steps yet.

In Jnario you don’t need to define a separate parser for your scenarios. Instead, you can directly add the necessary execution logic into your scenarios. You can think of a scenario as a normal Java class where the scenario is the class and each step is a separate method. So, we can setup the selenium infrastructure by declaring two fields. One field contains the web driver and one the web driver wait util. The web driver is responsible for controlling and accessing the browser. The syntax for declaring fields is similar to Xtend:

  Scenario: Searching for Jnario
     val driver = new HtmlUnitDriver
     val wait = new WebDriverWait(driver, 30)

Now we need to make our Given step executable. We simply use the selenium API to retrieve a webpage via the web driver. Step parameters, such as the URL, can be accessed via the implicit variable args, which is a list of all parameter strings:

   Given I opened "http://www.google.com"
     driver.get(args.first)

The web search is performed using the driver’s findElement API. Note that in Jnario static members are accessed by :: instead of . as in Java:

   When I search for "Jnario"
     val searchBox = driver.findElement(By::name("q"))
     searchBox.sendKeys(args.first)
     searchBox.submit

Finally, we check whether the search results contain the expected string. As it can take a while until the browser returns our search result, we need to define a waiting condition. We use the WebDriverWait, which we declared as a field earlier.

The nice thing in Jnario is that instead of implementing the wait condition in an anonymous subclass, we can use Xtend’s lambda expressions. A lambda expression is declared within brackets and will be automatically converted into an instance of Function, which is required by WebDriverWait#until. Lambda expressions are one of the features making code written in Jnario/Xtend a lot more readable than plain Java code.

When the web page is returned on time, we retrieve the content of the webpage and assert that our expected string is contained. The assertion is written using Jnario’s should expressions. Finally, we clean up and close the browser via the web driver:

   Then the result should contain "Jnario - Executable Specifications for Java"
     wait.until[ findElement(By::id("resultStats")) != null ]
     val content = driver.findElement(By::tagName("body")).getText() 
     content should contain args.first
     driver.close

That’s all we need to do to make our scenario executable. We can now run it as a normal JUnit test and check whether the Google search really works as expected. Here is the complete definition of our feature:

package org.jnario.selenium

import org.openqa.selenium.By
import org.openqa.selenium.support.ui.WebDriverWait
import org.openqa.selenium.htmlunit.HtmlUnitDriver

Feature: Searching for web pages via Google

  ...

  Scenario: Searching for Jnario
     val driver = new HtmlUnitDriver
     val wait = new WebDriverWait(driver, 30)

   Given I opened "http://www.google.com"
     driver.get(args.first)

   When I search for "Jnario"
     val searchBox = driver.findElement(By::name("q"))
     searchBox.sendKeys(args.first)
     searchBox.submit

   Then the result should contain "Jnario - Executable Specifications for Java"
     wait.until[findElement(By::id("resultStats")) != null]
     val content = driver.findElement(By::tagName("body")).getText() 
     content should contain args.first
     driver.close

When you think now that your feature is no longer as readable as before, you might be right, but you can quickly change this by pressing Ctrl/Cmd + SHIFT + f in the editor to make the code magically disappear (and reappear).

Adding another Scenario

Let’s test whether Google search not only works for Jnario, but also for the Xtend homepage. In Jnario you can reuse existing steps and their implementation in other scenarios. So we can easily add another scenario based on our existing steps. We just change the parameters to search for xtend homepage instead.

Feature: Searching for web pages via Google

  ...

  Scenario: Searching for Jnario

    Given I opened "http://www.google.com" in a browser
    When I search for "Jnario"
    Then the result should contain "Jnario - Executable Specifications for Java"
   
  Scenario: Searching for Xtend

    Given I opened "http://www.google.com"
    When I search for "Xtend Lang"
    Then the result should contain "Xtend - Modernized Java"

The Jnario editor offers code completion via Ctrl + SPACE showing all available steps. Note how the keyword color varies in steps. It is green if the step has an implementation, red if no step with implementation exists and grey if another step with implementation exists.

Using Spec Extensions

There is one problem in the implementation of our scenario. We close the browser in our Then step. This makes it impossible to write tests like:

  Scenario: Searching for Something

    Given I opened "http://www.google.com"
    When I search for "Something"
    Then the result should contain "Something"
    And the result should contain "Something else"

When we execute the Then step a second time we won’t be able to retrieve the contents of the web page, as the driver is already closed. We need to move the closing of the driver into a separate tear down method. In Jnario this is supported via spec extensions. A spec extension encapsulates common helper method together with setup and tear down logic.

In our example, we create a new Xtend (or Java) class in which we extend the HtmlUnitDriver:

package org.jnario.selenium

import org.junit.After
import org.openqa.selenium.htmlunit.HtmlUnitDriver

class HtmlUnitDriverExtension extends HtmlUnitDriver {
    
    @After override void close(){
       super.close()
    }

}

We simply override the close method and add the JUnit @After annotation. This way we tell Jnario to execute this method after our scenario is performed. Now, we need to replace the HtmlUnitDriver in our feature with our HtmlUnitDriverExtension and add the additional extension keyword:

extension HtmlUnitDriverExtension driver = new HtmlUnitDriverExtension

Extensions are a Xtend feature which allows extending the behavior of objects without changing their class. In our example, it is now possible to call all driver methods directly without the field name. For example, we can now write:

val searchBox = findElement(By::name("q"))

instead of:

val searchBox = driver.findElement(By::name("q"))

This makes extension fields a great way to encapsulate testing helpers without adding additional syntactic noise to your tests! Here is our updated scenario:

package org.jnario.selenium

import org.openqa.selenium.By
import org.openqa.selenium.support.ui.WebDriverWait

Feature: Searching for web pages via Google

  ...

  Scenario: Searching for Jnario
     extension HtmlUnitDriverExtension driver = new HtmlUnitDriverExtension
     val wait = new WebDriverWait(driver, 30)

   Given I opened "http://www.google.com"
     get(args.first)

   When I search for "Jnario"
     val searchBox = findElement(By::name("q"))
     searchBox.sendKeys(args.first)
     searchBox.submit

   Then the result should contain "Jnario - Executable Specifications for Java"
     wait.until[findElement(By::id("resultStats")) != null]
     val content = findElement(By::tagName("body")).getText() 
     content should contain args.first

Getting things dry

Another thing, which could be improved in our feature definition, is that we define the same precondition in both scenarios. This is a duplication, which makes it harder to maintain our features in the future. We can avoid this by using background scenarios, similar to Cucumber. A background scenario defines steps to be executed before each scenario. Using a background, we can rewrite our scenario by moving the given step from both scenarios into a single background scenario:

package org.jnario.selenium

import org.openqa.selenium.By
import org.openqa.selenium.support.ui.WebDriverWait

Feature: Searching for web pages via Google

  ...

  Background:
     extension HtmlUnitDriverExtension  driver = new HtmlUnitDriverExtension
     val wait = new WebDriverWait(driver, 30)
     
   Given I opened "http://www.google.com"
     get(args.first)

  Scenario: Searching for Jnario

   When I search for "Jnario"
     val searchBox = findElement(By::name("q"))
     searchBox.sendKeys(args.first)
     searchBox.submit

   Then the result should contain "Jnario - Executable Specifications for Java"
     wait.until[findElement(By::id("resultStats")) != null]
     val content = findElement(By::tagName("body")).getText() 
     content should contain args.first

  Scenario: Searching for Xtend
     
    When I search for "Xtend Lang"
    Then the result should contain "Xtend - Modernized Java"

Generating a report

As we set up our project using maven, we can easily create HTML reports from our spec. The generated reports contain a nicely formatted HTML version of our feature and will also tell us which scenario passed and which failed. These reports are a great way to communicate the current state of a project with the stakeholders.

First we need to execute our spec via maven:

$ mvn clean test

Afterwards we can generate the HTML reports to target/jnario-doc via:

$ mvn org.jnario:report:generate

Summary

In this post we have seen how easy it is to write acceptance tests with Jnario. However, Jnario provides a lot more features than what we have covered in this post. If you want try Jnario or learn more about it, head over to the official page www.jnario.org. There is also a mailing list available for questions and discussions. You should follow me on twitter if you want to stay up-to-date with Jnario.

Eclipse Internationalization Part 2/4 – New Message Extension by Dirk Fauth and Tom Schindl

In my last blog post I explained the current available solutions for translating an Eclipse 4 application and what is wrong with them.

In this blog post I will show you a new solution for translating your Eclipse 4 application. This one is created as an OSGi service and gets rid of all the disadvantages of the existing solutions. The main idea and implementation was created by Tom Schindl, while I extended it to the current state, so we are writing this blog post together.

To use the services you need to install the latest E4 tools into your IDE or at least create a target-platform that contains the location to it. You could for example use the p2 update site for the E4 tools provided by vogella to get the latest version. (see here for more information http://www.vogella.com/blog/2013/03/12/eclipse-4-tools-update-sites-available-from-vogella/)

As the constant based solution has several benefits when used in combination with the tooling, e.g. code completion, refactoring and find references, the solution designed by Tom uses a similar approach. The big difference is, that it is not constant but member based. So using that solution is working on an instance of a message class, which means that it can be collected by the garbage collector if it is not referenced anymore and values can be changed at runtime.

Another advantage over the existing mechanisms is a more technical one. The existing translation mechanism in Eclipse is based on Java 1.4 and has some workaround code to deal with a special use case. What most people are not aware of is that the process on resolving a resource bundle is a little bit different than resolving a key out of a loaded resource bundle. Guess you have a loaded resource bundle for the locale de_DE, the search order for a key in that resource bundle looks like this:

  1. bundle_de_DE.properties
  2. bundle_de.properties
  3. bundle.properties

So it is searching from the most specific to the default bundle for that key. If the default bundle is configured to contain the English translations, if you missed to translate a key to German, the English one will be returned.

For resolving a resource bundle the process differs slightly with a huge impact. Guess you are running on a system that has the German locale set as default locale. Your application contains only the German and the default resource bundle files as shown above. What would you expect to get for translation if you set the application locale to fr_FR? Only knowing about the process above, you would expect to get the English translations out of the default resource bundle. But on resolving and loading the resource bundle, the default locale is used as fallback. So the following search order is used to resolve the bundle for fr_FR:

  1. bundle_fr_FR.properties
  2. bundle_fr.properties
  3. bundle_de_DE.properties
  4. bundle_de.properties
  5. bundle.properties

This means you will get the German translations on a German system if you try to localize your application to fr_FR and there are no such resource bundle files in your application.

In Equinox resolving the resource bundle was implemented like resolving keys without taking the default locale as fallback into account. That was reported and fixed a while ago (https://bugs.eclipse.org/bugs/show_bug.cgi?id=330602). A technical switch was introduced that allows to specify the equinox.root.locale as system property. If it is not set it will be treated as en by default. Now if the value for equinox.root.locale is en and the locale with language code en is requested, the default locale is not used as fallback.

Also the loading of resource bundles out of an OSGi bundle is a bit different because of the fragment support and the classloader per bundle. Using the Java 1.4 API dealing with all of these facts was quite difficult and caused the limitation that only properties based resource bundles are supported.

With Java 1.6 the ResourceBundle.Control class was introduced. It allows you to take control on how resource bundles are loaded, how the candidate locales are determined, e.g. using a fallback locale or not, and how the caching of the loaded resource bundles should be handled. The new message extension is based on Java 1.6 and makes use of this ResourceBundle.Control to deal with the described issues above in a more convenient way. Using the Java default mechanism instead of the custom workaround also enables the usage of class based resource bundles. The advantage of using class based resource bundles will be explained in the last blog post in this series.

To use the new message extension you need to add the org.eclipse.e4.tools.services bundle to the required plugins in your MANIFEST.MF. This bundle contains the OSGi services that are necessary for the new message extension and will give you access to two new annotations, @Message and @Translation.

To explain those annotations and their usage we first need to create the Messages class that will contain our translations.

public class Messages {
	public String label_message;
}

Comparing the implementation with the constant based OSGi NLS solution you will notice that

  • Messages is a POJO and does not implement or extend something
  • There are no constants but member variables
  • There is no static initialization block needed anymore

Now that we have the Messages class, we need to configure where to get the translation values that should be put into those member variables. As different developers have different opinions on where to put their resource bundles to, the new message extension supports a quite flexible approach to specify where the resource bundle files can be found. When processing the initialization, the mechanism searches for the resource bundle files in the following order:

  1. Check for a configuration via @Message annotation
    @Message(contributorURI=”...”)
    public class Messages {
    	public String label_message;
    }
  2. Check for resource bundle files with the same base name and in the same package as the Messages class
    NamedMessages
  3. Check for OSGi resource bundles configured in MANIFEST.MF
    If you placed your resource bundle files in OSGI-INF/l10n and named in bundle, there is nothing else you have to do

@Message annotation

The @Message annotation is optional and only necessary if you want to configure the location of the resource bundle files or the caching behaviour. To configure the location of the resource bundle files, you need to set the contributorURI parameter to the annotation. This parameter supports the following location patterns:

  • platform:/[plugin|fragment]/[Bundle-SymbolicName]
    Load the OSGi resource bundle out of the bundle/fragment named [Bundle-SymbolicName]
    For example:
    @Message(contributorURI="platform:/plugin/com.beone.e4.translation.extension")
    will load the OSGi resource bundle that is configured in the MANIFEST.MF of the com.beone.e4.translation.extension plugin
  • platform:/[plugin|fragment]/[Bundle-SymbolicName]/[Path]/[Basename]
    Load the resource bundle specified by [Path] and [Basename] out of the bundle/fragment named [Bundle-SymbolicName].
    For example:
    @Message(contributorURI="platform:/plugin/com.beone.e4.translation/resources/another")
    will load the resource bundle that is located in the folder resources/other in the com.beone.e4.translation plugin.
  • bundleclass://[plugin|fragment]/[Fully-Qualified-Classname]
    Instantiate the class based resourcebundle specified by [Fully-Qualified-Classname] out of the bundle/fragment named [Bundle-SymbolicName]. Note that the class needs to be a subtype of ResourceBundle.
    For example:
    @Message(contributorURI="bundleclass://com.beone.e4.translation/com.beone.e4.translation.resources.MockBundle")
    will load the class based resource bundle MockBundle in package com.beone.e4.translation.resources in the com.beone.e4.translation plugin.

Using the bundleclass contributorURI enables you to use class based resource bundles. What’s possible by implementing them will be explained in a later post.

While the constant based OSGi NLS translation mechanism had no chance to update the translation values at runtime and kept them in memory forever, you can specify the caching behaviour for messages in the new message extension. This is done by the referenceType parameter of the @Message annotation.

If the same translations are requested for injection at several places, for memory efficiency the same instance will be returned. This is achieved by internally caching the created instances as a SoftReference by default. As they are not hard references, once all requestors are garbage collected (e.g. the parts were closed) the message instance can be garbage collected as well. Using SoftReferences as default has the advantage that e.g. if a part is closed and opened again within a very short time, the message instance can be reused instead of being garbage collected and newly created. In case the default behavior does not suite your needs the @Message annotation provides the following caching/garbage collection strategies:

  • NONE: The message instance is not cached. Each requestor gets its own instance.
  • WEAK: The message instance is cached as a weak reference. If every requestor was garbage collected, the message instance is also discarded at the next garbage collection cycle.
  • SOFT: The message instance is cached as a soft reference. If every requestor was garbage collected, the message instance is not immediately discarded with the next garbage collection cycle, but will retain for a while in memory.

The strategy to use can be specified by setting the annotation parameter referenceType. The following for example will set the strategy to ReferenceType.NONE which means that every requestor will get its own instance of the messages class:

@Message(referenceType=ReferenceType.NONE)

@Translation annotation

After the messages class is created and connected to the resource bundle, it can simply be used by injecting the Messages instance with the @Translation annotation:

@Inject
@Translation
private Messages messages;
...
myLabel.setText(messages.label_message);

Compared with the TranslationService that is already available in Eclipse 4, you are injecting your Messages instance without the need to know the contributionURI of the containing bundle or the key of the translation you are requesting.

@PostConstruct annotation

With the latest implementation it is possibility to add methods annotated with @PostConstruct. Following the dependency injection rules, this method will be executed after the Messages instance is created. This allows you to use placeholders like with using the constant based NLS.bind() solution. Guess you have a property that looks like this:

my.label.message = {0} says {1}

You could initialize this property by adding a method annotated with @PostConstruct to your Messages class.

public class Messages {
	public String my_label_message;

	@PostConstruct
	public void format() {
		my_label_message = MessageFormat.format(
			my_label_message, "Dirk", "Cool");
	}
}

Note that the method annotated with @PostConstruct in the Messages class does not support parameters as it doesn’t support dependency injection at that place. This is quite the default behaviour when thinking of @PostConstruct in the JavaEE context. As @PostConstruct in Eclipse 4 generally supports dependency injection, we need to mention that in this special case it is not supported.

A small but personally huge improvement in properties key handling is the handling of the dot as property key separator. Using the constant based solution you need to use a separator that is valid within a Java variable, e.g. the underscore. This is because the dot is not valid as part of a field name and the binding from key to constant is directly without transformation. The new message extension at least supports the dot as key separator within the properties. So the properties can look like you know them from other Java frameworks. Of course you still can’t use it as separator in the fields. But as you can see in the example above, using the dot in the properties file is possible when using the underscore as separator in the Messages field.

Links:

Buckminster rmap to p2 (composite) repository metadata

ECF has been using an rmap to b3aggr xslt stylesheet for a while now, and today I needed a similar stylesheet to convert to p2 composite repositories (single sourcing repositories feed from Buckminster to the p2 director). It takes an rmap and spits out composite repository metadata referring to all http:// and ftp:// provider uris in the rmap. For an example check out this rmap and the generated metadata. As a generator use
xsltproc --stringparam timestamp $((`date +%s * 1000)) --stringparam repository file:///a/local/p2/repo/ rmap2compositeRepository.xsl my.rmap
In case anybody else needs it, here is the xslt stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:bm="http://www.eclipse.org/buckminster/RMap-1.0">
    <xsl:output method="xml" indent="yes" encoding="UTF-8"/>

    <xsl:strip-space elements="*"/>

    <!-- overwrite via parameters -->
    <xsl:param name="repository">file:///dev/null</xsl:param>
    <xsl:param name="title">vogella Packages Repository</xsl:param>
    <xsl:param name="timestamp">13691573970000</xsl:param>
    <xsl:param name="type">org.eclipse.equinox.internal.p2.artifact.repository.CompositeArtifactRepository</xsl:param>

    <xsl:template match="bm:provider">
        <!-- only accept public http|ftp repositories -->
        <xsl:if test="starts-with(bm:uri/@format, 'http://') or starts-with(bm:uri/@format, 'ftp://')">

                <!-- remove dangling ?importType=binary -->
                <xsl:choose>
                        <xsl:when test="contains(bm:uri/@format, '?importType=binary')">
                        	<child location="{substring-before(bm:uri/@format, '?importType=binary')}"/>
                        </xsl:when>
                        <xsl:otherwise>
                        	<child location="{bm:uri/@format}"/>
                        </xsl:otherwise>
                </xsl:choose>
        </xsl:if>
    </xsl:template>

    <xsl:template match="/">

            <repository name='&quot;{$title}&quot;' type='{$type}' version='1.0.0'>

              <properties size='2'>
                <property name='p2.compressed' value='true'/>
                <property name='p2.timestamp' value='{$timestamp}'/>
              </properties>
              <children>
                <child location='{$repository}'/>
                <!-- match all the child nodes of the template match=/ node -->
                <xsl:apply-templates/>
              </children>
            </repository>

    </xsl:template>

</xsl:stylesheet>
May 21, 2013

Remediation support, goodbye cryptic p2 dependency error message.

Thanks to the sponsoring of JBoss, you can now say goodbye to the cryptic dependency error messages. Indeed, starting with Eclipse Kepler, when p2 is not able to complete the requested installation, it proactively searches for alternate ways to help you proceed.This search for alternate solutions is done automatically as soon as p2 realizes that it can't proceed with the installation. No special

What happened at the Eclipse Stammtisch Zurich

Last week we had a great time at the Eclipse Stammtisch Zurich.

Eclipse Scout Talk

Eclipse Scout Talk

Ken Lee and Matthias Zimmermann presented Eclipse Scout. The motto this year: “Write your application once – run on rich, web and mobile”. Since last year Application written on top of the Eclipse Scout Framework can be rendered in a Browser with Eclipse RAP (Remote Application Platform). With Kepler this renderer was extended (model transformation, optimized components, optimized theme) to support mobile and tablets. Scout application can be rendered as web applications for those devices.

Xtext meets Orion Talk

Xtext meets Orion Talk

Holger Schill demonstrated his prototype that allows editing Xtext based DSL in web editors. It is based on Orion (with some modifications) and it uses some help of an Eclipse IDE running as a server (it calculates the editor behavior: quick tip, validations…). It was a really interesting talk, only one slide and a big demo.

Eclipse Orion Talk

Eclipse Orion Talk

Eclipse Orion: “It is not Eclipse in the browser; it is a new editor in the web (using the browser as a platform)”. That is what Mike Milinkovich explained during its talk. The demonstration was really impressive. The primary targeted programming languages are coming from the web (html, javascript, css…). It is really impressive, in comparison to the editor providing only syntax highlighting. You can try it online on orionhub.

Measure for Measure Talk

Measure for Measure Talk

The presentation of Werner Keil was about Eclipse UOMo, a project that ease the correct use of units in a Java project. This is particularly useful when different system communicate which each other. As illustration Werner choose the Shakespeare quote “Say what you will, my false outweighs your true”. Indeed, when not properly handled a system might define 32 liters, where another understands 32 gallons.

Democamp Zurich

We will be happy to meet the Eclipse Community in Zurich for the Kepler Democamp. It will take place on 27th June at the ETH main building.

Meet the Eclipse Scout team at the following other events.

Consuming emf bundles from p2 with maven : b3

Some of the eclipse libraries are not so thightly bound to OSGi and lately I wanted to use EMF in a grails project. It came to me that there are no current maven artifacts available for EMF, so I had to roll my own.

Asking stackoverflow, I first tried to re-jar the bundles with tycho, but that gave me all the OSGI-deps in one jar, what wasn't what I was looking for. After reding through some discussions around maven and p2 in the eclipse bugzilla, I noticed that b3 has the capability to mirror a p2 repository in a maven compliant layout.

As I wanted to use the xsd to ecore converter I created a aggregation for the xsd sdk
notice the maven config at the end of the aggregator tag.

https://gist.github.com/eiswind/5381710

Then I uploaded it to google drive, so that I can consume the repo from heroku build. One major drawback is, that the source bundles are not maven conformant, so that attaching them automagically won't work.

Building a custom RAP Widget based on Select2

This weekend a started to play aorund with new new RAP API introduced in 2.0. It really looks promising.

I started off with the CKEditor Example and created a combo-replacement based on Select2.js. By the way I had more a fight with the select2 api (that I didn't know) than with the rap api thats quite straightforward. I could answer nearly all of my questions from the source.

Here's the example for those who want to try:

It supports markup and (what I always miss on the standard combo) it has "clear selection". When you create it with SWT.MULTI it supports the cute Multiselect feature of select2.

https://gist.github.com/eiswind/5611873 java backend
https://gist.github.com/eiswind/5611866 js client

EMF Dos and Don´ts #10

EMF is a very powerful framework and with power comes…responsibility. You can achieve great things with a minimum of effort using EMF, but if something goes wrong, you can also spend hours trying to find out why. This blog post is part of a series on things you should do and things you should not do when using EMF. You can use the link to the series pilot to navigate to the start and the link below to navigate to the next blog once it is published.

EMF Dos #10: Use EMF ComposedAdapterFactory

In my previous blog post, I discussed AdapterFactoryLabelProvider and AdapterFactoryContentProvider, which can be used to provide labels and children for your entities in viewers. Both require an AdapterFactory in their constructors that will be used to retrieve the actual ItemProviders and their entity-specific implementation.

If you pass in the AdapterFactory of a specific model, the provider will only be able to provide labels for entities of the given model. However, viewers often need to display entities of multiple models. Of course, there is a solution to this with EMF: ComposedAdapterFactory.

A ComposedAdapterFactory is a composition of AdapterFactories, as the name implies. You can construct it with a collection of AdapterFactories, and it will delegate calls to adapt() to the resepective AdapterFactory based on the entity type. If you want to display multiple models in one viewer, you just combine all the models’ AdapterFactories into one ComposedAdapterFactory and pass it to the AdapterFactoryLabelProvider and AdapterFactoryContentProvider.

If you do not want to restrict your viewer to specific models but want to use all models available in your current target platform, you can pass in ComposedAdapterFactory.Descriptor.Registry.INSTANCE, which is the registry of all available AdapterFactories. By default, the  AdapterFactory of a generated Edit-Plugin is registered via the org.eclipse.emf.edit.itemProviderAdapterFactories extension point and thereby added to the aforementioned registry.

If the AdapterFactoryLabelProvider/AdapterFactoryContentProvider and the ComposedAdapterFactory are based on the registry, your viewers can be fully decoupled from the actual models they display while still providing customized icons, labels and content.

Stay tuned for more Dos and Don´ts in my next blog!


TwitterGoogle+LinkedInFacebook

2 Comments. Tagged with eclipse, emf, eclipse, emf

RFP 154 Network Interface Information Service now publicly available

Java standard APIs (i.e. java.net.NetworkInterface, java.net.InetAddress)provide functions that allow IP network interface information, such as the IPaddress and MAC address to be obtained.However, the bundle that wants to get network interface information has tomonitor whether the information has changed or not for a certain period oftime. Changes in network interface can be pushed to the
May 20, 2013

Another Xtend and JavaFX Story

For my spare time JavaFX project, I was looking for a way to export a scene to SVG. Googling a bit I stumbled over a blog entry by Gerrit Grunwald who implemented an JavaFX shape to SVG path converter class for the JFXtras project. It looked good so I decided to give it a try.

 

Java to Xtend

The class is of course written in Java. Even though there is no technical reason - Java and Xtend classes can coexist in the same project without any problems - I wanted to convert it to Xtend as well. I am a lazy guy. Luckily Krzysztof Rzymkowski had recently posted on the Xtend group that he had started to implement a Java to Xtend converter. It even has a web interface, and except for one slight issue with a for-loop it worked like a charm. Great work, Krzysztof!

Of course the resulting code is pretty Java-like, so I wanted to improve on it using more of the cool Xtend features. I found quite a few spots to do so, reducing the amount of code significantly and enhancing readability a lot. The remainder of this post is about this ongoing love of JavaFX and Xtend. The complete source code will likely be made open-source soon.

 

Dispatch Methods

The class starts with a method that only contains an instanceof-cascade to delegate to the conversion method for the specific subclass of Shape the parameter has:
public static String shapeToSvgString(final Shape SHAPE) {
   final StringBuilder fxPath = new StringBuilder();
   if (Line.class.equals(SHAPE.getClass())) {
      fxPath.append(convertLine((Line) SHAPE));
   } else if (Arc.class.equals(SHAPE.getClass())) { 
      fxPath.append(convertArc((Arc) SHAPE)); 
   } else if (QuadCurve.class.equals(SHAPE.getClass())) {
      fxPath.append(convertQuadCurve((QuadCurve) SHAPE));
   } ...
In Xtend I can use dispatch methods to realize this: They must have the same method and number of parameters, but different parameter types. The Xtend compiler then generates the dispatcher method with the instanceof-cascade automatically. So renaming the delegate methods and marking them as dispatch made the dispatcher method obsolete.
def dispatch String toSvgString(Line line) ...
def dispatch String toSvgString(Arc arc) ...
def dispatch String toSvgString(QuadCurve quadCurve) ...
Tip: If you want to delegate from one dispatch case to another, the original methods are available with an underscore preceeding their name.

Templates

An SVG path is kind of a cryptic string. In the Java code it is assembled using a StringBuilder, e.g.
final StringBuilder fxPath = new StringBuilder();
fxPath.append("M ").append(CENTER_X).append(" ")
.append(CENTER_Y - RADIUS).append(" ");
fxPath.append("C ")
.append(CENTER_X + CONTROL_DISTANCE)
.append(" ").append(CENTER_Y - RADIUS).append(" ")
.append(CENTER_X + RADIUS).append(" ")
.append(CENTER_Y - CONTROL_DISTANCE)
.append(" ")
.append(CENTER_X + RADIUS).append(" ")
.append(CENTER_Y).append(" ");
...
That's the best you can do with Java. In Xtend we have template expressions - multiline strings which can be interrupted with values from expressions. Even IF-conditions and FOR-loops are supported. With carefully chosen regular expressions for find/replace and some manual fine-tuning the above becomes nicely readable
'''M «centerX» «centerY - radius»
   C «centerX + controlDistance» «centerY - radius»
   «centerX + radius» «centerY - controlDistance»
   «centerX + radius» «centerY»
...

Switch Expression

I found another finer-grained instanceof-cascade in the convertPath method:
final StringBuilder fxPath = new StringBuilder();
for (PathElement element : PATH.getElements()) {
if (MoveTo.class.equals(element.getClass())) {
fxPath.append("M ")
.append(((MoveTo) element).getX()).append(" ")
.append(((MoveTo) element).getY()).append(" ");
} else if (LineTo.class.equals(element.getClass())) {
fxPath.append("L ")
.append(((LineTo) element).getX()).append(" ")
.append(((LineTo) element).getY()).append(" ");
} else if (CubicCurveTo.class.equals(element.getClass())) {
fxPath.append("C ")
...
As the bodies of the if-statements are so simple, I decided to use Xtend's switch instead. It allows to use type guards for the cases and automatically cast the switch variable to that type inside the case's body:
val it = new StringBuilder
for (element : path.elements) {
   switch element {
      MoveTo: append('''M «element.x» «element.y» ''')
      LineTo: append('''L «element.x» «element.y» ''')
      CubicCurveTo: append('''C «element.controlX1»...
I could further use the operator => instead of the Builder class and the operator <=> replacing Double.compare.

Extension Import (Client Side)

From a client side, the shapeToSvgString method is a utility method for Shapes. In Xtend, you can import such methods using a static extension import. That makes them callable in extension syntax, as if the method was defined in the class of the first parameter. To further improve readability, I renamed the methods to toSvgString such that I can now write
import static extension ...ShapeConverter.*
...
new Rectangle.toSvgString

Moving to a Mac

With my new gig at Talend I have requested a MacBook Pro as a company computer, thinking that since I’m now an architect I will have to do more writing and (god forbid) slides. Of course I will continue to develop software, both for the company and in my open source work. For years, my preferred development platform has been Unix (shows how old I am, I really mean Unix) or Linux. And I have had to work on all three of Windows, Linux and the Mac to test my software. Though I had a Mac, I did not work on it very much. Thanks to Eclipse things just worked there pretty well, I only had a few Mac-specific issues.

So I started to move everything to the Mac and I was shocked at how good it was. Really just good. Everything just feels better than the Ubuntu GUI that I was using (Gnome 3 — I just could not deal with Unity). I spent the money and got the Thunderbolt display and it’s just amazing, so big and clear, and it is essentially a docking station. Everything works fine with my odd keyboard and mouse.

Unfortunately, there is an Eclipse SWT issue (it looks like) which is preventing me from running all 3000 or so of the data transformation unit tests on the Mac, so I have spent a couple of days working on characterizing it, and the thing that I found really shocking about the Mac was Instruments. I could get a ton of profiling information from a running program with an amazing GUI with no effort. By combining this with JProfiler, I should be able to get what I need to characterize (and even possibly fix) this leak problem.

I have never considered having Windows as my daily machine, and now that I have had the Mac, I’m never going back. It’s just that good.


Now at Talend

After many years of leading Oakland Software to develop really good data transformation technology, I have moved to a new phase, having sold these assets to Talend. A little while ago, I joined Talend as a Senior Architect responsible for data transformation as well as other cross product issues and I’m very excited to be part of this team of extremely bright and talented folks.

For quite a while now the Oakland Data Transformer has worked well with the Talend ESB runtime technologies, and now that it’s part of Talend we will work on integration at the Talend Open Studio level for a future Talend release. You will hear more about that as the work progresses.

I am very grateful to the open source community, mostly to my friends at Eclipse on which my product is based. It would not have been possible to make such a high functionality and robust product without the extensive infrastructure provided by Eclipse to do such things. I think however that the most important part of Eclipse is the culture. It’s a culture of openness, mutual respect, and encouragement. People are encouraged to be nice, helpful, and not at all arrogant and this is the case with everyone I have worked with there over the years. It’s been an amazing experience being part of it and I hope to continue my small contributions to Eclipse.


Jenkins EC2 work

About a year ago, I have gotten involved pretty extensively in the Jenkins EC2 plugin where I’m now the maintainer. This was motivated by wanting to move my company’s (Oakland Software — now mostly part of Talend) build process to EC2 and finding out that it was simply not possible unless some significant work was done on the plugin. Seeing that the plugin was missing an active maintainer, I requested the responsibility (which was quickly granted as it the custom in Jenkins).

I have done 3 major releases in the last year with both contributions originated by me and from many members of the community adding significant features like:

  1. Support stopping instead of terminating instances
  2. Allow the use of EC2 spot instances
  3. Proper support for multiple clouds
  4. Greatly increase the accuracy and reliability of starting and stopping instances and adhering to limits
  5. Many bug fixes

I remain active with this project and working closely with several members of the Jenkins community to improve it. With these improvements the plugin has become more popular gaining nearly 200 new installations in the past year.

In addition to coordinating and helping with contributions, I would like to start a conversation about looking the new Google Compute Engine service, which is similar to EC2. We should be able to leverage what we have learned in the EC2 plugin and to the refactoring necessary to cleanly support the Google service in addition to Amazon’s. Ideas and contributions are welcome.


May 17, 2013

Remove “Build path specifies execution environment…” warnings from Problems View

I have often workspaces with projects which specify Java 1.5 as minimal execution environment. On my machine there is no JDK 1.5 installed, and it turns out that getting one for Mac OSX Mountain Lion is not trivial. Actually I don’t need a JDK 1.5, since the standard 1.6 JDK is compatible. However, this raises in the workspace these annoying warnings.

screenshot 2013-05-17 um 10.32.31

In the Execution Environments setting it is possible to mark the Java 1.6 installation as compatible to the J2SE-1.5 Execution Environment:

screenshot 2013-05-17 um 10.52.31

Although the JDK 1.6 is marked compatible now, it is not “strictly compatible”, so the warning message remains.

Next you could try to disable the warning message. There is a setting for this in the preference dialog Java/Compiler/Building:

screenshot 2013-05-17 um 10.35.17

After changing the setting you are asked to rebuild the projects. But again, the warning do not disappear. I suspect this to be a bug and raised Bug#408317 for this.

So the last chance is to filter these warnings. Therefore select the options menu in the Problems View and open the “Configure Contents” dialog. In the “Types” selection tree expand the “Java Build Path Problems” node and uncheck “JRE System Library Problem”.

screenshot 2013-05-17 um 11.03.53

Finally the warning messages disappear from the Problems View. However, they are just filtered from the view, the projects themselves will still have these resource markers, so you will have a warning overlay icon on the project in the Package Explorer View although the Problems View might be empty.

But this raises the next problem: Now the warning disappears and the code is compiled with Java 1.6, and thus against the 1.6 API. This leads to the problem that you could accidently use API from >= 1.6. For example, usage of String#isEmpty() would compile even if the Execution Environment is set to J2SE-1.5 (the Execution Environment anyway just defines the lowest requirement) and also if Java source compatibility is set to 1.6 in the compiler settings.

We need to detect this unwanted use of API that is not 1.5 compatible. Therefore the PDE tooling offers support to install an Execution Environment Description for J2SE-1.5 and set up API tooling. This will finally allow us to detect illegal API use:

screenshot 2013-05-17 um 14.00.15

I like to thank Laurent Goubet and Mikael Barbero for their valuable comments on the potential API problems.


Android Studio: our new, shiny Android IDE

The cat is out of the bag: yesterday, during Google I/O‘s keynote, we announced our new IntelliJ IDEA-based Android IDE, Android Studio. This is what my team has been working on for the past months.

From what I read on the web, Android Studio has been pretty well received. I personally heard nice comments about it, from “awesome!” to “fantastic!” and “really cool.”

Here are some highlights about Android Studio. I’ll be writing more detailed blogs about our IDE soon. Before I continue, let me make this clear:

This is a personal blog. The opinions expressed here represent my own and not those of my employer, Google.

With that out of the way, here we go:

Our goal is to be Gradle-centric

We are working closely with the Gradleware folks on a new Gradle-based build system. Right now, with Android Studio, you can create new Gradle-based Android projects or import existing ones. When you build your project in Android Studio, we disable the default IDEA Java builders and delegate the build to Gradle. You get the same output from building within Android Studio or from the command line. Our goal is to have Gradle build files as the only source of truth.

This is an early access preview

Even though it is possible to create applications with Android Studio, there are still rough corners, bugs and features that we have not implemented yet. It would be great to get as many bug reports and feature requests from early adopters. Here is the list of known issues.

We still support Eclipse

We will be supporting Eclipse ADT as well. In fact, we plan to add similar Gradle support to ADT. The catch here is that given limitations in Eclipse, especially JDT, we cannot guarantee a development experience as smooth as Android Studio. You can, however, export your Eclipse-based Android project as a Gradle project, and then import it into Android Studio.

This is not a fork of IntelliJ IDEA

We have been working, and continue to work, really close with JetBrains, the folks behind the best Java IDE, IDEA. They implemented the changes we needed in their platform in order to develop Android Studio. Eventually, you will be able drop Android Studio as a plug-in into your copy of IDEA.

That’s it for now. Stay tuned for more Android Studio posts :)

Update: Xav‘s and Tor‘s Google I/O talk “What’s New in Android Developer Tools” is on YouTube!

May 16, 2013

EMF Dos and Don´ts #9

EMF is a very powerful framework and with power comes…responsibility. You can achieve great things with a minimum of effort using EMF, but if something goes wrong, you can also spend hours trying to find out why. This blog post is part of a series on things you should do and things you should not do when using EMF. You can use the link to the series pilot to navigate to the start and the link below to navigate to the next blog once it is published.

EMF Dos #9: Use EMF ItemProviders

To display entities in a tree view or in other views, you need a label provider and a content provider. The label provider provides an icon and a text to display each entity type. The content provider defines the children of an entity. Additionally, the label and content providers need to notify their viewers if the label or content changes due to data changes. The viewers will update only if there are data changes. You could implement the label and content providers manually, which is a lot of work, or you can rely on EMF-generated infrastructure.

For every entity defined in your Ecore, EMF will generate an ItemProvider in the Edit-Plugin. The ItemProvider implements methods to get an icon and a text for the entity (getText() and getImage()). Since you want to display all kinds of entities in a tree view, you need to create a label provider that will know the type of your entity and use the matching ItemProvider to retrieve a text and an icon. This label provider needs to implement  the ILabelProvider interface. Similarly, a content provider would have to implement the ITreeContentProvider interface and define the children for all the different kinds of entities. For this purpose, EMF provides a fully functional label and content providers: AdapterFactoryLabelProvider and AdapterFactoryContentProvider. They both work in the same way,  so I will focus on the AdapterFactoryLabelProvider.

Conceptually, an AdapterFactoryLabelProvider is able to provide labels for all supported entities by delegating to the appropriate generated ItemProviders. Technically, the AdapterFactoryLabelProvider requires an AdapterFactory to do this (see the constructor). An AdapterFactory creates adapters (wrappers) for a given entity. For each EMF model, EMF generates an AdapterFactory for the ItemProviders of its entities. Basically, the adapt() method of the AdapterFactory returns the appropriate ItemProvider for a specific  entity.

To construct an AdapterFactoryLabelProvider,  you can pass in the AdapterFactory of your model, and the label provider will be able to display your entities based on their ItemProviders.

If you want to display entities from multiple models you can use a ComposedAdapterFactory, which I will describe in my next blog.

The AdapterFactoryLabelProvider will —  with the help of the ItemProviders — update its viewers if any of the entities it provided a label for change. Furthermore, the AdapterFactoryLabelProvider is very loosely coupled to the ItemProviders that implement entity-specific display behaviour.

Since the ItemProviders are generated (but can be adapted if necessary), the AdapterFactoryLabelProvider and AdapterFactoryContentProvider really are a big productivity boost in displaying EMF-based entities in your viewers.

Stay tuned for more Dos and Don´ts in my next blog!

 


TwitterGoogle+LinkedInFacebook

Leave a Comment. Tagged with eclipse, emf, eclipse, emf

Inactive Blogs