Ouertani Slim was born in Tunisia in 1981. Now he is a software engineer since 2004 and he is Java 6 and Spring certified with 100% and 94% respectively. He is very interested in Java technology, Scala and open source projects. He believes that programming is one of the hardest jobs and most beautiful in the world. Slim has posted 32 posts at DZone. You can read more from them at their website. View Full User Profile

OSGi Annotation Extender

09.10.2009
| 7171 views |
  • submit to reddit
We have finished one big OSGi project with many tools : JPA, GPRS, SMS, FTP, JNA, SPRING, Jetty, ext.js .... after about one year with heterogeneous team. Now, I have switched to another JEE projects as " an architect". But I still love OSGi.

I have blogged more about extender, and this post is not an exception. I will try to present a simple annotation extender to publish OSGi services.

For this reason we will create 3 projects :

1- osgi.annotations : annotation lib
2- annotations.extender : extender used to publish annotated class
3- client : service to be published as a test

osgi.annotations

We will create a RegisterService annotation type with RUNTIME Retention and ElementType.TYPE target as following
package com.jtunisie.osgi.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 *
 * @author slim ouertani
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface RegisterService {

    String id();

    NamedInterface[] NamedInterfaces();

    Prop[] Props() default {};
}

  • id : used for debug
  • NamedInterface[] : list of interfaces (target is ANNOTATION_TYPE and as single value annotation)
  • Prop[] : optional additional service properties
package com.jtunisie.osgi.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 *
 * @author slim ouertani
 */

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface NamedInterface {

    Class value();
}
package com.jtunisie.osgi.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 *
 * @author slim ouertani
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Props {

    String key();

    String value();
}
It is very simple as a start up, but we can add other parameters as registration type(such as bundle context, extender context,...)

annotations.extender

This is a very basic extender to listen to all installed bundles (Activator implements BundleActivator, BundleListener ) and lists all class using :   Enumeration<?> entrs = b.findEntries("/", "*.class", true);

For each class we we call loadClass witch will scan if this class is a candidate to be published. We call the loadClass method using bundle classloader
  private void loadClass(Bundle b, String clazz) {
        try {
            Class loaded = b.loadClass(clazz);

            System.out.println("Loaded class [" + loaded + "]");
            boolean annotationPresent = loaded.isAnnotationPresent(RegisterService.class);
            System.out.println("" + annotationPresent);
            if (annotationPresent) {
                publishService(loaded, b);

            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
if an annotation is present, we get data and we will publish service using it's context( we can do it using extender context but ;) )
 private void publishService(Class loaded, Bundle bundle) throws IllegalAccessException, InstantiationException {
        RegisterService annotation = loaded.getAnnotation(RegisterService.class);
        String id = annotation.id();
        NamedInterface[] interfaces = annotation.NamedInterfaces();
        Prop[] with = annotation.Props();
        Properties p = new Properties();
        for (Prop props : with) {
            p.put(props.key(), props.value());
        }
        Object newInstance = loaded.newInstance();
        for (NamedInterface object : interfaces) {
            //register service
            System.out.println("[ " + id + " ] registring service ..." + object.value().getName());
            bundle.getBundleContext().registerService(object.value().getName(), newInstance, p);
        }
    }
it's all for our first extender III- client. it's a simple pojo class and we annotate it using our annotation lib
import com.jtunisie.osgi.annotation.RegisterService;
import com.jtunisie.osgi.annotation.client.IService;
import com.jtunisie.osgi.annotation.NamedInterface;
import com.jtunisie.osgi.annotation.Prop;

/**
 *
 * @author slim ouertani
 */
@RegisterService(id = "tunisie",
NamedInterfaces = {@NamedInterface(IService.class)},
    Props = {
    @Prop(key = "url", value = "/jtunisie"),
    @Prop(key = "publish", value = "hessian")
})
public class ToPublish implements IService {

    public ToPublish() {
        System.out.println("service published..");
    }
}
and if we install the bundle service will be published

Console output :

osgi> up 48

osgi> New bundle: annotation.client-1.0-SNAPSHOT_1.0.0.SNAPSHOT [48]
file: /com/jtunisie/osgi/annotation/client/IService.classpath : /com/jtunisie/osgi/annotation/client/IService.class
c: com.jtunisie.osgi.annotation.client.IService
Loaded class [interface com.jtunisie.osgi.annotation.client.IService]
false
file: /com/jtunisie/osgi/annotation/client/impl/ToPublish.classpath : /com/jtunisie/osgi/annotation/client/impl/ToPublish.class
c: com.jtunisie.osgi.annotation.client.impl.ToPublish
Loaded class [class com.jtunisie.osgi.annotation.client.impl.ToPublish]
true
service published..
[ l ] registering service ...com.jtunisie.osgi.annotation.client.IService


osgi> b 48
annotation.client-1.0-SNAPSHOT_1.0.0.SNAPSHOT [48]
Id=48, Status=ACTIVE Data Root=/home/sst/NetBeansProjects/env/configuration/org.eclipse.osgi/bundles/48/data
Registered Services
{com.jtunisie.osgi.annotation.client.IService}={service.id=44}
No services in use.
Exported packages
com.jtunisie.osgi.annotation.client; version="0.0.0"[exported]
Imported packages
com.jtunisie.osgi.annotation; version="0.0.0"<annotation-0.0.1-SNAPSHOT_0.0.1.SNAPSHOT [47]>
No fragment bundles
Named class space
annotation.client-1.0-SNAPSHOT; bundle-version="1.0.0.SNAPSHOT"[provided]
No required bundles
 

We remark that our service is declared as Registered Services.

SCA extender :

We can use this annotation to be published in the SCA fashion like :
@RegisterService(id = "tunisie",
NamedInterfaces = {@NamedInterface(IService.class)},
    Props = {
    @Prop(key = "url", value = "/jtunisie"),
    @Prop(key = "publish", value = "hessian")
})
public class ToPublish implements IService {

    public ToPublish() {
        System.out.println("service published..");
    }
}

Next Step :

We have seen the power of the extender pattern in the OSGi world and how to use annotations. But this example isn't complete. We can do more, such as :
  • Publish by default all implemented interfaces
  • Check if a class really implements listed interfaces
  • Use adynamic proxy and register it ( not really instance) for many purpose ;)
  • Unregister service
  • @serviceReference as springOSGI
  • Add additional properties to MANIFEST to reduce scan file loop
  •  Service factory
  •  ...

The source code is under svn :svn checkout http://osgipublishannodation.googlecode.com/svn/trunk/ osgipublishannodation-read-only

Conclusion :

 Using annotations is a direction in publishing and consuming an OSGi service but I highly recommended DSL and if you have time take a look on scala with osgi. 
Published at DZone with permission of its author, Slim Ouertani.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

David Parks replied on Thu, 2009/09/10 - 3:07pm

Very interesting.  The 'scala with osgi' link is broken and I'm curious -- can you fix it?

 

Slim Ouertani replied on Fri, 2009/09/11 - 3:11am in response to: David Parks

Thanks,

 you can try this link for curiosity

http://www.slideshare.net/heiko.seeberger/jax-09-osgi-on-scala

and if you want to see more documentation and source code about scala DSL :

http://wiki.github.com/hseeberger/scalamodules

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.