Features Download

From: Steven E. Harris <seh-VmQCmMdMyN0AvxtiuMwx3w <at> public.gmane.org>
Subject: System and context class loaders (was: How to use launcher.jar in 3.3.0-M7?)
Newsgroups: gmane.comp.ide.eclipse.equinox.devel
Date: Thursday 24th May 2007 06:01:07 UTC (over 11 years ago)
Thomas Watson  writes:

> To do this the the system.bundle must export the packages available
> from the outer execution environment.  This can be done by install
> system.bundle fragments which export additional packages from the
> execution environment or by setting the
> org.osgi.framework.systempackages Java property.  But the only way
> the framework can actually load the classes from these additional
> exported packages is if the framework's classloader has access to
> the classloader of the outer application.  There is a new option
> added to 3.3 to specify that the current classloader should be used
> as the parent classloader of the framework classloader.  Setting
> osgi.frameworkParentClassloader=current will set the framework's
> parent classloader to the same classloader which loaded
> org.eclipse.equinox.launcher.Main.

I'm quoting this paragraph at length here because it may pertain to my
question, but I'm not sure.

Today I set about trying to configure the java.util.logging.LogManager
to use a specific configuration properties file. One can override the
default configuration initialization in two ways:

o Set the system property java.util.logging.config.file to point to a
  properties file, which must be an absolute path, or a relative path
  resolved against the current working directory.

o Set the system property java.util.logging.config.class to name a
  class that will be default-constructed, at which point an instance
  of this class can initialize the LogManager's globally accessible

I'd like to use a logging configuration file located in the OSGi
framework's "configuration area", exposed both by the system
properties osgi.configuration.area and osgi.sharedConfiguration.area,
as well as the org.eclipse.osgi.service.datalocation.Location service.

To do so, I have to wait until at least the first pass of framework
initialization completes to have these properties set to the right
values. I figured I'd set java.util.logging.config.class property to a
special class that, upon construction, reads the
osgi.(sharedC|c)onfiguration.area property, and loads a file located
in that directory. Writing that class was easy, but getting the
LogManager class to find it proves to be more challenging.

The LogManager.readConfiguration() method tries to load the class in
two ways:

o ClassLoader.getSystemClassLoader.loadClass(name)

o Thread.currentThread().getContextClassLoader().loadClass(name)

I put my configuration class in a framework extension bundle, but
discovered that the extension bundle winds up on neither of these two
class loader's paths.

As a rather baroque workaround, I set up an Equinox hook configurator
and, in its addHooks() method, pushed the current class loader into
the thread's context class loader slot, forced the LogManager to pass
through its readConfiguration() method, then restored the context
class loader to its original value. I'm not convinced all that should
be necessary.

Is there some way to make a class in a bundle visible to either the
system class loader or a context class loader (without manually
manipulating the context class loader)?

I see that there is an "extension" parameter one can supply to the
Fragment-Host header, with values "framework" or "bootclasspath",
mentioned in section 3.15 of the OSGi R4 core specification. However,
there's not discussion in 3.15.2 to clarify whether either of these
two directives can arrange for a class in a bundle to be visible to
the loading approach used by LogManager (system class loader and
thread context class loader).

Does the osgi.frameworkParentClassloader property mentioned above play
into a possible solution?

Steven E. Harris
CD: 4ms