‘OSGi Demystified’ is a series of articles addressing common OSGi issues in CICS. We offer insight into OSGi, discuss best practices, and provide setup and configuration advice. This is the second in the series of section 2, to see the previous section discussing CICS bundles, Liberty bundles, and OSGi services, here’s the link to the first in the section link. In this section of articles we’ll address a number of common Java and OSGi class loader problems you might encounter in CICS OSGi and Liberty JVM servers. This follows on from OSGi Demystified: 2.3 – OSGi resolution. To catch up on this section, follow the link to the previous blog post.
- Closing words on the boot compatibility and how it works within CICS TS V5.3+.
- The affects of switching boot compatibility off.
- Conclusion to section 2 of the OSGi Demystified series.
Addendum – Boot Compatibility
From CICS TS V5.3, the OSGi runtime compensates for the lack of strict development tool dependency checking by performing a type of class loader delegation; affectionately referred to as ‘boot compatibility’. Boot compatibility instructs the Equinox framework to perform a last gasp delegation to the boot class loader. If the class is not found through the explicit dependency declarations (i.e. the Import-Package statements), then, and only then, will delegation to the boot class loader happen. Consider it a ‘get out of jail for a small fee’ option. The small fee is one of performance and of tolerance to improperly specified dependencies.
That said, if you have the freedom to make application changes, we suggest you turn OFF this mollycoddling behaviour by adding the following option to the JVM profile of your JVM server:
# Switch off OSGi boot compatibility so that it highlights when Import-Package dependencies have been omitted -Dosgi.compatibility.bootdelegation=false
What happens with Boot Compatibility OFF?
1) Nothing different happens? Put your halo on. Either your code doesn’t import any of the boot delegated packages, or you already added those dependencies to the Import-Package statement in your MANIFEST.MF. Consider yourself optimised.
2) Your bundle(s) failed to resolve. That’s a good thing, really! Now you can explicitly add the dependencies (indicated by the
NoClassDefFoundErrors) to your bundle MANIFEST.MF until it once again resolves and starts. Sit back, feel smug. Class loading will be more efficient, and your bundle’s interface is well-defined and more portable. The CICS OSGi default settings are no longer required to protect your application.
Of course there is a quicker eyeballing method. If you can view the import statements in the Java source, go ahead and determine whether all the packages provided from outside of your bundle have a corresponding Import-Package statement in the MANIFEST.MF.
While we’re still on the Import-Package soap-box, (and please don’t ever use Require-bundle, it is a legacy header which ties you to a specific bundle implementation losing flexibility and package granularity) we must draw attention to the version information on your Import-Package statement:
- Never omit the version qualifier, because you’ll get ‘anything’
- Never specify a single version, because it is interpreted by OSGi as a minimum and when an incompatible interface change comes along, you’ll walk right into it
- Always specify a version range up to; but not including; the next likely interface breakage
If you aren’t already familiar with OSGi semantic versioning please read about it, and you’ll see how it can be used to tolerate bug fixes (micro version changes), API additions (minor version changes) while protecting you against major version changes (Interface breakages).
A good example of how to give flexibility to your application is
Import-Package: com.ibm.cics.server;version="[1.0.0,2.0.0)". Such a version range tolerates newer versions of JCICS, while providing a heads up if IBM makes an incompatible change. In this syntax, version 1.0.0 and upwards are included – denoted by the square bracket, while version 2.0.0 is excluded – denoted by a round bracket.
In this series of articles we highlighted the differences between the
NoClassDefFoundError and the
ClassNotFoundException. We suggested probable causes of each failure condition, and provided the “Four Scopes of OSGi resolution” as a rule of thumb for fixing them.
We provided guidance on how to achieve stricter OSGi compliance and take performance advantages by explicitly declaring all of your bundles dependencies. Finally, strong hints were made that you should avoid dynamic class loading – there are better ways.