I've spent some time thinking about the current situation with config
setup and have some things to share. Please excuse the long-winded mail.
The orginal problem by Paul:
> >>fault. ClassLoader.getResource() does not look inside packages and will
> >>only find files at the root of classpath entries, unless the resource is
> >>specified with a path and that's something we currently can't do. There
> >>are ways around that (I just implemented a nifty solution that does 99% of
> >>what you want) but one obscure problem remains, so for the time being I
> >>recommend you put the config files where they work.
I suggested using new DefaultConfiguration(new File("/full/path")) but
that does not work as expected either.
Andrus Adamchik wrote:
> I think such code will be very useful for things like locating DbAdapter
> implementations and/or JDBC driver implementations in the outside jar
> files in the Modeler. But scanning all packages to locate project
My thoughts! I used something similar in WO once to dynamically iterate
through all classes of a WOFramework and find plugins. It was actually
very fast (~2 sec) when combined with a lookup cache. It's a shame
something like this (or better) is not part of the standard classes.
> configuration file (cayenne.xml) seems a bit risky and adds
> non-deterministic factor to an already convoluted CLASSPATH/ClassLoader mix.
Yes, and after experimenting further with Paul's problem I concluded that
simply scanning all packages is not only error-prone with duplicates, but
also it won't even work correctly, since Package.getPackages() only
returns packages that have been used by a classloader to load classes.
Even Package.getPackage("not.yet.loaded") does not trigger its loading,
you have to access an existing class inside that package. No workaround.
Soo..I really thought about what Paul wanted to achieve. Until now it
never occurred to me that having the config files on the top level of the
project would be a problem, but it really is the norm if you think
further. There's no good reason not to have several configuration 'sets'
for a single application on the classpath at the same time, and picking
one e.g. at startup; this can be achieved by simply using packages (which
are nothing but namespaces, just like directories) and a single class in
that package (to enable package loading). This class just needs to be an
empty subclass of my new PackageConfiguration that I just checked into my
sandbox. Please have a look at it.
Usage is simple: Configuration.initSharedConfig(new
MyPackageConfiguration()) where MyPackageConfiguration is an empty
subclass in its own package, together with all the config files. No other
changes are necessary. Unfortunately, until I had this working, I had to
look at all related classes and figure out exactly how they were working -
with the current classes 'simply subclassing' is IMHO really obscure. :(
But it can be fixed easily, even without breaking anything! :)
There are several things that make config customization for the beginner
harder than necessary. getDomainConfig() and getMapConfig(location) both
return an InputStream, which is source-agnostic (good) but unfortunately
makes it hard to find out where the data actually comes from. This is
necessary because DriverDataSourceFactory makes the assumption that the
DataSource with a "name" can be loaded from exactly that same file 'in the
current directory'. This can be solved by overriding 'load(String)' (again
see the sandbox) but it took me ~2 hours just to find out who is loading
what, when, where, why and how, and that I have to provide my own
DriverDataSourceFactory subclass in addition to a custom config.
Another problem for subclassers might be that DefaultConfiguration IMHO
does too many things at once - both classpath loading and file loading.
Classpath loading only looks into the toplevel of the classpath and all
jars. File loading does not work at all (!) because the DataSource won't
be found, this is actually the same bug as already described (no path
information available in RuntimeLoadDelegate.shouldLoadDataNode()). We
could just delete this Constructor and functionality or fix it (better).
DefaultConfiguration's projectFile() and projectDir() both return File,
which makes it hard to fix the classpath loading. Using a single mechanism
(most likely URL, in my sandbox I've used Strings) might be easier to use
and is definitely easier to subclass: for example if you want to name your
project file differently than "cayenne.xml" you don't have to rewrite the
full loading mechanism.
ResourceLocator could be enhanced later with a 'recursive' flag that does
the deep search over all known packages, as I did at first.
Please have a look at the two (very short!) classes in sandbox/holger/..
and let me know what you think. Having all config files in a project
package is IMHO very common, works nicely and will not put off newbies
because they cannot get the config working the way they expect to. It's
unfortunate that we don't have NSBundle and all its niftyness, but that
doesn't mean we shouldn't solve the problem. ;-)
thanks for reading,
Holger
This archive was generated by hypermail 2.0.0 : Wed Feb 26 2003 - 16:16:05 EST