Wednesday, June 22, 2016

GEF4 Dot Oh Dot Oh

I am proud to announce that with today's Eclipse Neon release we have officially published the new GEF4 components in version 1.0.0, exposing their up to now only preliminary API. We have worked intensively on the code base since the 0.2.0 (Mars.1) release and have achieved quite a lot.

Polishing API

From an adopters viewpoint, the (up to now provisional) API has been cleaned up and harmonized in nearly all places. We have for instance adopted JavaFX collections and properties throughout, so that we can now use only a single notification mechanism in all places. As outlined in detail in an earlier post, this also enables us to use JavaFX bindings, which makes framework and client code more concise. Especially the GEF4 FX component has profited a lot from this. We have further simplified the contract of the GEF4 Layout component to no longer rely on own interface abstractions for data exchange, but to use a GEF4 Graph model, similar to what GEF4 Zest already did for rendering. And we have harmonized the GEF4 Zest API, especially those parts related to JFace. The New and Noteworthy page gives a quite detailed overview of the most important API changes.

Improving DOT

From an end-users viewpoint, the GEF4 DOT component has been brought a huge step nearer to its final goal of being a full Graphviz DOT authoring environment (even if its still a far way to go). The Xtext editor can now also parse and validate certain attribute values, and the Graph view is capable of rendering a first set of node shapes, as well as edge styles and decorations. All DOT spline types are now also supported. In addition to the 'emulated' layout we provided so far, where a GEF4 Layout algorithm is used to mimic the Graphviz layout, we now support a 'native' mode, in which the native dot executable (the path to which is specified via a preference) is used:

















'Pimping' FX and MVC

Connection handling has been significantly improved. We have added support for orthogonal routing in addition to straight routing, and we have separated out an IConnectionRouter, which is responsible for manipulating the bend/control points, as well as an IConnectionInterpolator, which determines the to be rendered curve geometry. Routers and interpolators can be freely combined, so a connection can now be routed orthogonally, while it can still be rendered ‚smoothly‘ using Bézier curves:



















In addition, connection decorations are now properly clipped (which lies within the responsibility of the interpolator), and a 'clickable area‘ (a transparent fat curve that overlays the connection) can now be used to make a connection clickable even when the zoom level is large (we have added this functionality to the GeometryNode so it is usable in an even broader scope).

Within GEF4 MVC we have accordingly enhanced FXBendConnectionPolicy to provide interaction support for manipulating connections that are orthogonally routed. These can now be manipulated using segment handles rather than handles for way/control points:


We have further enabled that distinct bindings can be specified for viewers with different roles. That allows us to use an FXViewer both as palette and content viewer, so a palette can now be easily realized. We have augmented the MVC Logo example to serve as a demonstrator:


Sunday, April 24, 2016

GEF4 Common Collections and Properties - Guava goes FX

As a preparation for our upcoming Neon release, I intensively worked on adopting JavaFX collections and properties to the entire GEF4 code base (see #484774).

We had already used them before, but only in those parts of the framework that directly depend on the JavaFX toolkit. In all other places we had used our own extensions to Java Beans properties, because we did not want to introduce JavaFX dependencies there. However, as JavaFX is part of JavaSE 1.7 and JavaSE-1.8 and its collections and properties are completely independent of the UI toolkit, we (no longer) considered the additional dependencies as being a real show stopper. Instead, we highly valued the chance to provide only a single notification mechanism to our adopters. The very rich possibilities offered by JavaFX's binding mechanism in addition tipped the scales.

As JavaFX only provides observable variants for Set, Map, and List, I had to create observable variants and related (collection) properties for those Google Guava collections we use (Multiset and SetMultimap) as a prerequisite. I had to dig deep into the implementation details of JavaFX collections and properties to achieve this, learned quite a lot, and found the one or other oddity that I think is worth to be shared. I also implemented a couple of replacement classes to fix problems in JavaFX collections and properties, which are published as part of GEF4 Common. 

But before going into details, let me shortly explain what JavaFX observable collection and properties are about.

Properties, Observable Collections, and (Observable) Collection Properties


In general, a JavaFX property may be regarded as a specialization of a Java Beans property. What it adds is support for lazy computation of its value as well as for notification of invalidation (a lazily computed value may need to be re-computed) and change listeners, which may - in contrast to Java Beans - be registered directly at the property, not at the enclosing bean.

Using JavaFX properties implies a certain API style (similar to Java Beans), as it is expected to provide a getter and setter to access the property value, as well as an accessor for the property itself. We may consider javafx.scene.Node as an example, which amongst various others provides a boolean pickOnBounds property that (is lazily created and) controls whether picking is computed by intersecting with the rectangular bounds of the node or not:

  public abstract class Node implements EventTarget, Stylable {
    ...
    private BooleanProperty pickOnBounds;
    
    public final void setPickOnBounds(boolean value) {
      pickOnBoundsProperty().set(value);
    }
    
    public final boolean isPickOnBounds() {
      return pickOnBounds == null ? false : pickOnBounds.get();
    }
    
    public final BooleanProperty pickOnBoundsProperty() {
      if (pickOnBounds == null) {
        pickOnBounds = new SimpleBooleanProperty(this, "pickOnBounds");
      }
      return pickOnBounds;
    }
  }

In addition to the notification support already mentioned, values of properties may be bound to values of others, or even to values that are computed by more complex expressions, via so called bindings. This is a quite powerful mechanism that reduces the need for custom listener implementations significantly. If the pickOnBounds value of one node should for instance be kept equal to the pickOnBounds value of another, the following binding is all that is required:

  node1.pickOnBoundsProperty().bind(node2.pickOnBoundsProperty());

Binding it to a more complex boolean expression is pretty easy as well:

  node1.pickOnBoundsProperty().bind(node2.pickOnBoundsProperty().or(node3.visibleProperty()));

One can even define own bindings that compute the property value (lazily) based on values of arbitrary other properties:

  node1.pickOnBoundsProperty().bind(new BooleanBinding() {
    {
      // specify dependencies to other properties, whose changes
      // will trigger the re-computation of our value
      super.bind(node2.pickOnBoundsProperty());
      super.bind(node3.layoutBoundsProperty());
    }
    
    @Override
    protected boolean computeValue() {
      // some arbitrary expression based on the values of our dependencies
      return node2.pickOnBoundsProperty().get() &&
             node3.layoutBoundsProperty().get().isEmpty();
    }
  });

JavaFX provides property implementations for all Java primitives (BooleanPropertyDoublePropertyFloatPropertyIntegerPropertyLongPropertyStringProperty, as well as a generic ObjectProperty, which can be used to wrap arbitrary object values. It is important to point out that an ObjectProperty will of course only notify invalidation and change listeners in case the property value is changed, i.e. it is altered to refer to a different object identity, not when changes are applied to the contained property value. Accordingly, an ObjectProperty that wraps a collection only notifies about changes in case a different collection is set as property value, not when the currently observed collection is changed by adding elements to or removing elements from it:

  ObjectProperty<List<Integer>> observableListObjectProperty = new SimpleObjectProperty<>();
  observableListObjectProperty.addListener(new ChangeListener<List<Integer>>() {
    @Override
    public void changed(ObservableValue<? extends List<Integer>> observable,
                List<Integer> oldValue, List<Integer> newValue)    
      System.out.println("Change from " + oldValue + " to " + newValue);
    }
  });
  
  // change listener will be notified about identity change from 'null' to '[]'
  observableListObjectProperty.set(new ArrayList<Integer>());
  // change listener will not be notified
  observableListObjectProperty.get().addAll(Arrays.asList(1, 2, 3));

This is where JavaFX observable collections come into play. As Java does not provide notification support in its standard collections, JavaFX delivers dedicated observable variants: ObservableListObservableMap and ObservableSet. They all support invalidation listener notification (as properties do) and in addition define their own respective change listeners (ListChangeListenerMapChangeListener, and SetChangeListener).

ObservableList also extends List by adding setAll(E... elements) and setAll(Collection<? extends E> c), which combines a clear() with an addAll(Collection< ? extends E> c) into a single atomic replace operation, as well as a remove(int from, int to) that supports removal within an index interval. This allows to 'reduce noise', which is quite important to a graphical framework like GEF, where complex computations might be triggered by changes.

List changes are iterable, i.e. they comprise several sub-changes, so that even a complex operation like setAll(Collection<? extends E> c) results in a single change notification:

  ObservableList<Integer> observableList = FXCollections.observableArrayList();
  observableList.addListener(new ListChangeListener<Integer>() {
    
    @Override
    public void onChanged(Change<? extends Integer> change) {
      while (change.next()) {
        int from = change.getFrom();
        int to = change.getTo();
        // iterate through the sub-changes
        if (change.wasReplaced()) {
          // replacement (simultaneous removal and addition in a continuous range)
         System.out.println("Replaced " + change.getRemoved()  
                   + " with " + change.getAddedSubList() + ".");
        } else if (change.wasAdded()) {
          // addition (added sublist within from-to range)
         System.out.println("Added " + change.getAddedSubList() 
                   + " within [" + from + ", " + to + ").");
        } else if (change.wasRemoved()) {
          // removal (change provides removed sublist and from index)
  System.out.println("Removed " + change.getRemoved() + " at " + from + ".");
        } else if (change.wasPermutated()) {
          // permutation (change provides mapping of old indexes to new indexes)
  System.out.print("Permutated within [" + change.getFrom() + ", " + to + "):");
  for (int i = from; i < to; i++) {
    System.out.print((i == from ? " " : ", "
                        +  i + " -> " + change.getPermutation(i)
                        + (i == to - 1 ? ".\n" : ""));
  }
        }
      }
    }
  });
  
  // one comprised change: 'Added [3, 1, 2] within [0, 3).'
  observableList.setAll(Arrays.asList(3, 1, 2));
  
  // one comprised change: 'Permutated within [0, 3): 0 -> 2, 1 -> 0, 2 -> 1.'
  Collections.sort(observableList);
  
  // one comprised change: 'Replaced [1, 2, 3] with [4, 5, 6].'     
  observableList.setAll(Arrays.asList(4, 5, 6));
  
  // two comprised changes: 'Removed [4] at index 0.', 'Removed [6] at index 1.'
  observableList.removeAll(Arrays.asList(4, 6));

Similar to properties, observable collections may even be used to establish bindings using so called content bindings:

  // ensure that elements of list are synchronized with that of observableList
  List<Integer> list = new ArrayList<>();
  Bindings.bindContent(list, observableList);

As such, observable collections are quite usable, even if not being wrapped into a property. As long as the identity of an observable collection is not to be changed, it may directly be exposed without being wrapped into a property. And that's exactly how JavaFX uses them in its own API. As an example consider javafx.scene.Parent, which exposes its children via an ObservableList:

  public abstract class Parent extends Node {
    ...
  protected ObservableList<Node> getChildren() {
      return children;
    }
    
    @ReturnsUnmodifiableCollection
    public ObservableList<Node> getChildrenUnmodifiable() {
      return unmodifiableChildren;
    }
  }

Wrapping it into a property however is required, if a collection's identity is to be changed (in a way transparent to listeners) or properties are to be bound to it. In principle an observable collection could be wrapped directly into an ObjectProperty but this has the disadvantage that two listeners are required if collection changes are to be properly tracked.

Consider an ObservableList being wrapped into a SimpleObjectProperty as an example. While changes to the list can be observed by registering a ListChangeListener a ChangeListener is required in addition to keep track of changes to the property's value itself (and to transfer the list change listener from an old property value to a new one):

  ObjectProperty<ObservableList<Integer>> observableListObjectProperty
    new SimpleObjectProperty<>();
  
  final ListChangeListener<Integer> listChangeListener = new  ListChangeListener<Integer>(){
    @Override
    public void onChanged(ListChangeListener.Change<? extends Integer> c) {
      // react to list changes
    }
  };
  
  // register list change listener at (current) property value
  observableListObjectProperty.get().addListener(listChangeListener);
  
  // register change listener to transfer list change listener
  observableListObjectProperty.addListener(new ChangeListener<ObservableList<Integer>>() {
      @Override
      public void changed(ObservableValue<? extends ObservableList<Integer>> observable,
                  ObservableList<Integer> oldValue,
                  ObservableList<Integer> newValue) {
        // transfer list change listener from old value to new one
        if(oldValue != null && oldValue != newValue){
          oldValue.removeListener(listChangeListener);
        }
        if(newValue != null && oldValue != newValue){
          newValue.addListener(listChangeListener);
        }
      }
    });
  }

As this is quite cumbersome, JavaFX offers respective collection properties that can be used as an alternative: ListPropertySetProperty, and MapProperty. They support invalidation and change listeners as well as the respective collection specific listeners and will even synthesize a collection change when the observed property value is changed:

  ListProperty<Integer> listProperty = new SimpleListProperty<>(
    FXCollections.<Integer> observableArrayList());
  
  final ListChangeListener<Integer> listChangeListener = new ListChangeListener<Integer>() {
    @Override
    public void onChanged(ListChangeListener.Change<? extends Integer> change) {
      // handle list changes
    }
  };
  listProperty.addListener(listChangeListener);
  
  // forwarded list change: 'Added [1, 2, 3] within [0, 3).'
  listProperty.addAll(Arrays.asList(1, 2, 3));
  
  // synthesized list change: 'Replaced [1, 2, 3] with [4, 5, 6].'
  listProperty.set(FXCollections.observableArrayList(4, 5, 6));

In addition, collection properties define their own (read-only) properties for emptiness, equality, size, etc., so that advanced bindings can also be created:

  // bind boolean property to 'isEmpty'
  BooleanProperty someBooleanProperty = new SimpleBooleanProperty();
  someBooleanProperty.bind(listProperty.emptyProperty());
  
  // bind integer property to 'size'
  IntegerProperty someIntegerProperty = new SimpleIntegerProperty();
  someIntegerProperty.bind(listProperty.sizeProperty());

While observable properties are thus not required to notify about collection changes (which is already possible using observable collections alone), they add quite some comfort when having to deal with situations where collections may be replaced or where bindings have to rely on certain properties (emptiness, size, etc.) of a collection.


GEF4 Common Collections


As already mentioned, GEF4 MVC uses some of Google Guava's collection classes, while JavaFX only offers observable variants of SetMap, and List. In order to facilitate a unique style for property change notifications in our complete code base, observable variants had to be created up front. That actually involved more design decisions than I had expected. To my own surprise, I also ended up with a replacement class for ObservableList and a utility class to augment the original API, because that seemed quite necessary in a couple of places.

Obtaining atomic changes

As this might not be directly obvious from what was said before, let me point out that only ObservableList is indeed capable of notifying about changes atomically in the way laid out beforeObservableSet and ObservableMap notify their listeners for each elementary change individually. That is, an ObservableMap notifies change listeners independently for each affected key change, while ObservableSet will do likewise for each affected element. Calling clear() on an ObservableMap or can thus lead to various change notifications.

I have no idea why the observable collections API was designed in such an inhomogeneous way (it's discussed at JDK-8092534 without providing much more insight), but I think that an observable collection should rather behave like ObservableList, i.e. fire only a single change notification for each  method call. If all required operations can be performed atomically via dedicated methods, a client can fully control which notifications are produced. As already laid out, ObservableList follows this to some extend with the additionally provided setAll() methods that combine clear() and addAll() into a single atomic operation, which would otherwise yield two notifications. However, an atomic move() operation is still lacking for ObservableList, so that movement of elements currently cannot be performed atomically.

When creating ObservableSetMultimap and ObservableMultiset, I tried to follow the contract of ObservableList for the above mentioned reasons. Both notify their listeners through a single atomic change for each method call, which provides details about elementary sub-changes (related to a single element or key), very similar to ListChangeListener#ChangeIn accordance to the addAll() of ObservableList, I added a replaceAll() operation to both to offer an atomic operation via which the contents of the collections can be replaced. Change notifications are iterable, as for ObservableList:

  ObservableSetMultimap<Integer, String> observableSetMultimapCollectionUtils.<Integer, String> observableHashMultimap();
  observableSetMultimap.addListener(new SetMultimapChangeListener<Integer, String>() {
    @Override
    public void onChanged(SetMultimapChangeListener.Change<? extends Integer,
                                                           ? extends String> change) {
      while (change.next()) {
        if (change.wasAdded()) {
          // values added for key
          System.out.println("Added " + change.getValuesAdded() 
                           + " for key " + change.getKey() + ".");
        } else if (change.wasRemoved()) {
          // values removed for key
          System.out.println("Removed " + change.getValuesRemoved() + " for key " 
                           + change.getKey() + ".");
        }
      }
    }
  });
  
  // one comprised change: 'Added [1] for key 1.'
  observableSetMultimap.put(1, "1");
  
  // one comprised change: 'Added [2] for key 2.'
  observableSetMultimap.put(2, "2");
  
  // two comprised changes: 'Removed [1] for key 1.', 'Removed [2] for key 2.'
  observableSetMultimap.clear();

I also though about providing replacement classes for ObservableMap and ObservableSet that rule out the inhomogeneity of the JavaFX collections API, but this would have required to extend their respective listener interfaces, and I thus abstained. 

Retrieving the "previous" contents of an observable collection

While in principle I like the API of ListChangeListener#Change, what really bothers me is that there is no convenience method to retrieve the old state of an ObservableList before it was changed. It has to be recomputed from the respective addition, removal, and permutation sub-changes (which will be propagated when sorting the list) that are comprised. 

When creating ObservableMultiset and ObservableSetMultimap, I added a getPreviousContent() method to both, so clients can easily access the contents the collection contained before the change was applied. I also added a utility method (within CollectionUtils) that can be used to retrieve the previous contents of an ObservableList:

  ObservableList<Integer> observableList = FXCollections.observableArrayList();
  observableList.addAll(4, 3, 1, 5, 2);
  observableList.addListener(new ListChangeListener<Integer>() {
    @Override
    public void onChanged(ListChangeListener.Change<? extends Integer> change) {
      System.out.println("Previous contents: " + CollectionUtils.getPreviousContents(change));
    }
  });
  
  // Previous contents: [4, 3, 1, 5, 2]
  observableList.set(3, 7);
  // Previous contents: [4, 3, 1, 7, 2]
  observableList.clear();

Obtaining immutable changes from an observable collection

While list fires atomic changes, its change objects are not immutable (see JDK-8092504). Thus, when a listener manipulates the observed list as a result to a change notification, the change object it currently processed will actually be changed. This is a likely pitfall, as client code may not even be aware that it is actually called from within a change notification context. Consider the following snippet:


  ObservableList<Integer> observableList = FXCollections
.observableArrayList();
  observableList.addListener(new ListChangeListener<Integer>() {
    @Override
    public void onChanged(ListChangeListener.Change<? extends Integer> change) {
      while (change.next()) {
        System.out.println(change);
      }
      // manipulate the list from within the change notification
      if (!change.getList().contains(2)) {
((List<Integer>) change.getList()).add(2);
      }
    }
  });
  // change list by adding element '1'
  observableList.add(1);

It will yield the following in valid change notifications:


  { [1] added at 0 }
  { [1, 2] added at 0 }

Again, I cannot understand why this was designed that way, but the documentation clearly states that the list may not be manipulated from within a change notification context and the implementation follows it consequently by finalizing the change object only after all listeners have been notified. In a framework as GEF having non immutable change objects is a real show stopper. Accordingly, I designed ObservableMultiset and ObservableSetMultimap to use immutable change objects only. I also created a replacement class for com.sun.javafx.collections.ObservableListWrapper (the class that is instantiated when calling FXCollections.observableArrayList()) that produces immutable change objects. It can be created using a respective utility method:

  ObservableList observableList = CollectionUtils.observableArrayList();

When using the replacement class in the above quoted scenario, it will yield the following output:

  Added[1] at 0.
  Added[2] at 1.

As ObservableSet and ObservableMap are not capable of comprising several changes into a single atomic one, the immutability problem does not arise there, so the alternative ObservableList implementation is all that is needed.

GEF4 Common (Collection) Properties


In addition to the ObservableMultiset and ObservableSetMultimap collections, I also added respective properties (and related bindings) to wrap these values to GEF4 Common: SimpleMultisetPropertyReadOnlyMultisetPropertySimpleSetMultimapProperty, and ReadOnlySetMultimapProperty.

It should no longer be surprising that I did not only create these, but also ended up with replacement classes for JavaFX's own collection properties (SimpleSetPropertyExReadOnlySetWrapperExSimpleMapPropertyExReadOnlyMapWrapperExSimpleListPropertyExReadOnlyListWrapperEx), because a comparable, consistent behavior could otherwise not be guaranteed.

Stopping the noise

As I have elaborated quite intensively already, observable collection notify about element changes, whereas properties notify about (identity) changes of their contained (observable) value. Collection properties in addition forward all collection notifications, so that a replacement of the property's value is transparent to collection listeners.

However, this is not the full story. The observable collection properties offered by JavaFX fire change notifications even if the observed value did not change (JDK-8089169). That is, every collection change will not only lead to the notification of collection-specific change listeners, but also to the notification of all property change listeners:

  SimpleListProperty<Integer> listProperty = new SimpleListProperty<>(
    FXCollections.<Integer> observableArrayList());
  
  listProperty.addListener(new ChangeListener<ObservableList<Integer>>() {
    @Override
    public void changed(ObservableValue<? extends ObservableList<Integer>> observable,
                        ObservableList<Integer> oldValue,
                        ObservableList<Integer> newValue) {
      System.out.println("Observable (collection) value changed.");
    }
  });
  
  listProperty.addListener(new ListChangeListener<Integer>() {
    @Override
    public void onChanged(ListChangeListener.Change<? extends Integer> c) {
      System.out.println("Collection changed.");
    }
  });
  
  // will (incorrectly) notify (property) change listeners in addition to
  // list change listeners
  listProperty.add(5);
  
  // will (correctly) notify list change listeners and (property) change
  // listeners
  listProperty.set(FXCollections.<Integer> observableArrayList());

As this leads to a lot of unwanted noise, I have ensured that MultisetProperty and SetMultimapProperty, which are provided as part of GEF4 Common, do not babble likewise. I ensured that the replacement classes we provide for the JavaFX collection properties behave accordingly, too.

Guarding notifications consistently

JavaFX observable collection capture all exceptions that occur during a listener notification. That is, the listener notification is guarded as follows:

  try {
    listener.onChanged(change);
  } catch (Exception e) {
    Thread.currentThread().getUncaughtExceptionHandler().
    uncaughtException(Thread.currentThread(), e);
  }

Interestingly, JavaFX properties don't behave like that. Thus, all observable collection properties are inconsistent in a sense that collection change listener invocations will be guarded, while (property) change listener notifications won't. Again, I have ensured that the GEF4 Common provided collection properties show consistent behavior by guarding all their listener notifications, and I have done likewise for the replacement classes we provide.

Fixing further issues and ensuring JavaSE-1.7 compatibility

Having the replacement classes at hand, I also fixed some further inconsistencies that bothered us quite severely. This includes the recently introduced regression that JavaFX MapProperty removes all attached change listeners when just one is to be removed (JDK-8136465), as well as the fact that read-only properties can currently not be properly bound (JDK-8089557).

As GEF4 still aims at providing support for JavaSE-1.7, I tried to ensure that all collection properties we provide, including the replacement classes, can be used in a JavaSE-1.7 environment, too. Except that the static methods JavaFX offers to create and remove bindings cannot be applied (because the binding mechanism has been completely revised from JavaSE-1.7 to JavaSE-1.8), this could be achieved.

While we make intensive use of GEF4 Common Collections and Properties in our own GEF4 framework, GEF4 Common can be used independently. If you need observable variants of Google Guava's Multiset or SetMultimap, or if you want to get rid of the aforementioned inconsistencies, it may be worth taking a look.