1

Spring noob here.

I have an osgi service defined as follows in one of my bundles:

<osgi:service id="myModelInterpreter" ref="myModelInterpreterService" interface="*.IModelInterpreter" />

I know I can access it from another bundle via the BundleContext doing getServiceReference (passing down IModelInterpreter.class.getName) and then getService.

Is there a way to get the service via the id (myModelInterpreter) instead of using the Interface (passed down as IModelInterpreter.class.getName to getServiceReference)?

Any help appreciated.

JohnIdol
  • 48,899
  • 61
  • 158
  • 242
  • What is your reasoning behind trying to instantiate the bean yourself. – dardo Oct 12 '12 at 13:49
  • "instantiate an object" do you mean it would be a spring bean instance? Is the class (its name as String para) managed by Spring? – Kent Oct 12 '12 at 13:51
  • @Kent yes the class is managed by spring, it's not in my build path as it's exposed as a discoverable osgi service so I cannot use reflection – JohnIdol Oct 12 '12 at 13:52
  • Not sure if it would work, but maybe you can try to do a `Class.forName(String className)` and use the result of that call to to invoke `AutowireCapableBeanFactory.createBean`. – mthmulders Oct 12 '12 at 13:53
  • Retagged to include osgi, as I am understanding it currently, you need to be able to include an osgi managed bean in the spring container at runtime. – dardo Oct 12 '12 at 14:00
  • What are you going to do with the bean in your code, if you don't have access at compile time? Do you have an interface available? – artbristol Oct 12 '12 at 14:03
  • @artbristol I sure do have an interface :) – JohnIdol Oct 12 '12 at 14:17
  • @JohnIdol Use getBean with the interface class then. However if this is your first time using Spring and OSGi, I recommend you check out Gemini Blueprint http://www.eclipse.org/gemini/blueprint/ – artbristol Oct 12 '12 at 14:25
  • all - I just edited my question, hopefully it makes more sense now – JohnIdol Oct 12 '12 at 16:17
  • Is that declaration done using Spring DM? – Robin Oct 12 '12 at 17:55
  • @Robin yes, it's in the osgi-config.xml file for the bundle that exposes the osgi service – JohnIdol Oct 12 '12 at 18:18
  • I am curious as to why you accepted an answer that uses a declarative approach when you commented on my answer that you cannot use a declarative approach. – Robin Oct 15 '12 at 13:35
  • @Robin Christian's answer provides me with a way (filters, of which an example is included) of identifying the osgi service beyond the interface. I am not gonna use the declaration of the reference for the service consumer, will use the API to apply the filter on the interface + my custom "id" property, which allows me to dynamically select the correct service based on external configuration. – JohnIdol Oct 15 '12 at 13:41
  • @Robin I see you had suggested the same thing as Christian's answer in a comment. Taking into account your comment, from my point of view the 2 answers are equivalent. What would really help is an example of how to access the service programmatically using the interface and the custom property as a filter (or even a link to an example, can't seem to find much), but I guess that's another question :) – JohnIdol Oct 15 '12 at 13:47

3 Answers3

2

I dont think you can get the service by the id you specified in the spring config as it is an internal setting of the spring context. What you can do is add some service proprties to the service and filter for them.

Like this:

<service ref="myModelInterpreterService" interface="*.IModelInterpreter">
  <service-properties>
    <beans:entry key="myId" value="myModelInterpreter"/>
  </service-properties>
</service>

Then in the other bundle you can filter for the properties:

<reference id="myModelInterpreterService" interface="com.xyz.IModelInterpreter"
  filter="(myId=myModelInterpreter)"/>
Christian Schneider
  • 19,420
  • 2
  • 39
  • 64
  • This sounds very close to what I need - thanks. I'll give it a shot. Any examples of that filtering by property? Also - just to clear a few doubt I have, shouldn't I able to grab the service by id as an y other bean in the spring context? r is it different because it's a service (hence not a bean)? – JohnIdol Oct 14 '12 at 22:23
  • 1
    My answer above contains a filter for the property myId (my=myModelInterpreter). You can use filters like that on any property you define with the service. A service is very different from a bean. A bean is a spring internal construct and has no meaning outside the spring context. A service is specified in the OSGi spec. Spring allows to define OSGi services but not all of the metadata of the bean are published. Probably the properties you define explicitly are all that you can see from another bundle. – Christian Schneider Oct 15 '12 at 11:05
  • Clear now: "Spring allows to define OSGi services but not all of the metadata of the bean are published." - thanks a lot for your help. – JohnIdol Oct 15 '12 at 11:44
  • Actually you can use the id, Spring DM will publish the bean id as a property of the service. This is why the reference tag of a DM config file has an optional "bean-name" attribute which will then automatically filter on that property. You can get the full name of the property via the console after the service is published if you are looking up outside of DM. – Robin Oct 15 '12 at 13:28
  • @Robin interesting - are you saying the id is not gonna be the same id that I declare in the service bundle? And is there a way to programmatically get the service by id then as any other bean from the Spring context? – JohnIdol Oct 15 '12 at 13:44
1

Since you are already using Spring DM to declare your service, the simplest way to consume it is to do the same with another dm config.

<osgi:reference id="modelInterpreter" interface="IModelInterpreter" />

This can also be represented like this to filter to a specific Spring bean.

<osgi:reference id="modelInterpreter" bean-name="myModelInterpreter" interface="IModelInterpreter" />

Then you simply use the bean "modelInterpreter in your regular Spring config in the consumer bundle. This same line can be accomplished using the bean-name as well, but I am pretty sure it will still require the interface or interfaces attribute, as these are the only accepted means of looking up OSGi services. Using the bean-name simply sugar coats the usage of a property filter on the service lookup, which in most cases you don't want as it actually creates a tighter dependency between bundles. It is easier for instance to mock your dependency without such a tight coupling.

If, on the other hand, you want to get access to the service without using DM, then I would recommend that you use the straight up OSGi way using either direct access (via code) to the registry or inject it using DS (Declarative Services).

I would stay away from using regular Spring to directly access OSGi services. Use Spring to do configuration within your bundle only, and externalize the interbundle dependencies with Spring DM.

Robin
  • 24,062
  • 5
  • 49
  • 58
  • Thanks for your answer. My issue is that I need to "lookup" the service based on an eternal configuration value (the id) so I cannot declaratively put down my reference to a given service. I basically need to read a bunch of service ids from a config file and get all services that correspond to those ids, run through them and invoke generic methods. I don't know how many there are - for instance I have more than one service that implements IModelInterpreter, that's why I need to look them up them by some kind of id (I picked the id of the service definition). – JohnIdol Oct 12 '12 at 19:04
  • 1
    You can do that by using the id's as properties when the service is registered and filtering on that property when you look up a service reference. Spring DM already puts the bean id as such property. I would declare the property more explicitly though. You will still need the interface for the lookup though, I don't think there is any way around that. – Robin Oct 15 '12 at 13:24
-2

Or just use

Object obj = beanFactory.createBean(YourClass.class);
Adrian Adamczyk
  • 3,000
  • 5
  • 25
  • 41