- Authors
Shadi Abras, Thomas Calmant
This tutorial presents how to use the iPOPO framework and its associated service-oriented component model. The concepts of the service-oriented component model are introduced, followed by a simple example that demonstrates the features of iPOPO. This framework uses decorators to describe components.
iPOPO aims to simplify service-oriented programming on OSGi frameworks in Python language; the name iPOPO is an abbreviation for injected POPO, where POPO would stand for Plain Old Python Object. The name is in fact a simple modification of the Apache iPOJO project, which stands for injected Plain Old Java Object
iPOPO provides a new way to develop OSGi/iPOJO-like service components in Python, simplifying service component implementation by transparently managing the dynamics of the environment as well as other non-functional requirements. The iPOPO framework allows developers to more clearly separate functional code (i.e. POPOs) from the non-functional code (i.e. dependency management, service provision, configuration, etc.). At run time, iPOPO combines the functional and non-functional aspects. To achieve this, iPOPO provides a simple and extensible service component model based on POPOs.
iPOPO is separated into two parts:
- Pelix, the underlying bundle and service registry
- iPOPO, the service-oriented component framework
It also defines three major concepts:
- A
bundle <refcard_bundles>
is a single Python module, i.e. a.py
file, that is loaded using the Pelix API. - A
service <refcard_services>
is a Python object that is registered to service registry using the Pelix API, associated to a set of specifications and to a dictionary of properties. - A
component <refcard_component>
is an instance of component factory, i.e. a class manipulated by iPOPO decorators. Those decorators injects information into the class that are later used by iPOPO to manage the components. Components are defined inside bundles.
In this tutorial we will present how to:
- Publish a service
- Require a service
- Use lifecycle callbacks to activate and deactivate components
To illustrate some of iPOPO features, we will implement a very simple application. Three bundles compose this application:
- A bundle that defines a component implementing a dictionary service (an English and a French dictionaries).
- One with a component requiring the dictionary service and providing a spell checker service.
- One that defines a component requiring the spell checker and providing a user line interface.
The spell dictionary components provide the spell_dictionary_service
specification. The spell checker provides a spell_checker_service
specification.
The example contains several bundles:
- spell_dictionary_EN.py defines a component that implements the Dictionary service, containing some English words.
- spell_dictionary_FR.py defines a component that implements the Dictionary service, containing some French words.
- spell_checker.py contains an implementation of a Spell Checker. The spell checker requires a dictionary service and checks if an input passage is correct, according to the words contained in the wished dictionary.
- spell_client.py provides commands for the
Pelix shell service <quick_shell>
. This component uses a spell checker service. The user can interact with the spell checker with this command line interface.
Finally, a main_pelix_launcher.py script starts the Pelix framework. It is not considered as a bundle as it is not loaded by the framework, but it can control the latter.
The spell_dictionary_EN
bundle is a simple implementation of the Dictionary service. It contains few English words.
/_static/tutorials/spell_checker/spell_dictionary_EN.py
- The
@Component
decorator is used to declare an iPOPO component. It must always be on top of other decorators. - The
@Provides
decorator indicates that the component provides a service. - The
@Instantiate
decorator instructs iPOPO to automatically create an instance of our component. The relation between components and instances is the same than between classes and objects in the object-oriented programming. - The
@Property
decorator indicates the properties associated to this component and to its services (e.g. French or English language). - The method decorated with
@Validate
will be called when the instance becomes valid. - The method decorated with
@Invalidate
will be called when the instance becomes invalid (e.g. when one its dependencies goes away) or is stopped.
For more information about decorators, see :ref:refcard_decorators.
The spell_dictionary_FR
bundle is a similar to the spell_dictionary_EN
one. It only differs in the language
component property, as it checks some French words declared during component validation.
/_static/tutorials/spell_checker/spell_dictionary_FR.py
It is important to note that the iPOPO factory name must be unique in a framework: only the first one to be registered with a given name will be taken into account. The name of component instances follows the same rule.
The spell_checker
bundle 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 iPOPO component requiring a Dictionary service and providing the Spell Checker service.
/_static/tutorials/spell_checker/spell_checker.py
- The
@Requires
decorator specifies a service dependency. This required service is injected in a local variable in this bundle. Itsaggregate
attribute tells iPOPO to collect the list of services providing the required specification, instead of the first one. - The
@BindField
decorator indicates that a new required service bounded to the platform. - The
@UnbindField
decorator indicates that one of required service has gone away.
The spell_client
bundle contains a very simple user interface allowing a user to interact with a spell checker service.
/_static/tutorials/spell_checker/spell_client.py
The component defined here implements and provides a shell command service, which will be consumed by the Pelix Shell Core Service. It registers a spell
shell command.
We have all the bundles required to start playing with the application. To run the example, we have to start Pelix, then all the required bundles.
/_static/tutorials/spell_checker/main_pelix_launcher.py
Launch the main_pelix_launcher.py
script. When the framework is running, type in the console: spell to enter your language choice and then your passage.
Here is a sample run, calling python main_pelix_launcher.py
:
INFO:pelix.shell.core:Shell services registered
An English dictionary has been added
** Pelix Shell prompt **
A French dictionary has been added
A dictionary checker has been started
1. Testing Spell Checker: Welcome to our framwork iPOPO
> Misspelled_words are: ['our', 'framwork']
A client for spell checker has been started
$ spell
Please enter your language, EN or FR: FR
Please enter your paragraph, or 'quit' to exit:
Bonjour le monde !
All words are well spelled !
Please enter your paragraph, or 'quit' to exit:
quit
$ spell
Please enter your language, EN or FR: EN
Please enter your paragraph, or 'quit' to exit:
Hello, world !
All words are well spelled !
Please enter your paragraph, or 'quit' to exit:
Bonjour le monde !
The misspelled words are: ['Bonjour', 'le', 'monde']
Please enter your paragraph, or 'quit' to exit:
quit
$ quit
Bye !
A spell client has been stopped
INFO:pelix.shell.core:Shell services unregistered
You can now go back to see other Tutorials
or take a look at the refcards
.