How to use blueprint programmatically? - osgi

Is it possible to wire blueprint services not by using XML (declaratively), but in the runtime?
What I want is an interface simmilar creating a BeanDefinition
ctx.registerBeanDefinition(beanName, BeanDefinition)
Somehow this should be called from a separate bundle that would start/stop services from other bundles

You should be able to lookup the blueprint context of your bundle since it's a registered service, and from there on you should be able to just do what you like with registering beans and so fort.

Related

Issue with service dynamism and blueprint

I have a non-blueprint bundle which provides a service via Declarative Service annotations.
I have another bundle, using blueprint, which contains a optional reference for this service and then injects this reference into a number of declared beans.
Starting up both within a Karaf container, the service is registered and the blueprint bundle can access it and use as intended. The configuration for the service providing bundle can be updated, and it is unbound and rebound again to the blueprint bundle which is perfect.
However, when the service providing bundle is restarted, or updated, the service is unbound but never rebound to the using bundle, so that the proxy object held by the blueprint reference never resolves to the service reference.
Sometimes restarting the blueprint bundle will fix this, but usually it requires a full framework restart to get it working again.
I do not get the same behavior when a non-blueprint bean is consuming the service via declarative services.
Has anyone had any similar issues with using a mix of DS and blueprint to provide/consume services?
Blueprint is not dynamic. It has a "damping" proxy which tries to wallpaper over service dynamism but does not always provide what is needed. In general, I would always use DS over Blueprint.

Does javax.imageio.spi.ServiceRegistry work in an OSGi container?

Can anyone tell me definitively if a osgi bundle that contains code that calls
javax.imageio.spi.ServiceRegistry
to find a service (in META-INF\service) will find that service, if that service implementation is in another bundle.
I'm not finding any documentation that is specific about this. I'm using the felix osgi container. Any pointers would be gratefully received.
I suspect it does work and my problem lies elsewhere as I notice that in the xdocreport osgi bundle fr.opensagres.xdocreport.core, ServiceRegistry gets used here but maybe its not supported on all osgi containers?
Out of the Box, OSGi doesn't support this, you'll need to tweak your code a bit.
But there are tools around like Aries SPI Fly and Pax-Swissbox that support you
in using these SPI "services"
No, it doesn't. I think it will only discover services in the system class loader, so that is pretty useless for bundles.
There might be a workaround, this post is pretty helpful, although I doubt if it is of any use to your problem.
Also OSGi 5 will have support for it ('Service Loader Mediator'). The reference implementation is SPI Fly from Apache Aries
Hi thanks everyone for your answers.
I think ServiceRegistry will work in an osgi container to instantiate a service but only within the same classloader.
And that's facilitated by use of osgi fragments. So as long as the implementer is in a fragment that defines its Fragment-host as the bundle that contains the class that has the ServiceRegistry lookup code, then ServiceRegistry will work.
This is why it is working in the xdocreport code I linked to.
In this case the ServiceLoader code is called from an abstract class in fr.opensagres.xdocreport.core (a bundle), which is extended by concrete class in fr.opensagres.xdocreport.document (so the ServiceRegistry call is in fr.opensagres.xdocreport.document). The Service implementation is in fr.opensagres.xdocreport.document.docx. a fragment whose has defined its frament-host as fr.opensagres.xdocreport.document.
So fr.opensagres.xdocreport.document and fr.opensagres.xdocreport.document.docx use the same class loader...so it works!
In XDocReport we wanted have a modular API reporting to manage :
any document kind (docx, odt, pptx...). And you can implement your own document kind if you wish and register it via javax.imageio.spi.ServiceRegistry.
any template engine kind (Freemarker, velocity...). And you can implement your own template kind if you wish and register it via javax.imageio.spi.ServiceRegistry.
any converter type (docx->pdf converter with POI+iText, docx->xhtml converter with POI, odt->pdf converter with ODFDOM+iText, odt->xhtml converter with ODFDOM...). And you can implement your own converter if you wish and register it via javax.imageio.spi.ServiceRegistry (ex: implement docx->pdf converter with docx4j+FOP, docx->pdf converter with JODConverter, etc).
As you have understood, javax.imageio.spi.ServiceRegistry works on OSGi context because we use OSGi fragment (share the same classloader) and not OSGi bundle. We have done this choice to manage non OSGi and OSGi context both with the same code.
We have decided to use OSGi fragment and not OSGi bundle because :
if we use OSGi bundle, we need to develop an OSGi Activator to register our discovery (in this context bundle, javax.imageio.spi.ServiceRegistry doesn't work).
if we use OSGi bundle, you need configure the start level for each bundles which register discovery.
The only disavantage to use OSGi fragment is that you cannot use in your OSGi container several version of XDocReport template, converter, document. But is it a good feature for XDocReport?
You must not that javax.imageio.spi.ServiceRegistry works with JDK5 (and JDK6). JDK6 provides java.util.ServiceLoader which is new clas to regsiter services as javax.imageio.spi.ServiceRegistry.
in XDocReport we wish to support JDK5+JDK6. XDocReport 0.9.8 used only javax.imageio.spi.ServiceRegistry. But it seems that Google App Engine forbid the use of this class (see our issue 132). So I have developped for XDocReport 1.0.0 JDKServiceLoader to manage with Java reflection both java.util.ServiceLoader and javax.imageio.spi.ServiceRegistry for JDK5 and JDK6.
Regards Angelo

How to import/use an exported bean from an osgi bundle into another osgi bundle

I am new to osgi and have very little experience with it. I have an osgi bundle which exports a bean as osgi service using in the config xml file. I want to use that service in another osgi bundle. Can anybody tell me how to do that? I am using maven and felix osgi.
It doesn't matter how the OSGi service is exported, using blueprint or smth else - since it is an OSGi service, your bundle can get it from the OSGi service registry.
For this you must:
Import its package in your bundle manifest, in order to declare the dependency.
You have to add
Import-Package: com.acme.theservicepackage
in META-INF/Manifest.mf
in your Activator class, you have to get the service from the service registry using your bundle context:
timeRef = bc.getServiceReference(TimeService.class.getName());
if (timeRef != null) {
timeService = (TimeService) bc.getService(timeRef);
}
Then you simply use the timeService (or whatever interface your service is using) by calling its methods, whatever they are.
There are many details here, you can use the helper ServiceTracker class instead, or blueprint, or declarative services... But since you seem to be new to OSGi, I have left it as simple as possible and have shown the most basic way to do it.
There are demos here for the basic OSGi services.
Do you want to use the service with blueprint? Your description "config xml" sounds a bit like it might be blueprint. In this case you can use
I have a full example on my website:
http://www.liquid-reality.de/x/DIBZ
The example shows how to export and import a service using blueprint.

Obtaining list of installed OSGI bundles at runtime

My application obtains class names from a properties file. Classes represented by these class names could reside in certain OSGI bundles unknown at advance so in order to instantiate them I firstly have to find which bundle these classes belong to. I'm thinking about getting all installed bundles from BundleContext#getBundles, this means I have to obtain reference to BundleContext in AbstractUIPlugin#start. But I'm not sure if holding reference to BundleContext is the right thing to do since it's should be used only in the start method. So I need advice from OSGI experts here about the alternatives to get list of bundles.
Any help would be greatly appreciated.
Regards,
Setya
This is not really how OSGi is intended. If a bundle has something to add to the 'global' context, you should register a service. So each bundle that has something to share can do that in its own start method.
Some other component (DS, ServiceTracker, Blueprint, something like that) can then listen to these events, and act accordingly.
This is really important, if you start manually searching through all bundles you completely lose the advantages of OSGi.
Like written before you should try to use services to achieve what you want. I guess you have an Interface with one or more implementations that should be installable at runtime. So if you control the bundles that implement the interface then simply let them install their implementation as a service by using an Activator or a blueprint context. You can use service properties to describe your implementation.
The bundles that need the implementation can then lookup the services using a service tracker or a service reference in blueprint.
If that is not possible then you can use the bundle context to obtain the running bundles and instantiate the classes but this is not how OSGi should work. You will run into classloading problems as the bundle that tries to instantiate the classes will not have direct access to them.
Your bundle gets control at start up through the bundle activator, or better, through DS. At that time it can register services with the services registry so others can find/use them.
The route your planning to go (properties that name classes) is evil since you undoubtedly will run in class loading hell. Modularity is about hiding your implementation details, the name of your implementation classes are such details.
Exposing implementation classes in properties files is really bad practice and it looses the advantage of modularity. It does not matter if another class refers to your implementation class or a property file, the problem is that the impl. class is exposed.
Unfortunately this model has become so prevalent in our industry that many developers think it is normal :-(
OSGi allows you share instances typed by interfaces in a way that allows the implementation class to only be known inside the module.

OSGi Declarative Service referencing non Declarative Service

I have a system declaring services "the old way", using activator methods.
Now I'm writing a new bundle using Declarative Services.
Is it possible to reference a service that is not published using the Declarative Services technique in my new bundle?
There is no "the old way" to publish you services into OSGi Service Registry. There is only one way with BundleContext.registerService(). You can do it manually from you activator, or Declarative Services / Blueprint engines can do it for you.
In your DS descriptor you just define references to services that are available in Service Registry.
Yes, it is possible. When you reference a service from a DS component, you don't need to worry about that service's internal implementation.
The other service may be another DS component, or it may be a Spring-DM component, or it may be published with explicit calls to the OSGi APIs. You don't care. It's just a service.

Resources