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?
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.
ReplyDeleteThanks 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.
ReplyDeleteThanks 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.
ReplyDeleteI 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 :)
ReplyDeleteNice.
ReplyDeleteA simple startup to the OSGi framework. Helped a lot and very nice.
ReplyDeleteHI,
ReplyDeleteNice 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.:
ReplyDeleteBundle-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.
ReplyDeleteBut 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 (';').
ReplyDeleteThe 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
ReplyDeleteHi Glyn,
ReplyDeleteFollowed 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.
ReplyDeleteAs 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?
ReplyDeleteHow can you access the service remotely from an external client?
ReplyDelete>How can you access the service
ReplyDelete>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. :-)
ReplyDeleteThanks Steve. I've made a note in the blog.
ReplyDeletethis is excellent. Absolutely cool beginners guide.
ReplyDeleteThank you very much Glyn, this is a excellent article for a beginner to start with OSGI.
ReplyDeleteOh, 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?
ReplyDeleteI 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.
ReplyDeleteHi,
ReplyDeleteThanks 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.
ReplyDelete