Thursday, 25 June 2015

OSGi 101 - Eclipse Equinox - Gogo console

In my previous article I described the basics around Apache Felix OSGi. Now I'll do the same but this time I'll focus on Eclipse Equinox OSGi. I'll show you every single step you need to follow and the final goal is to end up with fully functional OSGi console.

OK, let's begin! We will work with the latest available stable OSGi implementation (Mars, released on Wed, 3 Jun 2015). Here is the download section:

http://download.eclipse.org/equinox

When you download and extract the archive, you will end up with this folder structure:

Eclipse Equinox (Mars) - Folder Structure
Eclipse Equinox (Mars) - Folder Structure

If you follow the official quickstart guide provided by Eclipse, you know that you need to find the JAR file org.eclipse.osgi_<version>.jar. In this Equinox OSGi version, the file is here:

plugins\org.eclipse.osgi_3.10.100.v20150529-1857.jar

Now the next part - we need to run this JAR file. The procedure is the same as it was for the Apache Felix, nothing different here. Open console window, navigate to the folder where you have extracted the Equinox OSGi and execute the following:

java -jar plugins\org.eclipse.osgi_3.10.100.v20150529-1857.jar

Eclipse Equinox (Mars) - Step 01
Eclipse Equinox (Mars) - Step 01
You will end up with... nothing! Nothing is printed and nothing seems to happen. You can kill the process with Ctrl+C. The thing is that something is happening but we can't see it. We need to provide the -consoleLog parameter to our command line:

java -jar plugins\org.eclipse.osgi_3.10.100.v20150529-1857.jar -consoleLog

Eclipse Equinox (Mars) - Step 02
Eclipse Equinox (Mars) - Step 02
We see two problems. The first one is about the property eclipse.buildId with value unknown. At this point it's not really an issue. Nevertheless, we can provide some value by providing the property -Declipse.buildId=abc123 to the command line:

java -Declipse.buildId=abc123 -jar plugins\org.eclipse.osgi_3.10.100.v20150529-1857.jar -consoleLog

Eclipse Equinox (Mars) - Step 03
Eclipse Equinox (Mars) - Step 03
Great! We provided a property/value but this doesn't really solve our problem. The real issue here is that we need to provide additional OSGi bundles. The first one is org.eclipse.core.runtime and we can find it here:

plugins\org.eclipse.core.runtime_3.11.0.v20150405-1723.jar

Unfortunately we can't simply add this JAR to the classpath. We need to install it as OSGi bundle and then run it. Step by step - let's teach Equinox a lesson by telling it where the bundle is:

java -Declipse.buildId=abc123 -Dosgi.bundles=org.eclipse.core.runtime_3.11.0.v20150405-1723.jar -jar plugins\org.eclipse.osgi_3.10.100.v20150529-1857.jar -consoleLog

Eclipse Equinox (Mars) - Step 04
Eclipse Equinox (Mars) - Step 04
Interesting - it seems that Equinox now knows about the bundle org.eclipse.core.runtime but it can't resolve it because it depends on other bundles. As we can see, now we need to provide the OSGi bundle org.eclipse.equinox.common. The good news is that almost all bundles are following similar naming convention and there is direct relation between the bundle name and the corresponding JAR file. This is why it's quite easy to spot that the JAR file we need is this one:

plugins\org.eclipse.equinox.common_3.7.0.v20150402-1709.jar

We add it to our command line arguments and now we have the following:

java -Declipse.buildId=abc123 -Dosgi.bundles=org.eclipse.core.runtime_3.11.0.v20150405-1723.jar,org.eclipse.equinox.common_3.7.0.v20150402-1709.jar -jar plugins\org.eclipse.osgi_3.10.100.v20150529-1857.jar -consoleLog

Eclipse Equinox (Mars) - Step 05
Eclipse Equinox (Mars) - Step 05
As we can see from the log output, we still can't resolve the bundle org.eclipse.core.runtime because now we see that it depends on the bundle org.eclipse.core.jobs. We can check the required bundles by exploring the MANIFEST.MF file and for the bundle org.eclipse.core.runtime we see the following dependencies:

plugins\org.eclipse.core.runtime_3.11.0.v20150405-1723.jar\META-INF\MANIFEST.MF

Require-Bundle: javax.annotation;bundle-version="1.1.0";resolution:=op
 tional;visibility:=reexport,javax.inject;bundle-version="1.0.0";resol
 ution:=optional;visibility:=reexport,org.eclipse.osgi;bundle-version=
 "[3.7.0,4.0.0)";visibility:=reexport,org.eclipse.equinox.common;bundl
 e-version="[3.7.0,4.0.0)";visibility:=reexport,org.eclipse.core.jobs;
 bundle-version="[3.2.0,4.0.0)";visibility:=reexport,org.eclipse.equin
 ox.registry;bundle-version="[3.4.0,4.0.0)";visibility:=reexport,org.e
 clipse.equinox.preferences;bundle-version="[3.4.0,4.0.0)";visibility:
 =reexport,org.eclipse.core.contenttype;bundle-version="[3.3.0,4.0.0)"
 ;visibility:=reexport,org.eclipse.equinox.app;bundle-version="1.0.0";
 visibility:=reexport

Here is more easily readable version of all dependencies, required by org.eclipse.core.runtime:

org.eclipse.equinox.common
org.eclipse.core.jobs
org.eclipse.equinox.registry
org.eclipse.equinox.preferences
org.eclipse.core.contenttype
org.eclipse.equinox.app

The corresponding JAR files for the above OSGi bundles:

plugins\org.eclipse.osgi_3.10.100.v20150529-1857.jar
plugins\org.eclipse.equinox.common_3.7.0.v20150402-1709.jar
plugins\org.eclipse.core.jobs_3.7.0.v20150330-2103.jar
plugins\org.eclipse.equinox.registry_3.6.0.v20150318-1503.jar
plugins\org.eclipse.equinox.preferences_3.5.300.v20150408-1437.jar
plugins\org.eclipse.core.contenttype_3.5.0.v20150421-2214.jar
plugins\org.eclipse.equinox.app_1.3.300.v20150423-1356.jar

So, all we need to do is to provide all of the bundles (except for the org.eclipse.osgi dependency which is always available as part of the main JAR file). Therefore, we modify our command line accordingly:

java -Declipse.buildId=abc123 -Dosgi.bundles=org.eclipse.core.runtime_3.11.0.v20150405-1723.jar,org.eclipse.equinox.common_3.7.0.v20150402-1709.jar,org.eclipse.core.jobs_3.7.0.v20150330-2103.jar,org.eclipse.equinox.registry_3.6.0.v20150318-1503.jar,org.eclipse.equinox.preferences_3.5.300.v20150408-1437.jar,org.eclipse.core.contenttype_3.5.0.v20150421-2214.jar,org.eclipse.equinox.app_1.3.300.v20150423-1356.jar -jar plugins\org.eclipse.osgi_3.10.100.v20150529-1857.jar -consoleLog


Eclipse Equinox (Mars) - Step 06
Eclipse Equinox (Mars) - Step 06
So, we ended up where we started. Check the Step 02 screenshot above. :)

Actually that's not entirely true. Since we don't get any more "resolve" errors, we can safely assume that the problem is somewhere else. And it's all written in the console - we need not only to resolve all dependencies, but also to start the org.eclipse.core.runtime OSGi bundle. We will sligthly modify the command line and add @start at the end of the dependency JAR file:

java -Declipse.buildId=abc123 -Dosgi.bundles=org.eclipse.core.runtime_3.11.0.v20150405-1723.jar@start,org.eclipse.equinox.common_3.7.0.v20150402-1709.jar,org.eclipse.core.jobs_3.7.0.v20150330-2103.jar,org.eclipse.equinox.registry_3.6.0.v20150318-1503.jar,org.eclipse.equinox.preferences_3.5.300.v20150408-1437.jar,org.eclipse.core.contenttype_3.5.0.v20150421-2214.jar,org.eclipse.equinox.app_1.3.300.v20150423-1356.jar -jar plugins\org.eclipse.osgi_3.10.100.v20150529-1857.jar -consoleLog

Eclipse Equinox (Mars) - Step 07
Eclipse Equinox (Mars) - Step 07
Now we get totally different error: No application id has been found. This means that there is no OSGi application provided and there is nothing to run. We can suppress this error by providing another property to our command line:

java -Declipse.ignoreApp=true -Declipse.buildId=abc123 -Dosgi.bundles=org.eclipse.core.runtime_3.11.0.v20150405-1723.jar@start,org.eclipse.equinox.common_3.7.0.v20150402-1709.jar,org.eclipse.core.jobs_3.7.0.v20150330-2103.jar,org.eclipse.equinox.registry_3.6.0.v20150318-1503.jar,org.eclipse.equinox.preferences_3.5.300.v20150408-1437.jar,org.eclipse.core.contenttype_3.5.0.v20150421-2214.jar,org.eclipse.equinox.app_1.3.300.v20150423-1356.jar -jar plugins\org.eclipse.osgi_3.10.100.v20150529-1857.jar -consoleLog


Eclipse Equinox (Mars) - Step 08
Eclipse Equinox (Mars) - Step 08
So, we ended up exactly where we started. Check the Step 01 screenshot above. :)

There are no log messages and there are no errors. So, what's the problem? Actually there is no problem. Everything is up and running but we can't see it. In order to proceed we need OSGi console. Yep, that's right - all we did so far was just to run the Equinox OSGi framework and nothing more. Kind of disappointing, isn't it...

OK, let's get the console! The quickstart guide points you to the right direction. We need to add the -console parameter to our command line:

java -Declipse.ignoreApp=true -Declipse.buildId=abc123 -Dosgi.bundles=org.eclipse.core.runtime_3.11.0.v20150405-1723.jar@start,org.eclipse.equinox.common_3.7.0.v20150402-1709.jar,org.eclipse.core.jobs_3.7.0.v20150330-2103.jar,org.eclipse.equinox.registry_3.6.0.v20150318-1503.jar,org.eclipse.equinox.preferences_3.5.300.v20150408-1437.jar,org.eclipse.core.contenttype_3.5.0.v20150421-2214.jar,org.eclipse.equinox.app_1.3.300.v20150423-1356.jar -jar plugins\org.eclipse.osgi_3.10.100.v20150529-1857.jar -console -consoleLog

Eclipse Equinox (Mars) - Step 09
Eclipse Equinox (Mars) - Step 09
Well, we know what this means - the OSGi framework doesn't know about the bundle org.eclipse.equinox.console and therefore we need to add it to our list of bundles in the command line. The corresponding JAR file is this one:

plugins\org.eclipse.equinox.console_1.1.100.v20141023-1406.jar

And we add the JAR file to the command line:

java -Declipse.ignoreApp=true -Declipse.buildId=abc123 -Dosgi.bundles=org.eclipse.core.runtime_3.11.0.v20150405-1723.jar@start,org.eclipse.equinox.common_3.7.0.v20150402-1709.jar,org.eclipse.core.jobs_3.7.0.v20150330-2103.jar,org.eclipse.equinox.registry_3.6.0.v20150318-1503.jar,org.eclipse.equinox.preferences_3.5.300.v20150408-1437.jar,org.eclipse.core.contenttype_3.5.0.v20150421-2214.jar,org.eclipse.equinox.app_1.3.300.v20150423-1356.jar,org.eclipse.equinox.console_1.1.100.v20141023-1406.jar -jar plugins\org.eclipse.osgi_3.10.100.v20150529-1857.jar -console -consoleLog

Eclipse Equinox (Mars) - Step 10
Eclipse Equinox (Mars) - Step 10
It seems that the OSGi bundle org.eclipse.equinox.console depends on a bundle which exports the package org.apache.felix.service.command. This time the dependency is not on a bundle but on a package. So here comes the hard part - we need to find which is the bundle that exports this particular package. There is no easy or straight forward way to find the bundle. Considering that we have the keyword felix, most probably the bundle is one of the org.apache.felix.* JAR files.

By examining the WEB-INF\MANIFEST.MF we find the following in org.apache.felix.gogo.runtime_0.10.0.v201209301036.jar:

Manifest-Version: 1.0
Bundle-DocURL: http://www.apache.org/
Bundle-Localization: plugin
Bundle-SymbolicName: org.apache.felix.gogo.runtime
Eclipse-SourceReferences: scm:cvs:pserver:dev.eclipse.org:/cvsroot/too
 ls:org.eclipse.orbit/org.apache.felix.gogo.runtime;tag=v201209301036
Bundle-Activator: org.apache.felix.gogo.runtime.activator.Activator
Export-Package: org.apache.felix.service.command;status=provisional;ma
 ndatory:=status;version="0.10.0",org.apache.felix.gogo.api;uses:="org
 .apache.felix.service.command";version="0.10.0",org.apache.felix.serv
 ice.threadio;status=provisional;mandatory:=status;version="0.10.0"
Bundle-Version: 0.10.0.v201209301036
Bundle-Description: Apache Felix Gogo Subproject
Bundle-Vendor: %providerName
Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
Bundle-Name: %pluginName
Import-Package: org.apache.felix.gogo.api;version="0.10.0",org.apache.
 felix.service.command;status=provisional;version="0.10.0",org.apache.
 felix.service.threadio;status=provisional;version="0.10.0",org.osgi.f
 ramework,org.osgi.service.event;resolution:=optional,org.osgi.util.tr
 acker
Bundle-ManifestVersion: 2

So, the bundle file that we need to add to the command line is this one:

plugins\org.apache.felix.gogo.runtime_0.10.0.v201209301036.jar

Let's modify the command line and see what will happen:

java -Declipse.ignoreApp=true -Declipse.buildId=abc123 -Dosgi.bundles=org.eclipse.core.runtime_3.11.0.v20150405-1723.jar@start,org.eclipse.equinox.common_3.7.0.v20150402-1709.jar,org.eclipse.core.jobs_3.7.0.v20150330-2103.jar,org.eclipse.equinox.registry_3.6.0.v20150318-1503.jar,org.eclipse.equinox.preferences_3.5.300.v20150408-1437.jar,org.eclipse.core.contenttype_3.5.0.v20150421-2214.jar,org.eclipse.equinox.app_1.3.300.v20150423-1356.jar,org.eclipse.equinox.console_1.1.100.v20141023-1406.jar,org.apache.felix.gogo.runtime_0.10.0.v201209301036.jar -jar plugins\org.eclipse.osgi_3.10.100.v20150529-1857.jar -console -consoleLog


Eclipse Equinox (Mars) - Step 11
Eclipse Equinox (Mars) - Step 11
We already know the drill - we need to find the corresponding JAR file for the bundle org.apache.felix.gogo.shell and add it to the command line. Here is the file:

plugins\org.apache.felix.gogo.shell_0.10.0.v201212101605.jar

And here is the modified command line:

java -Declipse.ignoreApp=true -Declipse.buildId=abc123 -Dosgi.bundles=org.eclipse.core.runtime_3.11.0.v20150405-1723.jar@start,org.eclipse.equinox.common_3.7.0.v20150402-1709.jar,org.eclipse.core.jobs_3.7.0.v20150330-2103.jar,org.eclipse.equinox.registry_3.6.0.v20150318-1503.jar,org.eclipse.equinox.preferences_3.5.300.v20150408-1437.jar,org.eclipse.core.contenttype_3.5.0.v20150421-2214.jar,org.eclipse.equinox.app_1.3.300.v20150423-1356.jar,org.eclipse.equinox.console_1.1.100.v20141023-1406.jar,org.apache.felix.gogo.runtime_0.10.0.v201209301036.jar,org.apache.felix.gogo.shell_0.10.0.v201212101605.jar -jar plugins\org.eclipse.osgi_3.10.100.v20150529-1857.jar -console -consoleLog


Eclipse Equinox (Mars) - Step 12
Eclipse Equinox (Mars) - Step 12
Congratulations - you made it to the OSGi console! But... could it be so "easy"? Is there anything else? Let's see what we can do with this console!

Most commonly used help command is help, so let's try and see what will happen:

Eclipse Equinox (Mars) - Step 13
Eclipse Equinox (Mars) - Step 13
Hm... the help command prints something but it's definitely not useful. And in the very end we get another error for another missing bundle. In order to get full list of available commands we need to install, resolve and start the org.apache.felix.gogo.command bundle.

Let's do it in different way this time. We already have access to the OSGi console which means that we can administer OSGi bundles. First of all, let's examine the already existing bundles and see what we've got. The command is ss.

Eclipse Equinox (Mars) - Step 14
Eclipse Equinox (Mars) - Step 14
We see that all the bundles we added to our command line are active, which means that they are properly installed, all dependencies are resolved and currently all these bundles are in running state. The bundle org.apache.felix.gogo.command is not in the list, which means that this bundle is not installed and Equinox OSGi currently knows nothing about it. The JAR file for this OSGi bundle is:

plugins\org.apache.felix.gogo.command_0.10.0.v201209301215.jar

We can install OSGi compliant bundles from the OSGi console by using the install command:

install file:plugins/org.apache.felix.gogo.command_0.10.0.v201209301215.jar

Eclipse Equinox (Mars) - Step 15
Eclipse Equinox (Mars) - Step 15
The output is quite descriptive but the most important part to notice is the automatically assigned ID which in our case is 12. If we execute the ss command again, we will see the new bundle:

Eclipse Equinox (Mars) - Step 16
Eclipse Equinox (Mars) - Step 16
However, if we try to execute the help command again, we will end up with the same result as before. That's because our last bundle is installed but its dependencies are not resolved and finally we have to start it.

Let's resolve the dependencies for the last bundle. One way to do this is to use the refresh command. As parameter we will provide the ID for our bundle, so the final command is refresh 12.

Eclipse Equinox (Mars) - Step 17
Eclipse Equinox (Mars) - Step 17
As we can see now, the bundle is in resolved state which means that there are no dependencies and we can start it. The command is start and we will provide the bundle ID as parameter, so the final command is start 12.

Eclipse Equinox (Mars) - Step 18
Eclipse Equinox (Mars) - Step 18
Now the bundle is running. And the good news is that Equinox OSGi keeps track of all bundles, so you don't need to install/refresh/start this particular bundle manually. And if you execute the help command again, this time you will get enormously large list of available commands. The list is really large, so I'm not going to provide screenshot.

Of course, we can always add the bundle to our command line, just like we did with all other bundles before. It's a nice exercise, so I recommend you to try it. But don't forget to stop or uninstall the bundle first or otherwise you'll be cheating! :)

Here are few more Equinox OSGi commands to explore:

ss - shows information about installed bundles (stands for short status)

diag <id>- useful if the dependencies for bundle with ID provided as parameter can't be resolved for some reason.
Example: diag 12

help <command> - Displays more information about particular command.
Example: help diag

shutdown - nice way to end the OSGi session.

That's it! I have to admit that the Eclipse Equinox was much harder to make it run, compared to Apache Felix. The good news is that it's a one time effort. And you can always automate the process by using script files. You definitely don't want to write such complex and long command lines by hand!

In my next article I'll show you how to develop a very simple OSGi application and run it both in Apache Felix and Eclipse Equinox OSGi environments.

1 comment: