Skip to main content
Jump to: navigation, search

Difference between revisions of "GEF/GEF4/Common"

< GEF‎ | GEF4
(Adapt)
(Adapt)
 
(31 intermediate revisions by 2 users not shown)
Line 20: Line 20:
 
* [[#Activate|Activate]]: A general abstraction for ''activatable'' objects and a related support class
 
* [[#Activate|Activate]]: A general abstraction for ''activatable'' objects and a related support class
 
* [[#Adapt|Adapt]]: A general abstraction for ''adaptable'' objects and related support classes
 
* [[#Adapt|Adapt]]: A general abstraction for ''adaptable'' objects and related support classes
 +
* [[#Adapt.Inject|Adapt.Inject]]: [https://github.com/google/guice Google Guice]-based support for injecting and scoping adapters at adaptable objects
 +
* [[#Attributes|Attributes]]: A general abstraction of an attribute store
 +
* [[#Beans.Binding|Beans.Binding]]: JavaFX-style bindings for the properties provided by [[#Beans.Property|Beans.Property]].
 +
* [[#Beans.Property|Beans.Property]]: JavaFX-style properties for [https://github.com/google/guava Google Guava]'s [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/collect/Multiset.html com.google.common.collect.Multiset] and [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/collect/SetMultimap.html com.google.common.collect.SetMultimap] as well as replacements for JavaFX's Set, List, and Map collection properties
 +
* [[#Beans.Value|Beans.Value]]: Observable value abstraction related to the collections offered by [[#Collections|Collections]] as well as writable value abstractions related to the properties offered by [[#Beans.Property|Beans.Property]].
 +
* [[#Collections|Collections]]: JavaFX-style observable collections for [https://github.com/google/guava Google Guava]'s [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/collect/Multiset.html com.google.common.collect.Multiset] and [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/collect/SetMultimap.html com.google.common.collect.SetMultimap] collections and related listener abstractions.
 
* [[#Dispose|Dispose]]: A general abstraction for ''disposable'' objects
 
* [[#Dispose|Dispose]]: A general abstraction for ''disposable'' objects
* [[#Inject|Inject]]: Google Guice-based support for injecting and scoping adapters at adaptable objects
 
* [[#Notify|Notify]]: Observable collections and related listener abstractions
 
* [[#Properties|Properties]]: A general abstraction of a property store, a related support class, and a property change notifier
 
 
* [[#Reflect|Reflect]]: A utility class for working with Java Reflection
 
* [[#Reflect|Reflect]]: A utility class for working with Java Reflection
  
Line 37: Line 40:
  
 
==== IActivatable ====
 
==== IActivatable ====
An <code>IActivatable</code> maintains an 'active' state and can be activated and deactivated. It is also an [[#IPropertyChangeNotifier |IPropertyChangeNotifier]] to propagate changes to its 'active' state to registered [http://docs.oracle.com/javase/7/docs/api/index.html?java/beans/PropertyChangeListener.html PropertyChangeListener]s.
+
An <code>IActivatable</code> maintains an 'active' state and can be activated and deactivated. The active state of an <code>IActivatable</code> is exposed via an (observable) [http://docs.oracle.com/javafx/2/api/javafx/beans/property/ReadOnlyBooleanProperty.html javafx.beans.property.ReadOnlyBooleanProperty], so listeners can easily observe the active state.
  
 
==== ActivatableSupport ====
 
==== ActivatableSupport ====
Line 45: Line 48:
 
public class MyActivatable implements IActivatable {
 
public class MyActivatable implements IActivatable {
  
   // create delegates
+
   // create delegate
  private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
+
   private ActivatableSupport acs = new ActivatableSupport(this);
   private ActivatableSupport acs = new ActivatableSupport(this, pcs);
+
  
 
   public void activate() {
 
   public void activate() {
Line 57: Line 59:
 
</source>
 
</source>
  
It needs to be provided with a [http://docs.oracle.com/javase/7/docs/api/index.html?java/beans/PropertyChangeSupport.html PropertyChangeSupport], which will be used to notify listeners changes of the 'active' state. In case the [[#IActivatable |IActivatable]], by which it is used as a delegate, is also [[#IAdaptable, AdapterKey |IAdaptable]], it will ensure that all [[#IActivatable |IActivatable]] adapters are properly activated/deactivated when the [[#IActivatable |IActivatable]] is activated or deactivated (it will not activate/deactivate adapters when being registered; this is supported by [[#AdaptableSupport|AdaptableSupport]]).
+
In case the [[#IActivatable |IActivatable]], by which it is used as a delegate, is also [[#IAdaptable, AdapterKey |IAdaptable]], it will ensure that all [[#IActivatable |IActivatable]] adapters are properly activated/deactivated when the [[#IActivatable |IActivatable]] is activated or deactivated (it will not activate/deactivate adapters when being registered; this is supported by [[#AdaptableSupport|AdaptableSupport]]).
  
 
----
 
----
Line 65: Line 67:
 
*'''package: org.eclipse.gef4.common.adapt'''
 
*'''package: org.eclipse.gef4.common.adapt'''
  
The [[#Adapt|Adapt]] package provides a modernized interpretation of [http://help.eclipse.org/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/runtime/IAdaptable.html org.eclipse.core.runtime.IAdaptable], providing the following enhancements:
+
The [[#Adapt|Adapt]] package provides a modernized interpretation of [http://help.eclipse.org/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/runtime/IAdaptable.html org.eclipse.core.runtime.IAdaptable].
 +
 
 +
The motivation behind this extension and a short overview is given in [http://nyssen.blogspot.de/2014/11/iadaptable-gef4s-interpretation-of.html IAdaptable - GEF4's Interpretation of a Classic]. In detail, the enhancements provided by [[#Adapt|Adapt]] are:
  
# Adapters may be registered and retrieved by means of a [http://docs.guava-libraries.googlecode.com/git-history/v15.0/javadoc/com/google/common/reflect/TypeToken.html com.google.common.reflect.TypeToken] key as an alternative to a Class key, which ensures that adapters with parameterized types may also be registered and retrieved in a type-safe manner, not only via their raw type. For instance, an adapter instance ''a1'' of parameterized type ''A<T1>'' and an instance ''a2'' of type ''A<T2>'' can both be registered at an [[#IAdaptable, AdapterKey |IAdaptable]]. The [[GEF/GEF4/MVC |GEF4 MVC]] component makes use of this intensively, when registering providers, i.e. a Provider<? extends IGeometry> and a Provider<? extends IFXAnchor> can both be registered at an IVisualPart simultaneously.
+
# Adapters may be registered and retrieved by means of a [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/reflect/TypeToken.html com.google.common.reflect.TypeToken] key as an alternative to a Class key, which ensures that adapters with parameterized types may also be registered and retrieved in a type-safe manner, not only via their raw type. For instance, an adapter instance ''a1'' of parameterized type ''A<T1>'' and an instance ''a2'' of type ''A<T2>'' can both be registered at an [[#IAdaptable, AdapterKey |IAdaptable]]. The [[GEF/GEF4/MVC |GEF4 MVC]] component makes use of this intensively, when registering providers, i.e. a Provider<? extends IGeometry> and a Provider<? extends IFXAnchor> can both be registered at an IVisualPart simultaneously.
 
# Adapters may (optionally) be registered and retrieved by providing an additional role key, which allows to register multiple adapters of the same type (using different roles) at an [[#IAdaptable, AdapterKey |IAdaptable]]. For instance, adapter instances ''a1'' and ''a2'' of type ''A'' can both be registered at an adaptable using different roles. The [[GEF/GEF4/MVC |GEF4 MVC]] component again makes use of this, when registering providers. Different geometry providers (Provider<? extends IGeometry>) are e.g. registered for selection and hover feedback, by registering respective providers with respective roles.
 
# Adapters may (optionally) be registered and retrieved by providing an additional role key, which allows to register multiple adapters of the same type (using different roles) at an [[#IAdaptable, AdapterKey |IAdaptable]]. For instance, adapter instances ''a1'' and ''a2'' of type ''A'' can both be registered at an adaptable using different roles. The [[GEF/GEF4/MVC |GEF4 MVC]] component again makes use of this, when registering providers. Different geometry providers (Provider<? extends IGeometry>) are e.g. registered for selection and hover feedback, by registering respective providers with respective roles.
 
# Adapters may request a back-reference to the respective [[#IAdaptable, AdapterKey |IAdaptable]] they get registered at, by implementing a respective back-interface ([[#IAdaptable.Bound |IAdaptable.Bound]]). Again, this is intensively used within [[GEF/GEF4/MVC |GEF4 MVC]], where an IBehavior or IPolicy for instance needs to be aware of the host IVisualPart it is registered at.
 
# Adapters may request a back-reference to the respective [[#IAdaptable, AdapterKey |IAdaptable]] they get registered at, by implementing a respective back-interface ([[#IAdaptable.Bound |IAdaptable.Bound]]). Again, this is intensively used within [[GEF/GEF4/MVC |GEF4 MVC]], where an IBehavior or IPolicy for instance needs to be aware of the host IVisualPart it is registered at.
Line 78: Line 82:
 
==== IAdaptable, AdapterKey ====
 
==== IAdaptable, AdapterKey ====
  
An <code>IAdaptable</code> provides facilities to register adapters and to retrieve them via a combination of a type key ([http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/Class.html java.lang.Class] or [http://docs.guava-libraries.googlecode.com/git-history/v15.0/javadoc/com/google/common/reflect/TypeToken.html com.google.common.reflect.TypeToken]) and an (optional) [http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/String.html java.lang.String] role, which are combined in an <code>AdapterKey</code>. Having the option to use a [http://docs.guava-libraries.googlecode.com/git-history/v15.0/javadoc/com/google/common/reflect/TypeToken.html com.google.common.reflect.TypeToken] instead of a simple [http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/Class.html java.lang.Class] key, enables the type-safe retrieval of adapters with parameterized types. The combination with an additional (optional) role enables that multiple adapters of the same type may be registered at an <code>IAdaptable</code>.
+
An <code>IAdaptable</code> provides facilities to register adapters and to retrieve them via a combination of a type key ([http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/Class.html java.lang.Class] or [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/reflect/TypeToken.html com.google.common.reflect.TypeToken]) and an (optional) [http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/String.html java.lang.String] role, which are combined in an <code>AdapterKey</code>. Having the option to use a [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/reflect/TypeToken.html com.google.common.reflect.TypeToken] instead of a simple [http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/Class.html java.lang.Class] key, enables the type-safe retrieval of adapters with parameterized types. The combination with an additional (optional) role enables that multiple adapters of the same type may be registered at an <code>IAdaptable</code>.
  
 
The 'traditional' getAdapter(Class<T>) method provided by the Eclipse Core Runtime [http://help.eclipse.org/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/runtime/IAdaptable.html org.eclipse.core.runtime.IAdaptable] here is a mere convenience operation that will retrieve the single adapter registered with the respective [http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/Class.html java.lang.Class] key and the ''default'' role (or the only adapter registered under the given [http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/Class.html java.lang.Class] key, if there is only one adapter for that type key).  
 
The 'traditional' getAdapter(Class<T>) method provided by the Eclipse Core Runtime [http://help.eclipse.org/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/runtime/IAdaptable.html org.eclipse.core.runtime.IAdaptable] here is a mere convenience operation that will retrieve the single adapter registered with the respective [http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/Class.html java.lang.Class] key and the ''default'' role (or the only adapter registered under the given [http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/Class.html java.lang.Class] key, if there is only one adapter for that type key).  
  
Before retrieving adapters from an <code>IAdaptable</code>, they have to be registered. The registration again includes a role (while a 'default' role is used in case no role is provided) and might require additional information about the actual adapter type by means of a [http://docs.guava-libraries.googlecode.com/git-history/v15.0/javadoc/com/google/common/reflect/TypeToken.html com.google.common.reflect.TypeToken]. The additional type information is required in case it cannot be inferred from the registered adapter instance itself (which is the case for parameterized types).
+
Before retrieving adapters from an <code>IAdaptable</code>, they have to be registered. The registration again includes a role (while a 'default' role is used in case no role is provided) and might require additional information about the actual adapter type by means of a [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/reflect/TypeToken.html com.google.common.reflect.TypeToken]. The additional type information is required in case it cannot be inferred from the registered adapter instance itself (which is the case for parameterized types).
  
 
An adapter can thus now be registered and retrieved in various ways:
 
An adapter can thus now be registered and retrieved in various ways:
Line 104: Line 108:
 
</source>
 
</source>
  
To formalize support for notifying listeners about registration and unregistration of adapters, <code>IAdaptable</code> furthermore extends [[#IPropertyChangeNotifier |IPropertyChangeNotifier]], which provides capabilities for registering and unregistering respective listeners.
+
To formalize support for notifying listeners about registration and unregistration of adapters, <code>IAdaptable</code> provides its adapters via an [http://docs.oracle.com/javafx/2/api/javafx/collections/ObservableMap.html javafx.collections.ObservableMap] and an (unmodifiable) [http://docs.oracle.com/javafx/2/api/javafx/beans/property/ReadOnlyMapProperty.html javafx.beans.property.ReadOnlyMapProperty].
  
 
==== IAdaptable.Bound ====
 
==== IAdaptable.Bound ====
Line 138: Line 142:
 
public class MyAdaptable implements IAdaptable {
 
public class MyAdaptable implements IAdaptable {
  
   // create delegates
+
   // create delegate
  private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
+
   private AdaptableSupport<MyAdaptable> ads = new AdaptableSupport<MyAdaptable>(this);
   private AdaptableSupport<MyAdaptable> ads = new AdaptableSupport<MyAdaptable>(this, pcs);
+
  
 
   public <T> T getAdapter(AdapterKey<T> key){
 
   public <T> T getAdapter(AdapterKey<T> key){
Line 150: Line 153:
 
</source>
 
</source>
  
It needs to be provided with a [http://docs.oracle.com/javase/7/docs/api/index.html?java/beans/PropertyChangeSupport.html PropertyChangeSupport], which will be used to notify listeners about registration and unregistration of adapters. In case the [[#IAdaptable, AdapterKey |IAdaptable]], by which it is used as a delegate, is also [[#IActivatable |IActivatable]], it will ensure that all [[#IActivatable |IActivatable]] adapters are properly activated/deactivated when being registered/unregistered dependent on the active state of the adaptable at that moment (it will not activate/deactivate adapters when the adaptable is activated or deactivated; this is supported by [[#ActivatableSupport|ActivatableSupport]]).
+
In case the [[#IAdaptable, AdapterKey |IAdaptable]], by which it is used as a delegate, is also [[#IActivatable |IActivatable]], it will ensure that all [[#IActivatable |IActivatable]] adapters are properly activated/deactivated when being registered/unregistered dependent on the active state of the adaptable at that moment (it will not activate/deactivate adapters when the adaptable is activated or deactivated; this is supported by [[#ActivatableSupport|ActivatableSupport]]).
  
 
==== AdapterStore ====
 
==== AdapterStore ====
Line 157: Line 160:
 
----
 
----
  
=== Dispose  ===
+
=== Adapt.Inject  ===
 
+
*'''package: org.eclipse.gef4.common.dispose'''
+
 
+
The [[#Dispose|Dispose]] package provides an abstraction ([[#IDisposable |IDisposable]]) for objects that need to be notified when being disposed.
+
 
+
[[File:GEF4-Common-dispose.png|117px]]
+
 
+
==== IDisposable ====
+
 
+
An <code>IDisposable</code> needs to be disposed. While the <code>IDisposable</code> encapsulates the necessary steps that have to be performed when being disposed, the initiation of the disposal is left to its clients.
+
 
+
----
+
 
+
=== Inject  ===
+
  
*'''package: org.eclipse.gef4.common.inject'''
+
*'''package: org.eclipse.gef4.common.adapt.inject'''
  
The [[#Inject|Inject]] package contains [https://github.com/google/guice Google Guice]-based support for injecting adapters into an [[#IAdaptable, AdapterKey |IAdaptable]]. That is, if an [[#IAdaptable, AdapterKey |IAdaptable]] implementation provides an [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Inject.html @Inject]-annotated method with a single Map<AdapterKey<?>, Object> parameter, which is annotated with a respective inject annotation (@AdapterMap), and if corresponding adapter map-bindings targeting the [[#IAdaptable, AdapterKey |IAdaptable]] implementation are provided within a [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Module.html com.google.inject.Module], adapter instances can automatically be injected into instances of the [[#IAdaptable, AdapterKey |IAdaptable]]. It needs to be pointed out that respective adapter map-bindings are evaluated polymorphically, i.e. a concrete adaptable will also be injected with all adapters that registered for super types of it.
+
The [[#Adapt.Inject|Adapt.Inject]] package contains [https://github.com/google/guice Google Guice]-based support for injecting adapters into an [[#IAdaptable, AdapterKey |IAdaptable]]. That is, if an [[#IAdaptable, AdapterKey |IAdaptable]] implementation provides an @InjectAdapters annotation on its <T> setAdapter(TypeToken<T>, T, String) method, and if corresponding adapter (map) bindings qualified with an @AdapterMap annotation are provided within a [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Module.html com.google.inject.Module], adapter instances can automatically be injected into instances of the [[#IAdaptable, AdapterKey |IAdaptable]]. It needs to be pointed out that respective adapter (map) bindings are evaluated polymorphically, i.e. a concrete adaptable will also be injected with all adapters that registered for super types of it.
  
 
[[File:GEF4-Common-inject-adaptermap.png|969px]]
 
[[File:GEF4-Common-inject-adaptermap.png|969px]]
Line 183: Line 172:
 
[[File:GEF4-Common-inject-adaptablescopes.png|763px]]
 
[[File:GEF4-Common-inject-adaptablescopes.png|763px]]
  
==== AdapterMapInjectionSupport, AdaptableTypeListener, AdapterMapInjector ====
+
==== AdapterInjectionSupport, AdaptableTypeListener, AdapterInjector ====
To enable injection of adapters to an [[#IAdaptable, AdapterKey |IAdaptable]], a specific [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/spi/TypeListener.html com.google.inject.spi.TypeListener] (<code>AdaptableTypeListener</code>) needs to be registered in the [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Module.html com.google.inject.Module]. To ensure this is done properly, a respective support [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Module.html com.google.inject.Module] is provided, namely <code>AdapterMapInjectionSupport</code>, which can easily be integrated into a custom [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Module.html com.google.inject.Module] as follows:
+
To enable injection of adapters to an [[#IAdaptable, AdapterKey |IAdaptable]], a specific [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/spi/TypeListener.html com.google.inject.spi.TypeListener] (<code>AdaptableTypeListener</code>) needs to be registered in the [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Module.html com.google.inject.Module]. To ensure this is done properly, a respective support [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Module.html com.google.inject.Module] is provided, namely <code>AdapterInjectionSupport</code>, which can easily be integrated into a custom [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Module.html com.google.inject.Module] as follows:
  
 
<source lang="java" style="border-style:solid;border-color:#f2f2f2;border-width:1px;padding:10px;margin-bottom:10px">
 
<source lang="java" style="border-style:solid;border-color:#f2f2f2;border-width:1px;padding:10px;margin-bottom:10px">
Line 192: Line 181:
 
   protected void configure() {
 
   protected void configure() {
 
     // register adapter map injection support
 
     // register adapter map injection support
     install(new AdapterMapInjectionSupport());
+
     install(new AdapterInjectionSupport());
  
 
     ...
 
     ...
Line 199: Line 188:
 
</source>
 
</source>
  
This will ensure that the <code>AdaptableTypeListener</code> is properly registered (and itself injected). The <code>AdaptableTypeListener</code> will register a dedicated [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/MembersInjector.html com.google.inject.MembersInjector] (<code>AdapterMapInjector</code>) on all suitable [[#IAdaptable, AdapterKey |IAdaptable]] implementations it encounters.
+
This will ensure that the <code>AdaptableTypeListener</code> is properly registered (and itself injected). The <code>AdaptableTypeListener</code> will register a dedicated [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/MembersInjector.html com.google.inject.MembersInjector] (<code>AdapterInjector</code>) on all suitable [[#IAdaptable, AdapterKey |IAdaptable]] implementations it encounters.
  
==== AdapterMap, AdapterMaps ====
+
==== InjectAdapters ====
The <code>@AdapterMap</code> annotation is used in two ways. First, it is used to mark the injection point, i.e. the parameter of the method within the [[#IAdaptable, AdapterKey |IAdaptable]] implementation that is to be injected. Second, it is used to specify respective adapter map-bindings within the [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Module.html com.google.inject.Module].
+
Specifying the injection point (i.e. the <T> setAdapter(TypeToken<T>, T, String) method within a respective [[#IAdaptable, AdapterKey |IAdaptable]] implementation is achieved by adding an @InjectAdapters annotation as follows:
 
+
Specifying the injection point within a respective [[#IAdaptable, AdapterKey |IAdaptable]] implementation is achieved by means of a method, which is marked for injection by means of an [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Inject.html @Inject] annotation, and furthermore provides a single Map<AdapterKey<?>, Object> parameter that is annotated with <code>@AdapterMap</code> as follows:
+
  
 
<source lang="java" style="border-style:solid;border-color:#f2f2f2;border-width:1px;padding:10px;margin-bottom:10px">
 
<source lang="java" style="border-style:solid;border-color:#f2f2f2;border-width:1px;padding:10px;margin-bottom:10px">
 
public class MyAdaptable implements IAdaptable {
 
public class MyAdaptable implements IAdaptable {
  
   @Inject(optional = true)
+
   @InjectAdapters
   public void setAdapters(@AdapterMap Map<AdapterKey<?>, Object> adaptersWithKeys) {
+
   public <T> void setAdapter(TypeToken<T> adapterType, T adapter, String role) {
 
     ...
 
     ...
 
   }
 
   }
Line 216: Line 203:
 
</source>
 
</source>
  
Specifying the to be injected adapters is performed by means of map-bindings in the [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Module.html com.google.inject.Module].
+
==== AdapterMap, AdapterMaps ====
 +
Specifying the to be injected adapters is performed by means of map bindings in the [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Module.html com.google.inject.Module], which are qualified with an @AdapterMap annotation. In case the actual type of the to be registered adapter cannot be inferred from the adapter instance itself, or from the respective binding, information about the actual adapter type has to be provided via the [[#IAdaptable, AdapterKey |AdapterKey]] used in all bindings. Where the type of an adapter can be inferred from the instance or the binding itself, it may be omitted.  
  
 
<source lang="java" style="border-style:solid;border-color:#f2f2f2;border-width:1px;padding:10px;margin-bottom:10px">
 
<source lang="java" style="border-style:solid;border-color:#f2f2f2;border-width:1px;padding:10px;margin-bottom:10px">
Line 225: Line 213:
 
     ...
 
     ...
  
    // obtain a map binder to bind adapters for the respective IAdaptable type.
+
  // obtain a map binder to bind adapters for the respective IAdaptable type.
    MapBinder<AdapterKey<?>, Object> adapterMapBinder = AdapterMaps.getAdapterMapBinder(binder(), MyAdaptable.class);
+
  MapBinder<AdapterKey<?>, Object> adapterMapBinder = AdapterMaps.getAdapterMapBinder(binder(), MyAdaptable.class);
 
      
 
      
   // add adapter (map) binding for binding adapter 'a' of raw type 'A' to each MyAdaptable instance
+
   // add adapter (map) binding for binding adapter 'a' of raw type 'A' with 'default' role to each MyAdaptable instance;
   adapterMapBinder.addBinding(AdapterKey.get(A.class)).toInstance(a);
+
  // type information can be omitted, as it can be inferred from the adapter instance
 +
   adapterMapBinder.addBinding(AdapterKey.defaultRole()).toInstance(a);
  
   // add adapter (map) binding for binding an instance of raw type 'A' to each MyAdaptable instance
+
   // add adapter (map) binding for binding an instance of raw type 'A' with role 'r' to each MyAdaptable instance;
   adapterMapBinder.addBinding(AdapterKey.get(A.class)).to(A.class);
+
  // type information can be omitted, as it can be inferred from the binding
 +
   adapterMapBinder.addBinding(AdapterKey.role("r").to(A.class);
  
   // add adapter (map) binding for binding adapter 'a' with parameterized type 'A<T>' to each MyAdaptable instance
+
   // add adapter (map) binding for binding adapter 'a' of parameterized type 'A<T>' with 'default' role to each MyAdaptable instance;
 +
  // type information is required, as it cannot be inferred from the adapter instance, nor from the binding
 
   adapterMapBinder.addBinding(AdapterKey.get(new TypeToken<A<T>>(){})).toInstance(a);  
 
   adapterMapBinder.addBinding(AdapterKey.get(new TypeToken<A<T>>(){})).toInstance(a);  
  
Line 244: Line 235:
 
When adapter map injection is properly enabled in the [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Module.html com.google.inject.Module], all suitable [[#IAdaptable, AdapterKey |IAdaptable]] instances that are created through an [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Injector.html com.google.inject.Injector], which is aware of the respective [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Module.html com.google.inject.Module], will be injected.  
 
When adapter map injection is properly enabled in the [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Module.html com.google.inject.Module], all suitable [[#IAdaptable, AdapterKey |IAdaptable]] instances that are created through an [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Injector.html com.google.inject.Injector], which is aware of the respective [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/Module.html com.google.inject.Module], will be injected.  
  
To this extend, the <code>@AdapterMap</code>-bindings can be compared to the Guice [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/name/Named.html @Named]-bindings, only that a [http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/Class.html java.lang.Class] instead of a [http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/String.html java.lang.String] key is used. However, <code>@AdapterMap</code>-bindings are more powerful, as they are evaluated polymorphically. That is, if a binding is specified for a specific [[#IAdaptable, AdapterKey |IAdaptable]], let's say 'A', it will be evaluated for instances of all subtypes of 'A' as well, as long as they are suitable for injection (i.e. they directly or via inheritance provide a respective method for adapter map injection). This is a very powerful mechanism that is used intensively by the [[GEF/GEF4/MVC |GEF4 MVC]] component. It allows to register certain adapters already for some abstract base type, so that each concrete sub-type will be injected with a respective adapter instance.
+
To this extend, the <code>@AdapterMap</code>-bindings can be compared to the Guice [http://google.github.io/guice/api-docs/3.0/javadoc/com/google/inject/name/Named.html @Named]-bindings, only that a [http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/Class.html java.lang.Class] instead of a [http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/String.html java.lang.String] key is used. However, <code>@AdapterMap</code>-bindings are more powerful, as they are evaluated polymorphically. That is, if a binding is specified for a specific [[#IAdaptable, AdapterKey |IAdaptable]], let's say 'A', it will be evaluated for instances of all subtypes of 'A' as well, as long as they are suitable for injection (i.e. they directly or via inheritance provide a respective method eligible for adapter injection). This is a very powerful mechanism that is used intensively by the [[GEF/GEF4/MVC |GEF4 MVC]] component. It allows to register certain adapters already for some abstract base type, so that each concrete sub-type will be injected with a respective adapter instance.
  
 
==== AdaptableScope, AdaptableScopes ====
 
==== AdaptableScope, AdaptableScopes ====
Line 292: Line 283:
 
----
 
----
  
=== Notify ===
+
=== Attributes ===
  
*'''package: org.eclipse.gef4.common.notify'''
+
*'''package: org.eclipse.gef4.common.attributes'''
  
The [[#Notify|Notify]] package provides observable collections ([[#ObservableMap, IMapObserver |ObservableMap]] and [[#ObservableList, IListObserver |ObservableList]]) and abstractions for respective observers ([[#ObservableMap, IMapObserver |IMapObserver]] and [[#ObservableList, IListObserver |IListObserver]]).
+
the [[#Attributes|Attributes]] package provides abstractions around string-key based (object) properties.
  
[[File:GEF4-Common-notify.png|696px]]
+
[[File:GEF4-Common-attributes.png|688px]]
  
==== ObservableMap, IMapObserver ====
+
==== IAttributeStore ====
An <code>ObservableMap</code> is a specific Google Guava [http://docs.guava-libraries.googlecode.com/git-history/v15.0/javadoc/index.html?com/google/common/collect/ForwardingMap.html com.google.common.collect.ForwardingMap], which adds support for observing changes via an <code>IMapObserver</code>. It is e.g. used by [[GEF/GEF4/Graph | GEF4 Graph]] to make the attributes of Graph, Node, and Edge observable.
+
The <code>IAttributeStore</code> is a general abstraction that provides support for storing and retrieving [http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/Object.html java.lang.Object] attributes via [http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/String.html java.lang.String] keys in the form of an (observable) map property.
  
==== ObservableList, IListObserver ====
+
==== IAttributeCopier ====
An <code>ObservableList</code> is a specific Google Guava [http://docs.guava-libraries.googlecode.com/git-history/v15.0/javadoc/index.html?com/google/common/collect/ForwardingList.html com.google.common.collect.ForwardingList], which adds support for observing changes via an <code>IListObserver</code>. It is e.g. used by [[GEF/GEF4/Graph | GEF4 Graph]] to make the edges and nodes of a Graph observable.
+
The <code>IAttributeCopier</code> is a general abstraction for a copier that can transfer/copy attributes from one [[#IAttributeStore|IAttributeStore]] to another. It provides static <code>NULL_COPY</code> and <code>SHALLOW_COPY</code> default copier implementations.
  
 
----
 
----
  
=== Properties ===
+
=== Beans.Binding ===
  
*'''package: org.eclipse.gef4.common.properties'''
+
*'''package: org.eclipse.gef4.common.beans.binding'''
  
The [[#Properties|Properties]] package provides abstractions and supporting classes to store and retrieve properties, as well as to notify about property changes.  
+
The [[#Beans.Binding | Beans.Binding]] package provides binding implementations for [https://github.com/google/guava Google Guava]'s [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/collect/Multiset.html com.google.common.collect.Multiset] and [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/collect/SetMultimap.html com.google.common.collect.SetMultimap] collections, as well as replacements for JavaFX's (internal) expression helper classes, which are used by the JavaFX property replacement classes provided by [[#Beans.Property | Beans.Property]].
  
[[File:GEF4-Common-properties.png|634px]]
+
[[File:GEF4-Common-beans-binding-guava.png|1141px]]
  
==== IPropertyChangeNotifier ====
+
[[File:GEF4-Common-beans-binding-fxreplacements.png|493px]]
An <code>IPropertyChangeNotifier</code> provides facilities to register and unregister [http://docs.oracle.com/javase/7/docs/api/index.html?java/beans/PropertyChangeListener.html PropertyChangeListener]s. It may easily be implemented by using a [http://docs.oracle.com/javase/7/docs/api/index.html?java/beans/PropertyChangeSupport.html java.beans.PropertyChangeSupport] as follows:
+
  
<source lang="java" style="border-style:solid;border-color:#f2f2f2;border-width:1px;padding:10px;margin-bottom:10px">
+
----
public class MyPropertyChangeNotifier implements IPropertyChangeNotifier {
+
  
  // create delegate
+
=== Beans.Property  ===
  private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
+
*'''package: org.eclipse.gef4.common.beans.property'''
  
  @Override
+
The [[#Beans.Property | Beans.Property]] package provides (observable) property abstractions and implementations for [https://github.com/google/guava Google Guava]'s [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/collect/Multiset.html com.google.common.collect.Multiset] and [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/collect/SetMultimap.html com.google.common.collect.SetMultimap] collections, as well as replacements for JavaFX's list, set, and map property base classes ([http://docs.oracle.com/javafx/2/api/javafx/beans/property/ReadOnlyMapPropertyBase.html javafx.beans.property.ReadOnlyMapPropertyBase], [http://docs.oracle.com/javafx/2/api/javafx/beans/property/ReadOnlyListPropertyBase.html javafx.beans.property.ReadOnlyListPropertyBase], [http://docs.oracle.com/javafx/2/api/javafx/beans/property/ReadOnlySetPropertyBase.html javafx.beans.property.ReadOnlySetPropertyBase], [http://docs.oracle.com/javafx/2/api/javafx/beans/property/SimpleMapProperty.html javafx.beans.property.SimpleMapProperty], [http://docs.oracle.com/javafx/2/api/javafx/beans/property/SimpleListProperty.html javafx.beans.property.SimpleListProperty], [http://docs.oracle.com/javafx/2/api/javafx/beans/property/SimpleSetProperty.html javafx.beans.property.SimpleSetProperty]).
  public void addPropertyChangeListener(PropertyChangeListener listener) {
+
    pcs.addPropertyChangeListener(listener);
+
  }
+
  
  @Override
+
A good overview about how to use the properties provided by [[#Beans.Property | Beans.Property]] is given in [http://nyssen.blogspot.de/2016/04/gef4-common-collections-and-properties.html GEF4 Common Collections and Properties - Guava goes FX].
  public void removePropertyChangeListener(PropertyChangeListener listener) {
+
    pcs.removePropertyChangeListener(listener);
+
  }
+
  
  ...
+
[[File:GEF4-Common-beans-property-guava.png|1431px]]
}
+
</source>
+
  
==== IPropertyStore ====
+
[[File:GEF4-Common-beans-property-fxreplacements.png|1074px]]
An <code>IPropertyStore</code> provides facilities to store and retrieve arbitrary valued properties via [http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/String.html java.lang.String] keys. Being an [[#IPropertyChangeNotifier |IPropertyChangeNotifier]], it is responsible of notifying any registered listeners about property value changes.
+
  
==== PropertyStoreSupport ====
+
----
To enforce that implementers of [[#IPropertyStore |IPropertyStore]] properly follow the contract, <code>PropertyStoreSupport</code> may be used. It does not formally implement the [[#IPropertyStore |IPropertyStore]] interface but provides implementations for all its methods and can thus be simply used as a delegate, as follows:
+
  
<source lang="java" style="border-style:solid;border-color:#f2f2f2;border-width:1px;padding:10px;margin-bottom:10px">
+
=== Beans.Value  ===
public class MyPropertyStore implements IPropertyStore {
+
  
  // create delegates
+
*'''package: org.eclipse.gef4.common.beans.value'''
  private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
+
 
  private PropertyStoreSupport pss = new PropertyStoreSupport(this, pcs);
+
The [[#Beans.Value | Beans.Value]] package provides ObservableValue and WritableValue abstractions related to [https://github.com/google/guava Google Guava]'s [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/collect/Multiset.html com.google.common.collect.Multiset] and [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/collect/SetMultimap.html com.google.common.collect.SetMultimap] collections. These are implemented by the observable collections and properties provided by [[#Collections | Collections]] and [[#Beans.Property | Beans.Property]].
 +
 
 +
[[File:GEF4-Common-beans-value.png|653px]]
 +
 
 +
----
 +
 
 +
=== Collections  ===
 +
 
 +
*'''package: org.eclipse.gef4.common.collections'''
 +
 
 +
The [[#Collections | Collections]] package provides observable variants of [https://github.com/google/guava Google Guava]'s [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/collect/Multiset.html com.google.common.collect.Multiset] and [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/collect/SetMultimap.html com.google.common.collect.SetMultimap] collections as well as a utility class via which these observable collection as well replacements for JavaFX's observable collections (that fix some issues) can be instantiated.
 +
 
 +
A good overview about how to use the collections provided by [[#Collections|Collections]] and some insight about the additions and workarounds for the JavaFX provided collections is given in [http://nyssen.blogspot.de/2016/04/gef4-common-collections-and-properties.html GEF4 Common Collections and Properties - Guava goes FX].
 +
 
 +
[[File:GEF4-Common-collections-guava.png|674px]]
 +
 
 +
==== CollectionUtils ====
 +
<code>CollectionUtils</code> is a utility class that augments  [http://docs.oracle.com/javafx/2/api/javafx/collections/FXCollections.html javafx.collections.FXCollections]. It provides static utility methods to create the observable equivalents for [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/collect/Multiset.html com.google.common.collect.Multiset] and [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/collect/SetMultimap.html com.google.common.collect.SetMultimap], as well as the replacement classes for the JavaFX collections that are provided.
 +
 
 +
==== ObservableMultiset, ObservableMultisetWrapper, UnmodifiableObservableMultisetWrapper ====
 +
<code>ObservableMultiset</code> is an observable variant of [https://github.com/google/guava Google Guava]'s [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/collect/Multiset.html com.google.common.collect.Multiset] in the style of a JavaFX observable collection. There are two concrete (internal) implementations, <code>ObservableMultisetWrapper</code> as well as <code>UnmodifiableObservableMultisetWrapper</code>, which should not be accessed directly but can be created using the utility operations provided by [[#CollectionUtils|CollectionUtils]].
 +
 
 +
==== ObservableSetMultimap, ObservableSetMultimapWrapper, UnmodifiableObservableSetMultimapWrapper ====
 +
<code>ObservableSetMultimap</code> is an observable variant of [http://google.github.io/guava/releases/15.0/api/docs/com/google/common/collect/SetMultimap.html com.google.common.collect.SetMultimap] in the style of a JavaFX observable collection. There are two concrete (internal) implementations, <code>ObservableSetMultimapWrapper</code> as well as <code>UnmodifiableObservableSetMultimapWrapper</code>, which should not be accessed directly but can be created using the utility operations provided by [[#CollectionUtils|CollectionUtils]].
 +
 
 +
[[File:GEF4-Common-collections-guava-listeners.png|871px]]
 +
 
 +
==== MultisetListenerHelper, SetMultimapListenerHelper ====
 +
The <code>MultisetListenerHelper</code> and <code>SetMultimapListenerHelper</code> are (internal) delegate classes that are used internally by [[#ObservableMultiset, ObservableMultisetWrapper, UnmodifiableObservableMultisetWrapper | ObservableMultiset]] and [#ObservableSetMultimap, ObservableSetMultimapWrapper, UnmodifiableObservableSetMultimapWrapper |ObservableSetMultimap]], as well as the related properties and bindings within [[#Beans.Binding|Beans.Binding]] and [[#Beans.Property|Beans.Property]] to maintain and notify registered listeners.
 +
 
 +
[[File:GEF4-Common-collections-fxreplacements.png|791px]]
 +
 
 +
==== ObservableListWrapperEx ====
 +
<code>ObservableListWrapperEx</code> is an (internal) replacement class for the ObservableListWrapper returned by [http://docs.oracle.com/javafx/2/api/javafx/collections/FXCollections.html javafx.collections.FXCollections] in its utility functions related to observable lists. It can be constructed using respective utility methods provided by [[#CollectionUtils|CollectionUtils]].
 +
 
 +
==== ListListenerHelperEx, SetListenerHelperEx, MapListenerHelperEx ====
 +
The <code>ListListenerHelperEx</code>, <code>SetListenerHelperEx</code>, and <code>MapListenerHelperEx</code> are (internal) delegate classes that replace the respective delegate classes used internally by the JavaFX implementations provided for [http://docs.oracle.com/javafx/2/api/javafx/collections/ObservableList.html javafx.collections.ObservableList], [http://docs.oracle.com/javafx/2/api/javafx/collections/ObservableSet.html javafx.collections.ObservableSet], and [http://docs.oracle.com/javafx/2/api/javafx/collections/ObservableMap.html javafx.collections.ObservableMap]. They are used by the [[#ObservableListWrapperEx| ObservableListWrapperEx]] as well as the replacements provided by [[#Beans.Binding|Beans.Binding]] and [[#Beans.Property|Beans.Property]] .
 +
 
 +
----
 +
 
 +
=== Dispose  ===
 +
 
 +
*'''package: org.eclipse.gef4.common.dispose'''
 +
 
 +
The [[#Dispose|Dispose]] package provides an abstraction ([[#IDisposable |IDisposable]]) for objects that need to be notified when being disposed.
 +
 
 +
[[File:GEF4-Common-dispose.png|117px]]
 +
 
 +
==== IDisposable ====
 +
 
 +
An <code>IDisposable</code> needs to be disposed. While the <code>IDisposable</code> encapsulates the necessary steps that have to be performed when being disposed, the initiation of the disposal is left to its clients.
  
  public void setProperty(String name, Object value) {
 
    pss.setProperty(name, value);
 
  }
 
 
 
  ...
 
}
 
</source>
 
 
----
 
----
  

Latest revision as of 04:41, 3 June 2016

Note to non-wiki readers: This documentation is generated from the Eclipse wiki - if you have corrections or additions it would be awesome if you added them in the original wiki page.


Introduction

The GEF4 Common component provides key concepts and infrastructure to be potentially used by all other GEF4 components. It is internally comprised out of a single Common module.

GEF4-Components-Common.png


Common

  • feature: org.eclipse.gef4.common
  • bundle: org.eclipse.gef4.common

The Common module of GEF4 Common provides basic abstractions and related support classes within the following packages:


Activate

  • package: org.eclipse.gef4.common.activate

The Activate package provides a general abstraction for objects that maintain an active state (IActivatable) as well as a support-class (ActivatableSupport) that can be used as a delegate to simply implement IActivatable conferment to its contract.

GEF4-Common-activate.png

IActivatable

An IActivatable maintains an 'active' state and can be activated and deactivated. The active state of an IActivatable is exposed via an (observable) javafx.beans.property.ReadOnlyBooleanProperty, so listeners can easily observe the active state.

ActivatableSupport

To enforce that implementers of IActivatable properly follow the above outlined contract, ActivatableSupport may be used. It does not formally implement the IActivatable interface but provides implementations for all its methods and can thus be simply used as a delegate, as follows:

public class MyActivatable implements IActivatable {
 
  // create delegate
  private ActivatableSupport acs = new ActivatableSupport(this);
 
  public void activate() {
    acs.activate();
  }
 
  ...
}

In case the IActivatable, by which it is used as a delegate, is also IAdaptable, it will ensure that all IActivatable adapters are properly activated/deactivated when the IActivatable is activated or deactivated (it will not activate/deactivate adapters when being registered; this is supported by AdaptableSupport).


Adapt

  • package: org.eclipse.gef4.common.adapt

The Adapt package provides a modernized interpretation of org.eclipse.core.runtime.IAdaptable.

The motivation behind this extension and a short overview is given in IAdaptable - GEF4's Interpretation of a Classic. In detail, the enhancements provided by Adapt are:

  1. Adapters may be registered and retrieved by means of a com.google.common.reflect.TypeToken key as an alternative to a Class key, which ensures that adapters with parameterized types may also be registered and retrieved in a type-safe manner, not only via their raw type. For instance, an adapter instance a1 of parameterized type A<T1> and an instance a2 of type A<T2> can both be registered at an IAdaptable. The GEF4 MVC component makes use of this intensively, when registering providers, i.e. a Provider<? extends IGeometry> and a Provider<? extends IFXAnchor> can both be registered at an IVisualPart simultaneously.
  2. Adapters may (optionally) be registered and retrieved by providing an additional role key, which allows to register multiple adapters of the same type (using different roles) at an IAdaptable. For instance, adapter instances a1 and a2 of type A can both be registered at an adaptable using different roles. The GEF4 MVC component again makes use of this, when registering providers. Different geometry providers (Provider<? extends IGeometry>) are e.g. registered for selection and hover feedback, by registering respective providers with respective roles.
  3. Adapters may request a back-reference to the respective IAdaptable they get registered at, by implementing a respective back-interface (IAdaptable.Bound). Again, this is intensively used within GEF4 MVC, where an IBehavior or IPolicy for instance needs to be aware of the host IVisualPart it is registered at.
  4. IAdaptable provides support for registering property change listeners, to be notified whenever adapters are registered or unregistered.

Besides the IAdaptable, IAdaptable.Bound, and AdapterKey abstractions that formalize the modernized adaptable pattern, the package also provides a supporting class (AdaptableSupport) to implement IAdaptable in compliance with its contract, as well as a standalone implementation (AdapterStore).

GEF4-Common-adapt.png

IAdaptable, AdapterKey

An IAdaptable provides facilities to register adapters and to retrieve them via a combination of a type key (java.lang.Class or com.google.common.reflect.TypeToken) and an (optional) java.lang.String role, which are combined in an AdapterKey. Having the option to use a com.google.common.reflect.TypeToken instead of a simple java.lang.Class key, enables the type-safe retrieval of adapters with parameterized types. The combination with an additional (optional) role enables that multiple adapters of the same type may be registered at an IAdaptable.

The 'traditional' getAdapter(Class<T>) method provided by the Eclipse Core Runtime org.eclipse.core.runtime.IAdaptable here is a mere convenience operation that will retrieve the single adapter registered with the respective java.lang.Class key and the default role (or the only adapter registered under the given java.lang.Class key, if there is only one adapter for that type key).

Before retrieving adapters from an IAdaptable, they have to be registered. The registration again includes a role (while a 'default' role is used in case no role is provided) and might require additional information about the actual adapter type by means of a com.google.common.reflect.TypeToken. The additional type information is required in case it cannot be inferred from the registered adapter instance itself (which is the case for parameterized types).

An adapter can thus now be registered and retrieved in various ways:

  // register and retrieve adapter 'a' of raw type 'A' under 'default' role (type info not required)
  adaptable.setAdapter(a);
  A a = adaptable.getAdapter(A.class);
 
  // register and retrieve adapter 'a' of parameterized type 'A<T>' under 'default' role (type info required)
  adaptable.setAdapter(new TypeToken<A<T>>(){}, a);
  A<T> a = adaptable.getAdapter(new TypeToken<A<T>>(){});
 
  // register and retrieve adapter 'a' of raw type 'A' under role 'a1' (type info not required)
  adaptable.setAdapter(a, "a1");
  A a = adaptable.getAdapter(AdapterKey.get(A.class, "a1"));
 
  // register and retrieve adapter 'a' of parameterized type 'A<T>' under role 'a1' (type info required)
  adaptable.setAdapter(new TypeToken<A<T>>(){}, a, "a1");
  A a = adaptable.getAdapter(AdapterKey.get(new TypeToken<A<T>>(){}, "a1"));

To formalize support for notifying listeners about registration and unregistration of adapters, IAdaptable provides its adapters via an javafx.collections.ObservableMap and an (unmodifiable) javafx.beans.property.ReadOnlyMapProperty.

IAdaptable.Bound

To formalize that an adapter may need to obtain a back reference to an IAdaptable, the IAdaptable.Bound interface was introduced. If an adapter implements this interface, the adaptable at which the adapter is registered is responsible of providing a back reference to the adapter as follows:

public class MyAdaptable implements IAdaptable {
 
  public <T> void setAdapter(T adapter) {
    ...
    if (adapter instanceof IAdaptable.Bound) {
      ((IAdaptable.Bound<A>) adapter).setAdaptable(this);
    ...
  }
 
  public <T> void unsetAdapter(T adapter) {
    ...
    if (adapter instanceof IAdaptable.Bound) {
      ((IAdaptable.Bound<A>) adapter).setAdaptable(null);
    }
    ...
  }
 
  ...
}

AdaptableSupport

To enforce that implementers of IAdaptable properly follow the above outlined contract, AdaptableSupport may be used. It does not formally implement the IAdaptable interface but provides implementations for all its methods and can thus be simply used as a delegate, as follows:

public class MyAdaptable implements IAdaptable {
 
  // create delegate
  private AdaptableSupport<MyAdaptable> ads = new AdaptableSupport<MyAdaptable>(this);
 
  public <T> T getAdapter(AdapterKey<T> key){
    return ads.getAdapter(key);
  }
 
  ...
}

In case the IAdaptable, by which it is used as a delegate, is also IActivatable, it will ensure that all IActivatable adapters are properly activated/deactivated when being registered/unregistered dependent on the active state of the adaptable at that moment (it will not activate/deactivate adapters when the adaptable is activated or deactivated; this is supported by ActivatableSupport).

AdapterStore

An AdaptableStore is an IAdaptable implementation that can be used standalone.


Adapt.Inject

  • package: org.eclipse.gef4.common.adapt.inject

The Adapt.Inject package contains Google Guice-based support for injecting adapters into an IAdaptable. That is, if an IAdaptable implementation provides an @InjectAdapters annotation on its <T> setAdapter(TypeToken<T>, T, String) method, and if corresponding adapter (map) bindings qualified with an @AdapterMap annotation are provided within a com.google.inject.Module, adapter instances can automatically be injected into instances of the IAdaptable. It needs to be pointed out that respective adapter (map) bindings are evaluated polymorphically, i.e. a concrete adaptable will also be injected with all adapters that registered for super types of it.

GEF4-Common-inject-adaptermap.png

In addition to basic injection support for adapters, the package also provides support for scoping all objects that are injected in the (transitive) context of an IAdaptable by means of a dedicated com.google.inject.Scope (AdaptableScope).

GEF4-Common-inject-adaptablescopes.png

AdapterInjectionSupport, AdaptableTypeListener, AdapterInjector

To enable injection of adapters to an IAdaptable, a specific com.google.inject.spi.TypeListener (AdaptableTypeListener) needs to be registered in the com.google.inject.Module. To ensure this is done properly, a respective support com.google.inject.Module is provided, namely AdapterInjectionSupport, which can easily be integrated into a custom com.google.inject.Module as follows:

public class MyModule extends AbstractModule {
 
  @Override
  protected void configure() {
    // register adapter map injection support
    install(new AdapterInjectionSupport());
 
    ...
  }
}

This will ensure that the AdaptableTypeListener is properly registered (and itself injected). The AdaptableTypeListener will register a dedicated com.google.inject.MembersInjector (AdapterInjector) on all suitable IAdaptable implementations it encounters.

InjectAdapters

Specifying the injection point (i.e. the <T> setAdapter(TypeToken<T>, T, String) method within a respective IAdaptable implementation is achieved by adding an @InjectAdapters annotation as follows:

public class MyAdaptable implements IAdaptable {
 
  @InjectAdapters
  public <T> void setAdapter(TypeToken<T> adapterType, T adapter, String role) {
    ...
  }
}

AdapterMap, AdapterMaps

Specifying the to be injected adapters is performed by means of map bindings in the com.google.inject.Module, which are qualified with an @AdapterMap annotation. In case the actual type of the to be registered adapter cannot be inferred from the adapter instance itself, or from the respective binding, information about the actual adapter type has to be provided via the AdapterKey used in all bindings. Where the type of an adapter can be inferred from the instance or the binding itself, it may be omitted.

public class MyModule extends AbstractModule {
 
  @Override
  protected void configure() {
    ...
 
   // obtain a map binder to bind adapters for the respective IAdaptable type.
   MapBinder<AdapterKey<?>, Object> adapterMapBinder = AdapterMaps.getAdapterMapBinder(binder(), MyAdaptable.class);
 
   // add adapter (map) binding for binding adapter 'a' of raw type 'A' with 'default' role to each MyAdaptable instance;
   // type information can be omitted, as it can be inferred from the adapter instance
   adapterMapBinder.addBinding(AdapterKey.defaultRole()).toInstance(a);
 
   // add adapter (map) binding for binding an instance of raw type 'A' with role 'r' to each MyAdaptable instance;
   // type information can be omitted, as it can be inferred from the binding
   adapterMapBinder.addBinding(AdapterKey.role("r").to(A.class);
 
   // add adapter (map) binding for binding adapter 'a' of parameterized type 'A<T>' with 'default' role to each MyAdaptable instance;
   // type information is required, as it cannot be inferred from the adapter instance, nor from the binding
   adapterMapBinder.addBinding(AdapterKey.get(new TypeToken<A<T>>(){})).toInstance(a); 
 
   ...
  }
}

When adapter map injection is properly enabled in the com.google.inject.Module, all suitable IAdaptable instances that are created through an com.google.inject.Injector, which is aware of the respective com.google.inject.Module, will be injected.

To this extend, the @AdapterMap-bindings can be compared to the Guice @Named-bindings, only that a java.lang.Class instead of a java.lang.String key is used. However, @AdapterMap-bindings are more powerful, as they are evaluated polymorphically. That is, if a binding is specified for a specific IAdaptable, let's say 'A', it will be evaluated for instances of all subtypes of 'A' as well, as long as they are suitable for injection (i.e. they directly or via inheritance provide a respective method eligible for adapter injection). This is a very powerful mechanism that is used intensively by the GEF4 MVC component. It allows to register certain adapters already for some abstract base type, so that each concrete sub-type will be injected with a respective adapter instance.

AdaptableScope, AdaptableScopes

An AdaptableScope is a Guice com.google.inject.Scope that is bound to an IAdaptable instance. It can be used to scope the object instances (not limited to adapters) during injection. To enable this, bindings have to be 'scoped' and the scope has to be entered for the respective IAdaptable instance before injection of adapters is triggered (which is supported best by using the AdaptableScopes support class).

Scoping bindings can simply be performed in a Guice com.google.inject.Module as follows:

public class MyModule extends AbstractModule {
 
  @Override
  protected void configure() {
    ...
 
    // within the context of IAdaptable 'A', reuse a single instance of type 'B'
    binder().bind(B.class).in(AdaptableScopes.typed(A.class));
 
    ...
  }
}

In order for the scoping to work properly, the scope has to be bound to a certain adaptable before performing injection of objects:

// enter scope for IAdaptable 'a1'
AdaptableScopes.enter(a1);
 
// all injections are now performed in the context of 'a1'
B b1 = injector.getInstance(B.class);
 
// switch scope to IAdaptable 'a2'
AdaptableScopes.enter(a2);
 
// all injections are now performed in the context of 'a2'
B b2 = injector.getInstance(B.class); // b2 != b1
 
// switch back context to 'a1'
AdaptableScopes.switchTo(a1);
 
B b3 = injector.getInstance(B.class); // b1 == b3

This mechanism is e.g. used by GEF4 MVC to scope the content models, which are adapters on a respective viewer. For instance, within the context of an IViewer, only one selection model instance should be used, no matter where it is injected; if an IBehavior e.g. uses members injection to obtain a reference to the selection model via a field, it should get the instance that is registered at its viewer.


Attributes

  • package: org.eclipse.gef4.common.attributes

the Attributes package provides abstractions around string-key based (object) properties.

GEF4-Common-attributes.png

IAttributeStore

The IAttributeStore is a general abstraction that provides support for storing and retrieving java.lang.Object attributes via java.lang.String keys in the form of an (observable) map property.

IAttributeCopier

The IAttributeCopier is a general abstraction for a copier that can transfer/copy attributes from one IAttributeStore to another. It provides static NULL_COPY and SHALLOW_COPY default copier implementations.


Beans.Binding

  • package: org.eclipse.gef4.common.beans.binding

The Beans.Binding package provides binding implementations for Google Guava's com.google.common.collect.Multiset and com.google.common.collect.SetMultimap collections, as well as replacements for JavaFX's (internal) expression helper classes, which are used by the JavaFX property replacement classes provided by Beans.Property.

GEF4-Common-beans-binding-guava.png

GEF4-Common-beans-binding-fxreplacements.png


Beans.Property

  • package: org.eclipse.gef4.common.beans.property

The Beans.Property package provides (observable) property abstractions and implementations for Google Guava's com.google.common.collect.Multiset and com.google.common.collect.SetMultimap collections, as well as replacements for JavaFX's list, set, and map property base classes (javafx.beans.property.ReadOnlyMapPropertyBase, javafx.beans.property.ReadOnlyListPropertyBase, javafx.beans.property.ReadOnlySetPropertyBase, javafx.beans.property.SimpleMapProperty, javafx.beans.property.SimpleListProperty, javafx.beans.property.SimpleSetProperty).

A good overview about how to use the properties provided by Beans.Property is given in GEF4 Common Collections and Properties - Guava goes FX.

GEF4-Common-beans-property-guava.png

GEF4-Common-beans-property-fxreplacements.png


Beans.Value

  • package: org.eclipse.gef4.common.beans.value

The Beans.Value package provides ObservableValue and WritableValue abstractions related to Google Guava's com.google.common.collect.Multiset and com.google.common.collect.SetMultimap collections. These are implemented by the observable collections and properties provided by Collections and Beans.Property.

GEF4-Common-beans-value.png


Collections

  • package: org.eclipse.gef4.common.collections

The Collections package provides observable variants of Google Guava's com.google.common.collect.Multiset and com.google.common.collect.SetMultimap collections as well as a utility class via which these observable collection as well replacements for JavaFX's observable collections (that fix some issues) can be instantiated.

A good overview about how to use the collections provided by Collections and some insight about the additions and workarounds for the JavaFX provided collections is given in GEF4 Common Collections and Properties - Guava goes FX.

GEF4-Common-collections-guava.png

CollectionUtils

CollectionUtils is a utility class that augments javafx.collections.FXCollections. It provides static utility methods to create the observable equivalents for com.google.common.collect.Multiset and com.google.common.collect.SetMultimap, as well as the replacement classes for the JavaFX collections that are provided.

ObservableMultiset, ObservableMultisetWrapper, UnmodifiableObservableMultisetWrapper

ObservableMultiset is an observable variant of Google Guava's com.google.common.collect.Multiset in the style of a JavaFX observable collection. There are two concrete (internal) implementations, ObservableMultisetWrapper as well as UnmodifiableObservableMultisetWrapper, which should not be accessed directly but can be created using the utility operations provided by CollectionUtils.

ObservableSetMultimap, ObservableSetMultimapWrapper, UnmodifiableObservableSetMultimapWrapper

ObservableSetMultimap is an observable variant of com.google.common.collect.SetMultimap in the style of a JavaFX observable collection. There are two concrete (internal) implementations, ObservableSetMultimapWrapper as well as UnmodifiableObservableSetMultimapWrapper, which should not be accessed directly but can be created using the utility operations provided by CollectionUtils.

GEF4-Common-collections-guava-listeners.png

MultisetListenerHelper, SetMultimapListenerHelper

The MultisetListenerHelper and SetMultimapListenerHelper are (internal) delegate classes that are used internally by ObservableMultiset and [#ObservableSetMultimap, ObservableSetMultimapWrapper, UnmodifiableObservableSetMultimapWrapper |ObservableSetMultimap]], as well as the related properties and bindings within Beans.Binding and Beans.Property to maintain and notify registered listeners.

GEF4-Common-collections-fxreplacements.png

ObservableListWrapperEx

ObservableListWrapperEx is an (internal) replacement class for the ObservableListWrapper returned by javafx.collections.FXCollections in its utility functions related to observable lists. It can be constructed using respective utility methods provided by CollectionUtils.

ListListenerHelperEx, SetListenerHelperEx, MapListenerHelperEx

The ListListenerHelperEx, SetListenerHelperEx, and MapListenerHelperEx are (internal) delegate classes that replace the respective delegate classes used internally by the JavaFX implementations provided for javafx.collections.ObservableList, javafx.collections.ObservableSet, and javafx.collections.ObservableMap. They are used by the ObservableListWrapperEx as well as the replacements provided by Beans.Binding and Beans.Property .


Dispose

  • package: org.eclipse.gef4.common.dispose

The Dispose package provides an abstraction (IDisposable) for objects that need to be notified when being disposed.

GEF4-Common-dispose.png

IDisposable

An IDisposable needs to be disposed. While the IDisposable encapsulates the necessary steps that have to be performed when being disposed, the initiation of the disposal is left to its clients.


Reflect

  • package: org.eclipse.gef4.common.reflect

The Reflect package provides a utility class (ReflectionUtils) that offers convenience operations in the context of Java reflection.

GEF4-Common-reflect.png

ReflectionUtils

The ReflectionUtils utilities provide support for getting and setting values of private fields by means of Java reflection.

Back to the top