This page presents how to use the iPOJO runtime and its associated service component model. The concepts of the service component model are introduced, followed by a simple example that demonstrates the features of iPOJO. This tutorial uses XML to describe components. However, iPOJO also supports annotations and a Java API for this purpose.
iPOJO aims to simplify service-oriented programming on OSGi frameworks; the name iPOJO is an abbreviation for injected POJO. iPOJO provides a new way to develop OSGi service components, simplifying service component implementation by transparently managing the dynamics of the environment as well as other non-functional requirements. The iPOJO framework allows developers to more clearly separate functional code (i.e., POJOs) from the non-functional code (i.e., dependency management, service provision, configuration, etc.). At run time, iPOJO combines the functional and non-functional aspects. To achieve this, iPOJO provides a simple and extensible service component model based on POJOs.
"POJO" is just an acronym for Plain Old Java Object, but it embodies a concept that the simpler and less intrusive the design of a given framework, the better. The name is used to emphasize that a given object is not somehow special, but is an ordinary Java Object. Martin Fowler, Rebecca Parsons and Josh Mackenzie coined the term POJO in September 2000: "We wondered why people were so against using regular objects in their systems and concluded that it was because simple objects lacked a fancy name. So we gave them one, and it's caught on very nicely." From a developer's perspective, the iPOJO framework strives as much as possible to only require POJOs.
A service component is able to provide and/or require services, where a service is an object that implements a given Java interface. In addition, iPOJO introduces a callback concept to notify a component about various state changes.
The component is a central concept in iPOJO. In the core iPOJO model, a component describes service dependencies, provided services, and callbacks; this information is recorded in the component's metadata. After components, the next most important concept in iPOJO is the component instance. A component instance is a special version of a component. By merging component metadata and instance configuration, the iPOJO runtime is able to discover and inject required services, publish provided services, and manage the component's life cycle.
In this tutorial we will present how to:
- Publish an OSGi service
- Require an OSGi service
- Use lifecycle callbacks to activate and deactivate components
To illustrate iPOJO features, we will implement a very simple application. This application is composed by three components:
- A component implementing a dictionary service
- A component requiring the dictionary service and providing a spellchecker service
- A component requiring the spellchecker and providing an user interface
This tutorial is based on Ant. So, you need to have the Ant program accessible in your path (see here to download and install Ant). Download the tutorial archive available here and then unzip it. The archive contains seven directories:
- spell.services contains service interfaces used by the applications
- spell.english contains an implementation of the Dictionary service (containing English words)
- spell.checker contains an implementation of a Spell Checker. The spell checker requires a dictionary service and check if an input passage is correct (according to the words contained in the dictionary).
- spell.gui contains a very simple user interface. This component uses a spell checker service. Then the user can interact with the spell checker with this user interface.
- The task directory contains Ant tasks used to build the project
- The solution directory contains an already developed version of the application.
- Finally, the felix folder contains a configured version of the Felix runtime
The spell.services project contains only service interfaces. It is not an iPOJO powered bundle.
Go inside the Spell.services directory and create the file "src/spell/services/DictionaryService.java" for the following Dictionary service interface:
Then, create the file src/spell/services/SpellChecker.java for the following Spell Checker service interface:
Once created, you can build the project by launching Ant from the project directory.
The created bundle is inside the output directory (spell.services.jar). The build process use BND. The bundle manifest is described in the spell.services.bnd file.
Once this project is done, we are able to implement a Dictionary service.
The spell.english project is a simple dictionary implementation of the Dictionary service. It contains few English words. This implementation is an iPOJO component.
The first step is to implement the service. Create the "src/spell/english/EnglishDictionary.java" file for the following Dictionary service implementation:
Notice that this class does not contains neither OSGi nor iPOJO specific code. It is just an implementation of the Dictionary Service interface.
Once created, we need to describe this component to ask iPOJO to manage it. To achieve this, create the "metadata.xml" file in the spell.english directory:
This file describes the Dictionary service implementation. First it creates a component. This component has a classname attribute containing the implementation class name. The 'provides' element indicates that the component provide a service. Provided service interfaces are computed by iPOJO, so it is not necessary to indicate them. The instance element asks iPOJO to create an instance of the described component when the bundle starts. The relation between components and instances is the same than between classes and objects in the object oriented programming. The component attribute indicates which component needs to be instantiated. By default, component type name is the implementation class (i.e. the classname attribute).
Then, we are able to create the bundle. In the spell.english directory launch the ant command:
The created bundle is inside the output directory (spell.english.jar). The build process is based on BND and on the iPOJO Ant task. The manifest of the bundle is described in the spell.english.bnd file.
The spell.checker project aims to provide a spell checker service. However, to serve this service, this implementation requires a dictionary service. During this step, we will create an iPOJO component requiring a Dictionary service and providing the Spell Checker service.
First create the file "src/spell/checker/SpellCheck.java" in the spell.checker directory for the following Check Speller service implementation:
This class implements the SpellChecker service interface as it will provide it. Moreover, it has a special field "_m_dictionary_". This field represents the required service. iPOJO will inject a Dictionary service when needed. So, the class can use it directly. Notice that this class as no OSGi specific code, both the service providing and the requiring are managed by iPOJO. If the used dictionary service leaves, iPOJO will try to find another provider. If no more providers are available, the instance is invalidated, and the provided service is withdrawn from the service registry.
Once implemented, we need to describe this component. Create the "metadata.xml" file in the spell.checker directory for the following component descriptor:
This description contains a 'requires' element. This element indicates to iPOJO to manage the service dependency. The field attributes describe in which member of the class the service need to be injected. It is not necessary to write the required service as it is computed by iPOJO. Notice that iPOJO can inject required service by invoking methods too.
Finally, we are able to build the bundle. As for previous projects, launch Ant from the project directory.
The spell.check.gui project contains a very simple user interface (in Swing) allowing a user to interact with a spell checker service.
Create the "src\spell\gui\SpellCheckerGui.java" for the following implementation:
Look at the three last methods. The check methods collect the user input and use a Check speller service to check this input. This method is called when the button is pressed by the user. The start and stop methods are lifecycle callbacks. As we need to display the user interface when the instance is created and to delete it when the instance stops, we need a way to be notified when we need to execute these actions. iPOJO provide an easy way to do this. The component provides two callback methods for its activation and deactivation, start and stop, respectively. Callbacks are used when the component needs to be informed about a component state change. In iPOJO, the component state is either INVALID (i.e., not all of the component's constraints are satisfied) or VALID (i.e., all of the component's constraints are satisfied). In this example, the start callback method set the GUI visibility to true; the stop callback method deletes the GUI. The component metadata will instruct iPOJO to invoke these methods when the component's state changes to VALID or INVALID respectively.
Create the metadata.xml file in the spell.chercker.gui directory with the following content:
The component element again has the 'classname' attribute that refers to the component implementation class. The 'requires' element describes the Check Speller service dependency by simply specifying its associated component field. The 'callback' elements describe which method to invoke when the component's state changes. Then the 'instance' element asks iPOJO to create an instance of the component.
Once this file is created, you can compile the project by launching ant in the spell.checker.gui directory.
To run the example, start Felix. A distribution of Felix is provided in the felix directory. This version is configured to launch iPOJO automatically. From the Felix directory, launch the following command to start the framework. Then enter a profile name.
You can check installed bundles by using the 'ps' command:
iPOJO runtime is the bundle 4. Once started, install the four created bundles as above:
When starting the GUI bundle, the user interface appears. Indeed, the Check Speller service is provided. You can interact with this service by entering a passage and clicking on the check button:
Then, stop the Dictionary service provider (with the stop 7) command. The GUI disappears. Indeed, Spell Checker service cannot be provided as it depends on the Dictionary service.
Then, restart the Dictionary service provider with the start 7 command. The GUI reappears immediately. You can try to stop the check speller service provider without stopping the dictionary service provider with the stop 8 command. As for the last manipulation, the GUI disappears.
To go further in the exploration, modify the spell.checker implementation. For example, add a simple trace, printing wrong words:
Then rebuild the spell.checker bundle and update it (with the 'update 8' command). You will see the gui "blinking". In fact, the gui was stopped as the required spell checker service was no more available. As soon as it was back, the gui restarts. The gui didn't lose its state. The other services weren't stopped during the update.
You can uninstall the check service bundle and then re-install a new one (or the same one), you will see the same behavior.
We saw how to use easily iPOJO to build service-oriented component. In this tutorial, we have demonstrated how to:
- Publish OSGi services
- Require OSGi services
- Use lifecycle callbacks to activate and deactivate components
iPOJO provides a lot of others features that you can try in the others available tutorials. Subscribe to the Felix users mailing list by sending a message to email@example.com; after subscribing, email questions or feedback to firstname.lastname@example.org.