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
Related
I am trying to brand a Apache Felix web console, but I am not able to find resource for the same. As per Apache Felix website,
Branding for the Web Console can be provided in two ways: By registering a BrandingPlugin service or by providing a branding properties files. The Web Console uses the branding from the BrandingPlugin service registered with the highest ranking.
But I am not understanding how to register a BrandingPlugin service? What and Jar files should I put? Is there any guidance or tutorial available for the same? If yes, can you guide me in this?
Since I am totaly getting confused with Apache Felix's website, since those documents are not clear on this.
You may find it helpful to do some background reading on OSGi services. OSGi provides a service registry, and most interactions in an OSGi environment are handled by registering and consuming services. It doesn't matter what jar file you put the service in; the only thing that matters is the interface name its registered under.
You can register services in lots of ways; programmatically from a BundleActivator, using Declarative Services (also known as SCR), and using Blueprint are some of the most popular patterns. Which one is easiest for you depends on how you're building your jars and what other OSGi facilities you're using. If you've already got an Activator the programmatic route may be the quickest way to get started; if you're using the Maven bundle plugin you may find SCR annotations easiest.
What you'll need to do is include an implementation of the 'BrandingPlugin' interface in a jar which gets started by your OSGi runtime, and register that implementation as an OSGi service. Once you've done this you should see that the Felix console discovers your BrandingPlugin implementation and uses it.
We run Restlet 2.1 in an OSGi environment (Equinox) as bundle (ie. not as library within a bundle). The problem is that the Restlet Engine does not detect helpers (like converters) that are provided by Restlet extensions. Specifically, the EngineClassLoader#getResources() call does not return any result. The extensions are also deployed as OSGi bundles in the target platform.
Is automatic converter registration actually supposed to work within OSGi environments?
In fact, Restlet supports such feature thanks to a dedicated activator (see the Activator class in the package org.restlet.engine.internal).
This activator introspects bundles to find out the following things:
servers corresponding to registered servers
servers corresponding to registered clients
authenticators corresponding to registered clients
converters
Be aware that to use this feature, we must use the OSGi edition of Restlet since it's the only that has the MANIFEST file of the org.restlet bundle with the activator class specified. Otherwise you don't have to care about the bundle loading order...
Hope it helps you.
Thierry
Unless the Restlet-bundle explicitly imports the packages that contain the extensions (and I doubt it does, and it shouldn't), it wouldn't be able to load them, because bundles have isolated class-spaces.
A possible solution would be to provide the extensions as fragments attached to the Restlet-bundle. Thus, if you make it use the bundle-classloader (the documentation says this can be done by setting the Engines classloader), it would be able to load classes from the fragments.
Indeed it doesn't quite work for OSGi, as it depends on the ability to see the entire class space.
The way to do this in OSGi would be to use the service registry for the extensions, but that only works for OSGi aware libraries.
There is some help on the way: In the recently released OSGi 5 (Service Loader Mediator) there will be support to 'bridge' META-INF/services (I don't know if Restlet uses those, though) onto OSGi services, so 'legacy' libraries should work well within OSGi.
There is an implementation in Apache Aries called Spi-Fly. I looked at it briefly a while back. It might do the trick for you, it might not.
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.
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.
As an OSGi newbie, I'm trying to wrap my head around the boundaries of the OSGi runtime. My app, which is not build on OSGi, i.e. it's not running in an OSGi container, starts an OSGi container into which we deploy OSGi bundles at run time. Some of these bundles register services. Later, in our non-OSGi code, we obtain those services and use them.
I'm having trouble wrapping my feeble mind around the OSGi boundaries here. To be specific, when I obtain a service and invoke one of its methods, can I assume that all of the subsequent execution is executing within the OSGi container (Felix)? In other words, are dependencies in that code resolved via the OSGi modularity mechanisms? Or did I lose that OSGi management because I am using the service from non-OSGi code?
If my question seems founded in obvious mistaken assumptions about OSGi, please feel free to point them out.
Chad, to more effectively answer your question, I'd like to know a few things:
1) How exactly are you getting the service reference from an external application?
2) Is the external application a stand-alone application, or is it inside of a different container? If so, there are ways to make that happen.
The question you pose is interesting. Lets put it into a context. Lets assume you are able to get a reference to an OSGi service from Felix by an external application. When you use this service, you will be interacting with it via an interface. In that interface in OSGi, you will have import statements referenced which will be used in the method signatures of the interface and also in any final attributes. These import statements will have thier matching dependant libraries defined in your pom.xml file.
In order to use the service by an external application, you will need to publish an API ".jar" file that will contain the interface, and will reference the interfaces' dependancies. Your external application will need to use that API, and will likely have it assembled into your .war, .jar, or .ear file's lib directory. Because of this, none of your external application's dependancies can conflict with your API dependancies.
As long as you can use the API, then you're right, none of the SPI's dependencies matter. You can use Spring 3.0.4.RELEASE in your external app and still use Spring 2.5.6.SNAPSHOT in your OSGi application. As long as the API doesn't have any dependancies that conflict with the external application, you should be ok. The trick here is that you need to put your interfaces into a minimal .jar file as your API, and then put your implementation details into an SPI. Your external ap will use the API, and inside OSGI, you will use both the API and SPI.
Please let me know if this helps.
If you can get the service, then the dependencies are satisfied by definition, because bundles cannot provide services unless their dependencies are satisfied. Executing services on the outside doesn't really change anything.