wwerner's blog

tutorials, tips and trivia on eclipse, osgi, web & xml technologies

OSGi Console in Helios, Monkey See/Monkey Do and a strange loop

with 4 comments

Helios comes with an OSGi console that is accessible from the GUI directly. This reminded me of the existence of an API to add custom commands to the console. I found this to be a simple and powerful concept; yet I perceive this feature to be rarely used in practice.
With equinox being used on the server more and more, adding your own custom application management commands is a simple way to provide for executing application specific maintenance tasks. How about a command that gathers all logs, creates a heap dump, zips everything, puts it onto an FTP server and sends you the download link by mail? Or perhaps you simply want to run some sanity checks?

In this post, we’ll create a custom command for the OSGi console that simply executes a JUnit test and prints the results.

More importantly, we’ll have to snoop around in internal eclipse packages to figure out how to attach the command to the existing console. We’ll try to do our snooping effectively. And we’ll exploit the dynamic nature of OSGi to streamline our development/build/test cycle (and thats gonna be fun).


Preparation

First, you need to grab the Helios Classic Editon build1 as this version includes the sources as well. We’ll use the OSGi console for the currently running eclipse instance that is available via the UI since 3.6M72

Now start eclipse, create a new workspace and go to the workbench.

Open the console view (Alt-Shift-Q,Q) and select “OSGi console” from the view menu.  You now have an OSGi console that allows you to interact with the running eclipse3.

Type “help” to get a list of available commands. You should do that even if you are a eclipse veteran, the list of available commands has grown considerably during the last years. There are commands to start/stop/install/refresh bundles, to view registered services, to configure runtime properties, to query the extension registry, to start and stop equinox applications and enable and disable components.

Let’s assume we want to be able to run integrity tests on a live system to check whether incoming issue reports could be due to some irregularities with system load, data or deployment issues. Lets also assume that application has a set of JUnit tests to do so. We want to be able to log onto the console and see what the results of our test suite are.

Test First

No, not that test first. To add a command to run our tests we need tests first, see? We simply create a new OSGi bundle targeting the equinox runtime using the “New project” wizard and add some tests to it. Make sure to have at least on failing test as we’ll print only failures from our command.

We also need some piece of code to let us run our tests. Luckily, JUnit provides a simple API for that4.


Monkey See, …

The basic steps are to implement the org.eclipse.osgi.framework.console.CommandProvider interface and to register it with the OSGi service registry. But this is covered in at least two tutorials by Chris Aniszczyk5 and his evil, quake playing twin6. You should definitely read them. Less chitchat than this post.

Instead of repeating this7, I’d rather show you how to figure it out for yourself. Reading code is an excellent way to learn8.

First, we need an entry point, a piece of code we know that has something to do with the console. So what do we know? Well, there is a console view, let’s go hunting for it’s implementation. To make sure that our searches include the code from the platform plug-ins, we will add them to the Java search.  Helios has a handy new button in the Plug-Ins view for that. 9

0-add-to-java-search

Fire up the search dialog 10, select the Plug-in Search tab, enter “org.eclipse.ui.views” as search string and select “Search for-> Extension Point”, “Limit to -> References” and “External Scope -> All”.

1-search-view

This search gives us 28 matches. One match is the one we are looking for: org.eclipse.ui.console.

2-search-view-result

Let’s open the declaration and switch over to the extensions tab. We can see the contribution the console view we were looking for, but also something that looks even more promising: An extension point called “org.eclipse.ui.console.consoleFactories”. Let’s see who contributes to this extension point. Choose “Find References” from its context menu.

3-search-console-factory-references
4-search-console-factory-references-result

Only four matches. I think we can rule out the one in team.cvs and debug.ui.  We’ll find what we are looking for in the org.eclipse.pde.ui bundle11.

5-found-osgi-console-contribution

The contribution contains the implementation class, so we open this class next. Copy the qualified name of the class, press Ctrl-Shift-T and paste the class name.

6-open-type

In the console factory, we find that a new console is instantiated in the getConsole() method. Let’s open the implementation by Ctrl-Click on the class name.

11-open-OSGiConsole

A first glance at this class does not immediately reveal where the console commands come from. We need to dig a little deeper aka start guessing and poking around wildly. To be able to run a command, the console input needs to be evaluated, thats for sure. So lets see if we can find where the input is read. In the OSGi console constructure, a new anonymous ConsoleSession is created. The ConsoleSession has a method called getInput() that returns an input stream. Let’s see who calls this method: place the cursor on the method name and press Ctrl-Alt-H to open the call hierarchy.

12-call-hierarchy

The first&direct caller, FrameworkConsole, seems not overly interesting in terms of command definitions. Let’s see what the next one, ConsoleManger looks like. A little hidden, somewhere in the middle we find a field of the type FrameworkCommandProvider. Now we’re pretty close to what we want to know. This is the place were – at least some – console commands are defined. The constructor’s comment pretty much tells us what to do:

So we need to implement a CommandProvider and register it with the service registry. For each command we want to implement, we need to have a method called “_<command name>”. We’ll implement only one command that calls our test runner. Additionally, I think we should implement the the getHelp() method to describe our command to the user.

It may be useful for your analysis to make changes to eclipse plug-ins to see how they behave. There is a simple recipe how you can do this without the risk of doing much harm: Import the respective plug-in from the target platform to the workspace, then create a launch configuration containing the workspace instead of the target platform bundle. You can now edit the standard eclipse bundle to gain a deeper understanding. When you are done, simply delete the bundle from the workspace (and from the disk as well).

17-import-project-from-target

… Monkey Do

Use the bundle project we have created in the first chapter. Add a new dependency to “org.eclipse.osgi.framework.console”, the package containing the CommandProvider interface.
13-additional-dependency

Create a new class using the new class wizard, have it implement CommandProvider and generate the inherited methods.

14-new-class-wizard

Implement the getHelp() method so the output looks similar to the other commands. Have a look at the FrameworkCommandProvider for reference. Note that you can use Alt-Left/Alt-Right to navigate in the edit/browse location history. Useful as you can easily switch back and forth between your class and the reference class without using your mouse.

We call our command “check”, so we also need to implement “check(CommandInterpreter intp)”. The command interpreter is used to output the results from our tests. Take a look at the “*” methods in FrameworkCommandProvider for examples.

The complete class looks like this12:

Now we need to register/de-register our command provider in the Activators start() resp. stop methods:

Having implemented all this, it’s time to look at our options for giving it a test drive

Strange Loops

We can either
  • start our bundle as eclipse application, open the console view and test our command
  • create a minimal run configuration and start the framework with the console and test there
  • build the bundle and install it into the running framework (the running eclipse instance)
  • or even install the bundle directly from it’s files in the workspace
While option two is probably the most reasonable approach (for separation of concerns and debugging issues), option four is certainly the most fun13. Since I wrote about run configs in an earlier post14 guess what we’ll do now. The only thing we need to do to make our bundle installable directly is to add the bin/ folder of our project to the runtime classpath.
15-runtime-classpath

Then we can use the console to install the bundle from the workspace. First, check that our command is not yet available by calling our  ”check” command. Our command is not found, so the help contents are displayed. Note that our command’s help text is missing as well. Then we can install the bundle if we know the project’s path on the harddrive.

16-project-location

-

We have now  installed a bundle that we are currently developing into our running eclipse instance. Isn’t that awesome? Of course you need to be careful with this approach as you can pretty much screw things up when fiddling with the hot bundle configuration of your IDE, but I think this approach actually makes sense when you are integrating with the IDE rather than building a standalone application.

Besides, I just love self-referential stuff.
What I mean by “strange loop” is — here goes a first stab, anyway — not a physical circuit but an abstract loop in which, in the series of stages that constitute the cycling-around, there is a shift from one level of abstraction (or structure) to another, which feels like an upwards movement in a hierarchy, and yet somehow the successive “upward” shifts turn out to give rise to a closed cycle. That is, despite one’s sense of departing ever further from one’s origin, one winds up, to one’s shock, exactly where one had started out. In short, a strange loop is a paradoxical level-crossing feedback loop. – Douglas R. Hofstadter
See also http://www.xkcd.com/555/, don’t forget to read the tooltip.

Conclusion

Besides highlighting the Host OSGi console included in Helios and trying to revive the memory of custom OSGi console commands, this article showed you how you can find out how stuff is done in eclipse by following the monkey see/monkey do rule and gave some tips how to apply this rule in practice.

I’d be happy to see more custom OSGi console commands in the wild. As I said in the teaser, I still think this concept is underused. Also remember that the OSGi console can be configured to be accessible remotely using telnet. Now don’t tell me you can’t think of use cases for that.

I’ll push the complete sources of the example to github during the next days. In the meantime: Let me know if you get stuck.

I hope you enjoyed reading and that I gave you one or the other idea that may help you in future projects. Thanks for reading.

  1. http://www.eclipse.org/downloads/packages/eclipse-classic-360/heliosr
  2. http://download.eclipse.org/eclipse/downloads/drops/S-3.6M7-201004291549/eclipse-news-M7.html#osgiconsole
  3. The screenshots were taken on 3.6M7, it looks a little different in the final release. The draft of this post has seen some idle cycles…
  4. http://www.junit.org/junit/javadoc/4.3/org/junit/runner/JUnitCore.html
  5. http://www.ibm.com/developerworks/library/os-ecl-osgiconsole/index.html
  6.  http://eclipsesource.com/blogs/2008/08/01/tip-custom-osgi-equinox-console-commands/
  7. Good Artists Copy, Great Artists Steal – Pablo Picasso, probably. Also look for T.S. Eliot quotes in that context. Steve Jobs stole it, too. In the late eighties, if you judge by his hair.
  8. Valiantly deciphering XML (plugin/application context/deployment descriptors) to learn how dependencies are wired at runtime, too. Provided the tooling is good. Otherwise it can be quite frustrating. Luckily the PDE tooling for navigating plugin.xml & manifest files is excellent. The search also feels a lot faster on Helios.
  9. You can do the same in pre-helios builds: In the Plug-ins view, select all plug-ins and choose ‘add to Java search’ from the context menu
  10. Ctrl-H
  11. This is not pre-recorded. I’m making it up as we go along. Perhaps I left out some dead ends, though. See if you can spot them in the screen shots.
  12. Yep, we simplified the getHelp() method. Using constants is good style,  but only if you use them more than once. KISS, for this example.
  13. In a weird, nerdy way, at least.
  14. http://blog.wolfgang-werner.net/building-on-equinox-and-restlet-1/#Running

Written by Wolfgang Werner

June 29th, 2010 at 11:52 pm

4 Responses to 'OSGi Console in Helios, Monkey See/Monkey Do and a strange loop'

Subscribe to comments with RSS or TrackBack to 'OSGi Console in Helios, Monkey See/Monkey Do and a strange loop'.

  1. Cool stuff Wolfgang!

    I think just exporting the bundle via the plug-in export wizard and installing into host would have work fine (if you apply changes). Nonetheless, the way you did it was pretty cool too ;)

    Chris Aniszczyk

    30 Jun 10 at 01:21

  2. Hi Wolfgang!

    Nice tutorial. We use Equinox console custom commands a lot in our current project. I’ve done some small experiment to replace standard Equinox console with Felix GoGo. Hope that you find some useful information there: http://www.osgilab.org/2010/06/how-to-replace-standard-equinox-shell.html

    Best regards,
    Dmytro

    Dmytro Pishchukhin

    30 Jun 10 at 07:04

  3. Hi Chris,

    thanks :-)
    Exporting the bundle and installing it afterwards would work equally fine, but involves an additional step. And I’m just lazy.

    As friend of mine – an engineer – told me with a blank stare when I asked him why he wanted to take apart some of my gadget stuff and reassemble it: “Because it is possible!”

    Wolfgang Werner

    30 Jun 10 at 08:55

  4. [...] A piece on the Equinox OSGi Console, basically the same as in an earlier post here. Published in eclipse Magazin 2.11. HTML, [...]

Leave a Reply

I'll never publish your email address ever. However, entering a valid address is required to ensure that you're not posting spam onto my pages (because that sucks). The address is also used to display your Gravatar picture next to your comments (if you have one).