[jsword-devel] Resource management in JSword

DM Smith dmsmith555 at yahoo.com
Wed Aug 30 19:22:52 MST 2006

This is a tutorial on how to redefine resources to your advantage.

It was motivated by Manfred's question on replacing icons. I will be  
using that as a final example.

We have a developer friendly resource lookup system in JSword. At the  
heart of it is a custom class loader called  
org.crosswire.common.util.CWClassLoader which uses a helper class  
org.crosswire.common.CallContext. CallContext returns the class of  
the caller.

The significant difference of CWClassLoader is it search algorithm.

The static method CWClassLoader.setHome establishes a program's  
notion of its home. We call this with ~/.jsword, ~/Application Data/ 
JSword, or ~/Library/Application Support/JSword for unix, windows and  
mac respectively.

We don't use CWClassLoader directly but use  
org.crosswire.common.util.ResourceUtil.getResource([Class clazz],  
String resourceName).

But the meat of the lookup is in CWClassLoader's method findResource 
(resourceName), which returns an URL to the resource or null, if not  
found. The trick in the whole of it is that the standard ClassLoader  
will look for resources with a relative path in the calling class's  
package and with a relative path will do a full search along the  
CLASSPATH. We essential cheat by algorithmically pre-appending  
"getHome()" to it. We also look for resources either as a file in the  
root of the path with package dot notation or along a directory path  
to the package.

Here is the order of the lookup for a resource foo in package  
(Let ~ be the equivalent of getHome() and not the user's home)

The last is the actual resource as we currently store it in the jar.
The second to last is how we used to store them in the jar.
The first is the easiest way to override resources.
The second is used when running code directly from java files or a  
file system with class files.

The second context where we use CWClassLoader is in handling  
internationalization (aka i18n).
When we want to lookup an internationalize resource we use  
CWClassLoader in a call to ResourceBundle.getBundle(...) as in:

ResourceBundle resources = ResourceBundle.getBundle(basis.getName(),  
Locale.getDefault(), new CWClassLoader(basis));

where basis is the Class that owns the resource.

The net upshot is that for a German in Germany the lookup is for the  
following names:
Now the lookup is per entry in the properties. This means that to  
override what is in foo.properties one only needs to create a more  
specific resource for their own locale.

The point of this is that any of the files that are loaded with  
ResourceBundle (and just about all are) you can override it  
incrementally by creating a locale specific semi-copy of the file.

For me, my locale is en_US. Since there is no en or en_US defined  
already, I can create foo_en.properties as a copy of foo.properties  
and then delete all the keys I don't want to change.

For a real example, let's say I want to override the desktop icons.  
These are defined in Desktop.properties in the form Action.smallIcon  
and Action.largeIcon. I would create a copy called  
org.crosswire.bibledesktop.desktop.Desktop_en.properties and place  
that in ~/Library/Application Support/JSword (e.g. on a Mac, see  
above for other locations) Then I'd delete all the lines that did not  
define smallIcon or largeIcon as well as the ones without values.  
Finally, change the values to the names of the icons you wish to use.  
Put these icons in ~/Library/Application Support/JSword. You might  
want to create an images directory there. Then the value would be  
something like images/cutSmall.png

This is not how we should do image replacement, but it serves as a  
quick way to test an idea to see if it is worthwhile to pursue.

It is also an easy way to share an idea, just create a zip of the new  
properties file and the images directory and give that out.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.crosswire.org/pipermail/jsword-devel/attachments/20060830/7a3e0fb8/attachment.html 

More information about the jsword-devel mailing list