22 January 2011

Transparent Asynchronous Remoting

The Scenario

A client needs to invoke a service interface with the following restrictions:
  • The service implementation is running on a remote machine.
  • This fact is transparent to the client, i.e. any service method invocation is just like a local method invocation.
  • The service methods are executed asychronously on the server, method invocations on the client return immediately (fire-and-forget).
  • All service methods have void return types.

The Solution with Java EE 6

With Java EE 6, the solution is quite simple, thanks to the @Asynchronous annotation introduced in EJB 3.1. You simply create a remote session bean and add this annotation to any business method or to the entire class. The container will then execute the given methods asynchronously.

Patrick Champion has a complete example in his blog, so there's no need for me to provide any sample code.

When your client is also a Java EE 6 application, you can simply @Inject the service interface and use a @Produces annotation on an @EJB reference somewhere else to direct the client to the appropriate implementation.

In addition, to avoid hardcoding the service URL in your client, you should define a local JNDI alias in your Java EE 6 container for the address of the remote service implementation, so you can move the remote implementation to another host without recompiling your client.

The Solution with Spring 3.0

Spring does not have an out-of-the box solution for this scenario. Spring Remoting provides transparent proxies for remote services, but these proxies are always synchronous. Since Spring 3.0, there annotation support for asynchronous execution, but this only applies to local beans.

However, it is not hard to combine these two features with some glue code to implement a solution for our scenario.

18 January 2011

reFit: Acceptance Testing for Java EE 6, Spring and OSGi

Even if you don't practice test-driven development, you are certainly familiar with the JUnit family of testing frameworks (including ports to other languages like cppunit, NUnit, or independent but similar approaches like TestNG).

This post is about the Fit framework family, which has a somewhat different focus and is not just another JUnit clone. In a nutshell, Fit represents expected and actual test results in tables, and you do not have to be a programmer to read or write them.

The following table has one column of inputs and two columns of outputs:

Each row of this table can be regarded as an acceptance test case. You can feed this table to a given system and compare the outputs:

It's only a couple of weeks ago I was introduced to Fit in my current project, and I must admit my first thought was "Why don't you just write a @Parameterized JUnit test?"

The answer is, JUnit is for developers, and developers only; Fit is for customers and developers.

You still need a developer to implement the skeleton logic of a test (called fixture in Fit), but anyone can write new test cases by adding rows or columns to a given Fit table.

The Fit method and the original Java implementation were created by Ward Cunningham in or around 2002, the project is hosted on Sourceforge and has been inactive since 2008.

The Fitnesse project integrates Fit with a Wiki, it includes a modified version of the original Fit implementation and is under active development. However, Fit and Fitnesse are incompatible, Fit lets you write your test tables in plain old HTML, whereas Fitnesse supports its own Wiki syntax only.

Our project has a fair amount of plain old HTML Fit tests, and our production code uses Spring, so it was a fairly natural idea to inject Spring beans from the system under test into our Fit test code.

Spring is just one (and not really my favourite) framework for dependency injection (and lots of others things). so I inevitably started thinking about how to use Fit together with Java EE or OSGi.

Thinking was followed by coding (yeah, it can be the other way round sometimes...), and this led to a project called reFit hosted on Google Code.

reFit is based on the latest Fit sources from SourceForge, it provides up-to-date Maven artifacts on Maven Central and integrations with Java EE 6, Spring and OSGi Declarative Services. The Java EE integration reuses parts of my jeeunit project.

In addition, reFit lets you run Fit tests under a JUnit wrapper or from a Maven plugin, both with or without Spring integration. reFit includes ready-to-run example code for Glassfish 3.1, Spring 3, Equinox and Weld SE.

There's more to come, I'm currently experimenting with a Web frontend and a WYSIWYG HTML editor.

For more details, check out the reFit Wiki.

04 January 2011

Eclipse Meta-Error

01 January 2011

Maven Plugin Inheritance

Writing Plugins for Maven is not hard, and Maven: The Complete Reference has an entire chapter on this subject. Of course, nothing is ever complete in real life or in software development, and one of the topics not covered in the book is plugin inheritance.

The scenario:
  • There is a (fictitious) maven-tea-plugin which takes a number of configuration parameters and has a tea goal. It is implemented by a TeaMojo.
  • You are writing a maven-greentea-plugin which has almost but not quite the same behaviour as the maven-tea-plugin. It takes the same parameters and has the same goals.
  • The natural idea is to derive a GreenTeaMojo from the TeaMojo and to override one or two methods of the base class, reusing all the parameters.
Unfortunately, this does not work, at least not out of the box. The problem is:
  • Maven uses poor man's Javadoc annotations to inject configuration parameters into Mojo classes.
  • This is still true in Maven 3.0, even though the traditional Plexus container has now been replaced by Guice.
  • The maven-plugin-plugin (i.e. the plugin responsible for plugin building) needs to scan the Mojo sources for Javadoc annotations, but the maven-tea-plugin sources are not visible during the build of the maven-greentea-plugin.
Now the maven-inherit-plugin from OPS4J fills the gap by looking up the plugin descriptor from the maven-tea-plugin and merging it with any additional parameters defined in the maven-greentea-plugin. To use it, just follow the documentation.

There is just one point to note: You have to add an @extendsPlugin annotation to your GreenTeaMojo to indicate the plugin you want to extend, but the value of this annotation is not quite obvious. It has to be either the plugin artifact id, or the plugin short name, tea in our case, but this requires the artifact id to be maven-tea-plugin or tea-maven-plugin.