@Mark: I doubt that this will work. Unloading a namespace would mean
to remove a class from a classloader and this does not work in Java.
OSGi handles this by removing the bundle's classloader completely.
@All: The huge added value that OSGi still has is multi-version
support. Lets say I want to use clojure.contrib version 1.1 and and
one of my other libraries wants to use clojure.contrib version 1.0.
This clearly does not work in Clojure currently since all
Clojure-based classes/namespaces live in one classloader. So currently
Clojure suffers from the same JAR-hell issues that are already solved
by OSGi :-/ Also, OSGi's service layer could be a nice way to decouple
some parts of the application. Additionally, several projects exist
that provide "infrastructure features" (e.g. remoting, web server) and
they all use the service registry for this.
I tried several integration approaches in Ogee but non of them really
worked out well:
* Full Isolation*
We can fully isolate different Clojure Modules (== logical group of
jar file(s)) by giving each of them their own classloader that
contains the clojure runtime. The problem is that Clojure's startup
time is approx. 1 sec so if we install 50 modules it would take way
too long to start the application.
* Isolation with fine-grained sharing *
I tried to extract common not-runtime specific Clojure classes into a
shared classloader to allow the modules to interact with each other.
E.g. classes like Var, IFn, ... However, there is a circular
dependency between Var -> something -> RT -> something -> Var and the
RT clearly has to stay isolated. Trying to split this cycle gave me a
LinkageError or something like that. Also, Clojure seems to rely on
the ContextClassLoader and I worry that one module could accidentally
pollute a "foreign" Clojure runtime.
I am currently not sure if OSGi's module layer makes sense at all in a
dynamic language. In a statically-typed language like Java, the use of
classes is baked into the bytecode. Therefore, when class A uses class
B, the resolver has to link A's classloader to B's classloader even
before A is loaded. That makes it impossible for A to use B in
different version. However, this constraint does not apply for a
dynamic language like Clojure at all!
I think a more idiomatic way for Clojure would be something like this:
A namespace could optionally declare a version number:
(ns package.fancylib :version 2)
This would generate a class like "fancylib__init__$version2.class" or
so. When other namespaces require/use the fancylib namespace _without_
a version a number, the Clojure runtime could easily find the latest
version:
1) find all "package/fancylib__init__$version*.class" files
2) order them
3) return first entry
When other namespaces require/use the fancylib _with_ a version number
(require 'package.fancylib :version 2), the Clojure runtime could
easily infer the correct classname.
I guess it is important that each module has its own class loader and
that there is one chaining parent clojure classloader. The module
classloader could transparently do the namespace mangling.
Ogee is currently based on OSGi but all Clojure modules live in the
same classloader. Whenever the Clojure setup changes, Ogee
automatically restarts the whole Clojure runtime so at least you get a
bit more dynamic feeling. The focus is currently on good idiomatic
service layer integration and support for servlets, remoting,
configuration management, etc. Maybe Ogee can later implement
something like what I described above but for performance reason it's
obviously preferable that the Clojure runtime itself provides
something in the future.
Cheers,
Roman
2009/10/6 Mark Derricutt <
ma...@talios.com>: