Posts Tagged Apache Felix

OSGi DevCon EclipseCon and OSGi Security

I hope you registered already for this years OSGi DevCon at EclipseCon? It’s less then two weeks away and it would be great to see you there.

EclipseCon 2008

In case you did I’d like to urge you to consider our talk about OSGi security.

I'm speaking at EclipseCon 2008

The program looks very interesting and OSGi is well represented throughout the conference.

Marcel Offermans and Karl Pauls will give a tutorial on the first day about Building Secure OSGi Applications.

This Tutorial focuses on embedding various OSGi framework implementations namely, Eclipse Equinox and Apache Felix, into applications as a means of plugin mechanism while taking advantage of the often overlooked benefits of this solution: security. The OSGi specifications have an extensive and very powerful security model that eases the difficult task of building secure, dynamically extensible, applications so don’t miss out on this opportunity.

People in and around the Netherlands, however, have another possibility to get to see this as we will give a boiled down version of the tutorial at the NLJUG jspring 2008 as well.

Thats all for today and we look forward to seeing you in Santa Clara!

regards,

, , , ,

No Comments

OSGi on Google Android using Apache Felix

UPDATE: A lot has changed in the world of Android & OSGi since writing this post. For the latest developments around this topic, go to: EZdroid community
Since Android 1.5 it is now possible to run Apache Felix without any changes on the phone!

So I was playing around with the Android Google is building … As somebody involved with OSGi for quite some years and a regular contributor to Apache Felix (the OSGi implementation of the Apache Software Foundation) the objective is clear: this platform needs an OSGi framework and Apache Felix is what it is going to be!

The task at hand can be split in two parts namely, figure out how to run the framework itself and extend it to be able to dynamically load bundles.

The former shouldn’t be a big problem because Apache Felix is easily portable and I personally made it run on a quite a number of JVMs. The later qualifies as tricky because for not yet publicly announced reasons Google chooses to not really provide a real JVM but something similar called dalvik.

One of the biggest differences (apart from added API) is that dalvik doesn’t execute Java bytecode directly but needs its own format. Tools are provided to convert from existing Java bytecode to dalvik alas, the conversion is not done at runtime.

Apache Felix on Google Android

The first step is to find the actual runtime on the emulator to save me going through the hassle of rebuilding and redeploying all the time:

> emulator &
> adb shell
# /system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar -version
    DalvikVM version 0.2.0
    Copyright (C) 2007 Google, Inc.
    Blah blah blah LICENSE blah blah.

Notice the funny last line – I’m not making this up :-) .

So for a straight forward scenario all we need is the felix.jar with the added dalvik bytecode:

> dx --dex --output=classes.dex bin/felix.jar
> aapt add bin/felix.jar classes.dex
> adb push bin/felix.jar /root/felix/bin/felix.jar
> adb shell
# cd root/felix
# /system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar \
  -classpath bin/felix.jar org.apache.felix.main.Main

Voila (well, in reality I needed to patch a little to get to this point because there was a bug or two – I’ll commit the fix to trunk).

Dynamically Loading Bundles on Google Android

The next part is the most critical one because we will need to do something that is officially not supported. We need to be able to load bundles i.e., dynamically load code. There is a way to do something in this direction in the official api but nothing close to the power of what we need (and want) for OSGi — hence, I spend sometime finding a loop-hole. It turns out that the normal ClassLoader approach will throw an exception saying that it is not possible to load java byte code. Fortunately, there is a class available that allows to load classes from dex files.

private static final Constructor m_dexFileClassConstructor;
private static final Method m_dexFileClassLoadClass;

static
{
    Constructor dexFileClassConstructor = null;
    Method dexFileClassLoadClass = null;
    try
    {
        Class dexFileClass =  Class.forName("android.dalvik.DexFile");
        dexFileClassConstructor = dexFileClass.getConstructor(
            new Class[] { java.io.File.class });
        dexFileClassLoadClass = dexFileClass.getMethod("loadClass",
            new Class[] { String.class, ClassLoader.class });
    }
    catch (Exception ex)
    {
        dexFileClassConstructor = null;
        dexFileClassLoadClass = null;
    }
    m_dexFileClassConstructor = dexFileClassConstructor;
    m_dexFileClassLoadClass = dexFileClassLoadClass;
}

private Object m_dexFile = null;

public synchronized Class getDexFileClass(String name, ClassLoader loader)
    throws Exception
{
    if (m_dexFile == null)
    {
        if ((m_dexFileClassConstructor != null) &&
              (m_dexFileClassLoadClass != null))
        {
            m_dexFile = m_dexFileClassConstructor.newInstance(
                new Object[] { m_file });
        }
        else
        {
            return null;
        }
    }

    return (Class) m_dexFileClassLoadClass.invoke(m_dexFile,
        new Object[] { name.replace('.','/'), loader });
}

This is the equivalent to using com.sun.* classes because the class is not inside the official package namespace but at any rate:

> dx --dex --output=classes.dex \
   bundle/org.apache.felix.shell-1.1.0-SNAPSHOT.jar

> aapt add bundle/org.apache.felix.shell-1.1.0-SNAPSHOT.jar classes.dex

> adb push bundle/org.apache.felix.shell-1.1.0-SNAPSHOT.jar \
  /root/felix/bundle/org.apache.felix.shell-1.1.0-SNAPSHOT.jar

> dx --dex --output=classes.dex \
   bundle/org.apache.felix.shell.tui-1.1.0-SNAPSHOT.jar

> aapt add bundle/org.apache.felix.shell.tui-1.1.0-SNAPSHOT.jar \
   classes.dex

> adb push bundle/org.apache.felix.shell.tui-1.1.0-SNAPSHOT.jar \
  /root/felix/bundle/org.apache.felix.shell-1.1.0-SNAPSHOT.jar

We also need a configuration that will make use of the bundles:

> adb push conf/config.properties /root/felix/conf/config.properties
> adb shell
# cd root/felix
# /system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar \
  -classpath bin/felix.jar org.apache.felix.main.Main

Welcome to Felix.
=================

-> ps

START LEVEL 1
   ID   State         Level  Name
[   0] [Active     ] [    0] System Bundle (0.0.0)
[   1] [Active     ] [    1] Apache Felix Shell Service (1.1.0.SNAPSHOT)
[   2] [Active     ] [    1] Apache Felix Shell TUI (1.1.0.SNAPSHOT)

-> shutdown

Now, for the added fun and as a prove of concept we are going to use the telnet bundle available form the OBR side. It is a little bit more involved because of an inner jar that needs to be processed as well.

> mkdir unpack && cd unpack
> jar -xf ../bundle/telnetd.jar
> dx --dex --output=classes.dex \
   com/softsell/open/osgi/telnetd/dtw.TelnetD.jar
> aapt add com/softsell/open/osgi/telnetd/dtw.TelnetD.jar  \
   classes.dex
> rm classes.dex
> jar -cmf META-INF/MANIFEST.MF ../bundle/telnetd.jar *
> cd .. && rm -rf unpack
> dx --dex --output=classes.dex bundle/telnetd.jar
> aapt add bundle/telnetd.jar classes.dex
> adb push bundle/telnetd.jar  /root/felix/bundle/telnetd.jar
> adb shell
# cd root/felix
# /system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar \
  -classpath bin/felix.jar org.apache.felix.main.Main

Welcome to Felix.
=================

-> ps

START LEVEL 1
   ID   State         Level  Name
[   0] [Active     ] [    0] System Bundle (0.0.0)
[   1] [Active     ] [    1] Apache Felix Shell Service (1.1.0.SNAPSHOT)
[   2] [Active     ] [    1] Apache Felix Shell TUI (1.1.0.SNAPSHOT)

-> install file:bundle/telnetd.jar
Bundle ID: 3
-> start 3
[Listening to Port 6623 with a connectivity queue size of 5]

With a little bit of work we are now able to telnet into our framework (we first have to add an redirect of the port):

> telnet localhost 5554
 Trying ::1...
  Connected to localhost.
 Escape character is '^]'.
 Android Console: type 'help' for a list of commands
  redir add tcp:4711:6623
 OK
 quit

Now the framework should be reachable on localhost under port 4711:

> telnet localhost 4711

 Welcome to the SoftSell OSGI Telnet Server

 Available Services:

 Felix

Enter Choice> Felix

Welcome to the OSGI command shell
=================================

-> ps
  ID   State         Level  Name
[   0] [Active     ] [    0] System Bundle (0.0.0)
[   1] [Active     ] [    1] Apache Felix Shell Service (1.1.0.SNAPSHOT)
[   2] [Active     ] [    1] Apache Felix Shell TUI (1.1.0.SNAPSHOT)
[   3] [Active     ] [    1] telnetd (1.0.0)
-> shutdown
connection closed by foreign host.

Success! With a small patch that enables to load classes from a dex file dynamically we have an OSGi framework working on Google’s Android. I will commit the patch for the bugs soon and the binary as well as the real patch are available from our opensource server.

That’s all for today; happy bundle hacking :-)

, , , ,

5 Comments

Getting started with Spring-OSGi — part 2

In the
previous
blog entry about Spring-OSGi, we demonstrated how to develop a simple
Spring-OSGi bundle that exposes a Spring bean as an OSGi service. In this installment
we’ll have a look at how you can use OSGi services in a Spring-OSGi bundle.
The sample code used in this blog builds on the sample of the previous blog
and can of course be
downloaded from our site.

For demonstrating the use of an external OSGi services, we’ll use a very simple bundle
exposing an AuditService service that looks like this:

public interface AuditService
{
    public void audit(String action);
}

The bundle provides an implementation of this interface that simply prints a message to
system out. You can download this bundle here; of course the
complete bundle source is available in the source
zip. It’s a plain (non-Spring) bundle
that use a standard OSGi activator; don’t bother if you don’t grasp all the details of this bundle
implementation: we’ll just use it as an external service. If you install and start this
bundle in Felix, you’ll see the new service appear when issue the services command.

Binding service to Spring bean

The next thing to do, is of course to adapt our reversestringbean bundle,
to use this service. We change the reverse method to audit-log all
invocations of the reverse method:

private AuditService m_auditService;

public String reverse(String arg) {
    if (m_auditService != null) {
        m_auditService.audit("reverse(String) called with argument '" + arg + "'");
    }
    ...
}

If you have Felix running with the previous version of
the reversestringbean bundle and made the change outlined above, you can
replace the old bundle with the new version (issue
an update command with the id of the old bundle and the file url of the
new version), and see that the reverse command is still working, even
though it has switched to the new version.
(If you get an error like “Unresolved package in bundle 19: package;
(package=nl.luminis.demo.audit)”, you forgot to install the audit bundle; install it
and try to start the reversestring bundle again.)

The new reversestringbean implementation is not using the audit service yet, because the service
reference is not set. When can make Spring do this, by specifying the service in
the spring.xml file:

<osgi:reference id="externalAuditService"
                interface="nl.luminis.demo.audit.AuditService"/>

and use this reference as property value for the bean that was already defined in the
same spring.xml file:

<bean name="reverseBean" class="nl.luminis.demo.reversestring.ReverseStringBean">
    <property name="auditService" ref="externalAuditService"/>
</bean>

When you build the bundle with the updated spring.xml file and reload it,
Spring will notice that
the reversestringbean bundle requires an AuditService, and
pass the bean a reference to that service. When you issue the reverse
command again, you’ll see the audit message printed to the console:

-> reverse hello there!
AuditService: reverse(String) called with argument ' hello there!'
!ereht olleh
->

Service not available

Now it’s time for a little experiment, to see how things behave when the audit service
is not (yet) available. After all, we’re now working in a service oriented environment
and service orientation is all about dynamics.

We’ll restart the Felix framework, with a non-active audit service. To do so, issue the
stop command on the audit service bundle and restart Felix. The framework will remember
each bundle’s last state, so after the restart, the state of the audit service bundle
will be “Resolved” (check this with the ps command). Note that we can’t
uninstall the audit service bundle, as it is the only bundle providing
the AuditService interface, and this interface (its class file)
is needed by the reversestringbean bundle. A better alternative would be
to split the audit service bundle and have the interface and implementation in two
separate bundles: in that case you could now uninstall the implementation bundle and
leave the interface bundle – this is left as an exercise for the reader ;-) .

Issue a reverse again: you’ll get a message (from the command bundle)
telling you that there
is no string service. If you’d study the output of the services command,
you’ll notice that although the reversestringbean bundle is started and
active, it is not publishing any service: not even Spring’s
org.springframework.context.ApplicationContext service we saw earlier.
The explanation for this behaviour is that Spring will not activate the bundle before
all its required dependencies are satisfied. You can verify this by starting the audit
service and trying again: now it works as before.

To continue our little experiment, stop the audit service again, study the output of
the services command and issue the reverse command
again. This time, the reverse string service is still there, even though the bundle’s
required services are not satisfied anymore. So, Spring refuses to start our bean when
the required service(s) (i.e. the audit service) are not there, but it doesn’t bother
to stop the bean when the required service(s) disappear. Personally I dislike this
non-symmetric behaviour and I think it shows that Spring was never designed for dynamic
systems: somehow they can’t really stop an ApplicationContext (and
restart it later) once it is created, I guess.

Optional service dependency

To return to our sample bundle that won’t start when there is not audit service:
this is not what we want. The reversestringbean bundle
should always perform the reverse operation; whether or not the audit service is there
(in a banking example this might not be the case, but for this example, assume
auditting is not crucial).
The solution is in the word “required”: if
we define the audit service to be optional, Spring will start the bundle, even when the
audit service is not there yet.

Let’s try this: add cardinality “0 to 1″ to the service reference definition:

<osgi:reference id="externalAuditService"
                interface="nl.luminis.demo.audit.AuditService"
                cardinality="0..1" />

and additionally, add the lazy-init="true" to the bean definition. Now
build and reload the bundle and issue another reverse command. To your
surprise (I guess…, at least to mine!), it still won’t work; you’ll get
a ServiceUnavailableException now.
Check the output of the services command: the reverse string
service is published. What’s going on here?

The point is that, in constrast to ‘plain’ OSGi behaviour, Spring provides the bean
with a proxy to the service, instead of a plain Java reference to the service
implementation (as the OSGi framework itself does). Moreover, this proxy is set,
irrespective of whether the service is available. The
ServiceUnavailableException is intentional: you should always be prepared
to get an exception when calling an external service.

I can agree with this last rule: in a dynamic environment, you can never be sure
whether a service is there; even when it was there a few minutes ago, it might be gone
at the very moment you’re using the service. However, in a case like this, I wouldn’t
expect the service proxy to be passed to the bean in the first place, until the service it
represents actually exists. We’ll come back to this in a minute.

Let’s add a try-catch block to the code around calling the service and try again.
This time it works as expected, although it might take a little longer than you expect:
that’s because Spring has a default wait time when it tries to find a service. You can
skip this by adding a attribute timeout="0" to
the <osgi:reference> element in the spring.xml file.
Now, the service behaves as expected: it does its job whether or not the audit service
is available, and it does it without any additional delay.

Dynamic services

There is an alternative to the setter injection, that better suits dynamic
behaviour: callback methods on the bean. As you’d expect from the Spring framework,
your bean doesn’t have to implement an interface in order to be listener; just add two
methods and specify their names in the spring.xml:

<osgi:reference id="externalAuditService"
                interface="nl.luminis.demo.audit.AuditService"
                cardinality="0..1">
  <osgi:listener ref="reverseBean"
                 bind-method="serviceAdded"
                 unbind-method="serviceRemoved"/>
</osgi:reference>

Note that the signature of the methods is fixed to this (at least in Spring-OSGi
1.0-m2; it was different in earlier versions, so it might as well differ in newer
versions):

public void serviceAdded(AuditService service, Dictionary d) {
    m_auditService = service;
}

public void serviceRemoved(AuditService service, Dictionary d) {
    m_auditService = null;
}

Don’t forget to remove the (setter injection) property from the bean definition. If you
add println's to these listener methods, you’ll see that these are indeed
called exactly at the moment the service appears or disappears.

You might wonder what happens when the cardinality is set to something else, e.g. 1 to
many 0 to many. In both cases, the setter that receives the service(s) is supposed to
receive a collection instead of a single service reference. The collection is managed
by Spring behind the scenes: each time you iterate over this collection, it’s contents
may be different, as it reflects the current state of the OSGi framework. Handling of
the case that there is no service is easy, as an iterator over the collection will
return nothing. However, one has still to cover for the
dreadfull ServiceUnavailableException, as a service may disappear between
the moment you get its reference from the collection and call a method on it.

Conclusion

We’ve seen how a normal Spring bean can interact with external OSGi services, and that
by using setter injection, the implementation of the bean doesn’t have to different
from a bean that is used within Spring exclusively. On the other hand, we’ve also seen
that a ServiceUnavailableException is always to be expected and that the
setter injection solution doesn’t combine very well with the dynamic behaviour of a
service oriented framework.

If you want to get it right, you can’t get away with a normal Spring bean
implementation that does not handle ServiceUnavailableException's and is
not prepared to handle missing dependencies. It’s an illusion that you can take an
existing Spring bean implementation and use it unmodified in an OSGi context. It’s
similar to having to deal with remote calls: you can’t hide remoteness from your
application, as remote calls might fail, and your code has to be aware of it – provided
you aim at robust code, of course. The same holds for a dynamic service oriented
environment: you have to deal with disappearing services, you can’t simply ignore
that. That is what makes OSGi different from old fashioned Spring usage that always
assumes that all beans are there, once the system is started.

The good news though, is that with Spring-OSGi, handling dynamic service is possible
and that it can’t be done without implementing specific interfaces. In that sense,
Spring-OSGi is non-intrusive, just like plain Spring is. You can’t ignore the fact that
you’ve to deal with disappearing services, but you can do it in a way that does not
limit reuse of your beans in other (non-OSGi) environments.

Finally a tip for those who want to experiment with the Spring-OSGi framework: enable
Spring (log4j) logging. It’s hard to get it all right the first time, especially with
all the xml-configuration stuff, and sometimes errors are swallowed by the framework,
leaving you in total dispair. Logging can enabled by passing a system property on the
java command line:

-Dlog4j.configuration=file:///your/path/to/spring-log4j.properties

You’ll find a sample log4j.properties file in the source zip. Happy coding!

, ,

No Comments

Getting started with Spring-OSGi

Getting started with Spring-OSGi

With the introduction of Spring OSGi,
it becomes relatively easy to split up a Spring application in separate OSGi bundles,
and have a much more modular application architecture, without all the classloading
hassle you may encounter when deploying components in J2EE application servers.

The purpose of this series of blog posts is to get you started with Spring-OSGi. We’ll
develop some simple examples that will get you up and running.
Theoretically, it is possible to use Eclipse for developing OSGi bundles using Spring,
but, at least in my experience, this is a bumpy road with lots of obstacles, and in the
end it does not lead to better understanding of the concepts. Therefore, the samples
presented here will be provided with simple ant build files and do not require special
tools to build or deploy. The complete source code of the samples can be found in this
zip file.

OSGi is (a standard defining) a service oriented framework as well as a number of
standard services that can be deployed on these frameworks. Key concepts are “bundles”
and “services”. A bundle is essentially a normal Java jar file and is the unit of
deployment, i.e. you can install, update and de-install them in a running
framework. Each bundle can publish one or more services, that can be used by other
bundles. Bundles can locate services by querying the OSGi service registry. One of the
most important aspects of OSGi, is that even bundles that use each others services,
have nothing more in common than the service interface.
A complete introduction on OSGi is beyond the scope of this blog post, but there is
enough information online, see for example
OSGi.nl,
www.aqute.biz/OSGi/Tutorial,
www.osgi.org,
felix.apache.org.

Hello…, OSGi

We’ll start with a simple “hello world” like sample, that exposes a trivial Spring bean
as an OSGi service. The next step will be to create a bundle that actually uses this
service, so we can run the demo in an OSGi framework and experiment with this. Also,
these samples will help us to setup the compile time and run time environment
correctly.

As said, we start with a simple, not to say trivial (Spring) bean. Here is its source:

package nl.luminis.demo.reversestring;

public class ReverseStringBean
{
    public String reverse(String arg) {
        String result = "";
        for (int i = arg.length() - 1; i >= 0; i--)
            result += arg.charAt(i);
        return result;
    }
}

To make it Spring bean, we have to add a configuration file that defines the bean. In
plain Spring this would be something like:

<beans xmlns="http://www.springframework.org/schema/beans">
  <bean name="reverseBean"
        class="nl.luminis.demo.reversestring.impl.ReverseStringImpl"/>
</beans>

(omitting xml namespace stuff for brevity, see the zip for complete source).

Exposing beans as OSGi services is fairly simple in Spring-OSGi. Basically, the only
thing you’ll have to do is to add an <osgi:service> element to the
spring xml configuration file like this:

<?xml version="1.0" encoding="UTF-8"?>
<beans> <!-- (again, namespace declarations omitted) -->

  <bean name="reverseBean"
        class="nl.luminis.demo.reversestring.ReverseStringImpl"/>
  <osgi:service ref="reverseBean"
                interface="nl.luminis.demo.string.ReverseString"/>

</beans>

Of course, we need an interface that defines the service we’re exposing, so we define
the ReverseString
interface and add the reverseString() method to it.

To make it a bundle, the last thing to do is add a manifest file with the (OSGi)
required entries:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: ReverseStringBean
Bundle-SymbolicName: ReverseStringBean
Bundle-Version: 1.0.0

Strictly speaking, not all of these entries are required, but it is common practice to
have at least these entries in the manifest file.

This completes our first bundle. If you’re familair with OSGi you might wonder if our
bundle doesnt’ need a BundleActivator, that provides start()
and stop() lifecyle methods that the OSGi framework can call to start or
stop our bundle. The answer is that it doesn’t need it, because Spring-OSGi works
similar to the OSGi declarative service specification: the framework will inspect the
service declaration and instantiate the service on our bundle’s behalf; instead of
publishing the service ourselves (from within the BundleActivators start method), the
framework “pulls” the service out of our bundle, so to speak.

Setting up the runtime environment

Now it’s time to set up our run time environment. For the demo we will
use Apache Felix 1.0, but you can deploy the
bundle in any OSGi framework, e.g. (Eclipse) Equinox, or Knopflerfish. Download felix
and start it by executing the jar file in its bin directory and enter a profile
name. If you enter ps on the prompt you’ll see that there are only three
bundles active: the system bundle (i.e. the framework ifself) and two bundles that
constitute the shell service that executes the commands your typing at the
prompt. Install our demo bundle by using the install command, passing it a
file url that points to the bundle:

-> install file:///Users/peter/.../reverestringbean.jar

You can start the bundle now, but it won’t register any services yet, as no
one is paying attention to our service declaration in the spring.xml
file. Execute the services command to confirm this.

As the final step in setting up the run time environment, we’ll install the Spring-OSGi
framework. For this demo, we used the milestone 2 release of Spring-OSGi 1.0; newer versions should work also, but of course, small (presumably subtle) differences may occur.
Make sure you download the “-with-dependencies” zip file.

Install these Spring-OSGi bundles from the dist directory:

  • spring-osgi-core-1.0-m2.jar
  • spring-osgi-extender-1.0-m2.jar
  • spring-osgi-io-1.0-m2.jar

These bundles depend on (but do not include) the plain Spring code, so you have to install
a number of bundles (all of which can be found in the lib
directory) that contain the plain spring framework modules:

  • spring-core-2.0.5-osgi-m2.jar (from spring-core/2.0.5-osgi-m2/)
  • spring-aop-2.0.5-osgi-m2.jar (from spring-aop/2.0.5-osgi-m2/)
  • spring-beans-2.0.5-osgi-m2.jar (from spring-beans/2.0.5-osgi-m2/)
  • spring-context-2.0.5-osgi-m2.jar (from spring-context/2.0.5-osgi-m2/)
  • aopalliance.osgi-1.0-SNAPSHOT.jar (from aopalliance.osgi/1.0-SNAPSHOT/)
  • backport-util-concurrent-3.0-SNAPSHOT.jar (from backport-util-concurrent/3.0-SNAPSHOT/)

Additionally, some SLF4J libraries
have to be installed. SLF4J is a logging facade for several logging implementations,
similar to Apache Commons Logging. An important difference with Apache Commons Logging
is that in order to determine what implementation to use, it does not rely on
classloading tricks that can cause a lot of trouble, especially when
used in dynamic environments like an OSGi framework.

From SLF4J you need the following libraries:

  • slf4j-api-1.4.3.jar (contains only the SLF4J API)
  • slf4j-log4j12-1.4.3.jar (implementation of SFL4J, hard-wired to log4j)
  • jcl104-over-slf4j-1.4.3.jar (100% compatible drop-in replacement for Commons Logging)

Just install them as normal bundles, these libraries are OSGi ready. The
jcl104-over-slf4j library contains modified versions
of org.apache.commons.logging.Log.java etc, that redirect to SLF4J. This
will take care of libraries using the Commons Logging API.

As we’ll be using log4j as the logging implementation that does the real work, we’ll
have to install that too. An OSGi compatible version of log4j can be found in the
Spring OSGi package

  • log4j.osgi-1.2.13-SNAPSHOT.jar (from src/spring-modules/spring-required-libraries/log4j/target)

but, you’ll have to build it first (with maven). Alternatively, you can download the
file here.

After you’ve installed these bundles, you can start them all. Note that if you try to
start some bundles before you installed them all, you’re likely to get errors about
unresolved packages; to avoid that you would have to install them in the right order.
You’ll probably see some warnings about resources files and namespace handlers that
can’t be found, which you can just ignore.

Now the Spring-OSGi extender is running, it should have discovered and published our
service. Due to a bug in the M2 release (fixed in later releases), it doesn’t yet work this way and you have to
restart our bundle. If you do so, you’ll get some warnings about BeanInfo classes not
being found; ignore these too.

Using the service

If you issue the services command once again, you’ll notice that our simple demo
bundle provides to services: nl.luminis.demo.string.ReverseString
and org.springframework.context.ApplicationContext. The latter is the
well known Spring application context, that is merely provided as OSGi service for
debugging purposes (you shouldn’t use it to access a bean from outside its bundle).

Essentially, we’re ready now, as our first spring enabled bundle is up and running and
publishes its service. However, we can’t be satisfied until we’ve actually seen it do
something “usefull”. To make that happen, we’ll write an extension for the felix
command interpreter, that will call our service. This extension will be a bundle on its
own. As it hooks in into the Felix command shell, this of course is a Felix specific
solution, but similar constructs exist for Equinox and Klopflerfish.

The heart of this command bundle is the execute() method, that tries to
locate the service and calls it:

public void execute(String line, PrintStream out, PrintStream err)
{
    // (...)
    ServiceReference ref = m_context.getServiceReference("nl.luminis.demo.string.ReverseString");
    Object service = (ref != null)? m_context.getService(ref): null;
    if (service != null)
        try {
            out.println(((ReverseString) service).reverse(arg));
        }
        catch (Exception e) {
            err.println("calling reverse string service failed: " + e);
        }
    else {
        err.println("no reverse string service, ref=" + ref);
    }
}

See the source.zip for the complete source code.

After installing and starting the command bundle, you’ll notice the new “reverse” command in the
help text:

-> help
...
install <URL> [<URL> ...]           - install bundle(s).
ps [-l | -s | -u]                   - list installed bundles.
resolve [<id> ...]                  - attempt to resolve the specified bundles.
reverse <arg>                       - reverses a string, using a ReverseString service
services [-u] [-a] [<id> ...]       - list registered or used services.
...

and issuing this command will finally show that our service works correctly:

-> reverse  OSGi is cool!
!looc si iGSO
->

This concludes our first working Spring-OSGi sample. It’s not yet a full-blown J2EE
application, but it clearly shows what is needed to make a basic Spring-OSGi bundle
work and have it publish a bean as an OSGi service. In future installments, we’ll have a
look at using external OSGi services in our beans, and experiment with some less
trivial bundles, including a simple web application and database access.

, ,

No Comments