Expand my Community achievements bar.

Don’t miss the AEM Skill Exchange in SF on Nov 14—hear from industry leaders, learn best practices, and enhance your AEM strategy with practical tips.
SOLVED

Using SlingScriptHelper.getServices to return multiple services

Avatar

Level 2

I'm trying to explore options for maintaining multiple versions of code. I have three bundles which are essentially identical, except for a version indicator in the symbolic name, and the return value of a service method. I can install these to Felix simultaneously. Version 1.0.4 of the bundle has a property on the service class named version with a value of "1.0.4". Version 1.0.3 of the bundle has no such property, and version 1.0.5 has "1.0.5".

If I call sling.getServices(MyInterface.class, "(version=*)") from a JSP, I always get an array of 1 element returned. I haven't totally figured out what the rules governing which version I get, but currently when I pass "(version=1.0.4)" as my filter, I get the 1.0.5 version, and when I pass "(version=1.0.5)", I get a zero-length array back. Is there something I'm doing wrong?

Thanks

1 Accepted Solution

Avatar

Correct answer by
Employee

Joel-

There's no way to do what you're describing using *just* JSPs. All JSPs share a single common classloader which, by definition, can only import a single version of a package. It is non-deterministic which of the three versions will be imported by the script classloader.

I don't have an explanation for the filter behavior - I would expect you to get null or the correct instance. But it doesn't really matter for your specific use case.

Regards,

Justin

View solution in original post

5 Replies

Avatar

Correct answer by
Employee

Joel-

There's no way to do what you're describing using *just* JSPs. All JSPs share a single common classloader which, by definition, can only import a single version of a package. It is non-deterministic which of the three versions will be imported by the script classloader.

I don't have an explanation for the filter behavior - I would expect you to get null or the correct instance. But it doesn't really matter for your specific use case.

Regards,

Justin

Avatar

Level 2

Thanks, guys.

Justin, are you saying there is a way using more than JSPs? I was also experimenting with having a separate bundle that acts as a factory to sort out the version behavior. My understanding is that different bundles have different classloaders, but I'm not terribly clear on how that comes into play when service objects are being provided by one bundle to another.

Avatar

Employee

Yes, but it is very ugly.

What you would need is three *separate* bundles, each importing a different package version. Each bundle would then export a uniquely named package. Since those packags are uniquely named, the script classloader would not have a conflict.

In general, when a bundle tries to get a service, it will only be able to access where the package is common between the providing bundle and the consuming bundle. Take a look at section 5.9.1 in the OSGi core specification.

Avatar

Level 2

Not sure if this is resolved.

Since services get registered with OSGI framework, IMHO we should be able to fetch any services irrespective of which bundle this is in. So I would believe joel_triemstra your use case should work without any extra work. The only thing you should be using the properties on the services to form the filter and not bundle specific data. 

Avatar

Level 10

It sounds like you are using the filter properly. I have searched for some examples of this; however, it seems to be a bit thin in examples in this area.

I will check with with our Eng team as the Sling Javadocs in this case are not much help:

http://sling.apache.org/apidocs/sling5/org/apache/sling/api/scripting/SlingScriptHelper.html#getServ..., java.lang.String)

Parameters:
serviceType - The type (interface) of the service.
filter - An optional filter (LDAP-like, see OSGi spec