Creating Services for the Jitsi

SIP Communicator 1.0 and later, are all based on the OSGi architecture and using the Apache Felix implementation (formerly known as Oscar) from Richard Hall. If you are unfamiliar with OSGi you might find the Apache Felix tutorials very handy.

Since OSGi is a standard, it is also possible to find documentation on writing OSGi bundles from other sources; for example, Sun provides a tutorial for both Windows and Solaris (they’re a bit outdated and were originally written for a discontinued OSGi implementation from SUN, but regardless of that the information in them is still pertinent and very helpful).

The Jitsi comes with a set of services that we call base. The Configuration, ProtocolProvider, Message and Call History, GUI and Media, are among others, such base services. All the base services come with a default implementation and a SLICK (Service Leveraging Implementation Compatibility Kit). Developers may provide alternative implementations to these or create new services. This section provides a few tips on how to do so.

Creating the Source Tree

Every service in the Jitsihas at least three associated packages: one for all the service interfaces, a second containing the default implementation and a third for the SLICK - a suite of tests that determine whether a particular implementation of that service could be considered complete and interoperable with plugins using the service (don’t worry if that’s unclear - I’ll explain it later).

Here’s how these packages are situated in the sip-communicator source tree. For a Smile service for example you’d have the following three packages:

  • net.java.sip.communicator.service.smile - for all service interfaces and classes. The entry point to the service should carry the same name as the package followed by the service suffix. Here that would be: SmileService.
  • net.java.sip.communicator.impl.smile - for the service implementation. All classes here should carry the same name as the interface they are implementing, followed by the impl suffix. For the entry point interface implementation this is a MUST and in this case we have: SmileServiceImpl.
  • net.java.sip.communicator.slick.smile - for the service SLICK. The entry point for the SLICK package should have the same name as the main service interface terminated by a Lick suffix (funny name isn’t it). For our Smile service this would be: SmileServiceLick.

When designing a new service from the ground up, you’ll need to provide content for all three of them.

If you are building up a service, keep in mind that it would be best if you respected this naming convention so that others could easily identify its various modules.

Here’s a bit more on the roles of these packages.

Package: net.java.sip.communicator.service.smile

That’s where all service interfaces as well as classes that would remain common for all implementations. Everyone using the smile service will actually be accessing these interfaces and will not (ideally) be touching the actual implementation. That means that you’d better keep them as simple and intuitive, and well documented as possible.

The main interface for a service should always carry the name of the service followed by the Service suffix. For a Smile service the name would be SmileService.

Package: net.java.sip.communicator.impl.smile

The impl tree contains classes that implement the interfaces from the service.smile package. A service can have several implementations, one of which is considered “default” and is officially maintained by sip-communicator.org (us).

All classes here should carry the same name as the interface they are implementing, followed by the “impl” suffix. For the entry point interface implementation this is a MUST and in the Smile case we have: SmileServiceImpl.

Package: net.java.sip.communicator.slick.smile

The slick package is what ensures that implementations are compatible and fully implement the respective service. A SLICK to a service is what a TCK is to a JSR… it’s all clear now isn’t it? :). Well imagine for example that you’d like to provide an implementation to one of the services already available in the sip-communicator. Let’s say that you’d like to implement the ProtocolProviderService over a protocol that is currently not supported by the Jitsi. Yet you’d like other bundles using that interface to continue functioning the same way as they would for any other protocol implementation. The most obvious way to verify that is to simply run SC and try out your implementation. This, however doesn’t guarantee that you haven’t left something out while testing (and there’s generally a lot to test). That’s where a SLICK comes in. Running a SLICK over a service implementation guarantees that your implementation has all the necessary features for other bundles to use it transparently.

SLICKs are also quite helpful for plain unit testing. Regularly running a slick over your service implementation helps keep bugs out and makes you feel confident that it runs the way it supposed to.

SLICKs in the Jitsi are developed using JUnit and you can find guidelines on using it in the Design of the JUnit Tests section, written by Brian Burch.

The entry point for the SLICK package should have the same name as the main service interface terminated by a “Lick” suffix (funny name isn’t it). For our Smile service this would be: SmileServiceLick. The reason for not terminating it by Slick is that the S in SLICK stands for Service and this is already a part of the name so there’s no point in doubling it (and besides we get that funny name :) )

Building your service through the project build.xml

Almost there! Once you have your service, implementation and slick, you’d have to plug them in the build.xml so that the get built and tested during CruiseControl continuous builds. You would have to build a bundle per SLICK and another one for the service and implementation. Note that if you are implementing a default implementation, you would have to include the service interfaces in the same bundle as the implementation.

You may use other bundles in the section as examples on how to create yours. Here’s how I’ve done it for the configuration slick:

    <!--BUNDLE-CONFIGURATION-SLICK-->
    <target name="bundle-configuration-slick" depends="rebuild">
        <jar compress="false" 
            destfile="${bundles.dest}/configuration-slick.jar" 
            manifest="test/net/java/sip/communicator/slick/configuration/
                      configuration.slick.manifest.mf">
            <zipfileset 
                dir="${dest}/net/java/sip/communicator/slick/configuration"
                prefix="net/java/sip/communicator/slick/configuration"/>
        </jar>
    </target>

In order to get it automatically built up during project builds, add a reference to your target in the depends parameter of “sc-bundles”.

In order to have your slick automatically executed during automated continuous builds, you need to add its name here among the others specified by the TEST_LIST property in the test target.

Updating the OSCAR/Felix configuration

One last thing left to do. In order for your bundles to get activated you would need to add them in the oscar.unit.test.properties or oscar.client.run.properties depending on whether you want them executed during automated testing or while running the client respectively.

Author: Emil Ivov