Home Projects ServiceBinding-Utils
ServiceBinding-Utils Overview Print E-mail

ServiceBinding-Utils provides OSGi developers with an API that would allow them to consume OSGi Services by writing the minimum amount of code (mostly it will be 1-3 line of code). The aim of this project is to reduce development time when consuming OSGi services without degrading application's performance or constraining it's design. The solution consists of a single bundle which weighs less than 25 kilobytes and provides ServiceBinding-Utils classes.

ServiceBinding-Utils Compared to other Service Binding Solutions

When consuming OSGi services I always had to choose between two options:

  • OSGi Framework API: On one hand the OSGi Framework API is performant and already included in any OSGi Environment, on the other, I end up writing 30-50 lines of code each time I consume a service - Of course 50 lines of code are only to have the service up to date, ranking and other requirements would need more code and mostly support classes.
  • Declarative Services Binding: This includes Spring-DM and implementations of the Declarative Services Specification. The declarative approach in general is efficient to use from a development point of view, but it impacts application's performance and constrains its design - Actually, depending on your application's design, sometimes it could appear unapplicable.

As for me, when my application already uses Spring, Spring-DM is the natural and simplest way to bind OSGi Services to my objects, but using Spring-DM for the sole purpose of binding service is a resource-inefficient approach. For instance, if I used Spring-DM for every example at DynamicJava.org that consumes OSGi Services then the size of each application would have raised by a little more than 2,5 megabytes, leave aside performance impacts.

ServiceBinding-Utils in Action

To give a better understanding of how ServiceBinding-Utils could simplify your life, below are few examples:

import org.dynamicjava.osgi.service_binding_utils.OsgiServiceBinder;
import org.dynamicjava.osgi.service_binding_utils.ServiceFilter;
import org.dynamicjava.osgi.service_binding_utils.BindingOptions;
import org.dynamicjava.osgi.service_binding_utils.Sorter;


OsgiServiceBinder binder = new OsgiServiceBinder(bundleContext);

/// Consumer1 is a class with a method: void setService(org.test.MyService service)
/// After the bind method is invoked, the binder will look in the OSGi Environment
/// for a service that implements the interface "org.test.MyService" then pass it 
/// as a param to the setService method of the Consumer1 class. Each time the 
/// service is updated the binder will invoke the setService method. In case 
/// multiple services exist that confirm to the condition, the one with highest 
/// ranking will be choosen.
Consumer1 consumer1 = new Consumer1();
binder.bind(consumer1, "setService",
		ServiceFilter.forInterface("org.test.MyService"));

/// Consumer2 is a class with a method:
/// void setServices(org.test.MyService[] service)
/// The binder will look in the OSGi Environment for services that implement the
/// "org.test.MyService" interface and has a property "serviceType" with value
/// "testService".
Consumer2 consumer2 = new Consumer2();
/// A variant which accepts an LDAP Filter string.
binder.bind(consumer2, "setServices",
		ServiceFilter.forInterfaceAndLdapFilter(
			"org.test.MyService", "(serviceType=testService)"));
/// Another variant which accepts a service properties dictionary
Dictionary serviceProperties = new Hashtable();
serviceProperties.put("serviceType", "testService");
binder.bind(consumer2, "setServices",
		ServiceFilter.forInterfacesAndServiceProperties(
			"org.test.MyService", serviceProperties));
			
/// Consumer3 is a class with one static method:
/// static void setService(org.test.MyService service)
binder.bind(Consumer3.class, "setService",
		ServiceFilter.forInterface("org.test.MyService"));
		
/// Consumer4 is a class with a static method:
/// static void setServices(org.test.MyService[] service)
/// The binder will look in the OSGi Environment for services that implement the
/// "org.test.MyService" interface then it will sort all of the service based
/// on the value of the service property "serviceType" in a descending order.
binder.bind(Consumer4.class, "setServices",
		ServiceFilter.forInterface("org.test.MyService"),
		new BindingOptions(Sorter.sortBy(false, "serviceType")));
		

As you can see, binding services to a property (through a setter method), watching service for updates, ranking, filtering, sorting and exception handling is already done for you, so all you have to do is to write 1-3 lines of code. Since the Binder can work with class instances and static methods I can't foresee any design constraints for its usage.

How To Use?

To use ServiceBinding-Utils you need to:

  • Download ServiceBinding-Utils Bundle from Releases Page and install it in your OSGi based application.
  • Import the package "org.dynamicjava.osgi.service_binding_utils" to your bundle.
  • If you want an object to watch a service then add a setter method to it that accepts one argument, the argument should be either a class that is assignable from service's class or an array whose component type is a class that is assignable from service's class. If the argument is an array then all services that confirm to the binding condition will be bound, if it's a single object then the service with highest ranking that confirms to the binding condition will be bound.

Example

The example consists of an API Bundle that provides service interfaces, 2 Service Provider Bundles that provides services that implement the interfaces in the API bundle and a Service Consumer Bundle which consumes the services using ServiceBinding-Utils. Consumer classes invoke the services they are bound to every 2 seconds so you could uninstall and install Service Provider Bundles at runtime and see consumers' reaction.

service-binding-utils-example.zip