Category Archives: osgi

So I am also back to hacking to…

So I am also back to hacking to get a REST service up, with some more excuses. Anyway, once again tried Restlet as I like its minimal set of jar files and simple interface. But even if it sometimes (from my googling) seems to be advertised as well documented, it actually seems rather poorly documented. Going to the Jersey user guide and reading that really helps me understand how Jersey works. There seems to be nothing similar in Restlet, it is more spread around with few lines about all the different platforms and extensions with just little info but not quite enough on anything. JBoss RestEasy on the other hand is a huge bunch of jar files for every little task one in itself. So Jersey it is then, which seems to be nicely documented but only a “reasonable set of jars”…

So how do I get Jersey to run inside OSGI?

Just using it in the standard way expressed in the Jersey docs, results in the exception

com.sun.jersey.api.container.ContainerException: The ResourceConfig instance does not contain any root resource classes.

I guess this is due to the standard OSGI classloader issues, as also noted for example in

http://coderthoughts.blogspot.com/2008/03/using-jersey-jsr311-inside-osgi-with.html

But how do I fix it? Writing my own ResourceConfig class seems like a huge task for something this simple, and something that could easily break in future Jersey versions. So this is the code I used to get the exception

Dictionary<String, String> config = new Hashtable<String, String>();
config.put("com.sun.jersey.config.property.packages", "my.package.rest");
httpService.registerServlet("/rest", new ServletContainer(), config, null);

 

So now my Resource classes are in package “my.package.rest”. But it all fails, doesn’t it.

Luckily the Jersey user guide has a nice example of using Jersey inside OSGI. The trick seems to be to not use the “packages” property but rather to change the above to

Dictionary<String, String> config = new Hashtable<String, String>();
config.put("javax.ws.rs.Application", JerseyApplication.class.getName());
httpService.registerServlet("/rest", new ServletContainer(), config, null);

 

So the difference is using the Application class to explicitly list the Resource classes. I guess this results in using the correct classloader, probably the one that loads the Application as well. Well, at least it works ūüôā

 

edit: the info for using Jersey with a servlet container is perhaps best given in the JavaDoc for package com.sun.jersey.spi.container.servlet, for example, at the time of this writing available at (browse your Jersey javadoc package if not):
http://jersey.java.net/nonav/apidocs/1.5/jersey/com/sun/jersey/spi/container/servlet/package-summary.html
for OSGI the jersey user guide OSGI example code (download from the link in user guide) is the best ..

wicket on OSGI + customized webapp url

I posted earlier about getting wicket to run on OSGI using the ServletFilter features of the Apache Felix ExtHttpService. Well, that one was done using the default “/*” filter pattern, that is capturing all requests. While Wicket will nicely pass through anything it does not want to handle, I wanted to put my web based UI under something like “/ui/”, meaning I wanted to capture a pattern like “/ui/*”. So, in order to do this, I set it up as

service.registerFilter(new WebUIWicketFilter(), "/ui/*", props, 0, null);

But this did not really work so nicely. While my filter was invoked (as evidenced by some printouts I put in), Wicket never did anything. After googling around and trying to read the WicketFilter source code, I figure that wicket does some form of url matching to figure out if the request is something that Wicket should process. And “/ui/” did not qualify for some reason. So I got it to work with the following addition

Hashtable<String, String> props = new Hashtable<String, String>();
props.put("applicationClassName", WebUIWicketApplication.class.getName());
props.put("filterMappingUrlPattern", "/ui/*");
try {
service.registerFilter(new WebUIWicketFilter(), "/ui/*", props, 0, null);
} catch (ServletException e) {

 

And here it is the line

props.put("filterMappingUrlPattern", "/ui/*");

that makes the difference. It seems that this is what causes Wicket to realize that the filter pattern given for Felix is intended to be a match for Wicket. Why is this? Don’t really know but I guess this is some form of standard parameter of the Java Servlet spec that is usually taken from the web.xml or something like that. Since I have no web.xml I need to populate it all myself. Well, that’s what I tell myself so I can move on to the next thing.. As long as it works (today), right?

 

debugging wicket with multiple osgi modules

previously my osgi app was all running from inside one single large bundle. so i decided to split the different components to their own bundles for various reasons. one of these provides a web-browser based user interface.

so as for every other component i just took this and put it in its own as well. strangely wicket started to report errors like “the page you have requested has expired”. and this only happened on a single page, which was actually a navigation page with just links to other pages. so WTF was wrong? took me plenty of time to figure this out. the navigation page is created with wicket by creating links using wickets objects in the page object. so one of these was referring to a page that had an instance variable that was of a type of a class that was located in another bundle now. so the “the page you have requested has expired” was actually an error of type classnotfoundexception but wicket was just showing this as a page expiration for some strange reason. i had to delete line by line the whole page code to find out which line it was breaking over.

before this i thought it might be the cache, which resulted in having to hack the wicket filter to print out the temp directories where it might put them. which of course returned null (the getattribute thing from servletcontext). so after bunch of googling and finding the wicket filecreatetorfactory or something like this in the wicket api docs, i found out i had to get the standard java temp directory property and check there. sure, there were some files in the C:/Documents/blaablaa directory. deleteing them had no effect.

well, after i found the line that broke it i soon figured i had to import the class for the web ui bundle. after this i kept having similar errors for other pages. this time i was thinking i was smarted and went looking for a debug log for wicket. which, by the way is horribly documented (not at all?). well, plenty of googleing around found that it uses slf4j and kind of reminded me of the problems i had starting with wicket to required the slf4j to be present. finally, configuring the logback to print stuff also for org.apache.wicket at debug level i started getting a log file where all the classnotfoundexceptions were present in stead of the page refresh poopoo. which btw, is hard to note from the console because of all the spam that is printed, rolling the exception away from the screen buffer. well, i configured wicket to produce its own log file in the end. maybe now i will do better in the future with this..

 

Setting up Felix HttpService

Well, every once in a year it is good to try to code something and not just write BS docs. Well as usual this time I am monkeying with getting a webapp running inside the Felix OSGI container. So what is the problem?

Well, First off, the documentation just says to download the Felix HttpService and use it. Then all documentation tells me to use it but there is no documentation on how to actually deploy it. So I download the “Felix http bundle” from the Felix website. Well, at least I download the “.tar.gz” file thinking it should include some docs and the service implementation. Nope, a single source file and ¬†a license text file. Eh? Well then after downloading plenty of other “http” files from the Felix website I finally decide to try to “jar” file separately. And yes, it contains a plenty of class files.

So after finally finding the correct file (the Felix Http Bundle JAR file), I set about trying to install it. So I add it to my bundle classpath and try to use it. Put in the bundle classpath and all that. Of course, it is an epix failure. So I start to browse the contents of the jar file to see what it is about. Well, after plenty of searching and initial misses, I finally find it has a manifest.fm. So I try to deploy it as a bundle in Felix. Oof, it loads. Maybe now it works?

Nope, lots of classpath exceptions. First off, I add the javax.servlet and javax.servlet.http to imports for my own bundle. Similarly for the osgi http service package. So maybe now my code runs and finds the Felix OSGI HttpService? Nope. Well, of course the basic failure is that you need to start the HTTP bundle before your own bundle to see it. But even after that, all it finds is a service registered under the name of HttpServlet, not HttpService. Eh?

Well.. Turns out (by browsing the .tar.gz java source code for the activator and finally some docs after that) that you need to configure Felix to start the embedded Jetty container as by default all containers it includes are disabled. Thanks for (not) documenting that. So add “org.apache.felix.http.jettyEnabled=true” into Felix config.properties. Ah yes, it tries to do something. Since it gives a failure to find the ManagementService class file. Well, from previous browsing of the Felix HTTP service activator I know it tries to load something like that. And in the manifest.mf for the HTTP service this is set to “optional” in resolving. So what gives, it should load right? It seems to be something belonging to OSGI itself right? Guess NOT.

So what next? I recall from all my googleing for these failures that someone was complaining about hard dependencies to a ConfigAdmin service somewhere. And yes, the docs mention you can use that. So I try to deploy the ConfigAdmin bundle. Oh yes, it works now. Thanks for (NOT) documenting that.

Well, finally the servlet runs. Now just to wonder what is the next failure..

OSGI classloaders, integration testing and all that

So I managed to get my services to communicate and all. After this I wanted to set up some basic (regression) tests that make sure they keep working together as before. Using the familiar JUnit4 I set on this adventure. It is a unit testing tool but works just fine for me with integration testing like this. As usual it all turned out to be much more difficult than I was expecting. First I need to start the services in an OSGI container. After some wondering around I finally found the way to do it is:

String bundleDir = “bundles”;

Map<String, String> config = new HashMap<String, String>();
config.put("felix.log.level", "1");
config.put("felix.auto.deploy.action", "install,update,start");
config.put(AutoProcessor.AUTO_DEPLOY_DIR_PROPERY, bundleDir);
ServiceLoader<FrameworkFactory> loader = ServiceLoader.load(FrameworkFactory.class);
FrameworkFactory factory = loader.iterator().next();
Framework fw = factory.newFramework(config);
fw.init();
BundleContext bc = fw.getBundleContext();
AutoProcessor.process(config, bc);
fw.start();
    ServiceLoader<FrameworkFactory> loader = ServiceLoader.load(FrameworkFactory.class);
    FrameworkFactory factory = loader.iterator().next();
    Framework fw = factory.newFramework(config);
    fw.init();
    BundleContext bc = fw.getBundleContext();
    AutoProcessor.process(config, bc);
    fw.start();

What does it all mean? It expects that in the working directory (set in the IDE run-dialog) a directory named “bundles” is located. In this directory my ant script deploys my own bundles and copies the Felix framework bundles I use. Then it enables the autodeploy feature of Felix to always load these bundles at startup (and update them). Finally it starts the container, loading my updated stuff in it.

With the container started and my bundles deployed I then wanted to invoke some services and check the end results. First of all it seems a bit hard to test much unless you have access to some state information from the components (services that is). So I had to add some new methods to the interfaces to support what I wanted to test. Then when I get the services from outside the container (using the framework object I just created) it fails.. With all sorts of strange exceptions. Luckily I was able to make some educated guesses that this must be some problems with the OSGI classloader vs the classloader used by the JRE to run my JUnit tests.

SO I looked at all sorts of stuff to see how to fix this. Pex testing tools are intended for something like this but start a maven instance to download a container, use RMI for calls and all sorts of strange things. All I wanted was to call a service running in the same VM. How hard can it be? So I try with simple reflection to call the method on the OSGI service class. Of course it keeps failing still.. So I figure I have to put the stuff in the container so it is loaded with the same classloader as the service bundle. Made it into a test service bundle just for testing. It now looks like this:

The part in the JUnit test that makes the call to the test bundle:

BundleContext bc = fw.getBundleContext();
ServiceReference reference = bc.getServiceReference(OSGITester.class.getName());
    final Object originalTester = bc.getService(reference);
    InvocationHandler handler = new InvocationHandler() {
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Method testMethod = originalTester.getClass().getMethod(method.getName(), method.getParameterTypes());
        testMethod.invoke(originalTester, args);
        return null;
      }
    };
    OSGITester tester = (OSGITester) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] {OSGITester.class}, handler);
    tester.init();
   tester.testMethod();

and the part in the test bundle that is called..

    ServiceReference reference = bc.getServiceReference(ServiceToBeTested.class.getName());

    ServiceToBeTested std = (ServiceToBeTested) std.getService(reference);

   AssertSomethingWithJunit()....

So the same problem seems to be here as in my previous post about Felix failing and Equinox working. I included the same class files in both bundles cause I thought it would be easy and nice and all that. I think this is what I did when Equinox worked and Felix did not. So must be some difference in Equinox reusing a classloader or something and Felix having different ones for different bundles. In any case it was still failing and I was starting to get pissed with it all.

In the end I got it working with this solution by making the BundleToBeTested export all packages that had something I wanted to test and the TesterBundle import them as well. Removing the duplicate class files from the bundle jar files was needed also. After this they seem to be using the same classloader (and whatever else is needed for the Felix magic) and now it all works.  Woohoo, I can make the tests as normal Java classes without any strange maven/RMI stuff and see all the reporting in my IDE as usual.

Now for something completely different..

bundles, services, …

So I have progressed some more with my wonderings about the wonders of OSGI and implementing some basic stuff.

First off, I had a number of services I wanted to implement. I started with a number of bundles each implementing a service of its own. Making these work together was problematic in Felix due to problems with getting them to access each others functionality. I was getting really strange errors when using the services from another bundle. On the other hand, all the bundles and services worked just fine when deployed in Equinox. Putting all my services in one bundle made it work again in Felix and so I decided to do that. It actually makes sense as these services are closely related and use each other. So I guess this is actually in line with the concept of a bundle. A bundle makes for an abstraction to “bundle” together a number of services. This is similar to component vs service, where I see a component as hosting the implementation of one of more services. In any case, I guess hosting all the related services in one bundle really makes sense as this way they can all access the classes etc. of each other and are using the same classloader.

registering bundles and listening to new services

So, some very basic stuff.. What is a bundle in OSGI? I was thinking about it as the service that is provided. But having now implemented one and tried to access it through the container it seems that this is another component vs service issue. So I think the bundle is a “component” in that it is a package (i.e. a “bundle”) of classes, code, etc. And it can provide 0-N services (zero or more). So is there some meaning to just providing a bundle without any content? I wouldn’t know so far.. But each bundle must then provide services for others explicitly, this is not done just by installing the bundle, unless the bundle code for activation does the service registration. This happens with BundleContext.registerService() method.

After this it is possible to listen to and react to service events by registering a service listener with BundleContext.addServiceListener(). This is where the initial failure was as I thought this would now give the bundles loaded but oh noes not so.. Also explains why Felix seems to load 3 bundles of its own (at least thats the default at this time, could change later ofc) but a listener reports 10+ services.

And for more spam in one post, when listening to the services with a ServiceListener, the event types are from ServiceEvent.REGISTER_EVENT etc. And to identify which service object it is that was registered the ServiceEvent.getServiceReference() object needs to be queried for a property called Constants.OBJECTCLASS to get the type. I guess this is documented in the spec so maybe I should read that.. lol

start of some OSGI adventures

and todays toy to waste my life playing with is the OSGI SOA based stuff. So in order to develop some server components, I have decided to use OSGI as it seems to fit nicely what I want to do.

First of all, I now try to find a nice container to best fit my needs. In the past (some years ago) I did some OSGI development and ended up using Equinox as the container. As far as I recall, this was due to some lacking features from other containers etc. So once again I started playing with Equinox as still seems to be most updated and being the core of Eclipse seems to be likely to be highly updated in the future as well.

But, as usual, the documentation for Equinox seems to suck big time. What I want is to have some automated deployment of my ant-packaged jar files to the container as I start it or whatever. I do not wish to type cryptic file URL’s etc. all the time. I could not find easy way to do this in Equinox. On Windows, it seems to lose all the bundles I install between reboots. So trying with update commands etc. does not seem to work. And all the strange directories it creates are also evil.. Maybe some of this is just my prejudice but it seems to suck. Not for the implementation, I think that is just great. Except for the fact that it is tied to Eclipse and starting the standalone jar with specified config dir seems to be impossible in Linux for a dumbass like me, because it looks for some cryptic Eclipse config directories. But I like to know what I am working with and how to use it. I was also interested in the optional services OSGI specifies and how to use them. Googling for some of them takes me to the Apache Felix site. So I decided to take a look at that then..

And now I decided to use Felix as my OSGI container for development at least. It is very nicely documented and focused on just providing a specific OSGI container. Even the optional services are nicely documented with clear code examples. Downloads seems a bit confusing but I’ll survive.

To make for automated loading and updating of all my bundles, I made a “bundles” directory where my ant-script tosses all the created jar files and copies all the bundles from the Felix install dir (OSGI console UI, etc.) to this same directory. Then passing this directory to the Felix install as the bundle dir causes it to find all my bundles. Changing the conf/config.ini dir to “load,update,start” all bundles causes it to automatically install all of them as I start the container. Some more configuration will be handy, I am sure but this will come later…