Recently I came across an issue where I had to refresh bundle A whenever bundle B is updated.
Would it be possible to refresh bundle A on B's activator?
Is it considered a good practice?
Any other suggestions on how to approach such a problem?
It would not be good practice to refresh bundle A in bundle B's activator since you couple them directly.
Bundle A must have a dependency on bundle B. After updating B, you can refresh bundle B which will also refresh B's dependency closure which should include A.
Related
I am reading "OGSi in Action" where in an interesting comment has been made :
"The module layer uses the metadata in bundles to make sure all their dependencies are satisfied before they can be used. This symbiotic relationship creates a chicken-and-egg situation when you want to use your bundles; to use a bundle you have to install it, but to
install a bundle you must have a bundle context, which are only given to bundles."
The book goes to great length in explaining bundle dependency resolution , but the "chicken and egg" scenario described above hasnt really been explored further. To install a bundle , BundleContext is needed, which is only provided to bundles. So who created the first "bootstrapping" bundle ? Is this contained in the "shells" that are provided (using packageAdmin?) ? PackageAdmin has
Bundle getBundle(Class clazz);
and Bundle can provide the BundleContext, but the bundle has to be installed first ... and so on !!
How does this work ?
See the Framework Launching API which provides the launcher with access to the system bundle's Bundle Context to install the "first" bundles.
From the javadoc of Bundle.getBundleContext():
If this bundle is not in the STARTING, ACTIVE, or STOPPING states or
this bundle is a fragment bundle, then this bundle has no valid
BundleContext. This method will return null if this bundle has no
valid BundleContext.
I do not know what the writer of the book thought about. If you install a bundle programmatically, you install it via the bundle context of other bundle.
With all my respect, I think this paragraph is wrong. This "chicken and egg" philosophical question could be raised in case of the system bundle. However, I do not think that answering the unnecessary question would give a better understanding for the reader, who wants to get started with OSGi.
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.
I meet a big concern, I have several bundle.
As
bundlecore
bundleui
bundleaddoncore
bundleui needs bundlecore,
bundleaddoncore needs bundlecore
When I update bundlecore with karaf, I noticed that bundleui and bundleaddoncore still using the old version? I must restart Karaf? Is this normal? if so what is the right way to recharge the dependent bundle?
No, you don't need to restart Karaf this is typical for OSGi. The Other bundles still use the old services or reference the "old" classes. After a bundle update you need to refresh the depending bundles, only with this your bundles do get resolved again and therefore use the new bundle.
To do so you either call refresh or just refresh in the Karaf console.
As the title suggests, I'm having problems with OSGI + Spring DM.
In my project design, i have a bundle A that requires a service svB and exports service svA. Bundle B requires svA and exports svB (among other things, of course). This seems to be causing a deadlock, as it appears both bundles are waiting for the other to go online. Is that sort of deadlock possible with Spring DM? Is there a solution to this?
This doesn't sound like a problem with Spring-DM, rather you have set yourself up for this deadlock: A depends on B, B depends on A, thus no-one can get any work done. To break out of this, you probably need to change your design, and enable either one of A or B to start without the other. Meanwhile, the other one should have some lazy-loading logic built into it (this would be your job) and continue it's start-up sequence when the other one has come online on it's own.
With OSGi Declarative Services, you are able to declare a dependency on a service but allow it to be absent at the time you are going to start (do this using the cardinality option.)
I'm having a problem discovering services that are provided by some OSGi bundles that are not being activated. Let me describe the situation:
Bundle A defines interface X
Bundles B, C, and D provide services that implement interface X
These bundles' services are registered via Spring DM, so they are only created when the bundle is activated and Spring DM initialized the application context defined in the bundle
Bundle A is activated and at some point asks the service registry for services for interface X. It doesn't find any, because bundles B, C, and D haven't been moved into the ACTIVE state (they are only RESOLVED).
I cannot seem to get bundles B, C, or D to start, and therefore register their services. Forcing them to start by adding them to the config.ini is not an option, because there can be any number of bundles that are installed in the application (via an Eclipse p2-like update mechanism) that implement interface X.
The application is an Eclipse 3.5-based RCP app, using Spring 2.5.6 and Spring DM 1.2.1.
How do I force these bundles to be activated?
What you really have is a dependency hierarchy problem, your proposed hacky solution is really just a band-aid over the underlying issue.
What you should really consider is the architecture of your system, as effectively what you have is a circular dependency (re: discussion in comments your original post). You have (like it or not) A requires services from (and in some sense depends on) B and C. Meanwhile, B and C directly depend on A, and as such, cannot start until A comes up.
In the best case, you can write code in B and C to listen for the existence of A, but this at best masks (as I mentioned) the underlying issue. What you should really consider is splitting A into two bundles, let's call them A1 and A2.
A1 should provide the interface which B and C require (depend on). A2 should have listeners for the services B and C depend on. At startup, if B and C are required services, A1 must be run, but A2 may start any time later, and everything should work.
I think I've found the solution to this problem, though it feels a bit hackish.
I ran across this thread where Adrian Colyer implied that an external "bundle watcher" could be responsible for activating bundles when they are installed into the framework.
So, my solution was to:
Add a custom header to bundle B, C, and D's respective manifests, e.g., "MyApp-AutoStart: true"
Create a bundle listener that responds when a bundle is moved into the RESOLVED state, and looks for the header
If the header's value is "true," the bundle listener calls bundle.start()
Using this method, the bundles I want to be started are started without having to resort to using config.ini, and they can come and go as they please, but their services are available when queried.
Also have a look at felix fileinstall, which watches a directory for bundles and automatically installs and starts them. When a file is deleted, the bundle is stopped and uninstalled as well.