3

I've come across a case where I want to use Blueprint (Aries) to resolve a dependency at run-time and the implementation is defined in the same bundle which requires it and will not be used in any other bundles. I am abstracting the implementation within this bundle to make it easier to mock the dependency when unit testing. If I put this service in its own bundle, it would lead to poor cohesion.

At run-time, the Blueprint says it is waiting for dependencies. How can I use Blueprint to realize dependency injection within a bundle?

<!-- Interface -->
<reference id="modelEntityMapper" interface="org.example.blog.rest.cxf.server.model.ModelEntityMapper" />
<!-- Implementation defined within same bundle -->
<bean id="modelEntityMapperImpl" class="org.example.blog.rest.cxf.server.model.impl.ModelEntityMapperImpl" />
<service ref="modelEntityMapperImpl" interface="org.example.blog.rest.cxf.server.model.ModelEntityMapper" />

<!-- Object which has dependency -->
<bean id="posts" class="org.example.blog.rest.cxf.server.BlogResourceImpl">
        <property name="modelEntityMapper" ref="modelEntityMapper" />
</bean>

Edit

I just tried the suggestion from @christian-scheider and Blueprint is still waiting for some service to satisfy ModelEntityMapper

The XML

<!-- Interface -->
<reference id="modelEntityMapper" interface="org.example.blog.rest.cxf.server.model.ModelEntityMapper" />
<!-- Implementation defined within same bundle -->
<bean id="modelEntityMapperImpl" class="org.example.blog.rest.cxf.server.model.impl.ModelEntityMapperImpl" />

<!-- Object which has dependency -->
<bean id="posts" class="org.example.blog.rest.cxf.server.BlogResourceImpl">
        <property name="modelEntityMapper" ref="modelEntityMapperImpl" />
</bean>

The Log

Bundle rest-cxf-server is waiting for dependencies [(objectClass=org.example.blog.rest.cxf.server.model.ModelEntityMapper)]

jdgilday
  • 866
  • 7
  • 21
  • It's just a guess, but where the `blogRepositoryApi` reference is defined? I'd also check whether the `org.example.blog.rest.cxf.server.model` package is exported and imported (not sure if it's relevant, but writing it down off the top of my head). – Jacek Laskowski Jan 08 '13 at 14:56

2 Answers2

3

Can you just refer to the bean of the service directly? If you define the service and the service reference in the same blueprint file then using an OSGi service does not make that much sense.

Christian Schneider
  • 19,420
  • 2
  • 39
  • 64
  • Agreed. Blueprint within a bundle works fine, but only if you don't use intermediary services. – Holly Cummins Jan 09 '13 at 19:26
  • I just tried it out but didn't have much luck. I should be able to directly reference the bean like the XML I [just added to the post](http://stackoverflow.com/q/14216300/501368)? – jdgilday Jan 09 '13 at 21:01
  • You did not remove the reference definition. So it waits for a service that will never be there. Try to remove the reference element and it should work. – Christian Schneider Jan 10 '13 at 09:38
  • @Holly: Am I right that the problem with the original approach was that blueprint waits till the service references are there until it starts the context. So it never gets to the point where its own service is installed? – Christian Schneider Jan 10 '13 at 09:41
  • @Christian, yes, it's a cycle which Blueprint can't satisfy. – Holly Cummins Jan 14 '13 at 16:51
2

I was unable to find detailed documentation on the Aries site related to referencing in bundles, so I'm going to reference the Eclipse Gemini Blueprint implementation documentation (formerly Spring Dynamic Modules). See the warning in section 9.2.1.1 of their documentation. Yes, technically this is related to their implementation, but I believe it's likely a similar story in Aries.

It is an error to declare a mandatory reference to a service that is also exported by the same bundle, this behaviour can cause application context creation to fail through either deadlock or timeout.

In a nutshell you typically either import (reference) an OSGi service or you export an OSGi service in the same bundle, usually you don't try to do both in a single bundle.

If you want this bundle to export a service of type ModelEntityMapper, then you'll need to export it with the service element. When other beans need a reference within the same bundle, you would use the ref attribute like you're using it. In this case, you would not need the reference element at all, but instead use the service element.

If you're not going to use the ModelEntityMapper bean outside of this bundle, you don't need to use a reference or service element in the configuration at all. You should be able to use it in the ref attribute without exporting it as an OSGi service - it's basically a bean internal to that bundle. In this case, you should be able to remove the reference element altogether: the <bean id="modelEntityMapperImpl" ... will create a bean internal to the bundle, and the <property name="modelEntityMapper" ref="modelEntityMapperImpl" /> element should be able to use that bean internally to the bundle.

If you want to import a reference of type ModelEntityMapper from OSGi if available, else use an internally defined fallback, that gets more complicated. You'd have to declare a non-mandatory reference and inject that reference into your class along with the internally defined bean and then have defaulting logic that checks the availability of them. Alternatively you could just define the implementation in a separate bundle from the interface.

Jason Day
  • 574
  • 4
  • 5