Use of Framework Extension Bundles in GlassFish V3
When you run an application in a plain vanilla Java platform, your code can access publicly visible internal JDK classes. While I understand it is a bad thing, but I do understand that sometimes developers have genuine reasons to access those internal APIs. e.g., our security module in GlassFish has to use some of the JDK Security classes. When one moves those programs to an OSGi environment, the assumption that every public JDK class is always visible to applications goes for a toss. When we started with our OSGi effort in GlassFish V3, we immediately faced the problems. So, how does one manage the situation? There are basically two ways to manage it in OSGi, viz:
a) Parent Delegation:
Parent Delegation is controlled by a system property called org.osgi.framework.bootdelegation. It contains a list of package names, which allows use of wildcard (*) to help keep the property value to a manageable size. When OSGi framework tries to load a class for a bundle, if the class belongs to java namespace, it immediately delegates to parent classloader. If the class does not belong to java namespace, it consults the aforementioned property. If it is mentioned there, it delegates to parent class loader. Else it goes through a very well defined sequence to locate the class failing which it throws ClassNotFoundException or NoClassDefFoundError or a similar exception.
b) system packages:
Now, let's look at system packages. There is a special bundle in the OSGi runtime which is known by Bundle-SymbolicName:system.bundle. This bundle like other OSGi bundles can export packages. It is used to export packages, such as framework APIs, JDK APIs, available in parent class loader. As a result, it allows the parent class loader to be teated as yet another bundle. Those exported packages can then take part in normal OSGi package wiring process. The list of packages that can be exported are controlled by a system property called org.osgi.framework.system.packages. If I am not mistaken, in the upcoming R4.2 spec, CPEG is defining a new property called org.osgi.framework.system.packages.extra, but that's not important for this discussion.
Please consult the OSGi spec for accurate description of these features. The spec is very nicely written. The description above is not as clear as you will find in the spec, which is obvious.
Parent Delegation is a necessary evil. It is there to primarily help avoid strong assumptions made by some JDK classes about class loading, but it is also helpful in solving class loading problems as explained in one of my earlier blogs. It breaks modularity, so it should be used at the last resort. So, we decided to use the second option.
In the second option, there is also a challenge. How do we know the list of all such internal packages? The list is a union of internal packages needed by all the modules running in GlassFish. There lies the problem. The list of modules is not fixed. After all, GlassFish V3 has multiple profiles (or distributions), e.g., web profile, classic profile, etc. The problem is compounded by the fact that user can install new modules and they may have newer requirements about system packages. So, managing them via a single property does not scale. Fortunately, framework extension bundles come to the rescue.
framework extension bundles
Framework extension bundle is a special type of bundle fragment. It can only attach to system bundle. So, it must have Fragment-Host set as either system.bundle (which portably identifies system bundle in all OSGi platforms) or use a framework specific name for system bundle and it must have extension attribute set to framework. e.g., the following header will do:
Fragment-Host: system.bundle; extension:=framework
There are restrictions about what headers it can use, but like any other fragment, it can use Export-Package header to export additional packages. All those additional packages eventually get exported via system bundle only. Now, imagine this: system bundle is already backed by parent class loader. It actually has access to all the classes loadable via parent class loader, but for modularity reasons, it does not export all of them. If you want some packages to be exported by system bundle, just come up a framework extension bundle which contains no actual class. It only contains some manifest headers like this:
Fragment-Host: system.bundle; extension:=framework Export-Package : sun.security; uses:="foo, bar"; version=1.0
Isn't this a powerful technique? This is actually one of the very few good use cases for fragment bundles. This allows us to decentralize the information which is so important in an extensible system like GlassFish V3. More over, system properties can't be controlled when a program is embedded in a host JVM.
GlassFish use case
What we do in GlassFish is we define org.osgi.framework.system.packages to contain the standard Java SE platform API packages only. We then install one or more extension bundles that are used to make internal JDK classes available via system bundle. Take a look at one written for EclipseLink's Oracle extensions