[jsword-devel] ActionFactory and ResourceBundles
Joe Walker
jsword-devel@crosswire.org
Mon, 05 Apr 2004 08:36:35 +0100
Hi,
It looks good. It is a better approach than I've used so far, I think.
The only reason I've not applied it is that I'm trying to get a 0.97
done. Which has proved to be bizarrely complex.
Just as soon as I've managed to get the version numbers sorted I'll
apply it.
Sorry for the delay.
Joe.
DM Smith wrote:
> I have created a few new classes:
> ActionFactory, creates actions from a ResourceBundle
> CWAction, a custom action that implements delegation
> CWClassLoader, a custom class loader needed to load resource bundles
>
> I used CW as an abbreviation for CrossWire (I could not figure out what
> the prefix Eir meant. But I guess that it was from another project.)
>
> I chose to implement independent classes so that they could be evaluated
> without affecting existing code.
>
> ActionFactory and CWAction are as I described them earlier.
>
> To use ActionFactory create one after calling Project.instance(). This
> allows for overrides to be gotten from ~/.jsword.
>
> Since it is not attached to the program, to see its behavior set
> breakpoints in ActionFactory and step away to your heart's content.
>
> I initially started with Properties and using ResourceUtil worked like a
> charm. It would load resources from files located in resource.jar named
> a.b.c.xxx.properties or from a jar along a path a/b/c/xxx.properties.
>
> However, ResourceUtil is fine for directly loading resources into
> properties, but ResourceBundle uses its classloader to find and get
> resources. And it tries for more than one resource. It also accepts
> calls of the form "ActionFactory" and
> "org.crosswire.common.swing.ActionFactory" to load the same file when
> called from org.crosswire.common.swing classes.
>
> But it chokes on absolute paths. The reason is that ResourceBundle
> interprets the names and then calls on its classloader in such a way
> that cannot find them. The net effect of this is that without providing
> a custom classloader, the resource had to be in the same directory as
> the class.
>
> Bummer.
>
> I figured we wanted to have a file
> org.crosswire.common.swing.ActionFactory.properties in the resource
> directory and that a developer could place a copy of it in ~/.jsword and
> modify it.
>
> This required a custom classloader. In reading up on Java 2 class
> loaders, I found that it is only necessary to override findResource. I
> also wanted to use the calling classes getResource if possible. With
> some more reading I found a technique to get the call context. [ I still
> need to test this in a WebStart environment to see if it works. If not I
> need to going back to passing the calling class into the constructor for
> the custom class loader ]
>
> At first I used ResourceUtil to get the resources, but I found some
> scenarios that it would not handle. The biggest was getting a
> ResourceBundle for a class by simple name (e.g. "ActionFactory").
> When I did this it expanded it in a way that ResourceUtil was not set up
> to handle. And then the form org.crosswire.common.swing.ActionFactory
> was re-interpreted into that same form. I started to add code to
> ResourceUtil, but ripped it back out. I did leave in some internal
> refactoring that makes the class more self documenting.
>
> I am using ResourceUtil.getHomeResource from the new classloader.
>
> To use the classloader pass it as the third argument to
> ResourceBundle.getBundle.
> I did it like this:
> ResourceBundle resources =
> ResourceBundle.getBundle(getClass().getName(),
> Locale.getDefault(),
> new CWClassLoader());
>
> _________________________________________________________________
> Tax headache? MSN Money provides relief with tax tips, tools, IRS forms
> and more! http://moneycentral.msn.com/tax/workshop/welcome.asp