On Tue, May 17, 2011 at 10:52 PM, Mark Evenson evenson@panix.com wrote:
On 5/17/11 10:24 PM, Alessio Stalla wrote: […]
a. CLASSPATH (the listing of directories and jar files where to look for classes) is not a runtime concept; it's only a variable (environment variable or command line switch) used to init the JVM's default class loader. Once the JVM is started, CLASSPATH doesn't make any more sense. b. At runtime there's a hierarchy of class loaders, that, without going too much in detail, define a sort of limited virtual filesystem. Resources in that filesystem might come from plain files, from contents of jars, from the network, from memory... So, classpath:foo.jar!/bar does not make much sense: the fact that bar comes from foo.jar is no longer important (and possibly not even known anymore) inside the virtual filesystem. This is not just theory, I can cite at least two examples: ABCL's very own functions compiled at runtime and loaded from memory, and anything running on JBoss>= 5, where applications are loaded with a classloader that does not expose jar files in any way. So, I would suggest simply classpath:/foo/bar/baz and leave it to the classloader to go and find /foo/bar/baz. This is precisely how the Spring framework does it, for example[1]. What you lose is the ability to enumerate the contents of the "file system": you can only ask for a resource by name and get back a stream if it exists. But I don't think we currently need the capability to enumerate.
So, if I understand you, 'classpath:/foo/bar/baz' just means find the entry '/foo/bar/baz' relative to something within the classpath?
No, not exactly. "/foo/bar/baz" is an absolute path, so it's not relative to something *within* the classloader search path; but it *is* relative to the actual classloader. I oversimplified; there's not a unique "virtual file system" (VFS) but a tree of them, and the root is the classloader you consider. A classloader is the aggregation of one or more sources (e.g. jars). Within ABCL, typically the classloader is the one that loaded ABCL, i.e. you don't have to worry about it and you can pretend there's a single VFS. It only becomes a problem in a scenario where ABCL is a library shared among several different applications (running on the same JVM): then, you would typically have to use each application's class loader. Relative paths are also possible; for example, you might want to load a FASL that is "next to" another one.
What happens if there are multiple classpath entries that satisfy this requirement, i.e. foobar.jar and barfoo.jar both contain '/foo/bar/baz'? Doesn't a "first one wins" strategy create ambiguity?
Yes, it does. There is a way to detect the ambiguity and get a list of all the resources with a given name [1]; we could decide to forbid that situation and signal an error (when loading Lisp code). For reference, it's not how things typically work in Java: the possibility of ambiguity is accepted, and while it is a source of bugs, it's also voluntarily exploited in certain scenarios to override classes without touching the containing jars. Granted, with a dynamic language, that becomes pretty much irrelevant. That said, my main points are: - you can't expect to always being able to detect which jar a resource comes from (or if it comes from a jar at all) - even if you could determine the jar, you could only check it afterwards, i.e. it's not "find jar, then look for resource" but "find resources, then choose the one from the right jar". Otherwise, the classpath: prefix is misleading. But then, what does "the right jar" mean if you're no longer using absolute paths? Suppose you have classpath:my.jar!/foo. What if the classloader knows both foo from /home/alessio/my.jar and foo from /usr/lib/my.jar? Which one is the right one?
[1] http://download.oracle.com/javase/1.4.2/docs/api/java/lang/ClassLoader.html#...
Alessio