Latest Posts

Archives [+]

Categories [+]

Authors [+]

Deploying OSGi Bundles into Sling with Maven

About a week ago I posted on how to create an OSGi bundle for Apache Sling. In the comments section of that post Sling developer Bertrand Delacretaz mentioned that the Maven build tool might save some work in that respect. Inspired by that comment I would like to show in this post how to convert the example to a Maven build.

If you have not done so start off by downloading and installing Maven and get familiar with the basic concepts, especially the pom.xml file where the build is configured.

A big advantage of using Maven for building OSGi bundles for Sling is that the descriptor files serviceComponents.xml and MANIFEST.MF are automatically generated from Java annotations in the source files. Therefore, it is not necessary anymore to explicitly write any descriptor files when Maven is used. Instead, a number of annotations need to be added to the HelloServiceImpl class:

...
/** HelloService implementation
*
* @scr.service
*
* @scr.component
* immediate="true"
* metatype="false"
*
* @scr.property
* name="service.description"
* value="A sample from Day"
*
* @scr.property
* name="service.vendor"
* value="Day"
*
*/

public class HelloServiceImpl implements
  HelloService{

/** @scr.reference */
private SlingRepository repository;
...

Maven will process the @scr. annotations. For example, the @scr.property annotations get converted into scr:property elements in serviceComponents.xml.

The @scr.reference annotation is even more useful. Not only does it generate the corresponding element in serviceComponents.xml but it also generates the bind/unbind methods for the injection of the repository object. As a consequence these two methods can be removed from the source code of HelloServiceImpl.

The rest of the configuration is done in the pom.xml file, especially the bits we need to get the correct MANIFEST.MF. Have a look at the attched pom.xml and consider the the lines

<configuration>
  <instructions>
    <Export-Package>
    !com.day.samples.impl,
    com.day.samples.*
    </Export-Package>
    <Private-Package>
    com.day.samples.*
    </Private-Package>
  </instructions>
</configuration>

This configuration will be picked up by Maven. It will write into MANIFEST.MF:

Export-Package: com.day.samples;uses:="javax.jcr"

All imports the bundle needs do not have to be configured explicitly, but are generated automatically into MANIFEST.MF. Nice!

Another useful feature is auto-deployment of the produced bundle into Sling. This is configured in pom.xml in the lines:

<configuration>
  <slingUrl>
  http://localhost:8080/system/console/install
  </slingUrl>
  <user>admin</user>
  <password>admin</password>
</configuration>

Make sure to adapt your port and password accordingly. For CRX Quickstart the port is likely to be 7402.

In order to enable Maven to find some additional (Maven) repositories that contain the Apache Snapshot two additional sections are necessary in pom.xml. See the parts repositories and pluginRepositories of that file.

As usual, all sources discussed in this post are attached. Download the jar, unpack it and execute

mvn install

This will compile and deploy the bundle into Sling without further manual work.

 
(optional)
6 comments
I just noticed a small glitch in the attached jar: the java files need to be in src/main/java in order to be picked up by mvn, of course.
0 Replies » Reply
i see a couple of downsides to using annotations for scr, dunno if they're unfounded or not:

1) you don't know at a glance what services you're registering
2) what if one service depends on another in the same bundle? if serviceComponents.xml loads each service in order, then one could put the dependent service after the service it depends on. but through annotations, this doesn't seem possible
0 Replies » Reply
@kaiser, I'm not sure what you mean by "you don't know at a glance what services you're registering", do you mean compared to an XML file that lists the services?

The @scr.service spec is clear, by default all interfaces implemented by the component are made available, and you can restrict to specific interfaces by listing them.

A service depending on another in the same bundle is not a problem, and neither is the order of service declarations. Services are started dynamically and asynchronously by Service Components Runtime (SRC), as needed to satisfy the dependencies, so you have no control on their starting order anyway.
0 Replies » Reply
hey bertrand, #1 is correct--if i'm a new developer on the team and checkout this project, i won't know automatically what services are provided in the bundle unless i go into the compiled jar. that's a minor thing though, more out of convenience.

#2 makes sense. by that extension, there's no way at all to guarantee a service being available? can a reasonable assumption be made that all properly made services will startup correctly at some point if their chain of dependencies also startup correctly?
0 Replies » Reply
also, what's a good usage for bundle activators? do they take the place of annotations/serviceComponents.xml?
0 Replies » Reply
@kaiser, all "properly made" services will start when their dependencies become available. Something that can be challenging is finding the point in time when all your services are available, that's the topic of the SLING-490 issue which is not yet implemented. For now, in our products, we run some tests over cq's RESTful interface to find out when the system is ready.

About bundle activators, they don't replace serviceComponents.xml but they are needed when the standard SCR startup/initialization semantics are not sufficient. The Sling bundles/extensions/threaddump bundle, for example, uses an Activator as it needs to register a custom UncaughtExceptionHandler, and sets up some Apache Felix extensions.

[1] https://issues.apache.org/jira/browse/SLING-490
0 Replies » Reply