Configuring OSGi package imports in CICS Java applications

The OSGi framework provides a comprehensive set of features for both application developers and JVM runtimes to control application modularity and declaration of dependencies.

Java™ applications that are deployed into CICS® JVM servers need to be packaged as OSGi bundles. In the OSGi JVM server environment Java class loading is controlled by the embedded OSGi framework. For this reason, Java classes are not loaded by the traditional CLASSPATH configuration, instead, each OSGi bundle has its own class loader and is used in combination with the OSGi framework to resolve any dependencies. Dependencies are typically provided by other OSGi bundles, or from the underlying JRE by virtue of the OSGi system bundle.

Code that requires access to a Java package that is not included within its own OSGi bundle must explicitly import the package as part of the OSGi bundle definition. Imported packages are specified as a comma-separated list on the Import-Package statement in the OSGi manifest. Conversely, a bundle that is the provider of these required packages must explicitly export the package from its own OSGi bundle definition. Exported packages are listed on the Export-Package statement in the provider OSGi bundle manifest. When both OSGi bundles are deployed into the environment, the dependency can be resolved by the OSGi framework at runtime.

Where are classes loaded from?

In an OSGi environment classes are loaded from the following locations, in search order:
  1. The core JRE, or java.* packages
  2. The parent class loader from the JVM boot class path (boot delegated packages)
  3. Imported packages from other OSGi bundles, or from the OSGi framework system bundle
  4. Required bundles (though best practice dictates Required bundles should be avoided)
  5. The current OSGi bundle's class loader (including anything on the Bundle-classpath)
  6. Bundle fragments
  7. Dynamic Imports

The JVM boot class path

Any java.* packages must be loaded by the JVM itself due to security restrictions in Java. Therefore, an OSGi bundle must not declare imports or exports for java.* packages - doing so is an error and installation of the bundle will fail. Class loading of java.* packages is implemented by delegation to the parent class loader of the JVM (referred to as boot delegation). Conversely, all other required packages such as com.ibm.* or Java SE components such as javax.* or org.xml.sax must be explicitly imported in the OSGi bundle manifest by using the relevant Import-Package statements.

The OSGi framework

The system bundle is a special bundle that represents the OSGi framework and is used to export a variety of system components. Export definitions from the system bundle are treated like regular bundle exports - they can have version numbers and are used to resolve import definitions as part of the normal bundle resolution process. The advantage of this approach is that other bundles can provide alternative (newer) implementations of the same packages should it be necessary. By default, all javax.* packages are exported by the system bundle and so must be imported by using Import-Package statements in the application's bundle manifest. In addition, the CICS JVM server extends the list of exported system bundles by ensuring that key packages from the z/OS Java runtime are added to the default list exported by the system bundle. Examples of classes in this category are com.ibm.jzos.fields.ByteArrayField which is part of IBMJZOS and javax.resource.cci.Record which is part of JCA (Java Connector Architecture). Exports from the system bundle can be extended by adding additional packages to the system property org.osgi.framework.system.packages.extra. Note, all additional packages must already be available from the JRE classpath before they can be exposed by the OSGi system bundle.

If you need to determine what is exported from the system bundle, this can be queried by configuring the OSGi console using the following JVM server profile options, where port is a free TCP/IP port.
OSGI_CONSOLE=true
-Dosgi.console=port
-Dfile.encoding=ISO-8859-1
After restarting the JVM server, you can connect to this port using telnet and query the system bundle with the bundle 0 command, which produces a detailed listing:
>bundle 0
....
 Exported packages
   org.eclipse.core.runtime.adaptor; version="0.0.0"[exported]
   org.eclipse.core.runtime.internal.adaptor; version="0.0.0"[exported]
   org.eclipse.equinox.log; version="1.0.0"[exported]
.....
Figure 1. OSGi package imports and class loaders
OSGi class loaders

Imports from other bundles

OSGi bundles that are installed into the OSGi framework can export packages for import by any other installed bundle. In the CICS JVM server environment, the com.ibm.cics.server bundle is installed by CICS and provides the JCICS classes which wrapper the CICS API. In addition, if a third-party component is available as an OSGi bundle, it can also be installed as either:
  • A middleware bundle using the JVM server OSGI_BUNDLES option. This is the usual approach for shared middleware components that do not need to be versioned without restarting the JVM server.
  • An OSGi bundle deployed within a CICS bundle. This option is useful for a modularized application with separately versioned components that do not need to be shared between applications. This is because the same version of an OSGi bundle cannot be installed more than once into the OSGi framework and it is usual for Java applications to be deployed in a single CICS bundle package to simplify deployment. If multiple CICS bundles contain duplicates of the same version of an OSGi bundle, then some of the CICS bundles will fail to install.
Note: If your application needs to import packages from a JAR that is not an OSGi bundle, then you can use the wrapping or injection techniques to create an OSGi bundle from the JAR, and export the required packages. You can then use either option in the list above to use this new OSGi bundle in your application. For more details on wrapping and injection refer to section 10.4 in IBM Redbook CICS and the JVM server – Developing and Deploying Java applications.

Imports from the current bundle

All packages in the same OSGI bundle as the application are available to the bundle class loader. If your application requires access to classes from a JAR that is not OSGi enabled then this can be added to the bundle classpath using the Bundle-ClassPath: statement in the OSGI bundle manifest. This limits class loading of a JAR to the deployed bundle, and prevents sharing the JAR outside of the scope of the OSGi bundle.

Note: Since CICS TS V5.3, the OSGi framework defaults to using a last resort boot delegation strategy for packages not found through any of the above OSGi bundle dependency resolution mechanisms. This means that packages other than java.* can also be loaded from the JVM boot classpath once all other bundle class loaders have been searched. This behavior is controlled via the osgi.compatibility.bootdelegation system property and allows the OSGi runtime to be more tolerant if explicit dependencies were overlooked at development time. For strict OSGi compliance set this option to false and ensure all the packages used in your OSGi bundles are explicitly declared in the bundle manifest. For further details refer to JVM system properties.