Now blogging at diego's weblog. See you over there!

auto-everything

I had a mini-epiphany when I was writing a search plugin for firebird in terms of being as automated as possible when exposing the functionality of the clevercactus plugin API. In Java, we are used to thinking in terms of classes and classpaths and so on--even ResourceBundles (for i18n) are primarily a class-based mechanism (although, yes, you can load a ResourceBundle from a property file).

As a result of the mini-epiphany, clevercactus is now undergoing refactoring to make the configuration both changeable and dynamic. Not necessarily runtime-dynamic (i.e., ala Swing) but reload-dynamic. All configuration is stored in XML files. Example? The resources.

Resource management for i18n is relatively simple: you create a level of indirection and you use the current locale (or a user-specified locale) to access the string you want for a particular case. This theoretically applies to any time of resources but 99% of the time strings are what used, either as text/labels/etc or filenames to access stuff (such as images).

So, how does clevercactus work now? There's a new directory called resources which must exist somewhere on the classpath. That directory contains a main file that points to all the resources and system-wide settings (such as which resource is the default, or the default for a particular language). A sample resource file looks like this:

<?xml version="1.0" encoding="UTF-8"?>

<resources>
<locale>
  <language>en</language>
  <country>US</country>
</locale>
<parent-resource-set>
  <locale>
    <language>en</language>
  </locale>
</parent-resource-set>
<resource>
	<name>REZ1</name>
	<value>some resource</value>
</resource>
<resource>
	<name>REZ2</name>
	<value>some other resource</value>
</resource>
<resource>
	<name>REZFILE</name>
	<value>/images/test.gif</value>
</resource>
<resource>
	<name>MULTIREZ</name>
	<value>value 1</value>
	<value>value 2</value>
	<value>value 3</value>
</resource>
</resources>
Because it's XML you can support cleanly multiple character sets, do validation (when the DTD is available :)), etc. I also added support for multi-values resources, which ResourceBundle doesn't allow (not easily anyway). Finally, note the parent-resource-set tag which allows to specify resource set hierarchies (the country is always optional, so it's not present in that particular example, but it could be).

ResourceManager, the main class, has two main access methods (aside from management methods such load(String path) and setSelectedResourceSet(Locale selectedLocale):

  public static String getString(String name);
and
  public static java.util.List getList(String name);
And the manager converts transparently between types if you request a list as a string and viceversa.

Then, if you drop a new resource file in the resources directory (something with extension .resources) then cc will pick it up automatically on the next restart. And presto! The new language is supported in cc. Nice eh?

This mechanism will apply to basically everything: plugins, menus, commands, etc. It will be interesting particularly for plugins. Regarding plugins in particular, as part of the refactoring the cc components themselves (email, etc) are being turned into plugins. Nothing better to test the framework properly. :)

Oh, and here's a simple nice trick I came up with to find the resources automatically in the classpath (It might be a well-known trick, but whatever--). The problem is that you know the main dir ("/resources") but you don't know where it resides in the classpath. So the code does something like this to perform the autodetection:

  java.net.URL classUrl = ResourceManager.class.getResource(path_sd);
  File fdir = new File(classUrl.getFile());
  String[] files = fdir.list();
  if (files != null) {
    for (int i = 0; i < files.length; i++) {
	String file = files[i].toLowerCase();
        if (file.endsWith(".resources")) {
            //load the file, etc.
        }
     }
   }
The lines in bold are what's important here: Java resolves the file within the classpath and from that you can derive a File object which then allows you to list the files in the directory. Useful and simple. :)

Okay, back to work. After this is all done, it's IMAP and the Calendar all the way.

Categories: soft.dev
Posted by diego on October 21, 2003 at 11:18 AM

Copyright © Diego Doval 2002-2011.