The purpose of this page is to provide a quick introduction to the iPOJO component model. Specifically, it reminds you:
As for OSGi, knowing the intricacies of iPOJO is NOT mandatory since most complexity is hidden by the IDE. However, understanding the iPOJO principles (modularity, service-orientation, late-binding) is a plus when getting to the exercises.
In OSGi,service management is entirely left to applications programmers. That is, programmers have to insert specific instructions in their code in order to follow the arrival and departure of services of interest and to react accordingly. This code is complex and highly error-prone (events can be missed, synchronisations can be forgotten, bad class versions can be called, stale references can be left, etc.).
Several approaches have been proposed to improve OSGi in terms of dependency management. Among them iPOJO is a solution of choice in the open source world.
iPOJO is a component model: its purpose is to provide programming facilities in order to lower business code complexity. Specifically, an iPOJO component is a “plain old Java object” (A Java class!) enriched with meta-data. Meta-data is used to generate complex code implementing non functional properties. This code is actually injected at compilation time by the ipojo framework.
In particular, code is injected in order to manage all the service-oriented interactions: service publication, service instantiation, service selection, service discovery. This is based on meta-data specifying services provided by a component and services required by the component, along with the resolution politics. Services are merely expressed as Java class interfaces.
To make it more concrete, look at the felix implementation of client for a DictionnaryService. As you can see, even this simple task requires a long piece of code to manage the dynamism.
The same declaration in iPOJO would require the declaration of the service in the component class (let’s call it DictionnaryClient.java) and the use of annotations to describe iPOJO meta-data. Here the meta-data informs iPOJO that the class is a component and that m_dictionnaryService is a service to be injected.
@Component public class DictionnaryClient { // This service is injected at runtime when a service is availlable : @requires private DictionaryService m_dictionnaryService; //**
Alternative XML syntax For those who don’t want to use annotations for meta-data, so as to separate class implementation from service declaration, iPOJO also supports an XML syntax (in a metadata.xml file) :
<component classname="org.example.DictionnaryClient" name="DictionnaryClient"> <requires specification="org.example.DictionaryService" field="m_dictionnaryService"/> </component>
The iCASA-IDE uses the XML syntax.
The service can then be used as is (the dynamism is managed by iPOJO) :
public checkword(String word){ if(m_dictionnaryService.checkWord(word)){ System.out.println("Correct."); }else{ System.out.println("Incorrect."); } }
Once implemented the component can be instanciated, whether programatically, whether using the XML :
<instance component="DictionnaryClient" name="myDictionnaryClient">
At compilation time, the ipojo framework also creates bundles containing iPOJO components (code and metadata). Bundles are used as the deployment unit and to resolve package dependencies, as it is usually done in OSGi.
iPOJO applications
An application is made of a number of interacting iPOJO components. These components are linked at runtime, throuh service interactions, by the execution framework. An application can be run only when all service dependencies are resolved.
Bundles and iPOJO Components
Bundles are concerned with code packaging and code dependencies.
Components are concerned with provided and required services and code instantiation.
Components have actually been introduced to allow developers to think in term of functionality instead of code. Let us take an example to illustrate that statement. Imagine that we have a word processor that use a spellchecker.
When using modules, we will most likely have :
If for a reason or another (code refactoring, product renaming, conflict in libraries) you need to change the name of packages, you will have to change the dependencies since dependencies are direct references to the code itself.
When using components, we will have :
The service “Spellchecking” will be described by an interface Spellchecking.java and some meta-information (“english” as a language for instance). Package names here are not important. If you change the name of a package or of an implementation class, there will be no consequence on the component dependencies.
One core functionality of iPOJO is the dependency management. This section gives a brief overview of iPOJO functionalities.
The most difficult task managed by iPOJO is the service requirement. The service providing is described in details in the iPOJO service requiring documentation. In short a dependency can be :
iPOJO supports different policies for injecting dependencies :
How do iPOJO know that a service is better ?
Service selection is based on service properties. Each services are ranked based on these properties. By default the ranking is random. But you can modify the ranking is performed by providing a standard java Comparator :
<requires field="m_dictionnaryService" policy="dynamic-priority" comparator="dict.MyComparator"/>
Each time a service is discovered, iPOJO will try to compare it to the other using this comparator. If the service is better that the one in use, it will be automatically substituted.
In iPOJO providing a service is simply implementing an interface :
@Component @Provides(specifications={DictionnaryService.class}) public class DictionnaryImpl implements DictionnaryService { // ...
Different policies may be applied for the creation of a service :
More details on the service requirement can be found in the iPOJO service providing documentation.
In this section, you have learned what a iPOJO component is and how to write your first bundle.
What you should remember is that iPOJO components and bundle are complementary. Bundles deal with how to hide and share the code and components deal with how to instantiate and use the functionalities.
In the next section, you will learn how to add properties to components and how to configure the instances.