[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
org.crosswire.common.utils.Bar:
(Let ~ be the equivalent of getHome() and not the user's home)
~/org.crosswire.common.utils.Bar.foo.properties
~/org/crosswire/common/utils/Bar/foo.properties
common.jar#org.crosswire.common.utils.Bar.foo.properties
common.jar#org/crosswire/common/utils/Bar/foo.properties
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:
foo_de_DE.properties
foo_de.properties
foo.properties
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