Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "Riena/Getting Started with injecting services and extensions"

(The Idea of Injecting Services and Extensions in Riena)
Line 23: Line 23:
 
where ´target´ is the pojo that gets a service injected. When services come and go they will be injected into or removed from the pojos. The method names for injecting/removing can be specified with the bind() and unbind() methods. If they are not defined default method names are assumed.
 
where ´target´ is the pojo that gets a service injected. When services come and go they will be injected into or removed from the pojos. The method names for injecting/removing can be specified with the bind() and unbind() methods. If they are not defined default method names are assumed.
  
Extensions get injected into pojos as instances of an interface. The interfaces need only to declare the <i>getters</i>. Dynamic proxies will be created for this interfaces which map the data from the extensions. A few simple rules are used for the mapping from extensions to the interfaces (lightweight xml/java mapping).
+
Extensions get injected into pojos as instances of an interface. The interfaces need only to declare the <i>getters</i>. Dynamic proxies will be created for the interfaces which map the data from the extensions. A few simple rules are used for the mapping from extensions to the interfaces (lightweight xml/java mapping).
 
Extension properties. i.e. attributes, sub-elements and element value can then accessed by <i>getters</i> in the interface definition. It is only necessary to define the interfaces for the mapping.
 
Extension properties. i.e. attributes, sub-elements and element value can then accessed by <i>getters</i> in the interface definition. It is only necessary to define the interfaces for the mapping.
  
The extension injector does not evaluate the extension schema, so it can only trust that the extension and the interface match.
+
The extension injector does not evaluate the extension schema, so it can only trust that the extension and the interface match with regards to a few basic rules:
 
+
The basic rules for the mapping are:
+
 
* one interface maps to one extension element type
 
* one interface maps to one extension element type
* an interface can only contain getters prefixed with:
+
* an interface can only contain <i>getters</i> prefixed with:
 
** get...
 
** get...
 
** is...
 
** is...

Revision as of 09:31, 15 July 2008

Riena Project > Getting Started> Getting Started with Injecting Services and Extensions

Getting Started with Injecting Services and Extensions

The Idea of Injecting Services and Extensions in Riena

//// NASCENT ////

Services and extensions are the main building blocks of Eclipse RCP applications. There is a long list of discussions and debates about when to use services and when to use extensions. So, we will not add another discussion here. We think that both are useful and have their permission.

One problem with both of them is that using them requires a lot of code that respects their life cycle and is quite error prone. Most of this code is embedded within the code that needs other services or extensions. This approach does not clearly separate concerns and it makes unit testing more difficult.

A common solution for this problem is the use of dependency injection frameworks such as Spring (http://springframework.org/) or HiveMind (http://hivemind.apache.org/).

Within Riena we are using a simple to use approach to inject services and extensions into objects (pojos). Our approach is code based, i.e. no xml configuration files. Furthermore we are using fluent interfaces (http://en.wikipedia.org/wiki/Fluent_interface) and conventions to simplify the injection definitions.

Service injecting examples:

Inject.service("ServiceClazz1").into(target).andStart(context);
Inject.service("ServiceClazz2").useFilter(filter).into(target).bind("register").unbind("unregister").andStart(context);
Inject.service("ServiceClazz3").useRanking().into(target).bind("register").unbind("unregister").andStart(context);

where ´target´ is the pojo that gets a service injected. When services come and go they will be injected into or removed from the pojos. The method names for injecting/removing can be specified with the bind() and unbind() methods. If they are not defined default method names are assumed.

Extensions get injected into pojos as instances of an interface. The interfaces need only to declare the getters. Dynamic proxies will be created for the interfaces which map the data from the extensions. A few simple rules are used for the mapping from extensions to the interfaces (lightweight xml/java mapping). Extension properties. i.e. attributes, sub-elements and element value can then accessed by getters in the interface definition. It is only necessary to define the interfaces for the mapping.

The extension injector does not evaluate the extension schema, so it can only trust that the extension and the interface match with regards to a few basic rules:

  • one interface maps to one extension element type
  • an interface can only contain getters prefixed with:
    • get...
    • is...
    • create...
  • The return type, the prefix and the name of the getters determine the mapping:
    • If the return type is an interface or an array of interfaces and the prefix is get than the mapping tries to resolve to a nested element or to nested elements.
    • If the return type is a primitive type or String and the prefix is get than the mapping tries to resolve to an attribute of the extension element enforcing type coercion. The prefix is can be used instead of the prefix get for boolean return types.
    • If the prefix is create than the mapping tries to create an new instance of the attribute´s value each time it is called.
  • The names of the getters name the element names and attribute names. A simple name mangling is performed like with java beans, e.g for the interface method getDatabaseURL the mapping looks for the name databaseURL.
    To enforce another name mapping for a method the annotation @MapName("name") can be used to specify the name of the element or attribute.
    The extension element´s value can be retrieved by either using the method get() or annotate a getter with @MapValue(). The return type must be String.

Extension injecting examples:

Inject.extension("extpoint1").into(target).andStart(context);
Inject.extension("extpoint2").useType(interface).into(target).bind("configure").useTranslation().andStart(context);
Inject.extension("extpoint3").expectExactly(1).into(target).andStart(context);

Back to the top