Thursday, December 4, 2008

Properties in OSGI Declarative Services and ServiceTracker

As proposed in my last blog "Dependencies and Services in OSGI Enterprise Applications" it seems that a new blog series was started ;-)

ServiceTracker vs Declarative Services

There was only a short statement last time - now some tips follow how to use properties in ServiceTracker vs Declarative Services (DS).

A ServiceTracker from my OSGI Server project was opened with this Filter: 

final String filterPool = "("
+Constants.OBJECTCLASS
+ "="
+ JDBCPoolComponent.class.getName()
+")";

So the ServiceTracker will get Services of Type JDBCPoolComponent - we are interested into the attribut JndiName:

private void processDataSources(JDBCPoolComponent service) {
  if (service.getJndiName().equals("foo_entity_data_source_hsql")) {
  // do something
  }
}

How could this be done using Declarative Services (equinox.ds): 

We're defining a reference to get exactly one specific service of type JDBCPoolComponent to know that a DataSource is ready. 

A first idea to declare this reference could be:


Launching the OSGI application, but the reference wasn't resolved. 

How could we find the reason ? At first we should test if the Filter is correct and there's no typo in the Interface.

Tip: Use of Equinox OSGI Console to test the Filter !

Try this command:

services (&(objectclass=org.ow2.easybeans.component.jdbcpool.JDBCPoolComponent)
(jndiName=foo_entity_data_source_hsql))

But no Service was found: No registered Services.

As next we try only to look for Services of Interface JDBCPoolComponent. Now our command looks like: 

services (objectclass=org.ow2.easybeans.component.jdbcpool.JDBCPoolComponent)

Some Services were listet - we also see the one we're looking for:

{org.ow2.easybeans.component.jdbcpool.JDBCPoolComponent}={classname=org.ow2.easybeans.component.jdbcpo......, xmlconfig=
  Registered by bundle: .../easybeans-component-jdbcpool_1.1.0-M3-SNAPSHOT.jar/

Analyzing the printed text we found: jndiName="foo_entity_data_source_hsql"
But there's a small difference: its the Property xmlconfig containing the informations. Thats the solution:

services (&(objectclass=org.ow2.easybeans.component.jdbcpool.JDBCPoolComponent)
(xmlconfig=*foo_entity_data_source_hsql*))

The Service we want to reference will be found and we know how to declare the reference inside the Service Component:



Why can the ServiceTracker use  getJndiName(), but the target Filter can't ?
getJndiName() is a Methode of JDBCPoolComponent, but JndiName isn't registered as Service Property ! 

Target Filter cannot access methods of implementation - only Service Properties. 

You maybe run into this using 3rdParty bundles where you have to live with their services as-is. If you're in luck its Open Source, you write a Bugzilla or JIRA and get it fixed in hours :-)

Remark:
You can take a look at my blog series about "OSGI Enterprise Applications" - the index is in the column right beside this blog.
There are also some submissions for EclipseCon 2009 - if you want to hear more about: comments are welcome ;-)


blog in german

2 comments:

Heiko Seeberger said...

Ekke,

Good to see someone elaborating on this topic.

You are asking: "Why can the ServiceTracker use getJndiName(), but the target Filter can't ?"

But the ServiceTracker cannot use getJndiName() neither. In your example code it also filters only on the service interface (JDBCPoolComponent) and the equals-check on the jndiName occours later in the code. The ServiceTracker will track any JDBCPoolComponent. Hence there is no difference in this regard ...

Heiko

ekke said...

Heiko,

thanks for making it more clear for the reader of the blog :-)

of course you're right - the Filter used to open the ServiceTracker also only has access to the Properties, not getJndiName().

so I want to describe my use-case better ;-)
(btw: some talk about this will be in another blog from my series "HowTo build an OSGI enterprise app server")

In my ServiceTracker I have to check if a specific DataSource is ready and then register another Service. So I track all JDBCPoolComponent and test if its the right one and then register this Service.

My goal was to try to use DS make it all by magic:
- reference to the one and only needed Service
- provide an own Service

In this case I was in luck and found the information in another Service Property. In another case there was no property, but the Easybeans team added it now.

...switching from ServiceTracker to DS I have to open my eyes, change Filters, add properties if possible and with some luck can move some ServiceTrackers to trash or reduce complexitiy.

I have to say, that using DS is much fun, I can delegate so much work to DS, have not to think about multi-threading... I know equinox.ds is watching it all :-)

over all I can structure the bundles and services of an application much better

ekke