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 … .

Advertisements
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

Making @Service annotation even cleverer

As some of you might know e(fx)clipse provides a Eclipse DI extension supporting more powerful feature when we deal with OSGi-Services:

  • Support for dynamics (eg if a higher-ranked service comes along you get it injected, …)
  • Support for service list
  • ServiceFactory support because the request is made from the correct Bundle

Since tonights build the @Service annotation has support to define:

  • A static compile time defined LDAP-Filter expression
    public class MySQLDIComponent {
      @Inject
      public void setDataSource(
        @Service(filterExpression="(dbtype=mysql)") 
        DataSource ds) {
         // ...
      }
    }
    
    public class H2DIComponent {
      @Inject
      public void setDataSource(
        @Service(filterExpression="(dbtype=h2)") 
        DataSource ds) {
         // ...
      }
    }
    
  • A dynamic LDAP-Filter expression who is calculated at runtime and can change at any time
    public class CurrentDatasource extends BaseValueObservable<String> implements OString {
      @Inject
      public CurrentDatasource(
        @Preference(key="database",defaultValue="h2") String database) {
        super("(dbtype="+database+")");
      }
    
      @Inject
      public void setDatabase(
        @Preference(key="database",defaultValue="h2") String database) {
        setValue("(dbtype="+database+")");
      }
    }
    
    public class DIComponent {
      @Inject
      public void setDataSource(
        @Service(dynamicFilterExpression=CurrentDatasource.class)
        DataSource ds) {
        // ...
      }
    }
    

    You notice the dynamic provider itself if integration fully into the DI-Story 😉

Posted in e(fx)clipse | Leave a comment

Improving Min/Max performance in “e4-on-JavaFX” applications

When it comes to performance in JavaFX one of the biggest problems is that if you detach and reattach a big SceneGraph-Part you run:

  • CSS-Pass
  • Layout-Pass

So in general one should avoid those operations as much as possible but there are situations you can’t get something implemented without doing exactly this kind of thing.

In the current architecture of e(fx)clipse we need to use this reparenting in case of minimizing/maximizing certain areas of your e4-on-JavaFX application which might lead to a very poor user experience if you eg have a MPartStack with many complex substructures (like eg our code editor).

Today we took a closer look for one of our customers to find out if we – the e(fx)clipse – framework can do anything to fix that problem and after some experiments we managed to come up with a solution who allows us to reparent the content of an MPartStack in constant time:

In general I’d say that such optimization should not be required and JavaFX CSS and Layout performance HAS to be improved in general and JavaFX-Components have to get smarter in not running CSS-Passes on SG-Parts who are currently not showing.

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

New SashLayout container has landed in e(fx)clipse

I just pushed a new layout-container who has a similar feature set than the JavaFX built-in SplitPane but ensures that proportions are not corrupted if you shrink the container (just watch the video below to get an idea what I mean).

The layout algorithm is not something I came up myself. I just reworked the one from SWT to be used in JavaFX.

Posted in e(fx)clipse | 8 Comments