Monthly Archive for: ‘February, 2009’
Since I got nice feedback from the community, I have published the source code of my ideas for a Java 6 annotation processor for OSGi Declarative Services. I have also set up a Wiki page that explains how to browse the code and run the demo and tests.
Any feedback would be highly appreciated.
Recently I took a deeper look at OSGi Declarative Services (DS), Spring Dynamic Modules, iPOJO and Peaberry. I have to admit that I like DS a lot (and even more in the upcoming OSGi 4.2 spec). But one thing I particularly liked about iPOJO was the possibility to either use XML or Java annotations. So, just for fun, I wrote a little Java 6 annotation processor for DS. The benefits I see are:
- Easier to use: Most Java programmers are familiar using annotations but probably don’t want to deal with XML
- Better refactoring support: The annotation processor takes care of it, like the renaming of bind/unbind methods
- Annotations know about the attributes of a class/method etc. and can make assumptions about the intention of the developer
I would like to give you an example. Let’s consider a simple use case: We have a Java POJO (TestComponent) that wants to be a DS Service component, provides two service interfaces (ITestService, ITestService2) and depends on another service (ITestReference). The corresponding Java class looks like this:
The corresponding XML for DS looks like this:
If you use Eclipse 3.5M5 you could easily edit this file using the new Service Component Editor, but with annotations you could create it automatically from a Java source. In my prototype I have created annotations for components and bindings. The annotated source code looks like this:
Using this file as input, my annotation processor generates exactly the above XML file. Let’s explain the above code a bit. The annotation processor knows about the class and the interfaces the class implements. From the fully qualified class name, both the component name and the implementation class are derived. Another convenience is: if no services interfaces are stated explicitly, the processor assumes that all implemented interfaces are supposed to be services this component wants to provide. I took this idea from iPOJO since I like it a lot and I guess this is a very common scenario. The bind annotation interprets the method’s parameter to be a service reference. In my prototype I just put the cardinality “1..1” and the policy “dynamic” as default values for the corresponding attributes of the annotation.
To use my annotation processor in Eclipse, I just had to extend the extension point org.eclipse.jdt.apt.core.annotationProcessorFactory and deploy my plug-in to the dropins folder of my current Eclipse IDE. If I want to use these annotations in a Java 6 project, I just have to enable the Java Compiler/Annotation Processing properties of that project and add my processor. Now, after every save of any Java file in that project, the annotations are processed and the XML files for DS are generated.
Before I continue the put more effort in this I would appreciate feedback from the community. So, please let me know if you would find this useful (and let me also know if you find this completely stupid :))
If someone would be interested in seeing the sources for the annotation processor, I could publish them shortly after a bit cleanup.
Java WebStart is a nice and easy way of deploying Java applications with one click from the web. In this blog I describe how to webstart an OSGi (Equinox) based application using Eclipse as IDE. First you develop your OSGi bundles as usual, to run your application, just create an OSGi framework launcher and run it. To webstart this set of bundles, you need to take care about a few things:
- All bundles have to be deployed as signed JAR files
- You need a feature that contains all the necessary bundles
- When exporting the feature, make sure that PDE creates a JNLP (Java Network Lauching Protocol) file (a checkbox in the export wizard) for this feature
- Provide a root JNLP file for you application
- Deploy your application to a web server and make sure that the web server is aware of the application/x-java-jnlp-file mime type
To sign the JAR files, you just need to create a keystore and a key. Sun’s tutorial gives a good overview about that. So, first create a feature and put all your bundles and the OSGi runtime bundles needed by your application in the feature. When exporting the feature, make sure that you sign all JARs and that a JNLP file is created (The wizards provides 2 tabs for that). For testing you can specify a file URL as Site URL for Java WebStart. Make sure that your site URL for testing is the file location where you deploy your feature. Here is an example for a file based Site URL: “file:/c:/temp/pm-feature-export”. Now, we need a root JNLP file and make sure it is deployed together with our feature. To do that, create a directory within your feature named “rootfiles”. In this directory, create a file yourapp.jnlp. To make sure that your JNLP file is deployed properly, edit the build.properties of your project and include “root=rootfiles” as first entry. Now you can edit the JNLP file. Here is the file I use for my dynamic OSGI demo:
<!-- URL to the site containing the jnlp application. It should match the value used on export. Href, the name of this file --> <!-- user readable name of the application --> <title>Person Manager (A dynamic Swing OSGi demo)</title> <!-- vendor name --> Kai Tödter <!-- vendor homepage --> <!-- product description --> Person Manager is a demo application to demonstrate best practices when it comes to dynamic OSGi based applications <!--request all permissions from the application. This does not change--> <!-- The name of the main class to execute. This does not change--> -nosplash <!-- Reference to the launcher jar. The version segment must be updated to the version being used--> <!-- Reference to all the plugins and features constituting the application --> <!-- Here we are referring to the wrapper feature since it transitively refers to all the other plug-ins necessary --> <!-- Information usually specified in the config.ini --> <!-- Indicate on a platform basis which JRE to use -->
While I don’t explain all the details, I focus on the Equinox specific things: In the resources section, you need to specify the main JAR file, which is your preferred Equinox launcher. The you have to link to the JNLP file for your feature. This JNLP file was created by PDE for you. Then you want to specify a few Equinox-specific properties:
- osgi.configuration.area: the configuration area where OSGi stores runtime information
- osgi.bundles: The list of bundles you want to start. You don’t have to specify versions here, just use the schema: @start. You can also specify the start level of the bundles like @2:start
- osgi.noShutdown: Must be true, since you did not specify an Eclipse application
- eclipse.ignoreApp: Must be true for the same reason
- org.osgi.framework.bootdelegation: Value “*” helps to load JRE classes, e.g. if you use a Swing GUI
Having created a similar JNLP file for your application, you can deploy it locally and test it usinf file based Java WebStart. If everything is OK, change the WebStart Site URL (in both, your root JNLP file and the feature export wizard) to the web server real URL.