Bundle A depends on Bundle XStream.
However Bundle XStream also needs access to classes in Bundle A, otherwise I can't do object deserialization ala (BundleA.class)xstream.fromXml(xmlString)
Now what I did is to Import-Package in Bundle XStream on my BundleA packages and exported them in BundleA, but since BundleA uses XStream as well, Eclipse detects a "cyclic reference". It all seems to run fine, but I don't see the point of this Eclipse error then?
How else would I solve this in osgi?
Generally, you should try to get a clear client-server package relation among your bundles. So if possible at all, you should get rid of the cyclic reference. In your situation that is possible.
In contrast to what you indicate, your XStream bundle is able to do de-serialization of objects from another bundle if you are able to tell the functionality to use a different class loader for loading the classes indicated in the stream. Since it seems you are using XStream, you can use:
xstream.setClassLoader(bundleAClassLoader);
where bundleAClassLoader is a class loader that has access to your domain classes (the class loader of bundle A). The Import-Package for the XStream bundle is in that case not necessary.
Related
I have two OSGi bundles A and B. Both are created with the API/implementation model. Both the bundles are activated through Blueprint mechanism. Both the API bundles export the interfaces whereas the implementation bundles don't export anything. Only A has dependency on B.
My issue is, I want to pass a resource file name (xml file) that resides in bundle A to Bundle B (after I get hold of B using the BundleContext.getServiceReferences() method) and then load the resource in Bundle B and process it. How can I achieve the same and is it even doable?
I read the following post and Neil Bartlett's answer suggest it should work.
Access resources in another osgi bundle?
However, when I read about getEntry, findEntries, getEntrypath methods, they don't talk about other bundles (or I misunderstood it). They talk only about fragments.
My question is, can I achieve what I am looking for using any of the above three methods? If so, can you please point to some other thread that has the answers or some sample code?
If this is not possible, can I use fragment bundles(containing only resources)? Again Bundle B is more like a provider where it can take any resource file and process it and satisfy clients requests (Bundle A). So even if I want to use bundle fragment approach, I need B to load the fragment bundle (only on needed basis) specified by clients (say they give the fragment bundle symbolic name). Please provide suggestions or other posts related to similar issues or any samples.
The easiest way to access a resource in a bundle is to use the classLoader of the bundle. In bundle A you get service MyService and do:
InputStream is = this.getClass().getResourceAsStream("myresource.xml");
MyService service.doSomething(is);
or if you prefer a URL:
URL url = this.getClass().getResource("myresource.xml");
MyService service.doSomething(url);
This works as we already resolve the resource before making the call. If you want to give the service just a relative path then you additionally need to give it the classLoader to get the resource from.
ClassLoader bundleALoader = this.getClass().getClassLoader();
MyService service.doSomething(bundleALoader, "myresource.xml");
Keep in mind though that this.getResource() will lookup the resource relatively to the package of "this" while classLoder.getResource() will lookup from the top of the name space.
Btw. These concepts also work fine outside of OSGi. The difference is only that in OSGi you have to make sure to use the classLoader that has visibility of a resource while outside there is often only one classLoader that sees all resources.
Getting an issue where class A cannot be cast to class A in osgi. Point is this class A is not being exported in any other bundle as well as where it is created. In the pom for exported-package it is mentioned "!A" so A is not exported. Still we get the issue. A re-install of the bundle works though. Cant recreate the issue and then suddenly it is back again . Any ideas.
The class is an entity class and internal - not in any other project
In maven-bundle-plugin we have
<Private-Package>
com.xxx.yyy.entity.*
</Private-Package>
<Export-Package>
!com.xxx.yyy.entity.*
</Export-Package>
We had similar issues when we used technologies that had String-Class caches without direct wiring to the bundle of the Class.
Let's say there is Bundle A and Bundle T (technology). Bundle A is updated and but the classes that were loaded during the first time Bundle A was started are still in the cache of Bundle T.
This can become really magical if there is a technology in the OSGi container that updates bundles during their restart. One typical case is when a technology wants to do bytecode manipulation on classes. It implements a Bundle Weaving Hook, but it must update all of the relevant bundles that were started before the magical technology bundle to be able to catch the classloadings. An example of such magical technology is Apache Aries Proxy.
Btw.: A stacktrace and some source code would help a lot to see in which technology the issue appears.
I am learning osgi framework. It says osgi works on strict class loading environment. I am unable to get what is Strict ClassLoading. Please help i am unable to get the concept
Thanks
Strict classloading means that a module (bundle) has to explicitly specify what it needs. In OSGi this is done using Manifest headers. Import-Package lists the packages and their version ranges the bundle needs and Export-Package lists the packages and their versions the bundle offers. In the OSGi runtime you then have a classloader per bundle that wires the bundles according to the exports and imports.
You should not define these headers by hand though. There is a nice tool named bnd or in maven the maven bundle plugin from felix which does most of the work for you. In this tutorial you find how this works in practice:
http://www.liquid-reality.de/x/DIBZ
You will see that I actually do not define to much by hand there. So build the code and into the meta-inf/Manifest to see what it does.
strict class loading environment means that the appropriate headers of the class need to be specified. for example the class path and the import-package
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.
I have a class with dependencies which I want to hot deploy without restarting the dependencies. The class has an interface but there's only one concrete implementation.
Initially I created a single bundle with exported the interface and registered the implementation using activator and implementation classes which were not exported. However, if I update the bundle, bundles which use the registered service get restarted after the update when PackageAdmin#refreshPackages is called (this is automatic when using fileinstall).
I have fixed this by creating a separate api bundle.
Is this the best way to achieve this?
Would you ever have a bundle which exports its api and includes the implementation in the same bundle. As far as I can see any give bundle would either export all its classes or no classes. What am I missing?
It is definitely a best practice to separate API bundles from their implementations in OSGi. If you do this, then any bundle that uses the API only needs to import classes from the API bundle, which can allow you to change implementations at runtime without restarting your dependent bundles.
Ideally your implementation bundle would implement the interface and export implementation as a service on the API provided interface. This allows the client bundles to utilize the service without referencing the implementation bundle.
In Apache Sling we do both: major APIs are in their own bundles, but for smaller things like extensions or optional components we often provide the default implementation in the same bundle as the API.
In the latter case, you can still allow for those default services to be replaceable, for example using service ranking values when you want to override them.
A bundle does not have to export all its classes, our bundles which include default services export just the API packages (and the default implementations are in different packages, obviously).
Unless there is a hard requirement to be able to replace implementation at runtime, without restarting client bundles, I would personally advocate keeping the explicit dependency link between API and implementation (either by including impl classes in the API bundle, or by having the API bundle import implementation packages from the impl. bundle).
The pb with the patterns suggested above is that they break the dependency chain. The benefits of dependency management go far beyond simple API compatibility, they also include ensuring predictable, consistent runtime behavior, as well as compatibility with the deployment ecosystem, and all of those require managing the implementation dependencies.