Insight into OSGi and Eclipse Extensions

Posted by U.S. Wickramasighe | Posted in , , , , , , , , | Posted on Thursday, May 14, 2009

I've been working on OSGi(Open Statndards Gateway initiative) and Eclipse extensions for a while. Both are of course very good frameworks (infact Eclipse Extension framework depends on OSGi ) that has sprung up not very long ago and has become very popular gradually. Obviously Eclipse's popularity as a project and IDE has served immensely towards the recognition of OSGi as a framework. Technically speaking Eclipse and all it's components (except it's kernel) runs on top of an OSGi framework implementation named equinox. Hence lot of software products and platforms are now turning into OSGi to make their software more extensible or scalable.

As most of you know , within the core of OSGi lies a class-loading mechanism , where each bundle (as so called in OSGi) would take the responsibility of loading classes of their own , and would facilitate exposing of a subset of classes to the outside world while others will remain internal to the respective bundles. Although OSGi uses same Jar and Manifest mechanisms to achieve this, it is a radical change from Sun's Jar specification where all the classes and packages are implicitly exposed while clients can use any class within, they want (of course if the respective class implementation supports it). It's OSGi Runtime that deals with loading the bundles , managing dependencies(resolving) and registering and consuming services...

OSGi Service is simply an plain old java object (POJO) which can be either state-full or stateless , or any kind of a java Object that does some useful stuff. These objects should be registered under a interface key name and hence in order to register correctly as an OSGi service , service objects need to implement the specified Interfaces. Inorder to register a service you need the BundleContext object , which is almost always taken from a Bundle Activator provided by the OSGi framework to the "start(BudleContext)" at the start of each bundle.Following shows an example..

public class TestMailboxActivator implements BundleActivator{
public void start ( BundleContext context ) throws Exception {

IMailbox mbox = new TestMailbox ( ) ;
Properties mailboxProps = new Properties();
mailboxPropos.put("name","FixedTestMail");
//registering the service under it's interface name
context.registerService(IMailbox.class.getName(),mbox,mailboxProps);
}
public void stop ( BundleContext context ) throws Exception { }
}
}
For the classes to work and resolve properly ,IMailbox Interface should be exposed in the respective bundle(as declared in "export package" Manifest entry) or should be in the same bundle as TestMailbox (which is usually not the case). As in the example , services can be provided with key,value pairs as metadata which will be very useful indeed. However consuming services is little more challenging than registering them especially since we don't know when will services come and go due to their inheretly dynamic behavior.

We may not know when will a bundle register a service object and when it will be destroyed.One way to resolve this problem is to always keep querrying service eachtime it need to be accessed as shown below.

ServiceReference ref = context.getServiceReference(IMailbox.class.getName());
if(ref != null) {
IMailbox mbox = (IMailbox)
context.getService(ref);
if(mbox != null) {
int count;
try{
count = mbox.getMessageCount();
}
finally{
context.ungetService(ref);
}

return count;
}
}

The method "ungetService" will tell the framework that it's nolonger using the service.This important since framework keeps a count of a particular service and when it reaches zero it will get it disposed.However using a ServiceTracker would make the above procedures a lot easier as well.

ie:-

ServiceTracker mboxTracker = new ServiceTracker(context,IMailbox.class.getName(),null);
mboxTracker.open();
IMailbox mbox = ( IMailbox ) mboxTracker . getService ( ) ;

Also Service trackers come useful when managing particular services that depend on other services as well. Suppose a service object "servicePayroll" depends on another service "payment" , where payroll object is useless without having payment in it's hand. Here "servicePayroll" service is dependant on "payment" and hence it is pointless to consume "servicePayroll" object if system already does not have a "payment" service registered in it. To solve this problem , we have listen in for the "payment" sevice to appear (when someone registers a "payment" service) and then register "servicePayroll" object so that now payroll is able to process payments and provide necessary details for it's clients.

However things get little complicated when implementing this solution. One reason is we have to take notice of the "payment" services registered before our listener has even started as listener does not take care of this matter. So we should look up service registry to take into account the previously registered "payment" services. Also while we looking up the registry there may come a moment ,a "payment" object has been registered , however since we haven't registered our listener yet , this will go unnoticed. So we should register our service listener to listen to "payment" services first and then start lookup secondly.Again there will be some complications in overlapping and duplicate services so we should take care of them as well..

This obviously is very complex and cumbersome code and that's where Sevice Trackers come into the rescue.ServiceTracker objects handle these scenarios for us and provide us with nice and easy interface to work with..Service tracker code is almost the same , but additionaly to handle listening and registering of dependent services we have to provide service tracker object with new "ServiceTrackerCustomizer" object..it Provides very useful and important addingService(ServiceReference) method , which is invoked whenever tracked service is found in the registry or when someone registers it.


ServiceTracker paymentTracker = new ServiceTracker(context,IPayment.class.getName(),new PaymentTrackerCustomizer(context));
mboxTracker.open();

public Class PaymentTrackerCustomizer implements ServiceTrackerCustomizer(){
private BundleContext context;
.......

public Object addingService(ServiceReference ref){
payment = (Payment)context.getService(ref)
Payroll proll = new Payroll(payment);

//Returns ServiceRegistration object
return context.registerService(IPayroll.class.getName(),proll,null);
}

.........
}

addingService can return either null or any object (in this case ServiceRegistration object). Then when ever you call ServiceTracker's (ie:-paymentTracker) getService() method you will get the returned object (from addingService()) as the service object.

So this is so far for now , about OSGi and Services. I'll talk about Eclipse extensions and extension points with the next post..So keep n touch and Thank you for reading...


Running Eclipse on Ubuntu

Posted by U.S. Wickramasighe | Posted in , , , , | Posted on Tuesday, April 21, 2009

For starters, Running Eclipse IDE under Ubuntu would be a major hedache. You may encounter unusual number of errors including at Start-up , when running plugins , software updating , etc. Though the reason cannot be exactly pointed out , several issues standout among the rest ..First and foremost is the Eclipse SWT (Standard Widget ToolKit). Though a standard java lib ,SWT depends a lot on native platform features in order to provide nicer, richer graphical interface than AWT or Swing .

Therefore SWT library needs to be installed (if not provided ) for each platform you are running in but still may encounter errors (ie:-XPCOM Error , Widert Disposed too early, etc) due to dependencies on web browser ,etc. Eclipse Runtime GCJ would be another reason behind many issues including when running plugins, software updates, java debugging , etc. GCJ is the java compiler + runtime provided by GCC (GCJ v1.5) , which is actually an open-source implementation of java kernel provided with ubuntu , which unfortunately Eclipse picks up as it's default JRE for most Linux platforms.GCJ is not properly tested and not a intended Runtime expected by Eclipse Developers hence would be the origin for a lot of in-compatibilities.

Several work-arounds generally solve all these issues ,

  • set Eclipse java virtual machine to java 1.5 0r 1.6 provided by SUN . This can be set in command line using ./eclipse -vm /${path to JDK Home}/bin/java or in eclipse.ini file specifying
    -vm
    /${path to JDK Home}/bin/java
  • if a Startup problem is there try updating Ubuntu or install latest xulrunner and XPCOM (sudo apt-get install xulrunner) packages for ubuntu and append to eclipse.ini
    -Dorg.eclipse.swt.browser.XULRunnerPath=/usr/lib/xulrunner/xulrunner

Using Maven2 (Contd..)

Posted by U.S. Wickramasighe | Posted in , , , | Posted on Friday, April 03, 2009

Maven2 has very easy to use API for building Source code..I find it very easy to work with Maven2 due to this factor. Basic command for building is 'mvn install' but it's almost always a good idea to build using 'mvn clean install' since it does cleanup of already built code and then starts building fresh..
Before building always make sure your source code resides in '/src/main/java' and resources resides in '/src/main resources' . This is the default behavior for Maven2 and you can always modify it in super 'Pom' (or in you project pom as well ) which is the default root pom for all the pom's for Maven2.

commands

mvn clean install -> compile source and do necessary packaging

mvn compile -> compile and run

options

-Dmaven.test.skip=true -> Sometimes it's better to skip unit tests and test cases , since it will be taking lot of time

-o -> offline building . it's better to use this option if you know necessary plugins and dependencies are residing locally and upto date. Buiding with this option will take much less time since no downloading would occur from remote repositories.

-U -> if maven displays an error of unavailable/error in a plugin use this option. this will force Maven to download the plugin and resume the life cycle


Notes

Please note that if you are building a hudge tree of source code , maven will require a lot of memory to keep it's persistant data. So if the memory limit exceeds Maven2 build proccess will be terminated with out of memory error. So always make sure to set 'Xmx' Memory for Maven to a higher value in these scenarios..

  • open ${Maven_Home}/bin/mvn shell script file... (in Windows mvn.bat)
  • Put set MAVEN_OPTS='-Xmx=1024m' at the start of the script file. Here 1024m can be replaced by any value you desire and only limited by the physical memory of your machine (should be a large value for aforementioned scenario)
For more information on Maven and it's build process go to http://maven.apache.org/
------------------------------------------------------------------------------
My previous post Using maven2 part1