The iPOJO Felix sub-project

In short, Apache Felix iPOJO provides dependency injection features for OSGi frameworks. Some of its features simplify the tasks of registering and retrieving services on a framework by taking care of the life-cycle management of declared services. More advanced uses of it involve code manipulation.

iPOJO stands for injected Plain Old Java Objects and does not require specific interfaces to be implemented for integration— the components it uses are regular Java objects. It determines the needs of a component instance, based on its characteristics described in the bundle manifest.

The iPOJO components also work following the Extender Pattern, the general mechanism is the same; bundles that require dependency injection and publishing of services are tagged with a specific manifest header. The iPOJO extender components listen to bundles starting and stopping and grab those that have this header declared. The tag contains information on the requirements of the bundles from iPOJO, which fulfills them by interacting with the framework.

The following diagram, which not surprisingly looks a lot like the previous one for the web extender, describes this functional relationship:

The iPOJO Felix sub-project

Components and instances

iPOJO recognizes bundles that require its functionality through the iPOJO-Components header in the bundle manifest. This header declares the parts of the bundle that require the services of iPOJO. iPOJO will look for the following two kinds of declarations in this header:

  • Component: It describes the characteristics of a component from an abstract point of view— the service it provides, dependencies it requires, and so on.
  • Instance: It declares the need for an instance of a specific component and its configuration.

In a way, components and instances can be compared to class definitions and object instances of those classes.

A component definition describes its requirements and capabilities. A component may:

  • Provide a service, thus request that iPOJO be aware of the interface it provides. In this case, iPOJO will associate the component with that interface and look for components that require it
  • Require a service as a dependency, thus request that iPOJO find implementations for that service and keep references to them up-to-date
  • Require properties to be set on instantiation, and request that iPOJO set the values for those properties before making the service available

Those component declarations are kept by iPOJO and are used when instances are requested.

Instances of a component are managed by iPOJO. It will manage their life-cycle, monitor changes in their dependencies (install, uninstall, update, and so on.), and update their consumers accordingly.

Tip

Components may also ask iPOJO to include their instances in the starting and stopping life-cycle stages, by providing callbacks that iPOJO would invoke at the appropriate time.

All of this information is encoded into the manifest header, which may become a long and complex task to do. Fortunately, the iPOJO Maven plugin allows this header to be generated from a simple metadata XML file.

iPOJO Maven plugin

There is an iPOJO Maven plugin to assist you with the composition of the iPOJO-Components manifest header. When it is configured to run as part of the bundle Maven build cycle, it will automatically construct the iPOJO-Components manifest header, based on an XML file.

The metadata file

The metadata XML file provided to the iPOJO plugin tells it which components and instances are to be declared for this bundle. If an alternative location is not specified in the configuration, the plugin will look for meta.xml in the root of the project or under the resources directory.

The following is a skeleton of this file that contains the placeholders for its parts. We'll look at each of those in greater detail through the following code:

<?xml version="1.0" encoding="UTF-8"?>
<ipojo
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="org.apache.felix.ipojo
http://felix.apache.org/ipojo/schemas/CURRENT/core.xsd"
xmlns="org.apache.felix.ipojo">
<component />
<component />
<instance />
<instance />
</ipojo>

Components

The component element declares a service that is to be handled by iPOJO. The component's target class is set through the classname attribute. An optional name can be given to the component and used to reference it.

The component element also declares what it provides to iPOJO, the framework, and what it requires from them.

The<provides/> and<requires/> elements have a rich set of declarative options, most of which are not covered here. We will focus on the basics needed for the integration.

For example, a component can provide a service, which is registered using the component's interfaces. It can also provide properties to be published with the service.

Examples of things a component can require are lifecycle callbacks (the component provides a method to be called when a lifecycle stage is achieved) or services that it needs set through injection.

Once you're comfortable with the use of iPOJO, it's recommended that you read about some more of those and experiment with them. For now, let's focus on a simple configuration; the one we'll put in place for our bookshelf service:

<component
name="BookshelfServiceImpl"
classname=
"com.packtpub.felix.bookshelf.service.impl.BookshelfServiceImpl">
<provides />

The component classname is specified along with an optional name. If the name is not set, the class name will be used instead.

The<provides /> element tags the component as providing a service based on the interfaces it implements. iPOJO will register instances of this component with the framework.

The service also requires its inventory field to be injected with an instance of a BookInventory.

<requires field="inventory" />
</component>

There's no need to tell iPOJO the type of the required injection. It will find out on its own by inspecting the type this field is declared as in the component class.

Callbacks involve the instances of the component during stages of its life-cycle. Basically, the component optionally provides a method to be called as it is validated and invalidated. In this case, we don't need it, but the syntax would be as follows:

<callback transition="validate" method="start" />
<callback transition="invalidate" method="stop" />
</component>

In the previous syntax, the start() method of the component would be called on component validation and the stop() method would be called during its invalidation. The callback target method names are arbitrary (that is, they don't have to be called start and stop).

Instances

The instance element requests the creation of an instance of a declared component. It specifies the component that needs to be instantiated, and an optional name for it, as well as the configuration of properties of the instance.

In our case, we're creating an instance of the component "BookshelfServiceImpl" that we've previously declared. We will name it bookshelf.service.impl; this name will appear later when we inspect the instances that iPOJO has detected.

<instance
component="BookshelfServiceImpl"
name="bookshelf.service.impl" />

If needed, properties that the component requires can also be set when declaring the instance:

<instance component="name-ref" name="inst-name">
<property name="propName" value="propValue"/>
</instance>

In our case, the required field is an instance of a component that iPOJO already manages. We, therefore, don't need to worry about setting it here.

Our final iPOJO meta.xml would look like this:

<ipojo
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="org.apache.felix.ipojo
http://felix.apache.org/ipojo/schemas/CURRENT/core.xsd"
xmlns="org.apache.felix.ipojo">
<component classname=
"com.packtpub.felix.bookshelf.service.impl.BookshelfServiceImpl"
name="BookshelfServiceImpl">
<provides />
<requires field="inventory" />
<requires field="log" />
</component>
<instance
component="BookshelfServiceImpl"
name="bookshelf.service.impl" />
</ipojo>

We will see all this again as we modify our bundles.

Tip

iPOJO Eclipse plugin

Writing iPOJO metadata files is fairly simple at this stage, because we're not using all the power it provides. Editing the file as XML is not difficult. As you start exploring more of iPOJO's features, also look at its Eclipse plugin. Among other uses, it speeds up the metadata edition tasks.

Using the plugin

Adding support for iPOJO to a Maven project is fairly simple. It consists of the following two steps:

  • Including the plugin in the POM's build plugins section and configuring it, optionally overriding the default settings
  • Declaring components and instances in the iPOJO meta.xml file

The iPOJO plugin is used in conjunction with the bundle plugin that we've been using so far. We will place the configuration file in src/main/ipojo/meta.xml.

The following is the POM build plugins section used for our bundles:

<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-ipojo-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>ipojo-bundle</goal>
</goals>
<configuration>
<metadata>src/main/ipojo/meta.xml</metadata>
</configuration>
</execution>
</executions>
</plugin>

This requests the execution of the ipojo-bundle goal and specifies the location of the iPOJO, metadata file. There are other configuration items that can be of interest. I recommend you check the plugin documentation for more information at: (http://felix.apache.org/site/ipojo-maven-plug-in.html).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.79.84