OSGi Annotation Extender
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
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
Console output :
We remark that our service is declared as Registered Services.
The source code is under svn :svn checkout http://osgipublishannodation.googlecode.com/svn/trunk/ osgipublishannodation-read-only
Published at DZone with permission of its author, Slim Ouertani.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 followingpackage 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.(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)
Tags:





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