Issue Details (XML | Word | Printable)

Key: OSGI-582
Type: Bug Bug
Status: Resolved Resolved
Resolution: Incomplete
Priority: Major Major
Assignee: Costin Leau
Reporter: Olof Jönsson
Votes: 0
Watchers: 2
Operations

If you were logged in you would be able to see more operations.
Spring OSGi

ServiceReference instances not created by the framework can't adhere to specification

Created: 15/Jul/08 03:22 PM   Updated: 01/Oct/08 02:49 AM
Component/s: CORE
Affects Version/s: 1.1
Fix Version/s: 1.1.2

Time Tracking:
Not Specified

File Attachments: 1. Text File OSGI-582.patch (22 kB)

Environment: Equinox
Issue Links:
Related
 


 Description  « Hide
According to the OSGi specification (at least version 4), ServiceReference instances must return the same value from hashCode() and true on equals() if they refer to the same service registration. The algorithms for hashCode() and equals() are not specified, however, which rules out mixing own implementations of ServiceReference with other implementations (except, of course, if the algoritms of the other implementations' hashCode() and equals() methods are known, possible to transfer and that their equals() method would uphold symmetricity and transitivity with our own implementations).

Spring OSGi 1.1 passes internal implementations of ServiceReference (org.springframework.osgi.service.importer.ServiceReferenceProxy) to bind/unbind-methods that require a ServiceReference. It also passes another internal implementation (org.springframework.osgi.service.importer.support.ServiceReferenceDelegate) when setting a ServiceReference property from a osgi:reference.

Apart from being out-of-spec, these ServiceReference instances will fail with a ClassCastException on Equinox when passing them to getService/ungetService on its BundleContext. Equinox tries to cast them to its own ServiceReference implementation, which isn't strange considering that the framework should be in control of which ServiceReference instances are abound according to the reasons given above. See also discussion about it here: https://bugs.eclipse.org/bugs/show_bug.cgi?id=240659

I don't know the results of doing this in another OSGi framework.



 All   Comments   Work Log   Change History   FishEye   Builds      Sort Order: Ascending order - Click to sort in descending order
Olof Jönsson added a comment - 15/Jul/08 03:32 PM
This patch makes Spring pass framework instances of ServiceReference to the client code.

The patch also modifies the org.springframework.osgi.service.importer.ServiceReferenceProxy interface so it doesn't extend ServiceReference, something that amounts to most of the changes in the patch. This isn't strictly necessary, but it makes sense that it doesn't since it won't (and shouldn't) be used as a ServiceReference.

Costin Leau added a comment - 24/Jul/08 01:16 PM
Olof, if you need the native ServiceReference, cast the one managed by Spring-DM to ServiceReferenceProxy and then call getTargetServiceReference.
The idea behind the proxy service reference is that it's managed by Spring-DM automatically. you cannot reuse it with the platform but if the importer binds to a different service, this is automatically reflected to the service reference as well (notice that Spring-DM can inject a managed service or a managed service reference depending on your type).
As for not being able to use the service reference - I don't recall reading in the OSGi spec /javadoc about any restriction on ServiceReferences to be reusable by the framework.
I would argue that the framework could potentially double check the references passed in and use *only* the interface contract w/o any casting.

These being said, the reference documentation should contain more information about this topic. I'll open another issue for it.

Costin Leau added a comment - 24/Jul/08 01:25 PM
As a separate comment you are right about the equality impact. Since it's defined by an implementation, it might break between two different implementation of the same interface.
The contract holds true though for the same type of implementations.
I'll do some more thinking on this topic - from the top of my head, I think one improvement would be for the OSGI spec to specify also the equality/hashcode algorithm otherwise any implementation of the ServiceReference would break this contract.

Frederic Conrotte added a comment - 30/Sep/08 04:46 AM
Hi Costin,

I run also in ClassCastExceptions when casting an exposed bundle Service to its exposed interface using Spring DM 1.1.0

Regarding your first comment i tried the following to cast the ServiceReference to ServiceReferenceProxy :

protected Object getService(Class clazz)
{
     ServiceReference ref = bundleContext.getServiceReference(clazz.getName());
    
     //return bundleContext.getService(ref);

     // See Spring OSGi issue OSGI-582
     ServiceReferenceProxy proxy = (ServiceReferenceProxy) ref;
    
     return bundleContext.getService(proxy.getTargetServiceReference());
    
}

But i still got a ClassCastException:

java.lang.ClassCastException: org.eclipse.osgi.framework.internal.core.ServiceReferenceImpl

Could you give a hint ?

Costin Leau added a comment - 30/Sep/08 05:39 AM
This issue regards the managed service-reference instances injected by Spring from osgi:reference elements. See http://is.gd/3jLO for more information. You have basic usage of OSGi which doesn't apply here (though you can improve it by using Spring DM to handle the references for you).

Frederic Conrotte added a comment - 30/Sep/08 09:58 AM
Indeed, thanks for the pointer.

Costin Leau added a comment - 01/Oct/08 02:06 AM
The cast to the native service reference can be used as a workaround.

Olof Jönsson added a comment - 01/Oct/08 02:18 AM
If I already have a hard dependency on OSGi, which I must have to be using ServiceReferences, I should be aware of the dynamicity issues and handle them properly myself. I don't really see the value-add of getting a hard dependency on Spring-OSGi as well just to be able to use getService/ungetService (the ONLY use case for ServiceReferences). In that case I don't really see the need of exposing the OSGi ServiceReference at all...

/ Olof

Costin Leau added a comment - 01/Oct/08 02:49 AM
Olof, one of the features of Spring DM is to track and manage the OSGi service for you. In both cases (service reference injection or service listening), the service reference needs to reflect the service used. Since the service itself can change, the reference can become stale - hence the decision to add a tracking reference.
This is especially relevant in the first case when the service can change after its reference has been injected.
While the reference can be used for getting/ungetting the service, in case of Spring DM, since everything is managed already, there is no need to do this - maybe this is not clear from the docs, I'll try to improve them.
Access to the service reference is given so that one can access the OSGi specific properties of the service. You can accept a map but also might be interested in who's using the service and so on.

> I must have to be using ServiceReferences, I should be aware of the dynamicity issues and handle them properly myself
One can use ServiceReference, as I said above, to get access to more information about the environment while leaving Spring DM to do service management. Note that both the listener and injection are done through Spring DM which implies management. If that's not your case, then you can just inject the bundle context and start dealing with the services yourself.