Open main menu

CDOT Wiki β

Steps for Building Declarative Services

1. Study the Interfaces

2. Define the Bundle Service Interface

package cs.ecl.osgi.simple.declarativeservice.say;

public interface Sayable {
	String say();
}

An implementation of this interface could be:

package cs.ecl.osgi.simple.declarativeservice.say.internals;
import java.util.Date;
import cs.ecl.osgi.simple.declarativeservice.say.Sayable;

public class TodaySay implements Sayable {
	public String say() {
		return " Declarative Service: Today is " + new Date();
	}
}

3. Define the Service Descriptor

(the component.xml file)

The relationships between the interface that is exposed to the client and the implementation that is hidden, must be defined in a xml file:

<?xml version="1.0"?>
<component name="sayable">
	<implementation class="cs.ecl.osgi.simple.declarativeservice.say.internals.TodaySay"/>
	<service>
		<provide interface="cs.ecl.osgi.simple.declarativeservice.say.Sayable"/>
	</service>
</component>

3. Define the Bundle Consumer Class

The bundle consumer must implement the CommandProvider interface

package cs.ecl.osgi.simple.declarativeservice.consumer;

import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;

import cs.ecl.osgi.simple.declarativeservice.say.Sayable;

public class SaySingleConsumer implements CommandProvider {

	private Sayable s;

	public synchronized void bindSayable(Sayable s) {
		this.s = s;
	}

	public synchronized void unbindSayable(Sayable s) {
		this.s = null;
	}

	public synchronized void _run(CommandInterpreter ci) {
		if (s != null) {
			System.out.println(s.say());
		} else {
			ci.println("Error, No Service of type Sayable available");
		}
	}

	@Override
	public String getHelp() {
		return "\n\t run - EXECUTE the Sayable service";
	}
}

3. Define the Service Descriptor

(the component.xml file)
<?xml version="1.0"?>
<component name="singlesayconsumer">
    <implementation class="cs.ecl.osgi.simple.declarativeservice.consumer.SaySingleConsumer"/>
    <service>
        <provide interface="org.eclipse.osgi.framework.console.CommandProvider"/>
    </service>
    <reference name="SAYABLE"
        interface="cs.ecl.osgi.simple.declarativeservice.say.Sayable"
        bind="bindSayable"
        unbind="unbindSayable"
        cardinality="0..1"
        policy="dynamic"/>
</component>

The reference element in the service descriptor specifies that:

  • The component has a binding to a service, and the name of the binding is set to "SAYABLE"
  • The needed service is one which implements the "cs.ecl.osgi.simple.declarativeservice.say.Sayable" interface
  • To bind this component with a provider of the service, the framework must invoke the "bindSayable" method
  • Similarly, to unbind the component from a provider, the framework must invoke the "unbindSayable" method
  • The cardinality parameter has the form "x..y", where x can be either '0' or '1' and y can be either '1' or 'n'. The first parameter specifies optionality, and the second one specifies multiplicity.
    • For instance, x='0' means that a binding to the service is optional, while x='1' means that the binding is mandatory (otherwise the component can not be resolved and activated).
    • On the other hand, y='1' implies single binding only, where the component can only be bound to just one service provider at a time, while y='n' implies that multiple service providers can be bound to the component simultaneously.
  • The last parameter, policy, can be set to either "dynamic" or "static". This controls the binding to new service providers at runtime.
    • When the value is set to "static", then it is implied that the component cannot handle dynamic switching of service providers and thus the framework constructs a new instance of the component when the service provider changes.
    • On the other hand, when the policy is set to "dynamic", then the binding and unbinding of service providers takes place dynamically on the same component instance. As the former is more heavy-weight, it is recommended that the components are designed and implemented so that they support the dynamic policy. The default value is "static", which means that unless you specify the policy parameter as "dynamic", it is going to be set as "static".