Monday, November 18, 2019

Jakarta Microprofile REST Client in Eclipse

Today we are going to implement a simple REST client for an Eclipse RCP application. Now with Jakarta @ Eclipse and all these nice Microprofile implementations this should be a piece of cake, right? Now lets see...

Source code for this tutorial is available on github as a single zip archive, as a Team Project Set or you can browse the files online.

Step 1: Dependencies

The Eclipse Microprofile REST Client repository is a good place to get started. It points to several implementations (at the bottom of the readme). Unfortunately these implementations do not host any kind of p2 sites which we could use directly. So our next stop is Eclipse Orbit, but same situation there. This means we need to collect our dependencies manually.

For my example I used RESTEasy, simply as it was the only one I could get working within reasonable time. To fetch dependencies, download the latest version of RESTEasy. As the RESTEasy download package does not contain the REST client API, we need to fetch that from another source. I found it in the Apache CXF project, so download the latest version too. If you know a better source, please let me know in the comments.

Now create a new Plug-in from Existing JAR Archives. Click on Add External... and add all jars from resteasy-jaxrs-x.y.z.Final/lib/*.jar. Further add apache-cxf-x.y.z/lib/
This plug-in now contains all dependencies we need for our client. Unfortunately also a lot of other stuff we probably do not need, but we leave the cleanup for later.

Step 2: Define the REST service

For our example we will build a client for the Petstore Service, which can be used for testing purposes. Further it provides a swagger interface to test the REST calls online. I recommend to check out the API and play with some commands online and with curl.

Lets write a simple client for the store with its 4 commands. The simplest seems to be the inventory command, so we will start there. Create a new Java interface:
package com.codeandme.restclient.resteasy;


public interface IStoreService {

 Response getInventory();
Everything necessary for RESTEasy is provided via annotations:

  • @Path defines the path for the command of the REST service
  • @GET defines that we have to use a GET command (there exist annotations for POST, DELETE, PUT)
  • @Produces finally defines the type of data we do get in response from the server.
Step 3: Create an instance of the service

Create a new class StoreServiceFactory:
package com.codeandme.restclient.resteasy;


import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl;

public class StoreServiceFactory {

 public static IStoreService createStoreService() throws URISyntaxException {
  ResteasyClient client = new ResteasyClientBuilderImpl().build();
  ResteasyWebTarget target = URI(""));
  return target.proxy(IStoreService.class);

This is the programmatic way to create a client instance. There also exists another method called CDI, which I did not try out in Eclipse.

The service is ready and usable, so give it a try. The result object returned does contain some valuable information:

  • getStatus() provides the HTTP response status. 200 is expected for a successful getInventory()
  • getEntity() provides an InputStream which contains the JSON encoded response data from the server
Step 4: Response decoding

Our response is encoded as JSON collection of properties. In Java terms this basically reflects to a Map<String, String>. Instead of decoding the data manually, we let the framework do it for us:

Change the IStoreService to:

 Map<String, String> getInventory();
Anything else is done by the framework. Now how easy was that?

Step 5: POST request

To place an order we need order parameters. Best we encapsulate them in a dedicated Order class. From the definition of the order REST call we can see that we need following class properties: id, petId, quantity, shipDate, status, complete. Add these parameters as fields to the Order class and create getters/setters for them.

Now we can extend our IStoreService with the fileOrder() call:

public interface IStoreService {

 Map<String, String> getInventory();

 void fileOrder(Order order);

The Order automatically gets encoded as JSON object. No need for us to do the coding manually!

As parts of the path are the same for both calls, I moved the common component to the class level.

Step 6: Path parameters

To fetch an order we need to put the orderId in the request path. Coding of such parameters is put in curly braces. The parameter on the java call then gets annotated so the framework knows which parameter value to put into the path:

 Order getOrder(@PathParam("orderId") int orderId);

Again the framework takes care of the decoding of the JSON data.

Step 7: DELETE an Order

Deleting needs the orderId as before:

 void deleteOrder(@PathParam("orderId") int orderId);

The REST API does not provide a useful JSON response to the delete call. One option is to leave the response type to void. In case the command fails, an exception will be thrown (eg when the orderId is not found and the server returns 404).

Another option is to set the return type to Now we do get everything the server sends back and no execption is thrown anymore. Sometimes we might only be interested in the status code. This can be fetched when setting the return type to Response.Status. Again, no exception will be thrown on a 404.

Optional: Only have required RESTEasy dependencies

Looking at all these jars I could not figure out a good way to get rid of the ones unused by the REST client. So I provided unit tests for all my calls and then removed dependencies step by step until I found the minimal set of required jars.

Monday, July 8, 2019

Building UIs with EASE

You probably used EASE before to automate daily tasks in your IDE or to augment toolbars and menus with custom functionality. But so far scripts could not be used to build UIs. This changed with the recent contribution of the UI Builder module.

What it is all about
The UI Builder module allows to create views and dialogs by pure script code in your IDE. It is great for custom views that developers do not want to put into their products, for rapid prototyping and even for mocking.

The aim of EASE is to hide layout complexity as much as possible and provide a simple, yet flexible way to implement typical UI tasks.

Example 1: Input Form
We will start by creating a simple input form for address data.

loadModule("/System/UI Builder");
createView("Create Contact");

createLabel("First Name:");
var txtFirstName = createText();
createLabel("Last Name:");
var txtLastName = createText();
This snippet will create a dynamic view as shown below:
The renderer used will apply a GridLayout. By setting the columnCount to 2 we may simply add our elements without providing any additional layout information - a simple way to create basic layouts.

If needed EASE provides more control by providing layout information when creating components:

createView("Create Contact");
createLabel("First Name:", "1/1 >x");
var txtFirstName = createText("2-4/1 o!");
createLabel("Last Name:", "1/2 >x");
var txtLastName = createText("2-4/2 o!");
Creates the same view as above, but now with detailed layout information.
As an example "1/2 >x" means: first column, second row, horizontal align right, vertical align middle. A full documentation on the syntax is provided in the module documentation (Hover over the UI Builder module in the Modules Explorer view).

Now lets create a combo viewer to select a country for the address:
cmbCountry = createComboViewer(["Austria", "Germany", "India", "USA"])
Simple, isn't it?

So far we did not need to react on any of our UI elements. Next step is to create a button which needs some kind of callback action:
createButton("Save 1", 'print("you hit the save button")')
createButton("Save 2", saveAddress)

function saveAddress() {
 print("This is the save method");
The first version of a button adds the callback code as string argument. When the button gets pressed, the callback code will be executed. You may call any script code that the engine is capable of interpreting.

The second version looks a bit cleaner, as it defines a function saveAddress() which is called on a button click. Note that we provide a function reference to createButton().

View the full example of this script on our script repository. In addition to some more layouting it also contains a working implementation of the save action to store addresses as JSON data files.

Interacting with SWT controls

The saveAddress() method needs to read data from the input fields of our form. This could be done using
var firstName = txtFirstName.getText();
Unfortunately SWT Controls can only be queried in the UI thread, while the script engine is executed in its own thread. To move code execution to the UI thread, the UI module provides a function executeUI(). By default this functionality is disabled as a bad script executed in the UI thread might stall your Eclipse IDE. To enable it you need to set a checkbox in Preferences/Scripting. The full call then looks like this:
var firstName = executeUI('txtFirstName.getText();');

Example 2: A viewer for our phone numbers

Now that we are able to create some sample data, we also need a viewer for our phone numbers. Say we are able to load all our addresses into an array, the only thing we need is a table viewer to visualize our entries. Following 2 lines will do the job:
var addresses = readAddresses();
var tableViewer = createTableViewer(addresses)
Where readAddresses() collects our *.address files and stores them into an array.

So the viewer works, however we need to define how our columns shall be rendered.
createViewerColumn(tableViewer, "Name", createLabelProvider("getProviderElement().firstName + ' ' + getProviderElement().lastName"))
createViewerColumn(tableViewer, "Phone", createLabelProvider("getProviderElement().phone"))
Whenever a callback needs a viewer element, getProviderElement() holds the actual element.
We are done! 3 lines of code for a TableViewer does not sound too bad, right? Again a full example is available on our script repository. It automatically loads *.address files from your workspace and displays them in the view.

Example 3: A workspace viewer

We had a TableViewer before, now lets try a TreeViewer. As a tree needs structure, we need to provide a callback to calculate child elements from a given parent:
var viewer = createTreeViewer(getWorkspace().getProjects(), getChildren);

function getChildren() {
 if (getProviderElement() instanceof org.eclipse.core.resources.IContainer)
  return getProviderElement().members();
 return null;
So simple! The full example looks like this:
Example 4: Math function viewer

The last example demonstrates how to add a custom Control to a view.
For plotting we use the Charting module that is shipped with EASE. The source code should be pretty much self explanatory.

Some Tips & Tricks

  • Layouting is dynamic.
    Unlike the Java GridLayout you do not need to fill all cells of your layout. The EASE renderer takes care to automatically fill empty cells with placeholders
  • Elements can be replaced.
    If you use coordinates when creating controls, you may easily replace a given control by another one. This simplifies the process of layouting (eg if you experience with alignments) and even allows a view to dynamically change its components depending on some external data/events
  • Full control.
    While some methods from SWT do not have a corresponding script function, still all SWT calls may be used as the create* methods expose the underlying SWT instances.
  • Layout help.
    To simplify layouting use the showGrid() function. It displays cell borders that help you to see row/column borders.

Monday, March 25, 2019

JFace TableViewer sorting via Drag and Drop

Recently I wanted to sort elements in a TableViewer via drag and drop and was astonished that I could not find  existing helper classes or tutorial for this fairly trivial use case. So here is one for you in case you got the same use case.

Source code for this tutorial is available on github as a single zip archive, as a Team Project Set or you can browse the files online.

If you are just interested in the helper class, have a look at DnDSortingSupport.


To have something to work on I will start with a TableViewer containing some data stored in a java.util.List. It is a default TableViewer and therefore I expect you have something similar ready for your experiments.

Step 1: Add drag support

Drag and Drop support for SWT is implemented via DragSource and DropTarget instances. To define that we can drag data, we need to bind a DragSource to a Control.
  DragSource dragSource = new DragSource(tableViewer.getControl(), DND.DROP_MOVE);
  dragSource.addDragListener(new DragSourceAdapter() {

   public void dragStart(DragSourceEvent event) {
    event.doit = !tableViewer.getStructuredSelection().isEmpty();

   public void dragSetData(DragSourceEvent event) {
    if (LocalSelectionTransfer.getTransfer().isSupportedType(event.dataType)) {
     LocalSelectionTransfer.getTransfer().setSelectionSetTime(event.time & 0xFFFF);

   public void dragFinished(DragSourceEvent event) {

In line 1 we create the DragSource and define allowed DnD operations. As we want to sort elements, we only allow DND.MOVE operations. Then we define the way data gets transferred from the DragSource to the DropTarget. As we stay within  the same Eclipse application we may use a LocalSelectionTransfer.

The first thing that happens on a drag is dragStart(). Technically the selection cannot be empty as we have to select something before we start the operation, so this implementation is merely to understand how we could deny the operation right from the start.

After the drop operation got accepted in the DropTarget (see below) we get asked to dragSetData() and define what data we are moving. setSelectionSetTime() is not needed by our DropTarget, so again this is for completeness only.

Finally we need to clean up after the operation is done.

Step 2: Add drop support

Implementation is similar like before, just now we need a DropTarget. Instead of writing our own DropTargetListener we may use a ViewerDropAdapter which covers most of the required work already.
  DropTarget dropTarget = new DropTarget(tableViewer.getControl(), DND.DROP_MOVE);
  dropTarget.addDropListener(new ViewerDropAdapter(tableViewer) {

   public void dragEnter(DropTargetEvent event) {
    // make sure drag was triggered from current tableViewer
    if (event.widget instanceof DropTarget) {
     boolean isSameViewer = tableViewer.getControl().equals(((DropTarget) event.widget).getControl());
     if (isSameViewer) {
      event.detail = DND.DROP_MOVE;
     } else
      event.detail = DND.DROP_NONE;
    } else
     event.detail = DND.DROP_NONE;

   public boolean validateDrop(Object target, int operation, TransferData transferType) {
    return true;

   public boolean performDrop(Object target) {
    int location = determineLocation(getCurrentEvent());
    if (location == LOCATION_BEFORE) {
     if (modelManipulator.insertBefore(getSelectedElement(), getCurrentTarget())) {
      return true;

    } else if (location == LOCATION_AFTER) {
     if (modelManipulator.insertAfter(getSelectedElement(), getCurrentTarget())) {
      return true;

    return false;

   private Object getSelectedElement() {
    return ((IStructuredSelection) LocalSelectionTransfer.getTransfer().getSelection()).getFirstElement();

dragEnter() is the first thing that happens on the drop part of DnD. The default implementation is already fine. Our implementation additionally checks that the drag source is our current TableViewer. Further we disable the selectionFeedback. The feedback visually shows the user whether we drop before an element, on the element, or after it. The ViewerDropAdapter already supports these kind of feedbacks. Until bug 545733 gets fixed the helper class contains a small patch to provide before/after feedback only. It does not make sense to drop on another element when we do sorting, right?

validateDrop() will be queried multiple times. We might check that we do not drop the table element on itself, but we spared this check for the current example.

performDrop() finally implements the drop operation. To keep the helper class generic I used an interface that allows to insert elements before or after another element. An implementation of it needs to be passed to the helper class.

 public interface IModelManipulator {
  boolean insertBefore(Object source, Object target);

  boolean insertAfter(Object source, Object target);
The helper class comes with an implementation for java.util.List, which you may reuse.

Tuesday, December 18, 2018

Jenkins 7: Pipeline Support

Next step in our Jenkins tutorials is to add support for pipeline builds.

Jenkins Tutorials

For a list of all jenkins related tutorials see Jenkins Tutorials Overview.

Source code for this tutorial is available on github as a single zip archive, as a Team Project Set or you can browse the files online.

Step 1: Adjusting the code

Good news first: our code (including jelly) from the previous tutorial is ready to be used in pipeline without change. There are some considerations to be taken when writing pipeline plugins, but we already took care of this.

In pipeline each build step needs a name to be addressed. By default this would be the class name and a call would look like this:
step([$class: 'HelloBuilder', buildMessage: 'Hello from pipeline'])

When using the @Symbol annotation on the Descriptor we can provide a nicer name for our build step.

Step 2: Adding dependencies to the execution environment

Our current test target does not support pipeline jobs as we did not add the right dependencies to the pom file so far. We will first see how to add dependencies in general, in the next step we will fix the build afterwards.

To add support for pipeline, add following definition to your pom.xml:

We always need groupId, artifactId and a version. To get these parameters you would typically look up a plugin on the Jenkins plugin site. Locate the link to the source code (Github) and open the pom.xml of the corresponding plugin. There you will find definitions for groupId and artifactId.

Available versions can be found on the Jenkins Artifactory server (we added this server to our pom already). There navigate to the public folder, then follow the structure down, first opening folder from the groupId followed by the artifactId. For the pipeline dependency we would open public/org/jenkins-ci/plugins/workflow/workflow-aggregator. Latest version at the time of writing is 2.6.

Setting the scope to test means that we do not have a build dependency on the plugin. Instead we need it only deployed and enabled on our test instance.

When adding build dependencies you should run
mvn -DdownloadSources=true -DdownloadJavadocs=true -DoutputDirectory=target/eclipse-classes eclipse:eclipse
like we did in the first tutorial. It will update the .classpath file in your eclipse project, automatically adding required libraries to the build path. Take care that also the .project file gets rewritten!

Step 3: Dependency Resolution

We added our dependency, so everything should be done, right?
Wrong! The maven-enforcer-plugin verifies plugin dependencies for us and will detect some incompatibilities, eg:
Require upper bound dependencies error for org.jenkins-ci.plugins:script-security:1.39 paths to dependency are:
This is one of multiple dependency conflicts detected. It seems that maven at first resolves the dependency with the lowest version number. As some plugins need a newer version, we need to resolve the dependency by our own.

The simplest way I found is to check for the highest version of the required plugin (in the upper case: script-security) and add it to our dependencies sections in the pom.xml file. I was hoping for some maven help on this process, but failed. So I ended up adding required dependencies manually until the build was satisfied.

You might run into other build problems, eg after adding a test dependency to the symbol-annotation plugin, my build started to fail, not being able to resolve Symbol.class anymore. Reason is that symbol-annotation is actually a build dependency rather than a test dependency. By binding it to the test scope only we broke the build.

Once you sorted out all dependencies (see resulting pom.xml) your test instance will be able to run pipeline jobs.

Step 4: Testing the Build Step in Pipeline

On your test instance create a new Pipeline and add following script:
node {
    stage('Greetings') {
        greet buildDelay: 'long', buildMessage: 'Hello pipeline build'
Coding the command line for our build step can either be done manually or by using the Pipeline Syntax helper. The link is available right below the Script section in your job configuration. Jenkins makes use of our previous jelly definitions to display a visual helper for the Hello Build step. We may set all optional parameters on the UI and let Jenkins create the command line to be used in the pipeline script.

Monday, December 3, 2018

Jenkins 6: Advanced Configuration Area

Our build is advancing. Today we want to move optional fields into an advanced section and provide reasonable defaults for these entries.

Jenkins Tutorials

For a list of all jenkins related tutorials see Jenkins Tutorials Overview.

Source code for this tutorial is available on github as a single zip archive, as a Team Project Set or you can browse the files online.

Step 1: Advanced UI Section

To simplify the job setup we now move all parameters except the build message to an advanced section.
The only thing necessary in the config.jelly file is to create the section and move all affected input elements into it:
 <f:entry title="Custom build message" field="buildMessage">
  <f:textbox default="${descriptor.getDefaultBuildMessage()}" />

  <f:entry title="Fail this build" field="failBuild">
   <f:checkbox />

  <f:entry title="Build Delay" field="buildDelay">
   <f:select />

Afterwards the UI looks like this:

Step 2: Java Refactoring

Basically we do not need to change anything in the Java code to make this work. However we want to prepare a little for pipeline builds, so we remove non-required parameters from the constructor and create separate setters for them. To make Jenkins aware of these setters, use the @DataBoundSetter annotation:
public class HelloBuilder extends Builder implements SimpleBuildStep {

 private boolean fFailBuild = false;

 private String fBuildMessage;

 private String fBuildDelay = "none";

 public HelloBuilder(String buildMessage) {
  fBuildMessage = buildMessage;

 public void setFailBuild(boolean failBuild) {
  fFailBuild = failBuild;
 public void setBuildDelay(String buildDelay) {
  fBuildDelay = buildDelay;

Whenever a parameter is not required, remove it from the constructor and use a setter for it.

Jenkins 5: Combo Boxes

Combo boxes are the next UI element we will add to our builder.

Jenkins Tutorials

For a list of all jenkins related tutorials see Jenkins Tutorials Overview.

Source code for this tutorial is available on github as a single zip archive, as a Team Project Set or you can browse the files online.

Step 1: UI Definition

In the config.jelly file we simply define that we want to use a combo box:
 <f:entry title="Build Delay" field="buildDelay">
  <f:select />
The definition does not contain entries to select. These will be populated by the Descriptor class.

Step 2: Item Definition

Jenkins will look for a method called doFill<field>Items in our Descriptor class to populate the combo. We are doing a first approach now to understand the scheme:
  public ListBoxModel doFillBuildDelayItems() {
   ListBoxModel model = new ListBoxModel();
   model.add(new Option("None", "none"));
   model.add(new Option("Short", "short"));
   model.add(new Option("Long", "long"));
   return model;
ListBoxModel is basically an ArrayList of Option instances. The first string represents the text visible to the user, the second one the value that will actually be stored in our variable (see next step).

If we would populate the combo this way, the first item would always be selected by default, even if we re-open a job that was configured differently. The Option constructor allows for a third parameter defining the selected state. We then just need to know the value that got stored with the job definition. Therefore we can inject the desired query parameter into our method parameters:
  public ListBoxModel doFillBuildDelayItems(@QueryParameter String buildDelay) {
   ListBoxModel model = new ListBoxModel();

   model.add(new Option("None", "none", "none".equals(buildDelay)));
   model.add(new Option("Short", "short", "short".equals(buildDelay)));
   model.add(new Option("Long", "long" , "long".equals(buildDelay)));

   return model;
Now buildDelay contains the value that got stored by the user when the build step was originally configured. By comparing its string representation we can set the right option in the combo. Typically combo options could be populated from an Enum. To reduce the risk of typos we could write a small helper to create our Options:
 public static Option createOption(Enum<?> enumOption, String jobOption) {
  return new Option(enumOption.toString(),,;

Step 3: Glueing it all together

Finally we need to extend our constructor with the new parameter. Then we can use it in our build step:
public class HelloBuilder extends Builder implements SimpleBuildStep {

 private String fBuildDelay;

 public HelloBuilder(boolean failBuild, String buildMessage, String buildDelay) {
  fBuildDelay = buildDelay;

 public void perform(Run<?, ?> run, FilePath workspace, Launcher launcher, TaskListener listener)
   throws InterruptedException, IOException {
  listener.getLogger().println("This is the Hello plugin!");

  switch (getBuildDelay()) {
  case "long":
   Thread.sleep(10 * 1000);

  case "short":
   Thread.sleep(3 * 1000);

  case "none":
   // fall through
   // nothing to do

  if (isFailBuild())
   throw new AbortException("Build error forced by plugin settings");

 public String getBuildDelay() {
  return fBuildDelay;

Jenkins 4: Unit Tests

Now that our builder plugin is working we should start writing some unit tests for it.

Jenkins Tutorials

For a list of all jenkins related tutorials see Jenkins Tutorials Overview.

Source code for this tutorial is available on github as a single zip archive, as a Team Project Set or you can browse the files online.

Step 1: Wrinting a simple test case

Jenkins tests can be written as JUnit tests. The test instance needed for execution tests can be created using a JUnit Rule.

Create a new JUnit Test Case com.codeandme.jenkins.builder.HelloBuilderTest in the src/test/java folder:
public class HelloBuilderTest {

 public JenkinsRule fJenkinsInstance = new JenkinsRule();
 public void successfulBuild() throws Exception {
  HelloBuilder builder = new HelloBuilder(false, "JUnit test run");
  FreeStyleProject job = fJenkinsInstance.createFreeStyleProject();
  FreeStyleBuild build = fJenkinsInstance.buildAndAssertSuccess(job);
  fJenkinsInstance.assertLogContains("JUnit test run", build);
In line 4 we create a test instance for our unit test. This instance is used from line 10 onwards to create and run our test job. The instance provides a set of assertion commands which we use to check the build result and the log output of the job execution.

You can run these tests as JUnit tests right from Eclipse or you can execute them via maven by running
mvn test

Step 2: A test expecting an execution fail

We use the same approach as before. To check for a failed build we need to run the build job a little bit different:
 public void failedBuild() throws Exception {
  HelloBuilder builder = new HelloBuilder(true, "JUnit test fail");
  FreeStyleProject job = fJenkinsInstance.createFreeStyleProject();
  QueueTaskFuture<FreeStyleBuild> buildResult = job.scheduleBuild2(0);
  fJenkinsInstance.assertBuildStatus(Result.FAILURE, buildResult);
  fJenkinsInstance.assertLogContains("JUnit test fail", buildResult.get());