Building e4 JavaFX applications with gitlab-ci and docker

We’ve decided internally sometime ago to use a self-hosted gitlab instance for our projects.

To get started quickly we first only used the ticket-system and keep our jenkins-instance to do our builds which works fine but it somehow bothered me that we’ve been unable to use the gitlab-ci system integrated directly into the gitlab-instance.

So yesterday we started to explore how we can do builds using the docker integration of gitlab-ci and after some troubles with FreeBSD & docker (where our gitlab instance is hosted on) we managed to get a build going.

If you want to do that as well. You can make use of a docker-image we prepared containing:

  • Maven 3.3.x
  • Oracle-JDK-8

(we unfortunately could not use the java-images provided by dockerhub because they ship OpenJDK8 who does not include JavaFX).

So if you run your e4 on JavaFX project as well on gitlab all you need to do is to add a gitlab-ci.yml to your git-repository holding the following content:

image: tomsontom/oracle-java8-mvn:latest

build:
  script: "cd my.project.app.releng; mvn clean package"

e(fx)clipse 2.4.0 & Eclipse Neon Builds available

For those who want to get an easy head start into JavaFX development with Eclipse as an IDE BestSolution provides a service many developers make use of (eg in June the IDE got downloaded 4000 times).

We provide All-in-One builds similar to the ones you can grab from Eclipse.org but we bundle even some external libraries for you with it.

We now managed to update the provided IDE to the latest and greatest:

  • Eclipse 4.6.0 SDK
  • e(fx)clipse 2.4.0
  • Xtext 2.10.0
  • EGit 4.4.0
  • WST-XML 3.8.0
  • Subclipse 1.8.20
  • m2e 1.7.0
  • bndtools 3.2.0
  • AnyEditTools 2.6.1
  • Findbugs 3.0.2
  • Eclemma 2.3.3

Finally if you like this an other services (eg. leaving no question at the newsgroup unanswered) BestSolution provides for free think about sponsoring our work.

If you rely on e(fx)clipse for your commercial product we suggest you sign a service and support contract with BestSolution.

e(fx)clipse 2.4.0 released

we are happy to announce that e(fx)clipse 2.4.0 has been released last week. The main working area in this release has once more been the code editor framework.

Code editor framework

Starting with this release we are have replacement for all features one is used from your Eclipse IDE Code-Editing framework, like keyboard navigation, hover-information, … .

We’ve as always taken extra care that we are not introduce JavaFX dependencies but kept a clean split between core-services providing the plain data and visualization services presenting those plain data points (eg in JavaFX).

  • Lexical-Code-Highlighting improvements:
    • Our custom rules have been adjusted to match the highlighting behavior known from the Eclipse Java-Editor.
      Old

      New

    • New rules to eg support lua multi-line string and comments. I confess I’ve not seen a language before who has a similar concept for multi-line constructs. If you are not familiar with lua let me try to explain it. A multi-line comment starts with --[ followed by an optional number of "="-chars followed by another "[" and then ends with "]" the same amount of "="-chars than you used in the start section followed by another "]"
      --[==[
      I'm a multi line
      comment
      ]==]
      
      lua-code
      
      --[====[
      I'm a multi line
      comment
      ]====]
      

      We have enhanced our highlighting format to support this kind of rules. For lua it looks like this:

      // ...
      rule {
        multi_line __lua_ml_comment   "--[" pattern '(=*)' '['   => "]{0}]"
        single_line __lua_sl_comment  "--"  => ''
        multi_line __lua_ml_string    "["  pattern '(=*)' '['   => "]{0}]"
        single_line __lua_string      "'"   => "'" escaped by "\\"
        single_line __lua_string      '"'   => '"' escaped by "\\"
      }
      // ...
      
    • While the ldef-language allows to specify rules very easy those rules have to be defined up-front which sometimes is not possible to the highlighting needs to adapt based on other conditions. We enhanced the system to contribute rules dynamically by registering a service of type DynamicScannerRuleCalculator
  • Autocomplete improvments: You can now configure the editor to invoke auto-complete system not only on CTRL+Space but as well eg at the moment you type "."-character
  • Code navigation support: This release introduces code navigation like you know it from your Eclipse IDE (including low-level APIs to jump to positions inside your editor control)
  • Support for block matching: We implemented exemplary code to show how one can implement block matching (eg matching braces)
  • Code rearrangement with DnD: We now have support to rearrange code parts using DnD
  • Support for undo/redo: We’ve now connected the editor to the undo/redo system available in eclipse.text

e4 on JavaFX

Prebuilt Perspective Switchers

The framework now provides:

  • A perspective switcher control one can embed into the TrimBar (PerspectiveSwitcherComponent)
  • A heavy and a lightweight perspective switcher dialog and a handler to trigger the dialog the appropriate one

New tag to center MWindow

You can now add the tag "efx-center-on-screen" to your Application.e4xmi and the window will be centered on screen.

Tab-Context-Menu

One can now register MPopupMenu on an MPart who is translated into a context-menu assigned to the Tab in a TabPane. Just taq the MPopupMenu with "tabmenu" and e4 on JavaFX will take care for you to render the context menu.

Other new runtime APIs

TextUtil#templateValuSubstitutor(String,Map)

This new helper allows you to evaluate simple template expressions and applying formats on it.

class Person {
   String name = "Tom";
   Date birthday = new Date(1,4,79);
}

Person p = new Person();
TextUtil.templateValuSubstitutor( 
  "The birthday from ${p.name} is on ${p.birthday,date,short}", Collections.singletonMap("p",p) );

ImageProvider support HiDPI images

JavaFX itself supports HiDPI images already since sometime but the internal abstraction who is used by e4 on JavaFX lacked such a support. This has been fixed with this release.

Delayed observables

To appropriately support undo/redo in form based UIs it is very important to collect changes in logical units. A good example is the that you probably would not require the user to undo each and every keystroke in a text-field. To address this use case Eclipse Databinding for SWT has the concept of so called delayed observables who wait for a certain amount of time before they inform others about their modification.

Eclipse Databinding for JavaFX controls now has the same concept.

TextField f = new TextField();
IObservableValue textObs = JavaFXUIProperties.text2().observeDelayed(400, f);

Error-Decoration

For form base UIs it is crucial to display validation information. We added new API to our control-library to who supports field decorations. The API is designed to work equally well in a basic scenario as well as when using MVVM (in the same vein we added new properties you can publish in your ViewModels)

static class VM {
  private final ValidatedStringProperty firstname;
  private final ValidatedStringProperty lastname;
  private final StatusAggregator aggregator;

  public VM(String firstname, String lastname) {
    this.firstname = new ValidatedSimpleStringProperty(new SimpleStringProperty(this, "firstname",firstname));
    this.firstname.registerValidator(s -> s.isEmpty() ? Status.status(State.ERROR, -1, "Vorname muß befüllt sein", null) : Status.ok());

    this.lastname = new ValidatedSimpleStringProperty(new SimpleStringProperty(this, "lastname", lastname));
    this.lastname.registerValidator(s -> s.isEmpty() ? Status.status(State.ERROR, -1, "Nachname muß befüllt sein", null) : Status.ok());

    this.aggregator = new StatusAggregator(this.firstname,this.lastname);
  }
}

VM vm = new VM("Tom", "Schindl");

{
  Label l = new Label("Vorname");
  p.getChildren().add(l);

  TextField field = new TextField();
  field.textProperty().bindBidirectional(vm.firstname.bindProperty());

  NodeDecorator.apply(field, vm.firstname);
  p.getChildren().add(field);
}

e(fx)clipse 2.3.0 released

Right for EclipseConNA 2016 next week we released e(fx)clipse 2.3.0. This release mainly provides features in the runtime layer.

Where to get it from

If you are interested in the Tooling you can:

If you want to develop e4 application who use JavaFX instead of SWT you need to point your target-platform and built towards http://download.eclipse.org/efxclipse/runtime-released/2.3.0/site.

Let’s take a look of the most interesting new features and changes.

Source editing

A lot of work has gone into the StyledTextArea where we rewrote the internals and implemented our own virtual-flow element instead of reusing the ListView provided by the JavaFX library.

We also did this to provide many new features:

  • Keyboard navigation like in the Eclipse IDE
  • Support for Error-Markers in the text area (see screenshot below)
  • Support to display white space characters (see video below)
  • Pluggable Rulers for the left Editor side

The following screen shot demonstrates the error markers inside the text:
screen_errormarker

The following video provides you an overview what features the code editor widget provides with the 2.3.0 release.

Object Serialization / Deserialization

We enhanced the ObjectSerializer-API allowing adding support for collections with none basic types (eg. a Set/List of Enums).

@Inject
ObjectSerializer serializer;

enum States {
  STATE_1,
  STATE_2,
  STATE_3
}

public void serializeData() {
   String data = serializer
     .serializeCollection( Arrays.asList( STATE_1, STATE_2 ), States.class );
}

and as the @Preference-System of e(fx)clipse is delegating to the obserializer you can use it there too.

@Inject
@Preference(key="state")
Property<List<State>> stateList;

public void rememberState(List<State> state) {
  stateList.set( state );
}

Accessibility Improvements

We worked a bit on improvements of the accessibility support eg making use of the accessibilityPhrase defined in your E4-Application model, makeing FontIconView mouse transparent, … .

Preparing for JDK9

To implement certain features we need to none public JavaFX APIs, we got rid of most of them but there’s most likely still work do be done.

Using TypeScript LanguageService to build an JS/TypeScript IDE in Java

Yesterday I blogged about my endeavors into loading and using the TypeScript Language Service (V8 and Nashorn) and calling it from Java to get things like an outline, auto-completions, … .

Today I connected these headless pieces to my JavaFX-Editor-Framework. The result can be seen in the video below.

To get the TypeScript LanguageService feeling responsible not only for TypeScript files but also for JavaScript I used the 1.8 beta.

As you notice JS-Support is not yet really at a stage where it can replace eg Tern but I guess things are going to improve in future.

JavaScript Performance V8 vs Nashorn (for Typescript Language Service)

On the weekend I’ve worked on my API to interface with the Typescript language service from my Java code.

While the initial version I developed some months ago used the “tsserver” to communicate with the LanguageService I decided to rewrite that and to interface with the service directly (in memory or through an extra process).

For the in memory version I implemented 2 possible ways to load the JavaScript sources and call them

  • Nashorn
  • V8(with the help of j2v8)

I expected that Nashorn is slower than V8 already but after having implemented a small (none scientific) performance sample the numbers show that Nashorn is between 2 and 4 times slower than V8 (there’s only one call faster in Nashorn).

The sample code looks like this:

public static void main(String[] args) {
  try {
    System.err.println("V8");
    System.err.println("============");
    executeTests(timeit("Boostrap", () -> new V8Dispatcher()));
    System.err.println();
    System.err.println("Nashorn");
    System.err.println("============");
    executeTests(timeit("Nashorn", () -> new NashornDispatcher()));
  } catch (Throwable e) {
    e.printStackTrace();
  }
}

private static void executeTests(Dispatcher dispatcher) throws Exception {
  timeit("Project", () -> dispatcher.sendSingleValueRequest(
    "LanguageService", "createProject", String.class, "MyProject").get());

  timeit("File", () -> dispatcher.sendSingleValueRequest(
    "LanguageService", "addFile", String.class, "p_0", DispatcherPerformance.class.getResource("sample.ts")).get());

  timeit("File", () -> dispatcher.sendSingleValueRequest(
    "LanguageService", "addFile", String.class, "p_0", DispatcherPerformance.class.getResource("sample2.ts")).get());

  timeit("Outline", () -> dispatcher.sendMultiValueRequest(
    "LanguageService", "getNavigationBarItems", NavigationBarItemPojo.class, "p_0", "f_0").get());

  timeit("Outline", () -> dispatcher.sendMultiValueRequest(
    "LanguageService", "getNavigationBarItems", NavigationBarItemPojo.class, "p_0", "f_1").get());
}

Provides the following numbers:

V8
============
Boostrap : 386
Project : 72
File : 1
File : 0
Outline : 40
Outline : 10

Nashorn
============
Nashorn : 4061
Project : 45
File : 29
File : 2
Outline : 824
Outline : 39

The important numbers to compare are:

  • Bootstrap: ~400ms vs ~4000ms
  • 2nd Outline: ~10ms vs ~40ms

So performance indicates that the service should go with j2v8 but requiring that as hard dependency has the following disadvantages:

  • you need to ship different native binaries for each OS you want to run on
  • you need to ship v8 which might/or might not be a problem

So the strategy internally is that if j2v8 is available we’ll use v8, if not we fallback to the slower nashorn, a strategy I would recommend probably for your own projects as well.

If there are any Nashorn experts around who feel free to help me fix my implementation