Creating an OSGi bundle
Newcomers to OSGi may like a simple guide to developing a bundle. Peter Kriens has provided an extensive tutorial (December 2008: currently offline pending an overhaul) which is a must for anyone serious about learning OSGi. However, it has a long introduction and assumes you are happy to run Eclipse. So I thought I would provide a trival example that people could get going using only a Java SDK and their favourite text editor.
Here are instructions to create and run a trivial bundle, hopefully in about 10 minutes.
1. Download an OSGi framework (I used Equinox v3.2.1).
2. Paste the following code into the file org/foo/example/Example.java:
package org.foo.example; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class Example implements BundleActivator { public void start(BundleContext bc) { System.out.println("Hello world"); } public void stop(BundleContext bc) { System.out.println("Goodbye world"); } }
3. Compile the code:
> javac -cp org.eclipse.osgi_3.2.1.R32x_v20060919.jar org/foo/example/Example.java
4. Paste the following bundle manifest into the file MANIFEST.MF:
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.foo.example.Example Bundle-Version: 1 Bundle-Activator: org.foo.example.Example Import-Package: org.osgi.framework;version="1.3.0"Make sure you have a carriage return and/or newline character at the end of the last line as this is required (see manifest specification in the JAR specification).
5. Package the manifest and code into a bundle:
> jar cvfm example.jar MANIFEST.MF org
Note that the order of the flags is important - the f and m options need to appear in the same order as the jar file and manifest file parameters.
6. Run the resultant bundle example.jar interactively using the Equinox console, e.g.:
> java -jar org.eclipse.osgi_3.2.1.R32x_v20060919.jar -console osgi> install file:///osgi/blog/example/example.jar Bundle id is 6 osgi> start 6 Hello world osgi> stop 6 Goodbye world osgi> close
(close exits the framework).
That's it! Anyone care to comment how long it took them?
24 comments:
This is good stuff, Glyn. This is the kind of thing that people need to be aware of to levarage OSGi outside of Eclipse. Keep up the good work.
Thanks for this good tutorial. We're using OSGi on the SimpleCenter project (http://www.simplecenter.org), and we're definitely finding people struggling with the OSGi learning curve. Hopefully tutorials like this will help.
Thanks for the feedback. Are you aware of Neil Bartlett's series of OSGi tutorials on EclipseZone? These should help the people you have in mind.
I heard of SimpleCenter via a recent blog,
but I'm glad you made direct contact. Always interesting to hear about projects adopting OSGi!
8 seconds :)
Nice.
A simple startup to the OSGi framework. Helped a lot and very nice.
HI,
Nice tutorial to go for the beginners.
I just wanted to ask one question. If I wanted to included third party libraty (for example jidc.jar ) to my bundle...how should I proceed ???
THanks
You can include a third party jar inside your bundle by adding the third party jar to the root directory of the bundle jar file and then adding a bundle classpath header to the bundle's manifest, e.g.:
Bundle-ClassPath: .;jidc.jar
The result is a bundle containing the nested third party jar.
Alternatively, you could convert the third party jar into a bundle with particular exported packages which your application bundle could then import. You could either add a manifest to the third party jar or you could wrap the third party jar in a bundle containing just a manifest and the nested third party jar. The latter approach avoids having to crack open the third party jar if this would invalidate the license.
Putting the third party jar in a separate bundle would allow you to control the packages available to your application from the third party jar so, for example, you could protect your application from being sensitive to changes in internal packages of the third party jar.
Well, Thanks for the valuable comment.
But still, say I have third party jars jetty-6.1.7.jar, servlet-api-2.5-6.1.7.jar and my application imports packages from these jars like org.mortbay.jetty,org.mortbay.jetty.servlet
So, I think the new menifest file would be like
Manifest-Version: 1.0
Bundle-Description:
Bundle-Name: jetty
Bundle-ClassPath: .;jetty-6.1.7.jar;servlet-api-2.5-6.1.7.jar;jetty-util-6.1.7.jar
Export-Package: org.mortbay.jetty,org.mortbay.jetty.servlet,
Bundle-ManifestVersion: 2
Bundle-Vendor: NTNU
Bundle-SymbolicName: jetty
Bundle-Version: 1.0.1
But the Question is how about
Bundle-Activator:..... ???
The manifest is approximately correct, but note that bundle classpath entries should be separated by commas (',') rather than semicolons (';').
The bundle activator would presumably have to start up Jetty, but I don't profess any Jetty expertise, so I'll say no more. Sorry!
I get a 404 when clicking on your Equinox download link. Perhaps you have time to change it to http://archive.eclipse.org/eclipse/equinox/drops/R-3.2.1-200609210945/download.php?dropFile=org.eclipse.osgi_3.2.1.R32x_v20060919.jar
Hi Glyn,
Followed your instructions but I get a message that the activator for the bundle is invalid :-(
osgi> start 4
org.osgi.framework.BundleException: The activator org.foo.example.Example for bundle org.foo.example.Example 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(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
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(Thread.java:613)
Caused by: java.lang.NoClassDefFoundError: org/osgi/framework/BundleActivator
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:675)
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(ClassLoader.java:251)
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
What went wrong?
Hi Jonathan. I fixed the link - thanks for pointing that out.
As for your class loading error, the most likely cause is that you haven't followed step 4 to the letter. If you don't add a carriage return and/or newline character at the end of the last line of the manifest file, the bundle will fail to import the org.osgi.framework package and will be unable to load classes from that package, which is what appears to be happening.
If changing that doesn't fix the problem, please post back.
How can you access the service remotely from an external client?
How can you access the service remotely from an external client?
>How can you access the service
>remotely from an external client?
That's another story and not one which OSGi currently addresses. So called "distributed OSGi" is being considered for a later version of OSGi.
Peter Kriens has provided an extensive tutorial which is a must for anyone serious about learning OSGi. You may wish to note that this tutorial is removed at the moment, because Peter thinks it needs a serious update. :-)
Thanks Steve. I've made a note in the blog.
this is excellent. Absolutely cool beginners guide.
Thank you very much Glyn, this is a excellent article for a beginner to start with OSGI.
Oh, I have problems with that tutorial. According to http://www.eclipse.org/forums/index.php/t/340093/ - How should we start org.eclipse.equinox.console bundle?
I found the same problem a few minutes ago! If you use an older version of Equinox, such as 3.2.1, the tutorial works fine.
Hi,
Thanks for the tutorial, still a beginner in OSGi.
I'm having problems with step 6.
When I run the terminal command:
java -jar org.eclipse.osgi_3.2.1.R32x_v20060919.jar -console
The output is:
Exception in thread "main" java.lang.NullPointerException
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:186)
at org.eclipse.core.runtime.adaptor.EclipseStarter.main(EclipseStarter.java:150)
Have I missed out something?What am I doing wrong?
I'm afraid I stopped working on OSGi quite a few years ago. I just tried it and got the same exception as you. I tried again with org.eclipse.osgi_3.12.100.v20180210-1608.jar and that hung. Sorry. I suggest you contact the Equinox community at http://www.eclipse.org/equinox/resources.php.
Post a Comment