Difference between revisions of "GEF/GEF4/Common"
|Line 5:||Line 5:|
== Introduction ==
== Introduction ==
The [[GEF/GEF4/Common|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|Common]]''' module.
The [[GEF/GEF4/Common|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|Common]]''' module.
Revision as of 10:28, 22 May 2015
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.
The GEF4 Common (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.
- bundle: org.eclipse.gef4.common
The Common module of the GEF4 Common component provides basic abstractions and related support classes within the following packages:
- Activate: A general abstraction for activatable objects and a related support class
- Adapt: A general abstraction for adaptable objects and related support classes
- Dispose: A general abstraction for disposable objects
- Inject: Google Guice-based support for injecting and scoping adapters at adaptable objects
- Notify: Observable collections and related listener abstractions
- Properties: A general abstraction of a property store, a related support class, and a property change notifier
- Reflect: A utility class for working with Java Reflection
- 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.
IActivatable maintains an 'active' state and can be activated and deactivated. It is also an IPropertyChangeNotifier to propagate changes to its 'active' state to registered PropertyChangeListeners.
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:
It needs to be provided with a PropertyChangeSupport, which will be used to notify listeners changes of the 'active' state. 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).
- package: org.eclipse.gef4.common.adapt
The adapt package provides a modernized interpretation of the Eclipse Core Runtime's IAdaptable, providing the following enhancements:
- 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<IGeometry> and a Provider<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. 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<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 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.
- 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).
IAdaptable provides facilities to register and retrieve adapters via an
AdapterKey, which combines a type key (java.lang.Class or com.google.common.reflect.TypeToken) with an (optional) java.lang.String role. Having the option to use a com.google.common.reflect.TypeToken instead of a simple java.lang.Class key, enables the type-safe registration 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
The 'traditional' getAdapter(Class<? super 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).
An adapter can thus now be registered and retrieved in various ways:
To formalize support for notifying listeners about registration and unregistration of adapters,
IAdaptable furthermore extends IPropertyChangeNotifier, which provides capabilities for registering and unregistering respective listeners.
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:
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:
It needs to be provided with a PropertyChangeSupport, which will be used to notify listeners about registration and unregistration of adapters. 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).
AdaptableStore is an IAdaptable implementation that can be used standalone.
- package: org.eclipse.gef4.common.dispose
The dispose package provides an abstraction (IDisposable) for objects that need to be notified when being disposed.
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.
- package: org.eclipse.gef4.common.inject
This inject package contains Google Guice-based support for injecting adapters into an IAdaptable. That is, if an IAdaptable implementation provides an @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 implementation 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.
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).
AdapterMapInjectionSupport, AdaptableTypeListener, AdapterMapInjector
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
AdapterMapInjectionSupport, which can easily be integrated into a custom com.google.inject.Module as follows:
This will ensure that the
AdaptableTypeListener is properly registered (and itself injected). The
AdaptableTypeListener will register a dedicated com.google.inject.MembersInjector (
AdapterMapInjector) on all suitable IAdaptable implementations it encounters.
@AdapterMap 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 implementation that is to be injected. Second, it is used to specify respective adapter map-bindings within the com.google.inject.Module.
Specifying the injection point within a respective IAdaptable implementation is achieved by means of a method, which is marked for injection by means of an @Inject annotation, and furthermore provides a single Map<AdapterKey<?>, Object> parameter that is annotated with
@AdapterMap as follows:
Specifying the to be injected adapters is performed by means of map-bindings in the com.google.inject.Module.
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 an 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 for adapter map 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 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 <ode>AdaptableScopes</code> support class).
Scoping bindings can simply be performed in a Guice com.google.inject.Module as follows:
In order for the scoping to work properly, the scope has to be bound to a certain adaptable before performing injection of objects:
This mechanism is e.g. used by GEF4 MVC to scope the content models, which are adapters on an 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.
- package: org.eclipse.gef4.common.notify
ObservableMap is a specific Google Guava com.google.common.collect.ForwardingMap, which adds support for observing changes via an
IMapObserver. It is e.g. used by GEF4 Graph to make the attributes of Graph, Node, and Edge observable.
ObservableList is a specific Google Guava com.google.common.collect.ForwardingList, which adds support for observing changes via an
IListObserver. It is e.g. used by GEF4 Graph to make the edges and nodes of a Graph observable.
- package: org.eclipse.gef4.common.properties
The properties package provides abstractions and supporting classes to store and retrieve properties, as well as to notify about property changes.
IPropertyStore provides facilities to store and retrieve arbitrary valued properties via java.lang.String keys. Being an IPropertyChangeNotifier, it is responsible of notifying any registered listeners about property value changes.
To enforce that implementers of IPropertyStore properly follow the contract,
PropertyStoreSupport may be used. It does not formally implement the IPropertyStore interface but provides implementations for all its methods and can thus be simply used as a delegate, as follows:
- package: org.eclipse.gef4.common.reflect
The reflect package provides a utility class (ReflectionUtils) that offers convenience operations in the context of Java reflection.
ReflectionUtils utilities provide support for getting and setting values of private fields by means of Java reflection.