Forum Controls
Spotlight Features

The Rich Engineering Heritage Behind Dependency Injection

Andrew McVeigh takes us on a tour of the rich heritage behind dependency injection, what it represents, and tells us why its here to stay.

Java, the OLPC, and community responsibility

The "One Laptop Per Child" project has a great device ready to ship, but there's no Java on there. Let's think about working together to put Java on OLPC!
Replies: 16 - Pages: 2   [ 1 2 | Next ]
Threads: [ Previous | Next ]
  Click to reply to this thread Reply

Getting Started with OSGi: Registering a Service

At 10:26 AM on Feb 16, 2007, Neil Bartlett Javalobby Regulars wrote:

Welcome back to the EclipseZone OSGi mini-series. Finally, we're ready to get on to services. In my opinion, the service layer is the most exciting part of OSGi, so these next few installments should be fun.

Last time we looked at the example of a MovieFinder interface, which we said would be used by a MovieLister to search for movies. In fact you may recognize this example -- it is from Martin Fowler's famous paper on "Dependency Injection", also known as "Inversion of Control" or IoC.

Recall the problem that IoC tries to solve. A MovieLister doesn't particularly care where the raw movie data comes from, so we use the MovieFinder interface to hide such details from it. The idea is we can then substitute alternative implementations of MovieFinder , such as one that goes to a database or even one that calls an Amazon Web Service, since MovieLister only depends on the interface, not any particular implementation.

So far so good, but at some point we have to actually give a concrete implementation of MovieFinder to MovieLister . We do this by having an external container "push" a suitable object into it, rather than letting MovieLister go out and call a lookup method. Hence the term "Inversion of Control". Many such containers have been developed, for example PicoContainer, HiveMind, Spring, and even EJB 3.0. However there is one limiting factor of all these containers to date: they are mostly static. Once a MovieFinder is given to a MovieLister , it tends to be associated for the lifetime of the JVM.

OSGi also allows us to implement the IoC pattern, but in a dynamic way. It should be possible to dynamically supply implementations of MovieFinder to MovieLister and later remove them. Then we can hot-swap from an application that looks up movies in a flat text file to an application that looks them up with Amazon Web Services.

It is the Service Layer that helps us do this. Quite simply, we register a MovieFinder as a Service in the Service Registry. Later the MovieLister can be supplied with that MovieFinder Service. A Service therefore is nothing more than a Java object -- a POJO, if you will -- and it is registered under the name of a Java interface (a POJI?).

This time around, we will just look at registering the service with the registry. Later we will look at how to get the service out of the registry and supplied to a MovieLister .

We're going to add the BasicMovieFinder bundle that we built last time. We don't need to modify any existing classes, we just need to add a bundle activator. So copy this into osgitut/movies/impl/BasicMovieFinderActivator.java :

package osgitut.movies.impl;
 
import org.osgi.framework.*;
 
import osgitut.movies.*;
import java.util.Properties;
import java.util.Dictionary;
 
public class BasicMovieFinderActivator implements BundleActivator {
    private ServiceRegistration registration;
 
    public void start(BundleContext context) {
        MovieFinder finder = new BasicMovieFinderImpl();
 
        Dictionary props = new Properties();
        props.put("category", "misc");
 
        registration = context.registerService(
                               MovieFinder.class.getName(),
                               finder, props);
    }
 
    public void stop(BundleContext context) {
        registration.unregister();
    }
}


Now replace the content of BasicMovieFinder.mf :

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Basic Movie Finder
Bundle-SymbolicName: BasicMovieFinder
Bundle-Version: 1.0.0
Bundle-Activator: osgitut.movies.impl.BasicMovieFinderActivator
Import-Package: org.osgi.framework,
 osgitut.movies;version="[1.0.0,2.0.0)"
 


There are two things added to this manifest since last time. First is the Bundle-Activator line, which tells the framework about the new activator for our bundle -- we didn't need one last time. Also I have added org.osgi.framework to the imported packages. As our previous version of the bundle didn't interact with the framework, it didn't need to import the OSGi API packages.

Now you can rebuild BasicMovieFinder.jar :

> javac -classpath equinox.jar:MoviesInterface.jar osgitut/movies/impl/*.java
> jar cfm BasicMovieFinder.jar BasicMovieFinder.mf osgitut/movies/impl/*.class


Back in the OSGi console, you should still have BasicMovieFinder.jar installed from last time. So you just need to tell OSGi to update the bundle, by typing update N , where N is the numeric ID of the bundle (which you have found using ss ). Now start the bundle with the command start N and you should see... very little happen.

Actually we've just registered our first service with the OSGi service registry, but unfortunately there's nobody on the "other end", so the registration doesn't produce any visible effect. If we want to reassure ourselves that our code has actually done something, we're going to have to go digging, and we do that with the following command:

services (objectClass=*MovieFinder)


We should see the following output:

{osgitut.movies.MovieFinder}={category=misc, service.id=22}
  Registered by bundle: file:BasicMovieFinder.jar [4]
  No bundles using service.


Great, our service is registered! And I'd love to go on and tell you how to lookup that service and use it in another bundle, but that will have to wait until another day. In the meantime, see what you can do with the services command. For starters try typing services without the expression in parentheses afterwards -- that was actually a filter which reduced the number of services displayed to just the one we were interested in. Without the filter you will see all of the registered services. There are a surprisingly large number of them!
  Click to reply to this thread Reply
1. At 11:19 AM on Feb 18, 2007, Jin Blooming Javalobby Member wrote:

Re: Getting Started with OSGi: Registering a Service

Neil:
Good OSGi series articles! Is it possible to add other series articles' links in some place of each series' one? This allows readers to navigate between those series more conveniently.
Best regards,
Jin
  Click to reply to this thread Reply
3. At 12:44 PM on Feb 18, 2007, Neil Bartlett Javalobby Regulars wrote:

Re: Getting Started with OSGi: Registering a Service

Jin,

Funny you should ask...

http://neilbartlett.name/blog/osgi-articles/

I will be keeping the links on that page updated as each new article comes out.

Glad you're enjoying them!
Neil
  Click to reply to this thread Reply
4. At 4:57 AM on Feb 19, 2007, Jin Blooming Javalobby Member wrote:

Re: Getting Started with OSGi: Registering a Service

Neil, good blog, thanks^_^
  Click to reply to this thread Reply
5. At 6:12 AM on Mar 4, 2007, Richard Mahn Javalobby Newcomers wrote:

Re: Getting Started with OSGi: Registering a Service

Great set of articles !
Especially for someone like me who is just learning about the insides of eclipse & equinox.

I think there is a small typo.
In
> javac -classpath equinox.jar:MoviesInterface.jar osgitut/movies/impl/*.java
> jar cfm BasicMovieFinder.jar BasicMovieFinder.mf osgitut/movies/impl/*.class

in order to get the compile to work I had to change the ":" in the first line to a ";".

Also I'm using 3.3M5eh, with little experience on other versions. What I'm seeing is that I have to invoke the equinox.jar with a "-clean" to get an osgi with only a bundle 0 showing with a ss. I don't know if this is a bug in 3.3M5eh or a feature since the version of equinox you used in the articles.
  Click to reply to this thread Reply
6. At 9:11 AM on Mar 4, 2007, Neil Bartlett Javalobby Regulars wrote:

Re: Getting Started with OSGi: Registering a Service

Hi Richard,

It's not exactly a typo. You have to use colons and forward slashes on Linux, Mac OS etc, but semicolons and backslashes on Windows. It was my assumption that most experienced Java developers would have made the translation automatically :-)

You're right that invoking with -clean brings you back to a clean slate with none of the previously installed bundles present. However it isn't really necessary to do that in order to follow the tutorial. Unfortunately, the output you see from the ss command will inevitably diverge from what I get and what anybody else will get.

Regards
Neil
  Click to reply to this thread Reply
7. At 11:58 AM on Mar 16, 2007, Amine C. Javalobby Newcomers wrote:

Re: Getting Started with OSGi: Registering a Service

I went through this tutorial, but when I start the service (BasicMovieFinder) I am getting ClassNotFoundException for osgi classes. It look the osgi doesn't find its own classes?


org.osgi.framework.BundleException: The activator osgitut.movies.impl.BasicMovieFinderActivator for bundle BasicMovieFinder is invalid
at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadBundleActivator(AbstractBundle.java:141)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:962)
at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:317)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:256)
at org.eclipse.osgi.framework.internal.core.FrameworkCommandProvider._start(FrameworkCommandProvider.java:239)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.osgi.framework.internal.core.FrameworkCommandInterpreter.execute(FrameworkCommandInterpreter.java:145)
at org.eclipse.osgi.framework.internal.core.FrameworkConsole.docommand(FrameworkConsole.java:293)
at org.eclipse.osgi.framework.internal.core.FrameworkConsole.console(FrameworkConsole.java:278)
at org.eclipse.osgi.framework.internal.core.FrameworkConsole.run(FrameworkConsole.java:213)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NoClassDefFoundError: org/osgi/framework/BundleActivator
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.defineClass(DefaultClassLoader.java:160)
at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.defineClass(ClasspathManager.java:498)
at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findClassImpl(ClasspathManager.java:468)
at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findLocalClassImpl(ClasspathManager.java:427)
at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findLocalClass(ClasspathManager.java:410)
at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.findLocalClass(DefaultClassLoader.java:188)
at org.eclipse.osgi.framework.internal.core.BundleLoader.findLocalClass(BundleLoader.java:334)
at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:386)
at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:347)
at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:83)
at java.lang.ClassLoader.loadClass(Unknown Source)
at org.eclipse.osgi.framework.internal.core.BundleLoader.loadClass(BundleLoader.java:278)
at org.eclipse.osgi.framework.internal.core.BundleHost.loadClass(BundleHost.java:227)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadBundleActivator(AbstractBundle.java:134)
... 13 more
  Click to reply to this thread Reply
8. At 12:37 PM on Mar 16, 2007, Neil Bartlett Javalobby Regulars wrote:

Re: Getting Started with OSGi: Registering a Service

Hi Amine,

Could you check whether the package org.osgi.framework is listed in the Import-Package section of your bundle manifest?

Regards,
Neil
  Click to reply to this thread Reply
9. At 9:30 PM on Mar 18, 2007, Amine C. Javalobby Newcomers wrote:

Re: Getting Started with OSGi: Registering a Service

Neil,

Yes that was the problem. When I updated "BasicMovieFinder.mf" I wrote it in the wrong path. Thanks.

Amine.
  Click to reply to this thread Reply
10. At 7:08 PM on Mar 28, 2007, wtrichards Javalobby Newcomers wrote:

Re: Getting Started with OSGi: Registering a Service

Neil,
I think that this tutorial is helping me understand the OSGI much better that just reading the specs.
However, I am getting the same problem as Amine. I have checked the pathing in the BasicMovieFinder.mf. It looks like the following:
BasicMovieFinder.mf

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Basic Movie Finder
Bundle-SymbolicName: BasicMovieFinder
Bundle-Version: 1.0.0
Bundle-Activator: osgitut.movies.impl.BasicMovieFinderActivator
Import-Package: org.osgi.framework,
osgitut.movies;version="[1.0.0,2.0.0)"

What else is there to check? Is there a software bundle that has all the source files in it that could be downloaded. I might have as spelling mistake some where.
Any help appreciated.
Wayne
  Click to reply to this thread Reply
11. At 4:01 AM on Mar 29, 2007, Alex Blewitt DeveloperZone Top 100 wrote:

Re: Getting Started with OSGi: Registering a Service

The formatting of the post may be screwing it up, but you need at least one space for the 'osgitut.movies' line below. You can also put them on one line e.g.

Import:Package:org.osgi.framework,osgitut.movies

Alex.
  Click to reply to this thread Reply
12. At 10:43 PM on Mar 29, 2007, wtrichards Javalobby Newcomers wrote:

Re: Getting Started with OSGi: Registering a Service

That seems to fix the problem. Spaces in the paramater line due make a difference. Thanks
Wayne
  Click to reply to this thread Reply
13. At 3:58 AM on Apr 12, 2007, wolverine.my Javalobby Newcomers wrote:

Re: Getting Started with OSGi: Registering a Service

If I have a service which will loop forever... e.g. monitoring a directory until there is one input file available; Do we need to start another thread for this process?
  Click to reply to this thread Reply
14. At 4:16 AM on Apr 12, 2007, Neil Bartlett Javalobby Regulars wrote:

Re: Getting Started with OSGi: Registering a Service

wolverine,

Yes. Whenever the OSGi framework calls into your bundle, e.g. the BundleActivator.start() method, it expects you to return control to it in a reasonable amount of time.

You should therefore avoid writing infinite loops or doing anything that might block indefinitely, e.g. performing blocking I/O or monitor acquisition without a timeout. Otherwise you risk starving another bundle.

Neil
  Click to reply to this thread Reply
15. At 4:39 AM on Apr 12, 2007, Alex Blewitt DeveloperZone Top 100 wrote:

Re: Getting Started with OSGi: Registering a Service

NB if this happens, the bundle's state is shown as STARTING in the console. Depending on how many threads that the framework kicks off to start bundles, if you have too many of them it may prevent others from starting.

Of course, there's nothing to stop you starting off another Thread in the start() method; in fact, a number of things do this (e.g. the Jetty web server). You should check, though, that when the activator's stop() method is called, that it terminates any such started thread in a friendly way.

Alex.

thread.rss_message