Previous Topic

Next Topic

Book Contents

Book Index

Optimized service search

Optimized service searching in OSGi framework on service interface name and service registration properties

Overview

Framework supports a mechanism of optimized service search for service queries with a specific service interface name and a specific service property. The optimized search supports only simple service queries bundleContext.getServiceReferences(String className, String filter), where the filter has only one single property.

A bundle utility for end applications to make quick service queries for services with specific interface name and properties is also provided.

Optimized service search for framework

Framework maintains a cache, which will be checked first, when there are BundleContext.getServiceReferences(String className, String filter) queries with a filter, which contains only a single service registration property. Since the cache is maintained centrally in the framework, there is only a single cache, and it does not matter how many different applications will make service queries.

The OSGi Framework supports both declarative and programmatic descriptions for defining the service interface names and properties for an optimized service search.

Declarative approach

The following format (a static description via a system property) is used about the services, for which the framework should support optimized searching in the service registry:

mbs.services.optimizeSearchFilters=clause1,clause2,...
clause=objectClass;prop1,prop2,prop3,...

It is very likely, that only a single property is used per objectClass. Here is an example for the most common case:

mbs.services.optimizeSearchFilters=com.prosyst.mbs.services.fim.FunctionalItem;uid

Programmatic approach

This is a dynamic approach, which allows bundles dynamically to add and remove pairs of (service interface, service properties) in the framework, for which optimized service searching should be supported. Bundles should register/unregister instances of ServiceQueryOptimizerPlugin, when adding/removing such pairs.

public interface ServiceQueryOptimizerPlugin {

  /**
   * Describes the different service registration infos,  for which a software module is interested.
   *
   * @ return A list of {@link ServiceRegistrationInfo} objects.
   */
   public List<ServiceRegistrationInfo> getServiceRegistrationInfos();
}


public final class ServiceRegistrationInfo {

   private String objectClass;
   private List< String> propertyNames;

  /**
   * Constructs a {@code ServiceRegistrationInfo} object with an object class
   * and a list of property names.
   *
   * @param objectClass The object class  for service query optimizations.
   * @param propertyNames The property names  for service query optimizations.
   */
   public ServiceRegistrationInfo( String objectClass, List< String> propertyNames) {
     if (objectClass ==  null || objectClass.length() == 0) {
       throw new IllegalArgumentException( "ObjectClass null  or
        empty.");
    }
     if (propertyNames ==  null || propertyNames.isEmpty()) {
       throw new IllegalArgumentException( "No property names
        specified.");
    }
     this.objectClass = objectClass;
     this.propertyNames =  new ArrayList< String> (propertyNames);
  }

  /**
   * Constructs a {@code ServiceRegistrationInfo} object with an object class
   * and one or more property names.
   *
   * @param objectClass The object class  for service query optimizations.
   * @param propertyNames The property names  for service query optimizations.
   */
   public ServiceRegistrationInfo( String objectClass,  String... propertyNames) {
     if (objectClass ==  null || objectClass.length() == 0) {
       throw new IllegalArgumentException( "ObjectClass null  or
        empty.");
    }
     if (propertyNames.length == 0) {
       throw new IllegalArgumentException( "No
        property names specified.");
    }
     this.objectClass = objectClass;
     this.propertyNames = Arrays.asList(propertyNames);
  }

  /**
   * Getter  for the  interface of the object class.
   *
   * @ return the  interface of the object class.
   */
   public String getObjectClass() {
     return objectClass;
  }

  /**
   * Registration property names, whose values are unique  for every service registration under the specified
   * objectClass. So the value can be used as an additional key  for a more optimized search in the service registry.
   *
   * @ return the registration property names.
   */
   public List< String> getPropertyNames() {
     return propertyNames;
  }

}

Bundle utility for optimized service search

Since this tracker utility is implemented on top of the standard ServiceTracker, each utility will maintain its own separate cache (opposite to the optimized service search support in the framework).

public class PropertyIndexedServiceTracker {

   private TrackerCache                   tCache;
   private ServiceTracker< Object,  Object> tracker;

  /**
   * Constructs a tracker  for the specified object class
   *
   * @param context the bundle context of the user of the api. Its region of visibility and its permissions will be taken into
   * account,  while tracking the service registry.
   * @param objectClass the  interface name, under which the service is registered
   * @param propertyNames one or more service registration properties to be used as additional index  for a more efficient
   * service search. It is most efficient, when the property value is unique  for every service registration under the specified
   * <code>objectClass</code>.
   */
   public PropertyIndexedServiceTracker(BundleContext context,  String objectClass,  String... propertyNames) {
    tracker =  new ServiceTracker< Object,  Object>(context, objectClass,
        tCache =  new TrackerCache(context, propertyNames));
  }

  /**
   * Opens the tracker. Enables tracking of services.
   */
   public void open() {
    tracker.open();
  }

  /**
   * Opens the tracker. Enables tracking of services.
   *
   * @param trackAll  if true enables tracking of all services, no matter of its class loader namespace.
   */
   public void open( boolean trackAll) {
    tracker.open(trackAll);
  }

  /**
   * Retrieves all the services, registered under the <code>objectClass</code>, specified in the constructor and
   * with the specified service registration <code>property</code>, which has the specified <code>value</code>.
   * If the property values are unique, a list with a single service will be returned.
   *
   * @param property the service registration property key.
   * @param value the service registration property value.
   * @ return A <code>List</code> of services which have a matching value  for specified property
   * or <code> null</code>  if there are no such services.
   */
   public List< Object> getServices( String property,  Object value) {
     if (property ==  null) {
       Object[] services = tracker.getServices();
       return (services !=  null ? Arrays.asList(services) :  null);
    }
     return tCache.getServices(property.toLowerCase(), value);
  }

  /**
   * Retrieves all the services, registered under the <code>objectClass</code>, specified in the constructor and
   * the specified <code>property</code>.
   *
   * @param property the service registration property key.
   * @ return A <code>List</code> of services which have the specified property
   * or <code> null</code>  if there are no such services.
   */
   public List< Object> getServices( String property) {
     if (property ==  null) {
       Object[] services = tracker.getServices();
       return (services !=  null ? Arrays.asList(services) :  null);
    }
     return tCache.getServices(property.toLowerCase());
  }

  /**
   * Retrieves all the services, registered under the <code>objectClass</code>.
   *
   * @ return An array of service objects or  null if no services are being tracked.
   */
   public Object[] getServices() {
     return tracker.getServices();
  }

  /**
   * Closes the tracker. Disables tracking of services.
   */
   public void close() {
    tCache.close();
    tracker.close();
  }

}