Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "Context Class Loader Enhancements"

 
Line 32: Line 32:
  
 
== Requirements ==
 
== Requirements ==
 +
 +
# The solution MUST reduce or illiminate the need for code packaged in a bundle to call Thread.setContextClassLoader while calling library code
 +
# Library bundles MUST be able to use the context class loader to access classes needed by the library
 +
# other reqs ...
  
 
== Technical Solution ==
 
== Technical Solution ==

Revision as of 17:29, 12 September 2006

Overview

This design defines the behavior of the context class loader in the OSGi Framework. Many java libraries exist that use the context class loader. In an OSGi environment the context class loader is not defined. This leads to class loading issues when trying to package such libraries into bundles.

Terminology

Context Class Loader

A context class loader is associated with a Thread. This class loader is provided by the thread creator to code running in the thread for the purpose loading classes and resources. This class loader is useful for loading classes and resources that are not always available to the class loader which loaded the code running in the thread.

Context Switch

For the purpose of this design a Context Switch is defined as the point in an execution sequence when a component boundary is crossed from one component to the next.

Problem Description

Most OSGi-biased developers will concede that the majority of java libraries out there are not currently shipped as OSGi bundles and are not aware of the Modular Layer in the OSGi Framework. Many existing java libraries are designed to run inside a container (J2EE container, Applet container etc). Such containers explicitly define execution boundaries between the various components running within the container. The container controls the execution boundaries and knows when a boundary is being crossed from one component to the next.

This level of boundary control allows a container to switch the context of a thread when a component boundary is crossed. Typically when a container detects a context switch it will set the context class loader on the thread to a class loader associated with the component which is being entered. When the component is exited then the container will switch the context class loader back to the previous context class loader.

The OSGi Framework specification does not define what the context class loader should be set to and does not define when it should be switched. Part of the problem is the Framework is not always aware of when a component boundary is crossed. For some operations the Framework is aware of component boundaries, for example, when calling out to BundleActivators and event listeners. Switching the context class loader when calling out to these types of objects will not solve a large number of usecases.

Consider the following example:

  • Bundle W exports a package “some.foo.library”. This package contains code which uses the context class loader to load additional classes. Imagine it has some SPI like behavior where it loads classes based on some properties file similar to how javax.xml.parsers package works.
  • Bundle X exports a package “some.foo.stuff”. This package contains a service interface “some.foo.stuff.BarService”.
  • Bundle Y imports the “some.foo.stuff” package and registers a “BarService” implementation with the service registry.
  • Bundle Y also imports the “some.foo.library” and expects the exporter to be able to load classes from bundle Y. Bundle Y uses the “some.foo.library” package in its implementation of the “BarService”.
  • Bundle Z imports the “some.foo.stuff” package and gets the “BarService” from the service registry and uses it.

In this scenario imagine the framework sets the context class loader to Bundle Z’s class loader before calling its BundleActivator to start the bundle. In the BundleActivator of Z it gets the BarService if it is available and start making calls to it. At this point code in Bundle Y will get executed because it contains the implementation of the BarService. The implementation of the BarService then uses the package “some.foo.library”. This will cause the code in Bundle W to run that uses the context class loader. At this point the context class loader will be set to Bundle Z’s class loader. This class loader does not have access to the content in Bundle Y and will result in Bundle W’s library code not being able to load classes from Bundle Y.

As a work around to this issue Bundle Y could wrap all calls to code in the package “some.foo.library” with context class loader switches, but this puts a great burden on any developer using the package “some.foo.library”. This also calls into question the purpose of the Framework switching the context class loader at all (to Bundle Z’s class loader in the example above). Any time more than one component boundary is crossed the original context class loader will likely not be the one that is needed.

This design specifies a behavior for the context class loader that should help solve some of these issues.

Requirements

  1. The solution MUST reduce or illiminate the need for code packaged in a bundle to call Thread.setContextClassLoader while calling library code
  2. Library bundles MUST be able to use the context class loader to access classes needed by the library
  3. other reqs ...

Technical Solution

Back to the top