[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[equinox-dev] Re: Recipe to get extension bundle classes on the class path

Simon Kaegi <Simon_Kaegi@xxxxxxxxxx> writes:

> Rather than creating a custom LogManager and setting the two
> properties could you instead just use the default LogManager
> implementation and call LogManager.readConfiguration(InputStream)
> using a file you located in an Activator?

Yes, I've considered doing that, as it doesn't rely on any class
loading magic to work properly. Maybe it's just aesthetics that have
kept me from going this way, as it differs somewhat from the logging
system's intended customization points to provide the base, default
configuration.

And one solution is a subset of the other. Note that /within/ a class
nominated by the java.util.logging.config.class property one does the
same work: read the framework property, look for a file, and hand the
stream over to LogManager.readConfiguration(). The difference here is
that the first call to LogManager.getLogManager() causes LogManager to
go through its default initialization, checking the [...].class and
[...].file properties first. This means that my "in-OSGi"
configuration won't be the /default/ logging configuration; it can
only layer over whatever default initialization occurs by way of the
[...].class or [...].file properties. That's why I was trying to /be/
that first class used as the default initialization.

> If you're using the TCCL approach to load the class then
> ContextFinder should be sufficient. You shouldn't have to mess with
> anything else.
>
>> [...]
>>
>> > ContextFinder will load classes from the first bundle on the stack
>> > which should be your bundle that holds the implementation so it should
>> > just work.
>>
>> Does this apply to fragment bundles as well (specifically framework
>> extension bundles)?
> Yes.

I just tried it again, and it does not work. The setup is as follows:

o The framework calls on my hook configurator's addHooks() method.

o In that method, I call

    java.util.logging.LogManager.getLogManager();

o Note that the java.util.logging.config.class property names a class
  of mine in the same bundle as the hook configurator.

o java.util.logging.LogManager calls its own readConfiguration()
  method, consulting the system class loader, which fails.

o java.util.logging.LogManager.readConfiguration() then consults the
  TCCL, which appears in my debugger as follows:

    TCCL: sun.misc.Launcher$AppClassLoader
      parent: sun.misc.Launcher$ExtClassLoader
        parent: null

  That is, the ContextFinder isn't involved in the class loader tree.

> However unless you really need to you should just use a regular
> bundle for this case. You'll need an Activator to run and fragments
> cannot have an Activator.

I was trying to use a fragment bundle for two reasons. First, my
original intention was just to provide my initializer class to whoever
first tries to load it, so getting is "as close to the system bundle"
as possible made the most sense. Second, the hook configurators run
before the bundle activators, so, facing a race, I can get in there
for initialization with a hook configurator sooner than any other
bundles.

> Early during startup ContextFinder is set as the TCCL. All future
> threads created by the framework inherit the same TCCL.

I'm not seeing the evidence in the debugger, at least for whichever
thread is calling on HookConfigurator.addHooks(). Now that I check, I
see that this thread is the main application thread, starting way up
top with org.eclipse.equinox.launcher.Main():

,----
| main@1, priority=5, in group 'main', status: 'RUNNING'
| 	  addHooks():31, LoggingConfigHookConfigurator.java
| 	  loadConfigurators():168, HookRegistry.java
| 	  initialize():99, HookRegistry.java
| 	  <init>():97, BaseAdaptor.java
| 	  newInstance0():-1, NativeConstructorAccessorImpl.java
| 	  newInstance():39, NativeConstructorAccessorImpl.java
| 	  newInstance():27, DelegatingConstructorAccessorImpl.java
| 	  newInstance():513, Constructor.java
| 	  createAdaptor():776, EclipseStarter.java
| 	  startup():279, EclipseStarter.java
| 	  run():172, EclipseStarter.java
| 	  invoke0():-1, NativeMethodAccessorImpl.java
| 	  invoke():39, NativeMethodAccessorImpl.java
| 	  invoke():25, DelegatingMethodAccessorImpl.java
| 	  invoke():597, Method.java
| 	  invokeFramework():497, Main.java
| 	  basicRun():436, Main.java
| 	  run():1162, Main.java
| 	  main():1137, Main.java
`----

Is that the problem here?

> I suspect you were using ContextFinder and things started working
> when you used osgi.parentClassloader=fwk. As you noted this is not
> the best way to proceed.

That sounds about right. A few things work, and other things don't. I
figure it's better not to tread off into the non-default configuration
without understanding fully why it's necessary.

> I'm curious about what you're doing with hook configurators? I don't
> believe it should be necessary for setting up your logging. Was this
> just part of your experimenting or is it used elsewhere?

See above. I was mainly just trying to use an inert extension bundle,
but I added a hook configurator to mimic an early Activator so that I
could experiment with prodding at the TCCL.

> The critical piece when using the TCCL approach along with
> ContextFinder is that your implementation of LogManager has to be
> visible to the bundle where LogManager.readconfiguration is called.
> e.g. either in the same bundle or visible via Import-Package etc.

Yes, and in my test case I describe above, my hook configurator is
sitting in the same bundle as the logging initializer class I'm trying
to load.

Again, let me clarify that my intention was /not/ to use a hook
configurator or Activator to load my logging initializer class; I want
the Java logging framework to load my initializer class. The goal was
to make this initializer class available to whichever code path forced
LogManager to go looking for it, but I concede that that may be too
ambitious. I only started messing around with hook configurators to
see which class loaders were in use in calls into my bundle.

> Yes, ContextFinder generally just works in most cases. If it doesn't
> work we'd like to have a testcase understand why.

Should it work in the case I describe above, taking the call stack
into account?

> Yes. Framework extension bundles work in Equinox.

[...]

> In general the System bundle and System class loader should be
> treated as distinct.

Given that packages exported by extension bundles are not available to
the system class loader, to which class loaders are they available
then?

-- 
Steven E. Harris