dev@glassfish.java.net

Why we use DynamicImport-Package?

From: Sahoo <sahoo_at_sun.com>
Date: Thu, 28 Aug 2008 09:49:09 +0530

[Subject has been changed to reflect the topic being discussed]

Richard S. Hall wrote:
> Sahoo wrote:
>> Richard S. Hall wrote:
>>> If that is the case, then I am in agreement with you, it doesn't
>>> make sense that it could not load private classes from the bundle.
>>>
>>> Still, I do have some concerns about loading from exported packages.
>>> Does this mean that it uses DynamicImport-Package or is it just
>>> analyzing the bundle export metadata?
>> DynamicImport-Package.
>
> Hmm. Well, that is not what I would recommend,

I was anticipating a reply regarding use of DynamicImport-Package.
Thanks for raising it. I should have mentioned that we used
DynamicImport-Package in special circumstances only. None of our server
implementation bundles use DynamicImport-Package. Then, who uses
DynamicImport-Package? In a nutshell, it is used by a special OSGi
bundle that's only used in the context of deployed applications - these
applications are not OSGi bundles. More details given below:

As discussed in V3/OSGi one-pager [1], we have two kinds of artifacts
deployed in the server runtime, viz: a) several OSGi bundles
implementing the GlassFish runtime as well additional user supplied OSGi
bundles, b) applications (typically Java EE applications) deployed in
the server runtime. These applications are not OSGi bundles, so they can
*not* directly interact with OSGi runtime unless we convert them to OSGi
bundles. Although there are a lot of similarities between Java EE
deployment artifacts (ear/war/jar) and OSGi bundles, there are
significant differences as well. Converting Java EE applications to OSGi
bundles was considered, but the technique/principles are not solid
enough to be put in production yet. So, it is still in experimental
mode. We are going to work with OSGi EEG on specifying this first.
 
In the short term, the approach that has been taken so far is that OSGi
platform provides a basic runtime for GlassFish bundles. GlassFish
bundles provide the necessary runtime to the applications. So, it can be
thought of as a runtime inside a runtime. In addition to managing the
lifecycle of deployed applications, one of the key functionalities
provided by GlassFish runtime to the deployed applications is to create
a class loader hierarchy for every application. While creating such a
class loader, we have to be not only compliant with the class loading
requirements of the Java EE platform, we also have to be backward
compatible with earlier versions of GlassFish. The class loader
hierarchy (as in class loading delegation hierarchy) for applications
looks something like this (I have removed some elements that are not
needed for this discussion):

archive class loader [H]
      -> common class loader [D]
                  -> public API class loader [C]
                       -> classloader that loads Felix
                              -> extension class loader [B]
                                   -> null (a.k.a. bootstrap class
loader) [A]

Description of each element of the above delegation chain is given below:

A & B are JRE supplied class loaders.

C. public API class loader:
It is this class loader that makes available all the META-INF/services
resources and service implementation classes that are discovered using
the extender pattern. It also makes available all classes
exported by OSGi bundles installed in the runtime. This typically includes,
but not limited to, Java EE APIs and other GlassFish APIs that we want
applications to have access to. Currently, our server OSGi bundles
pretty much expose
every package for public use. This should be fixed as described in
https://glassfish.dev.java.net/issues/show_bug.cgi?id=5385.
This class loader is implemented as a simple delegation pattern: it
basically delegates to an OSGi Bundle which
has following import statement:
DynamicImport-Package: *

We let OSGi framework ensure that the class space for such a bundle is
consistent. We felt this simple technique helps us in providing a
consistent class space for applications in a dynamic environment like
GFv3, where new capabilities can be added as post-installation activity.
No other server implementation code uses this special OSGi bundle.

D. common class loader:
This is responsible for making available libraries and
classes installed in following places (in the order mentioned below):
glassfish_home/lib/, domain/classes/, domain/lib/. These are libraries
which are plain old jar files. They are shared by all applications. This
is needed for backward compatibility reasons.

H. archive class loader:
Responsible for loading classes from application archive (a
.jar/.war/.ear file). It is created for every application,as Java EE
spec mandates every archive to have a separate class space.

Now that I have told where and how we use DynamicImport-Package, let's
get back to the some of the issues raised by you. See reply below...
> because this will limit what it can see, for example, it could not
> deal with two different versions of the same package since this
> approach actually creates a wire to the exporter. Although this might
> not be a current use case, you never know about future use cases.
If we were able to map an application an OSGi bundle, could that OSGi
bundle consume more than one version of same package? We don't constrain
all our server OSGi bundles to use same version of the package. They
don't use Require-Bundle, nor do they use DynamicImport-Package, so
different bundles can use different package versions and we let OSGi
framework figure out if there is any inconsistent class space. With my
earlier explanation about where we use DynamicImport..., this should not
be an issue any more, right?
> Further, this means that the extender becomes dependent upon the
> exporter so if the exporter is uninstalled or updated and then
> refreshed, then the extender bundle will have to be refreshed too.
Yes.
>
> Following the extender approach, you could probe for exported packages
> too and then delegate to Bundle.loadClass() based on who exports what,
> this won't create a wire to the exporting bundle.
>
I am confused. One of our primary requirement is to have a class loader
hierarchy that provides a consistent class space, which means we can't
violate any of the loader constraints. If we don't create wires, are we
not going to violate temporal namespace consistency? e.g., at time t, if
we used bundle b to load class C, then at time t+1, we must use the same
bundle to load the same class, right? If we allow B to be uninstalled,
then we won't be able to find C any more, thus violating the temporal
consistency rule.
> Just some thoughts.
>
Thanks for sharing them. I hope I have been able to share some of our
implementation details with regards to use of OSGi. I would be glad to
discuss it further if you want. That will be good exercise for GlassFish.

Thanks,
Sahoo

[1]
http://wiki.glassfish.java.net/attach/V3FunctionalSpecs/GFv3Prelude-OSGi-onepager-v0.2.txt