Reader small image

You're reading from  Eclipse Plug-in Development Beginner's Guide - Second Edition

Product typeBook
Published inAug 2016
Reading LevelExpert
Publisher
ISBN-139781783980697
Edition2nd Edition
Languages
Tools
Right arrow
Author (1)
Alex Blewitt
Alex Blewitt
author image
Alex Blewitt

contacted on 30 aug 16 _____________ Dr Alex Blewitt has over 20 years of experience in Objective-C and has been using Apple frameworks since NeXTstep 3.0. He upgraded his NeXTstation for a TiBook when Apple released Mac OS X in 2001 and has been developing on it ever since. Alex currently works for an investment bank in London, writes for the on-line technology news site InfoQ and has published two other books for Packt publishing. He also has a number of apps on the Apple AppStore through Bandlem Limited. When he's not working on technology, and if the weather is nice, he likes to go flying from the nearby Cranfield airport. Alex writes regularly at his blog, http://alblue.bandlem.com, as well tweeting regularly from Twitter as @alblue. Acknowledgements This book would not have been possible without the ongoing love and support of my wife Amy, who has helped me through both the highs and lows of life. She gave me the freedom to work during the many late nights and weekends that it takes to produce a book and its associated code repository. She truly is the Lem of my life. I'd also like to thank my parents, Ann and Derek, for their encouragement and support during my formative years. It was this work ethic that allowed me to start my technology career as a teenager and to incorporate my first company before I was 25. I'd also like to congratulate them on their 50th wedding anniversary in 2015, and I look forward to reaching that goal with Amy. Thanks are due especially to the reviewer of this version of the book: Antonio Bello, as well as the previous version of this book: Nate Cook, James Robert and Arvid Gerstmann, who provided excellent feedback on the contents of this book during development and caught many errors in both the text and code. Any remaining errors are my own. I'd also like to thank my children Sam and Holly for inspiring me and hope that they too can achieve anything that they set their minds to. Finally, I'd like to thank Ben Moseley and Eren Kotan, both of whom introduced me to NeXT in the first place and set my career going on a twenty year journey to this book.
Read more about Alex Blewitt

Right arrow

Dynamic services


The OSGi specification defines four different layers:

  • Security Layer: In this layer, all actions are checked against a security permissions model

  • Module Layer: In this layer, modules are specified as bundles that have dependencies

  • Life Cycle Layer: This layer bundles coming and going and firing events

  • Service Layer: In this layer, dynamic services that come and go

The Services layer allows bundles to communicate by defining an API that can cross bundle layers. However, the services layer also allows the services to come and go dynamically, instead of being fixed at runtime.

This mechanism allows services to be exported over a network, and since the network can come and go (as can the remote endpoint) the OSGi services layer can replicate that same functionality.

Responding to services dynamically coming and going may add a slight difficulty to the client code, but it will be more robust in case of failure. The following sections will present different ways of achieving dynamism in services.

Resolving services each time

The easiest way of working with dynamic services is to list the services each time they are needed. The example so far uses this technique to allow different services to be contributed.

This technique can work if the list of services is infrequently needed. However each time the lookup is performed, there is a cost to the acquisition, which may not be desirable.

Using a ServiceTracker

The OSGi framework provides a ServiceTracker class which can be used to simplify the acquisition of one or more services in a standard way. Provided in the org.osgi.util.tracker package, the ServiceTracker class has a constructor that takes a class and a BundleContext object, along with an optional filter specification.

Tip

The ServiceTracker has an open method which must be called prior to use, as otherwise it will not return any services.

Add the package to the timezones bundle's manifest as an import:

Import-Package: org.osgi.util.tracker

Modify the TimeZonesFactory so that a ServiceTracker is acquired in a static initializer, and that open is called. This simplifies the use method to simply delegate to the service tracker:

public class TimeZonesFactory {
  private static final Bundle bundle =
    FrameworkUtil.getBundle(TimeZonesService.class);
  private static final BundleContext context =
    bundle.getBundleContext();
  private static final ServiceTracker<TimeZonesService,
    TimeZonesService> tracker = 
     new ServiceTracker<>(context,TimeZonesService.class, null);
  static {
    tracker.open(); // Remember to call this!
  }
  public static void use(Consumer<TimeZonesService> consumer) {
    consumer.accept(tracker.getService());
  }
}

The ServiceTracker also has a close method, which should be called when services are no longer required to be tracked.

Tip

Generally tying the service tracker's lifecycle to another lifecycle is more appropriate, as otherwise this can leak implementation.

Filtering services

The service tracker, as it is currently implemented, returns all compatible services that implement the interface (if true is passed to the open call, both compatible and incompatible services are returned; this should generally not be used).

It is also possible to use a filter to restrict the list of services that are returned. OSGi filters are specified using the LDAP filter syntax, which uses prefix notation and parentheses to group elements. Here is how to read it:

  • A and B: (&(A)(B))

  • A or B: (|(A)(B))

  • Not A: (!(A))

  • A equals B: (A=B)

  • A contains B: (A=*B*)

These can be nested to form complex queries.

The services command in the Equinox console allows a filter to be evaluated. Each service is published into the registry, and the filter objectClass= allows services matching a particular interface to be found, as was done earlier in the chapter:

osgi> services "(objectClass=*.TimeZonesService)"
{com.packtpub.e4.timezones.TimeZonesService}={service.ranking=2,
 component.name=TimeZonesProvider, component.id=0, service.id=48}

It's possible to filter on other properties as well. For example, DS registers a component.id property with a service, so this can be used to create a filter for just DS registered components:

osgi> services "(&(objectClass=*.TimeZonesService)(component.id=*))"
{com.packtpub.e4.timezones.TimeZonesService}={service.ranking=2,
 component.name=TimeZonesProvider, component.id=0, service.id=48}

This looks for services ending in TimeZonesService and which have a value for the component.id property.

Filters can be included in the ServiceTracker to ensure that only desired services are picked up. For example, to include only services that aren't registered by DS, the following can be coded into the ServiceTracker:

Filter filter = context.createFilter(
 "(&(objectClass=*.TimeZonesService)(!(component.id=*)))");
st = new ServiceTracker<TimeZonesService, TimeZonesService>(
 context, filter, null);
st.open();

Note

This may be useful to enable debugging; the filter could be overridden by a system property, for example. Note that the createFilter method throws a checked syntax exception if it is invalid, which must be handled in the code.

Obtaining a BundleContext without using an activator

Since the ServiceTracker needs the BundleContext to register a listener, it is conventional to set up a BundleActivator for the sole purpose of acquiring a BundleContext.

Since this incurs a performance penalty, using a different mechanism to acquire the context will speed the start-up process. Fortunately there is a class, FrameworkUtil, that can be used to acquire a Bundle for any given class, and from there, the BundleContext. This allows the implementation of the TimeZonesActivator to be removed:

BundleContext context = FrameworkUtil.
  getBundle(TimeZonesFactory.class).getBundleContext();

Using this mechanism adds no performance penalty and should be used in favor of a global static instance to the BundleContext. It also potentially allows the bundle's activator to be removed from the bundle.

Note

If the bundle is not started, it will not have a BundleContext and so the returned value here may be null. Code should defensively handle this case.

Dependent Services

It is fairly common that an OSGi service depends on other OSGi services. As such it can help if the services are set up and made available when the bundles are available. The Declarative Services approach can be used to register services on demand when the requirements are satisfied.

For DS, when the cardinality of the relationship is not optional (in other words, the relationship is 1..1 or 1..n), then the service won't be started until the required dependent services are available. For example, a menu service may not be required until the graphical user interface service is present; and services that wish to contribute to the menu service won't be able to work until the menu service is present.

Delaying the creation of the services until they are needed will result in shorter start-up times of the application.

lock icon
The rest of the page is locked
Previous PageNext Page
You have been reading a chapter from
Eclipse Plug-in Development Beginner's Guide - Second Edition
Published in: Aug 2016Publisher: ISBN-13: 9781783980697

Author (1)

author image
Alex Blewitt

contacted on 30 aug 16 _____________ Dr Alex Blewitt has over 20 years of experience in Objective-C and has been using Apple frameworks since NeXTstep 3.0. He upgraded his NeXTstation for a TiBook when Apple released Mac OS X in 2001 and has been developing on it ever since. Alex currently works for an investment bank in London, writes for the on-line technology news site InfoQ and has published two other books for Packt publishing. He also has a number of apps on the Apple AppStore through Bandlem Limited. When he's not working on technology, and if the weather is nice, he likes to go flying from the nearby Cranfield airport. Alex writes regularly at his blog, http://alblue.bandlem.com, as well tweeting regularly from Twitter as @alblue. Acknowledgements This book would not have been possible without the ongoing love and support of my wife Amy, who has helped me through both the highs and lows of life. She gave me the freedom to work during the many late nights and weekends that it takes to produce a book and its associated code repository. She truly is the Lem of my life. I'd also like to thank my parents, Ann and Derek, for their encouragement and support during my formative years. It was this work ethic that allowed me to start my technology career as a teenager and to incorporate my first company before I was 25. I'd also like to congratulate them on their 50th wedding anniversary in 2015, and I look forward to reaching that goal with Amy. Thanks are due especially to the reviewer of this version of the book: Antonio Bello, as well as the previous version of this book: Nate Cook, James Robert and Arvid Gerstmann, who provided excellent feedback on the contents of this book during development and caught many errors in both the text and code. Any remaining errors are my own. I'd also like to thank my children Sam and Holly for inspiring me and hope that they too can achieve anything that they set their minds to. Finally, I'd like to thank Ben Moseley and Eren Kotan, both of whom introduced me to NeXT in the first place and set my career going on a twenty year journey to this book.
Read more about Alex Blewitt