Differences

This shows you the differences between two versions of the page.

Link to this comparison view

component_factory [2015/03/16 14:01]
component_factory [2021/04/05 11:23] (current)
Line 1: Line 1:
 +====== Component Factory ======
 +Most of the time it is quite sufficient and probably should be so to use Singletons. In an OSGi environment this is the standard type of beans/services used in combination with DI (dependency injection).
  
 +But sometimes you need several instances of a component. The default pattern for this is a [[http://en.wikipedia.org/wiki/Factory_method_pattern | factory]].
 +
 +OSGi supports this in several ways.
 +
 +===== Declarative Services =====
 +This service can be used to let the system create instances of components for you. These instances can be retrieve programmatically or via method injection.
 +
 +Declarative Service also lets you define a factory for a component in a very simple way. You don't have to write the factory yourself. The system will create it for you.
 +
 +One of the very good parts of OSGi Declarative Services is that your component class can be totally free of OSGi classes.
 +
 +<sxh java; title: Component Class>
 +public class RestServiceClient {
 +
 +    public Object get() {
 +        // retrieve object from server
 +    }
 +}
 +</sxh>
 +
 +<sxh xml; title: Component Definition XML>
 +<?xml version="1.0" encoding="UTF-8"?>
 +<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" 
 +     factory="test.service.client" name="Rest Service Client">
 +   <implementation class="test.osgi.factory.RestServiceClient"/>
 +</scr:component>
 +</sxh>
 +
 +Just by specifying a factory attribute in the component definition the system will create a factory for it.
 +
 +==== Retrieve Component Instance ====
 +Most tutorials and articles describe how to write/create/declare a factory but most miss the part of how to retrieve an instance of this factory.
 +
 +The system will create the factory for you. It is registered as a component itself and implements ''org.osgi.service.component.ComponentFactory''. So you can get the factory by getting this service from the system. But as you can declare many factories there will be many factories registered with this class. You have to specify a criteria which identifies the factory you want. One criteria can be the factory element you specified in the component definition, ''component.factory="test.service.client"''.
 +
 +=== Programmatically Retrieve Component Instance ===
 +These are the necessary steps to manually get an instance of a component from a factory.
 +
 +Getting the service reference for the component factory:
 +  ServiceReference[] serviceReferences = context.getServiceReferences(ComponentFactory.class.getName(), "(component.factory=test.service.client)");
 +
 +Getting the component factory:
 +  ComponentFactory factory = (ComponentFactory) context.getService(serviceReferences[0]);
 +  
 +Getting an instance from the factory:
 +  ComponentInstance instance = factory.newInstance(null);
 +  
 +In this example ''null'' is passed to the //newInstance()// Method. The parameter specifies a ''java.util.Dictionary'' which can hold additional properties which are passed to the ''ComponentContext'' which can be accessed by the instantiated component in the //activate// Method by adding ''ComponentContext'' to the method as a parameter.
 +
 +<sxh java>
 +void activate(ComponentContext context) {
 +    Dictionary properties = context.getProperties();
 +    ...
 +}
 +</sxh>
 +
 +<note>I am using OSGi 4.2. More recent versions of the framework provide more elegant ways to work with services.</note>
 +
 +
 +==== Component Instances with Properties ====
 +There are several ways to add properties to an OSGi component.
 +
 +=== Static Properties ===
 +One way to add static properties to an OSGi component is to define them in the component definition xml file.
 +
 +<sxh xml>
 +<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" factory="test.service.client" name="Rest Service Client">
 +   ...
 +   <property name="extra.property.key" type="String" value="this is the extra property value"/>
 +</scr:component>
 +</sxh>
 +
 +
 +==== Component Instances with Service References ====
 +Anything specified in the component definition xml file will be used on the component instance, not the factory, f. e. properties and service references.
 +
 +So every service reference entered in the component definition will be used on each component instance.
 +
 +<sxh xml>
 +<?xml version="1.0" encoding="UTF-8"?>
 +<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" 
 +   factory="test.service.client" name="Rest Service Client">
 +   ...
 +   <reference bind="bindRestClientProvider" cardinality="0..1" interface="test.osgi.factory.RestClientProvider" name="restClientProvider" policy="dynamic" unbind="unbindRestClientProvider"/>
 +   ...
 +</scr:component>
 +</sxh>
 +
 +==== Component Instances with Managed Configuration ====
 +In an OSGi environment components can be provisioned with a configuration. This is also true for component instances created by a component factory.
 +
 +<sxh java>
 +public class RestServiceClient implements ManagedService {
 +
 +    void activate(ComponentContext context) {
 +        Dictionary properties = context.getProperties();
 +        System.out.println("activating employee service client with the context: " + context.toString());
 +    }
 +
 +    @Override
 +    public void updated(Dictionary properties) throws ConfigurationException {
 +        if (properties == null) {
 +            System.out.println("no configiuration");
 +        }
 +        else {
 +            System.out.println("configuration: " + properties);
 +        }
 +    }
 +}
 +</sxh>
 +
 +<sxh xml>
 +<?xml version="1.0" encoding="UTF-8"?>
 +<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" factory="test.service.client" name="Rest Service Client">
 +   ...
 +   <service>
 +      <provide interface="org.osgi.service.cm.ManagedService"/>
 +   </service>
 +   ...
 +</scr:component>
 +</sxh>
 +
 +<note important>If configured in this way every component instance gets the same configuration and will be updated if this configuration has been changed. It is also possible to create instances for each prepared configuration, see ''ManagedServiceFactory''.</note>
 +
 +
 +==== Disposing Component Instances ====
 +The created component instances are managed by the OSGi framework. To unregister a component instance the //dispose()// Method of the class ''ComponentInstance'' can be called.
 +
 +<sxh java>
 +  // get factory
 +  ComponentFactory factory = (ComponentFactory) context.getService(serviceReferences[0]);
 +
 +  // get instance
 +  ComponentInstance instance = factory.newInstance(null);
 +  
 +  ...
 +  // do something
 +  ...
 +       
 +  // unregister component instance
 +  instance.dispose();       
 +</sxh>
 +
 +
 +===== Links =====
 +  * [[http://floriansblog.wordpress.com/2011/06/01/user-scoped-services/ | User Scoped Services]]
 +  * [[http://floriansblog.wordpress.com/2011/05/26/something-you-cant-do-with-componentfactories/ | Something You can't do with Component Factories]]
 +  * [[http://njbartlett.name/2010/07/19/factory-components-in-ds.html | Multiple Component Instances with OSGi Declarative Services]]
 +
 +{{tag>osgi devel java}}