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

Registering a service declaratively


Registering services imperatively in the start method of an Activator method is one way of installing services in an OSGi framework. However it requires that the bundle be started, which requires that either the bundle is started automatically or has classes (such as API classes) accessed by default. Both approaches will mean that additional code has to run to bring the system into the desired state.

An alternative is to use one of the declarative service approaches, which represent the service definition in an external file. These are processed using an extender pattern, which looks out for bundles with a given file or files and then instantiates the service from this definition. It combines the declarative nature of the extension registry with the flexibility of OSGi services.

There are two providers of declarative service support, which both achieve a similar result but use slightly different configuration files and approaches. They are Declarative Services and Blueprint. Since the most common use case for Eclipse plug-ins is to use Declarative Services, they will be covered here (Blueprint is covered in Mastering Eclipse Plug-in Development by the same author).

Declarative Services

Declarative Services, or simply DS, was the original declarative implementation for instantiating services in a declarative fashion in an OSGi runtime. Both Equinox and Felix have DS modules, and it is a required part of the Eclipse 4 runtime, so can be trivially expected to be present. In the OSGi specification, it is referred to as the Services Component Runtime (SCR), which is why the associated package names use org.osgi.service.component.

The DS bundle needs to be started before it can process bundles; as a result, it is typically started early on. It listens to bundles being installed and then looks for a specific header in the META-INF/MANIFEST.MF:

Service-Component: OSGI-INF/*.xml

If the DS bundle finds this header, it looks for files contained in the bundle itself matching the file pattern specified. This is a comma-separated list, and can use a single wildcard * character (which will match file names but not directories).

The service document is then loaded and parsed, and used to instantiate and register services with the OSGi runtime environment. The XML document uses namespaces to represent the component, using http://www.osgi.org/xmlns/scr/v1.2.0. Different versions of SCR use different endings; v1.0.0 is defined as the first version, with v1.1.0 the second. The current version (as of the writing of this book) uses the suffix v1.3.0.

Each service document defines a single service, which has an implementation class as well as an identifier. The service can be registered under one or more interfaces, as well as optional priorities.

This can be used to remove the custom code in the TimeZonesActivator created previously, by deleting the class and removing the Bundle-Activator from the manifest.

If the application is run now, the service won't be registered. To register these as OSGi services declaratively, create a file called OSGI-INF/timezones.xml:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
 name="TimeZonesProvider">
 <implementation
  class="com.packtpub.e4.timezones.internal.TimeZonesProvider"/>
  <service>
   <provide
    interface="com.packtpub.e4.timezones.TimeZonesService"/>
  </service>
</scr:component>

Tip

Don't forget to tell Eclipse to consider this part of the build by adding OSGI-INF/ to the build.properties file in the bin.includes property.

As long as a declarative services provider is installed in the application and started, the service will be created on demand.

Note

Client bundles should be able to express a dependency on a Declarative Services provider by using the following requirement in the manifest:

Require-Capability:
 osgi.extender;osgi.extender="osgi.component"

However, this is not yet implemented in Eclipse.

The launch configuration can detect whether or not declarative services are installed with the Validate Bundles button, but at the moment the Add Required Bundles button does not resolve the problem. At present the org.eclipse.equinox.ds bundle must be resolved manually to fix this problem. It will also require org.eclipse.equinox.util and org.eclipse.osgi.services to be added to the launch configuration.

Properties and Declarative Services

Declarative Services can also be used to register properties with the service when it is registered. These properties can be sourced either from the services XML file or an external properties file.

To add the service.ranking property to the registered service, add the following into the services document:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
 name="TimeZonesProvider">
  ...
  <property name="service.ranking" type="Integer" value="2"/>
</scr:component>

When the application is restarted, the services console command will show that the service.ranking property is associated with the TimeZonesService:

osgi> services | grep timezones
{com.packtpub.e4.timezones.TimeZonesService}=
 {service.ranking=2,
  component.name=TimeZonesProvider,
  component.id=0,
  service.id=48,
  service.bundleid=11,
  service.scope=bundle}

Tip

If the property isn't listed, add a -clean argument to the Eclipse runtime console; sometimes the files are cached and PDE doesn't always notice when files are changed.

The property types can be one of:

  • String (default)

  • Long

  • Double

  • Float

  • Integer

  • Byte

  • Character

  • Boolean

  • Short

Additionally, arrays of elements can be specified by placing them in the body of the element instead of as an attribute:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
 name="TimeZonesProvider">
  ...
  <property name="compass.point" type="String">
    NORTH
    EAST
    SOUTH
    WEST
  </property>
</scr:component>

Service references in Declarative Services

As well as hard-coded values, it is also possible to set up references to services in DS. The service implementation can have bind and unbind methods, which are called when a service becomes available or goes away.

These can be mandatory or optional; if the dependency is mandatory then the service is not presented until its dependencies are available. If they are optional, the service can come up and be assigned later. They can also be single-valued or multi-valued. These are encoded in the relationships cardinality:

  • 0..1: This service is optional, either zero or one instance needed

  • 1..1: This service is mandatory, exactly one instance needed (default)

  • 0..n: This service is optional, may have zero or more instances

  • 1..n: This service is mandatory, may have one or more instances

This can be used to inject a LogService (from the org.osgi.service.log package; it may be necessary to add this as an imported package to the bundle) into the component. Modify the TimeZonesProvider to accept an instance of the LogService by adding a setLog and unsetLog method:

private LogService logService;
public void setLog(LogService logService) {
  this.logService = logService;
}
public void unsetLog(LogService logService) {
  this.logService = null;
}

This can be used to report on how many time zones are loaded in the getTimeZones method of the TimeZonesProvider class:

if (logService != null) {
  logService.log(LogService.LOG_INFO,
   "Time zones loaded with " + timeZones.size());
}

To configure DS to provide a log service, the following must be added to the timezones.xml file:

<scr:component name="TimeZonesProvider"
 xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
 ...
 <reference interface="org.osgi.service.log.LogService"
  cardinality="0..1" name="log" 
  bind="setLog" unbind="unsetLog"/>
</scr:component>

This tells DS that the log service is optional (so it will bring the service up before a LogService is available), and that setLog(log) will be called when it is available. DS also provides an unbind method which can be used to remove the service if it goes away. The instance is provided for both the setLog and unsetLog method, which may look strange—but when setting multiple elements the methods are typically called addThing and removeThing, which may be more appropriate.

Multiple components and debugging Declarative Services

Although this seems to imply that an XML file can only contain one component, in fact an XML parent element can be defined with multiple scr namespaced children. Since all elements outside the scr namespace are ignored, it is possible to embed an XHTML document with an scr namespaced element inside, and still have it picked up by Declarative Services:

<xhtml>
  <h1>Example HTML file with SCR elements</h1>
  <h2>Component One</h2>
  <scr:component name="One" xmlns:scr="http://...">
    …
  </scr:component>
  <h2>Component Two</h2>
  <scr:component name="Two" xmlns:scr="http://...">
    …
  </scr:component>
</xhtml>

Note that many developers will use a one-to-one mapping between service components and corresponding XML files; it is rare to see a single XML file with multiple service components. It is recommended to only put one component per XML file for ease of maintenance.

Tip

When using DS inside Equinox, using -Dequinox.ds.print=true gives additional diagnostic information on the state of the declarative services, including highlighting what services are waiting. For Felix, specifying -Dds.showtrace=true can increase logging, as can -Dds.loglevel=4.

Dynamic Service annotations

Although XML allows for flexibility, it has fallen out of fashion in the Java community in favor of Java annotations. The 1.2 version of the OSGi DS specification provides annotations that can be used to mark the code such that a build time processor can create the service component XML files automatically.

Tip

Note that the standard OSGi annotations are not read at runtime by the service but only build-time tools such as maven-scr-plugin. As a result they should be optionally imported, since they aren't needed at runtime, or with compile scope if using a Maven-based build.

To use the annotations, add the following as an Import-Package for the bundle in the MANIFEST.MF:

Import-Package:
 org.osgi.service.component.annotations;
 version="1.2.0";
 resolution:=optional

The @Component annotation can now be added to the individual classes that should be represented as services. Add this to the TimeZonesProvider:

import org.osgi.service.component.annotations.Component;
@Component(name="TimeZonesProvider2",
 service={TimeZonesService.class},
 property={"service.ranking:Integer=1"})
public class TimeZonesProvider implements TimeZonesService {
  ...
}

Processing annotations at Maven build time

If using Maven Tycho to build bundles, it is possible to add a Maven plug-in to generate the service xml files from components. Maven Tycho is covered in more detail in Chapter 12, Automated Builds with Tycho.

To configure the maven-scr-plugin to a build, first add the following dependency to the pom.xml file:

<dependencies>
  <dependency>
    <groupId>org.apache.felix</groupId>
    <artifactId>org.apache.felix.scr.ds-annotations</artifactId>
    <version>1.2.8</version>
    <scope>compile</scope>
  </dependency>
</dependencies>

This both provides the org.osgi.service.component.annotations classes as well as the processing engine necessary to generate the components. Note that even if other dependencies are given (say, osgi.enterprise or equinox.ds) this isn't sufficient on its own to generate the service.xml files.

Next the plugin needs to be added to the pom.xml file:

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.felix</groupId>
      <artifactId>maven-scr-plugin</artifactId>
      <version>1.22.0</version>
      <configuration>...</configuration>
      <executions>...</executions>
    </plugin>
  </plugins>
  <sourceDirectory>src</sourceDirectory>
</build>

The source directory needs to be specified to match the value of the source attribute of the build.properties file (which is used by eclipse-plugin instead of sourceDirectory), as otherwise the maven-scr-plugin cannot find the source files.

The plug-in needs to be configured specifically for eclipse-plugin projects. Firstly, the supported projects default to jar and bundle for the maven-scr-plugin, so it needs to be given additional configuration to permit processing eclipse-plugin projects.

Secondly the service files are written to target/classes/ by default. Although this will work, it makes for more difficult debugging in Eclipse. Instead, the maven-scr-plugin can be configured to write it to the project root, which will place the service files under OSGI-INF. This permits the code to be tested in Eclipse as well as exported using the standard build tools:

<configuration>
  <supportedProjectTypes>
    <supportedProjectType>eclipse-plugin</supportedProjectType>
  </supportedProjectTypes>
  <outputDirectory>${basedir}</outputDirectory>
</configuration>

Finally, to hook it in with the standard build process, add the following to the build:

<executions>
  <execution>
    <id>generate-scr</id>
    <goals>
      <goal>scr</goal>
    </goals>
  </execution>
</executions>

Now when the package is built, the service descriptor xml file will be automatically be regenerated based on the annotations. The file name is derived from the class name.

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