e(fx)clipse runtime library – Working with the (JavaFX) UI-Thread

When developing UI-Application a very frequent task is

  • to synchronizes yourself back from an worker-thread to the UI-Thread
  • schedule task to run in the future
  • Block the program flow and wait for a condition being met (in SWT called spinning the event loop)

JavaFX 8 has a public API for most of those building blocks (only exception is Event-Loop-Spinning who was an internal API in Java8 and is public API in 9) but using higher level API reduces the boilerplate code you need to implement.

Before we start let’s see how you can access to it in your maven-driven projects (I’m not gradle safey enough to show how it works there) you need to

  • add the efxclipse maven repository (at the time of this writing you need to nightly repository because you need at least 3.0.0)
  • add the following dependency
    <dependency>
      <groupId>at.bestsolution.efxclipse.rt</groupId>
      <artifactId>org.eclipse.fx.ui.controls</artifactId>
      <version>3.0.0-SNAPSHOT</version>
    </dependency>
    

Let’s take a look at some of those APIs and how they can help you write better code:

Writing back from worker thread

Let’s suppose we have a service who returns a search result as a CompletableFuture and we want to push the result – once available – to JavaFX ObjectProperty:

import org.eclipse.fx.core.ServiceUtils;

// Lookup the domain service in the service registry
PersonSearchService service = 
  ServiceUtils.getService(PersonSearchService.class);

ObjectProperty<Person> person = ...;

CompletableFuture<Person> result = 
  service.findByName("Tom","Schindl");

Let’s for a second suppose we can interact with our UI-Toolkit on ANY-Thread we could simply write:

result.thenAccept( person::set );

Unfortunately none of the UI-Toolkits I know would support this because they require you to sync on a special thread called the UI-Thread. JavaFX is not different in this aspect.

Plain JavaFX APIs:

result.thenAccept( p -> {
   Platform.runLater( () ->
     person.set(p);
   );
} );

Using e(fx)clipse’ ThreadSynchronize#asyncExec(T,Consumer<T>):

import org.eclipse.fx.core.ThreadSynchronize;

// ...

// Lookup the thready service in the service registry
ThreadSynchronize threadSync = 
  ServiceUtils.getService(ThreadSynchronize.class).get();

result.thenAccept( p -> {
   threadSync.asyncExec( p, person::set );
});

We got rid of the inner lambda and replaced it with a method reference, so the code got more readable but

Using e(fx)clipse’ ThreadSynchronize#wrap(Consumer<T>):

// ...
result.thenAccept( threadSync.wrap(person::set) );

we can get rid of all outer lambda as well and are back to fairly the same code as if we’d not had to worry about thread-synchronization at all.

Reading from a worker thread

Let’s suppose you have a Timer running who wants to read a JavaFX-Property from a TextField in 1 second from now you’d:

  • You’d better rewrite it to use a Timeline so that no thread sync is needed
  • You’d write the following magic lines of code:
TextField textField = ...

Timer t = new Timer();
t.schedule( new TimerTask() {
  @Override
  public void run() {
    CountDownLatch ll = new CountDownLatch(1);
    AtomicReference<String> data = new AtomicReference<>();
    Platform.runLater( () -> {
      data.set( textField.getText() );
      ll.countDown();
    });
    ll.await();
    String d = data.get();
    // further process the data 
  }
}, 1000 );

Let’s for a moment forget that this code fairly dangerous because it might create a dead lock situation (hence JavaFX only provides Platform.runLater(Runnable)) this is a huge amount of code to write! Let’s see what APIs e(fx)clipse has to improve the situation.

Using ThreadSynchronize#syncExec(Runnable):

ThreadSynchronize threadSync = 
  ServiceUtils.getService(ThreadSynchronize.class).get();

public void run() {
  AtomicReference<String> data = new AtomicReference<>();
  threadSync.syncExec( () -> {
    data.set( textField.getText() );
  } );
  String d = data.get();
  // further process the data 
}

Removes the need for the CountDownLatch

Using ThreadSynchronize#syncExec(Callable<V>, V):

public void run() {
  String d = threadSync.syncExec( textField::getText, "" );
}

Removes the need for the AtomicReference

Using ThreadSynchronize#scheduleExecution(long, Runnable):

ExecutorService s = ...;
threadSync.scheduleExecution( 1000, () -> {
   String data = textField.getText();
   s.submit( () -> ... );
} );

Removes the thread synchronization problems arising from Platform.runLater() call

Using ThreadSynchronize#scheduleExecution(long, Callable<T>) : CompletableFuture<T> :

threadSync.scheduleExecution( 1000, textField::getText )
  .thenAcceptAsync( d -> ... );

Removes the lambda and gets you to the wonderful CompletableFuture-API.

Block program flow

Generally speaking halting the program flow is a discouraged software pattern and you’d better work with Future and callbacks like Consumer but there might be (existing) API you have to support who requires you to halt the program flow and continue after a certain condition has been met.

To support such a usecase e(fx)clipse has org.eclipse.fx.ui.controls.Util#waitUntil( BlockCondition blockCondition ) you can use like this


Pane p = ...;

// Ask for name in an overlay
String askForName() {
  BlockCondition<String> condition = new BlockCondition<>();

  TextField t = new TextField();
  Button b = new Button("Proceed");
  b.setOnAction( e -> { condition.release(t.getText()); } );
  HBox box = new HBox(
    new Label("Name:"),
    t,
    b);
  box.setManaged(false);
  box.autosize();
  box.relocate( 
    p.getWidth() / 2 - box.getWidth() / 2, 
    p.getHeight() / 2 - box.getHeight() / 2 );
  p.getChildren().add( box );
  return Util.waitUntil( condition );
}
Advertisements
Posted in e(fx)clipse | 1 Comment

e4 on JavaFX with the bnd-maven-plugin (with VS Code)

Just a few minutes ago I blogged about our future plans for e(fx)clipse and to show you that we take the things mentionned there really serious I can provide you an initial report on the first 2 points from the the list:

  • Freedom of development style
  • Freedom of development tool

Since its inception the way to develop “e4 on JavaFX” meant:

  • useage Eclipse PDE inside your Eclipse IDE
  • useage Maven-Tycho as the headless build system

We will start to change that and in the weeks to come!

First and most important

We won’t take away ANYTHING – if you want to use PDE and Tycho please do so – we are going to support that development style like did in the past!

The future is pure maven/gradle

I’ve played around a lot in the past weeks with Eclipse, IntelliJ IDEA, Netbeans and VS Code to find what would work out best and I think I’ve reached a point where I can provide you some screenshots and screen casts.

Eclipse

In Eclipse all I need to develop my application is the m2e extension.

screen-maven-pure-eclipse

VS Code

To give me the extra kick I decided to give VS-Code and the Java-Extension from RedHat a shot.

The technology

Now that you have looked at the cool screen-cast let’s talk about the boring technology in the backend. We rely on 2 things:

Posted in Uncategorized | 6 Comments

e(fx)clipse and the future of e4 on JavaFX

We’ve been a bit silent in the last few months but the reason is not that our investment in e(fx)clipse has been stopped – it’s the complete opposite. We are involved in HUGE JavaFX projects built on top of e4 and JavaFX.

At EclipseCon Europe I gave a talk on the future direction of e(fx)clipse who is driven by 3 main topics who are going build the Foundation for a bright future of e4 on JavaFX:

  • Freedom of development style
  • Freedom of development tool
  • Freedom of runtime

Freedom of development style

As of today e(fx)clipse e4 development style is called “MANIFEST-first” which means you create your OSGi-MANIFEST and from there

  • Eclipse PDE derives Classpaths, … while you are in your Eclipse IDE
  • Eclipse Tycho derives Build-Paths, … to build applications on your CI-Instance

In future we are going to support other development styles as well:

  • bnd/bnd-tools for those of you who’d like to use what OSGi-gurus like Peter Kriens, Neil Bartlett, … prefer for OSGi-Development, we are already publishing an r5-index since some time. A nice side effect is that bnd support is also available eg in IntelliJ IDEA
  • pom/gradle-first for those of you who’d like to stay with maven/gradle but not all team-members are using Eclipse as their main IDE (or you are not using OSGi as the module system of choice – see more on that below)

Freedom of development tool

Since the first day I’ve spoken about “e4 on JavaFX”, I said that we – the e(fx)clipse project – don’t mind people using other IDEs like Netbeans or IntelliJ IDEA because we are an RCP framework allowing you to built sophisticated applications on top of the brand new Eclipse 4 Application Platform and if you don’t like the Eclipse IDE that’s fine with us.

Yes one part (the smaller one) of the Eclipse-project provides tooling to support developers who’ve chose Eclipse as the IDE, and yes we are an Eclipse project (like Jetty, Vert.x) and Eclipse is our primary development environment but just because it is our IDE of choice this must not mean that it is yours as well.

People already managed to use e(fx)clipse to develop application inside IntelliJ IDEA but in future we’d like to provide all developers an excellent out-of-the-box experience.

Freedom of Runtime-System

As of today you can run e4 applications only on the Eclipse Equinox OSGi-Container. In future we’d like to provide you many more options:

  • Run on ANY r5-OSGi-Container
  • Run without OSGi using NO Module-Container at all
  • Run on Java Platform Module System (JPMS)

Don’t get me wrong! We love OSGi and support for OSGi is still one of the primary targets of e(fx)clipse but we also understand the OSGi might not be the right tool for you and your team.

What’s next

As you might imagine all this is a HUGE amount of work but we (BestSolution.at) are committed to the future e(fx)clipse and we think it is crucial for e(fx)clipse’ future and initial steps have already been made.

Stay tuned for more exciting news in the next few weeks.

Posted in e(fx)clipse, Uncategorized | 1 Comment

Friday fun stuff – JavaFX Based Java IDE

While I’ve been working (and still work) on general IDE concept and frameworks I decided to today that I want to work on something simpler.

After having hacked the whole day I have now a basic Java IDE:

screen-light

screen-dark

Nothing fancy but something I can built upon next Friday … .

Posted in e(fx)clipse, Uncategorized | 3 Comments

e(fx)clipse support for Java9

Approximately a month ago we started to the work to run e(fx)clipse applications on Java9. We had to clean up our codebase a bit because sometimes we called into none-public API (eg impl_*) who has been made private or released as public API, used all sorts of reflection hacks (eg to get Tab-DnD working) who break on Java9 for obvious reasons.

It’s been quite some work but finally things are working!

The screenshot shows an sample e4 application I’ve written to get myself used to the new module-system API:

screen-j9

Supporting Java9 is a critical thing for the future of the e(fx)clipse platform but as important is that we won’t force you to use Java9 with JPMS but keep e(fx)clipse compatible to Java8 and Java9 for the 3.x and maybe 4.x stream.

To help us supporting both platforms we encapsulated API calls who are different in Java8 and Java9 into a small utility class you can make use of in your JavaFX applications just by adding a (maven) dependency on

...
  <repositories>
    <repository>
      <name>BestSolution e(fx)clipse releases</name>
      <id>efxclipse-releases</id>
      <url>http://maven.bestsolution.at/efxclipse-releases/</url>
     </repository>
     <repository>
       <name>BestSolution e(fx)clipse snapshots</name>
       <id>efxclipse-snapshots</id>
       <url>http://maven.bestsolution.at/efxclipse-snapshots/</url>
       <snapshots>
         <enabled>true</enabled>
        </snapshots>
      </repository>
  </repositories>
  <dependencies>
    ...
    <dependency>
      <groupId>at.bestsolution.efxclipse.rt</groupId>
      <artifactId>org.eclipse.fx.ui.controls</artifactId>
      <version>3.0.0-SNAPSHOT</version>
    </dependency>
    ...
  <dependencies>
...

in your Java code add a static import for org.eclipse.fx.ui.controls.JavaFXCompatUtil and if you eg want get all currently available windows just do it like this code snippet

import static org.eclipse.fx.ui.controls.JavaFXCompatUtil.*

// ...

JavaFXCompatUtil.getWindows();

Currently we use Reflection to switch between Java9 and Java8 APIs but in future multi-version jars might also be a solution.

To sum up I’m happy things are working so smooth on Java9, the only sad thing is that our performance hack to turn off the JavaFX-CSS-Engine under certain conditions does not work anymore in Java9 and we won’t be able to implement a replacement.

Posted in e(fx)clipse, Uncategorized | 3 Comments

e(fx)clipse runtime library – Dealing with listeners on JavaFX-Observables

Now that the e(fx)clipse runtime code base is available to any application developer (see this blog post). It is time to explore all the cool stuff it provides for Java(FX) application development.

In the next few weeks I’ll blog about new stuff and old stuff you can make use by just adding a dependency on one of our libraries. I’ll use maven in the samples because that’s what I’m most used to but IIRC things will work for gradle as well.

In this first post I’d like to draw your attention to an Utility-Class (org.eclipse.fx.core.observable.FXObservableUtil) I just checked in a few minutes ago into the repository helping you to write fewer and less error prone code:

FXObservableUtil.onChange for ObservableValue & Property

Let’s take a look at a first code-pattern, I’ve noticed frequently in my JavaFX code-bases:

private StringProperty p = ...;

void attachHandler() {
   p.addListener( this::handle );
}

void detachHandler() {
   p.removeListener( this::handle );
}

void handle(Observable ob, String ol, String ne) {
   System.out.println( ne );
}

The code above has the following problems:

  • I have to declare a method with 3 arguments although I only make use of the new value
  • I have created a huuuge listener leak (Arghhh!)

Let’s improve the situation by using one of our core-libraries org.eclipse.fx.core. Just the following to your maven build:

...
<repositories>
  ...
  <repository>
    <name>BestSolution e(fx)clipse snapshots</name>
    <id>efxclipse-snapshots</id>
    <url>http://maven.bestsolution.at/efxclipse-snapshots/</url>
    <snapshots>
      <enabled>true</enabled>
    </snapshots>
  </repository>
</repositories>
...
<dependencies>
  ...
  <dependency>
    <groupId>at.bestsolution.efxclipse.rt</groupId>
    <artifactId>org.eclipse.fx.core</artifactId>
    <version>3.0.0-SNAPSHOT</version>
  </dependency>
</dependencies>

And now we can change our code using an Utility-Class named org.eclipse.fx.core.observable.FXObservableUtil.

import org.eclipse.fx.core.observable.FXObservableUtil;

private StringProperty p = ...;
private Subscription s;

void attachHandler() {
   s = FXObservableUtil.onChange( p, this::handle );
}

void detachHandler() {
   if( s != null ) {
     s.dispose();
     s = null;
   }
}

void handle(Observable ob, String ol, String ne) {
   System.out.println( ne );
}

But we can improve the code even more because:

  • We can add static imports
  • Instead of using FXObservableUtil#onChange(ObservableValue<T>, ChangeListener<T>) we can use the overloaded method with the signature FXObservableUtil#onChange(ObservableValue<T>, Consumer<T>)
import static org.eclipse.fx.core.observable.FXObservableUtil.*;

private StringProperty p = ...;
private Subscription s;

void attachHandler() {
   s = onChange( p, System.out::println );
}

void detachHandler() {
   if( s != null ) {
     s.dispose();
     s = null;
   }
}

FXObservableUtil.onChange for ObservableList

In general the JavaFX APIs is designed very well to work with @FunctionalInterface types but IMHO there’s one big mistake that has happened when we look at the Observable-API who strikes back in case of ObservableList.

The class hierarchy in JavaFX looks like this:

+ Observable
  - addListener( InvalidationListener listener ) : void
  + ObservableValue
    - addListener( ChangeListener<? super T> listener )
  + ObservableList
    - addListener( ListChangeListener<? super E> listener )

The overloading of addListener() in case of ObservableValue is fine as ChangeListener#changed(ObservableValue<? extends T> , T , T ) requires 3 arguments wherease InvalidationListener#invalidated(Observable) takes only one.

In case of ObservableList unfortunately ListChangeListener#onChanged( Change<? extends E> c) like InvalidationListener#invalidated(Observable) accepts one argument. Because of this it’s impossible to benefit of the automatic type inference done by the compiler to remove boilerplate code for lambda expressions and you need to fill in the correct type in the lambdas argument section:

ObservableList<String> l = ...

l.addListener( (Change<? extends String> c) -> 
  { while( c.next() ) { /* ... */ } } );
// although you really wanted to write
l.addListener( c -> { while( c.next() ) { /* ... */ } } );

To make this usecase less type heavy FXObservableUtil distinguishes between

  • Invalidation: FXObservableUtil.onInvalidate(Observable,InvalidationListener)
  • Change: FXObservableUtil.onChange(ObservableList<E>,ListChangeListener<? super E>)
import static org.eclipse.fx.core.observable.FXObservableUtil.*;

ObservableList<String> l = ...
Subscription s = 
  onChange( l, c -> { while( c.next() ) { /* ... */ } } );
Posted in e(fx)clipse, Uncategorized | 3 Comments

Make it easy to consume e(fx)clipse libraries in maven (or gradle)

In the past we now and then published some of our artifacts on maven central but because this was a manual process we’ve often been too lazy leading to do it on each release. This leads frustration because while we’ve released e(fx)clipse 2.5.0 already, the maven bits are stuck on 2.2.0.

I think not being able to consume our code outside the OSGi world has led to the false impression that e(fx)clipse runtime is just about OSGi although central parts of our framework happily run outside OSGi and so can be used like any other library:

  • We have additional layout containers like RowLayoutPane, FillLayoutPane, GridLayoutPane, SashPane
  • We have additional controls like FileSystemViewers, StyledTextArea, FontIconNode
  • We have a complete code editor framework with syntax highlighting, auto-complete, line/error markers, hover-support, navigation support, …
  • A Service Registry supporting a subset of the OSGi-Declarative-Service Framework outside the OSGi world in plain Java – say good bye to ServiceLoader once you used our service stuff

Solving this problem was at the top of my list for the Q1/2017 and I’m happy to announce that the complete e(fx)clipse runtime target platform is available from a maven-repository starting from today.

We’ve chose to publish the artifacts to one of our own public servers (http://maven.bestsolution.at/) instead of maven-central and there are multiple reasons for that:

  • We need to get confidence that our OSGi-To-Maven-Dependency translation is correct
  • We need to extract more meta-information to publish accurate informations like Developers, SCM-URLs
  • We need to refine how we deal with none Eclipse dependencies like apache-commons, …

It’s a nice coincidence that Stephan Herrmann did the same for the Eclipse Platform, JDT and PDE but there are some differences (today) from what I read on his blog entry (don’t shoot me Stephan if I got it wrong):

  • Stephan uses some CBI-stuff to translate the OSGi-Dependencies to maven pom dependencies, we use a simple helper library to do the same thing
  • Stephan replaces OSS-Dependencies like Apache-Commons through the direct maven substitutions, we are republishing the dependencies as we publish them from the Eclipse Orbit Project or any other Eclipse project.
    The reason is that we want the maven artifact repository to contain 100% the same bits as our p2-update-site and r5-repository. That’s the current state and it might change in future!
Posted in e(fx)clipse | 7 Comments