The iPOJO API provides a third way to describe iPOJO components and instances. With the API, you can dynamically create new components types and create instances from them. Your component types are described with a Java API. To use the API, deploy and start the iPOJO-API bundle and the iPOJO core bundle.
- A simple example
- Deploying the API
- Primitive Component Type basics
- Immediate Component, Validate and Invalidate Method
- Declaring services
- Service Dependencies
- Temporal Dependencies
- Instance creation
- Managed Service and Propagation
- Managing iPOJO Factory
- Access to the introspection API
- Singleton Component Type
- Using external handlers
- Creating composition with the API
Let's imagine a simple component providing a service Foo. The following code is the implementation class of our component:
To create the component type and an instance of the component type just create a class, get the bundle context (either from a Bundle-Activator, or from an iPOJO component), and write the following code:
So, now let's imagine another component using this service. The following code is the implementation class of this component type:
It is a regular iPOJO component expecting to get a Foo service in the myFoo field. It also has a method executed when the instance is valid using the Foo service. To describe this component, just write the following lines:
Before being able to create component types at runtime, you need to deploy 3 bundles:
- iPOJO (core)
- iPOJO Composite
- iPOJO API
You can deploy all these bundles in one step thanks to OBR:
When you create a new Primitive component type (so, using a Java class as implementation), you must set the bundle context and the class name. Everything else is optional.
Note about inner classes: iPOJO is based on a bytecode manipulation. The API embeds the manipulator. So, when you initialize the component type, the specified class name is manipulated (if not already manipulated). So, as this force using a customized classloader, inner classes cannot be manipulated. So, inner class injection is not supported with the API.
To set the component type as immediate, just call the setImmediate(immediate) method on the primitive component type object.
To set validate and invalidate methods, just call the setValidate(method) and setInvalidate(method). Specify the method name that you want to call in argument.
To declare that a component provides a service, add a new service to your primitive component type.
The Service object can be configured. By default, it exposed every implemented interface (regular iPOJO behavior). So, you can:
- Add service property
- Set the creation strategy
- Set the exposed service specifications
To declare a service dependency, create and add a Dependency object. The dependency object offers all the iPOJO service dependency features. You can set the injected field and/or bind/unbind methods. Here is an example:
Thanks to the addProperty method, you can create component properties. Here is some example of properties:
Temporal dependencies are also supported:
The API allows you to create instances from the component type you described. Three differents methods.
The createInstance() method just creates an instance. The createInstance(String name) method allows to set the instance name. Finally, the createInstance(Dictionary configuration) allows setting the instance configuration. All those methods returns the ComponentInstance object allowing to manage the instance (stop, start, dispose).
You can enable/disable the property propagation thanks to the setPropagation method on the PrimitiveComponentType object.
You can also set the the managed service PID with the setManagedServicePID method. This method should be only use to give a default value of for singleton component. In all other case, the managed service pid has to be provided inside the instance configuration.
Beyond the PrimitiveComponentType, an iPOJO factory is hidden. You can configure this factory to be public or private with the setPublic method. You can also set the name of the factory with the setName method.
Then, you can access to the Factory object by calling the getFactory method.
The API provides bridge to get access to the iPOJO introspection API. The introspection API allows reconfiguring at runtime an instance (properties, service dependencies...). From Service and Dependency, Property and ServiceProperty objects, call the getXXXDescription method. You must give the instance that you want to introspect in argument. If the lookup success, you get an object allowing reconfiguring the service, dependency or property.
If you are sure to create only one instance of your component type, you can use the singleton component type class. This is a kind of primitive component type, but when you start it (with the create method), it will automatically create an instance.
The type created with the singleton component type are set to private by default. Instead of calling the start method, you have to call one of the create methods to start the type and create the instance.
You can also set the contained POJO object by using the setObject method. The given object MUST be compatible with the component implementation class.
iPOJO is extensible... So, it makes sense that the API is also extensible. So component type provides a method allowing to add external handler configuration:
The addHandler method allows you to add any handler description. A handler description is an object of a class implementing org.apache.felix.ipojo.api.HandlerConfiguration. Handler provider willing to support the API have to provide this class. For example, the example above uses Whiteboard that is the Whiteboard pattern handler description. This class is very simple, and is shown below:
The only required method is getElement returning the Element-Attribute structure representing the handler configuration (this uses the internal iPOJO data format). If the metadata cannot be generated, the class throws IllegalStateExceptions.
The API also allows you to create iPOJO compositions in a pretty simple way. So you can create compositions:
- containing internal instances
- importing services
- instantiating sub-services
- exporting services
- providing services (by delegation)
Here are some examples: