Geir Magnusson Jr. wrote:
Heh. I agree. I just was too busy in the VM/class library fire-
fight :)
Yes, perhaps you have just signed the death notice for this discussion
too. ;-)
So, given that my foray into architecture discussion was such a
stunning success, would you like to start the discussion of such a
thing might be approached? (Please change the subject, of course...)
We can try.
I have to admit up front that I know nothing about implementing a VM,
but I do have some knowledge about class loaders, having worked on an
OSGi framework implementation for a few years.
My view of the OSGi framework is that it really serves as a nice,
dynamic module layer for Java in general and its service-oriented
approach is a good way to structure applications. This has been my
approach to using/evangelizing the OSGi framework since I started with
it back in 2000. I recognize that the "dynamic" and "service-oriented"
parts of the OSGi framework are probably of little relevance to a JVM
implementation, so I will try not to discuss them.
However, having said that, I do think that the dynamic aspects could be
very interesting, because they would allow the JVM to dynamically deploy
and update modules as needed. That is all I will say about dynamics, I
promise. :-)
My view on packaging class libraries is rather simplistic, but it has
worked for many OSGi users. The approach is to package libraries into
JAR files, where the JAR file is an explicit module boundary. Each
module has metadata describing the packages it exports and imports (and
version information). A module JAR file may include classes, resources,
and native code.
Module JAR files are not directly made available via something like the
CLASSPATH, instead the module system reads the metadata for each module
(i.e., its export and import information) and resolves a given module's
imports to the available exports from other modules. A class loader is
created for each module and the module class loaders form a graph, where
edges represent an import-to-export resolution.
All classes of a given module are loaded by its own class loader. Any
classes from an imported package are loaded from the class loader of the
module that exports that package and to which the import was resolved.
In this fashion, the class delegation pattern among modules is a graph,
not a hierarchy...although the concept of a hierarchy of class loaders
still exists since it is built into the ClassLoader class.
Depending on how you wanted to implement the module system, you could
make the module containing the "java.*" packages special in the sense
that its class loader is the parent of all other module class loaders
and that modules do not need to explicitly import from it (which is the
approach used by OSGi). However, there is still possibly value in
requiring that modules do import those packages for version resolution
purposes.
As an example of all of this, consider this fictitious metadata for
packaging some libraries as modules (these example will not include all
of the real packages to keep things short):
Module-Name: Core
Export-Package: java.lang; exclude:="VM*"; version=1.5.0,
java.io; java.util; version=1.5.0
Native-Code: lib/libfoo.so; // I won't go into any syntax here :-)
This module is the core Java class library. It exports "java.lang", but
excludes exporting any classes from it whose name starts with "VM". The
"VM*" classes will be visible inside the module, but not to modules that
import "java.lang". Of course, excluding these classes wouldn't be
necessary if the "VM*" classes were package private. However, this
features allows you to make them public if you want. Another approach
that would be enabled is to just move the "VM*" classes to a different
package and make them public and simply not export that package, which
won't allow other modules to access them either.
[A side note about the syntax above: The syntax differentiates between
framework directives using the ":=" token, versus importer matching
attributes using the "=" token. Matching attributes are used by
importers to select exporters; see next example.]
Continuing with two more simple module examples:
Module-Name: OMG CORBA
Export-Package: org.omg.CORBA; org.omg.CORBA.portable; \
version=1.5.0
Module-Name: Javax RMI
Export-Package: javax.rmi; javax.rmi.CORBA \
version=1.5.0
Import-Package: org.omg.CORBA; org.omg.CORBA.portable; \
version="[1.5.0,1.6.0)"
The first module exports the CORBA packages, whereas the second one
imports the CORBA packages and exports the javax.rmi packages. The
import for the CORBA packages specifies a matching version range of
1.5.0<=x<1.6.0, under the assumption that micro version number changes
are backwards compatible.
Assuming that all of the various libraries are packaged up using similar
metadata, then you can imagine a simple approach where all of the
modules are placed into some directory and when the module system
starts, it scans the directory and does a consistency check and makes
sure it can successfully resolve all imports to exports, etc.
For backwards compatibility, a "system class loader" could be created
that delegated to all of the module class loaders, to get the current
boot class path type of approach. The application class loader would
then have this "system class loader" as its parent, so it could access
everything on the boot class path, as expected.
I admit that I have not given as much thought to this very last part,
since the OSGi framework doesn't have to do such stuff, but at first
blush it seems reasonable. Even then, it would still be nice if somehow
this module layer could be exposed, so that applications could be
written with it in mind if they so desired.
All of the above stuff (and more) is basically functioning in some form
in my current alpha release of Oscar 2.0:
http://oscar.objectweb.org/oscar-alpha.html
I await the list's wrath. :-)
-> richard
geir
On Jun 8, 2005, at 3:01 PM, Richard S. Hall wrote:
Apparently, only you and I agree. ;-)
Dalibor Topic wrote:
Richard S. Hall wrote:
To me, this is the point. I would like to see all of the libraries
built on to of the JVM to be packaged in a more module- like
fashion, so that their exports and imports are explicit. There
would be many benefits if this were done, rather than relying on
the current approach of assuming that everything is accessible.
+1
So, from my point of view, it is definitely going in the right
direction to make libraries understand which class loader they
should use to get to their own "module's" classes, as opposed to
just assuming they can get them from any application class loader.
+1 to that, too.
cheers,
dalibor topic