When a bundle is updated (say to fix a bug), what happens to other bundles that are currently using the one being updated?
Say that there are two bundles service and dao. Say that classes in service bundle are using classes in dao bundle when I issue command to update dao layer. Will the class in service layer using dao code get an exception?
Thanks for your response.
I meant to say updated with the same version.
until a bundle refresh occurs which includes the dependent bundle.
Bundle refresh operation is invoked by the user updating the bundle, right? Say that when user invokes refresh to update dao bundle, a class in bundle service invoked a method on a class in dao layer... what happens in this scenario?
I found this blog post helpful: http://solutionsfit.com/blog/2008/08/27/osgi-what-modularity-can-do-for-you-part-1/
From the post:
If we simply replace the bundle with a bundle that includes the fix, the container will unregister the old bundle and register the new bundle. The proxy can then handle the reference shuffling and resume the service invocation. This interaction will be almost instantaneous. Your customers will be completely oblivious to what has happened and you just saved your company a substantial amount of money (do I hear bonus?).
In this blog post, the call to authorizePayment() was put on hold until the updated bundle is available. What happens if the control is within the authorizePayment() method when bundle refresh happens?
How does OSGi work? OSGi is a set of specifications that define a dynamic component system for Java. These specifications allow for a development model in which an application is composed of several components, and then packed into bundles. These components communicate locally and through the network via services.
OSGi facilitates creating and managing modular Java components (called bundles) that can be deployed in a container. As a developer, you use the OSGi specification and tools to create one or more bundles. OSGi defines the lifecycle for these bundles. It also hosts them and supports their interactions in a container.
OSGi is a Java framework for developing and deploying modular software programs and libraries. Each bundle is a tightly coupled, dynamically loadable collection of classes, jars, and configuration files that explicitly declare their external dependencies (if any).
Each OSGi bundle is a tightly coupled, dynamically loadable collection of classes, jars, and configuration files. Each OSGi bundle explicitly declares the packages they provide and the packages they require. By enforcing explicit declarations, the OSGi framework can provide a powerful component model.
Bundles have 2 kind of dependencies:
Services are easy to withdraw because that is intrinsic to their design. Wires are harder because they are intricately woven in your objects and those objects are not aware of the dynamics. So when you install a new bundle, the old bundles stay as they are, your objects are not updated and the updated bundle still provides its wires as a zombie.
When you call refreshPackages the framework looks at those dependencies and finds the bundles that refer to those zombies. Every zombie is then stopped. The contract for a bundle is that it should cleanup. We help the bundle by doing a lot of cleanup for you, but some things are very bad, e.g. storing references in statics of other bundles or forgetting to stop threads that were started. Other bundles that depend in other ways on those bundles get notified of the bundle stopping so they can also clean up any references. After the bundles are stopped, the bundles are unresolved and then resolved again against the new bundles.
For real OSGi bundles the cleaning up is natural and not really visible in your code (as it should be). It is well supported by the tools like Declarative services, iPOJO, dependency manager, Spring, Blueprint, etc. The magic is focus on the µservices model and not dong class loading hacks.
Why are we not refreshing automatically? Well, we once did but refreshing is disruptive. In many cases you need to update multiple bundles. Having this disruption after each update would be unnecessary painful. That is, after an install or update you should ALWAYS do a refresh but you can bracket a number of installs/updates.
When you update a bundle, using the OSGi 'update' command, it is most likely to have other dependent bundles that are relying on it and already capturing a set of loaded classes from the old version of this bundle. A situation that typically conforms to the problem you described in your question.
In order to avoid possible inconsistency between the different versions of the classes enfolded by this bundle, the OSGi container decides to temporarily hide the new version of the updated bundle's classes from the outside world. You can think of it as kind of keeping the updated classes in isolation from the other bundles -momentarily-.
The point here is that the OSGi container can’t just start loading classes from the new version of the target bundle, because the dependent bundles would end up seeing old versions of the classes they already loaded, mixed with new versions of the same classes that were loaded after the update, which would incorporate an inconsistency that would result in an uncontrollable mess. The same goes for the bundle Uninstall, the bundle is removed from the installed list of bundles, but it is not removed from memory. It shall be kept around so that dependent bundles can continue to load classes from it.
So you can think of the 'update' command, as introducing a new version of the same bundle, to be only supplied to dependent bundles that are yet to come, -which are not yet there at the time of the update-. While the old version -that existed before the update-, remains in memory in order to assure backward compatibility and avoid any possible disruption to existing bundles that have already started to depend on the updated bundle.
Note, that the old versions are only kept in memory, which means that a restart to the server will result in eradicating all these old versions and bring the latest version to the table. This makes perfect sense, because there will be no need for backward compatibility, simply because all bundles are now starting at the same time..
What happens next, is that you have to explicitly invoke the 'refresh' command on specific bundles, -those which are depending on the updated bundle-, or instead you can choose to run the 'refresh' command without specifying a specific bundle, meaning that all bundles will be blindly refreshed. The 'refresh' command forces the rebuilding of the dependency tree of the target bundles, and coerce their class loaders to start loading their required classes from scratch.
Only then dependent bundles will start to see the changes you have made to the code of the classes living in the bundle that has been updated.
The rule is that
Existing resolved bundles already importing an older version of a class won’t be automatically rewired to the new bundle unless they’re refreshed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With