|
WBI PersistenceWith the WBI Development Kit version 4.4 a new persistence subsystem has been introduced. The new persistence mechanism retains a similar, though simplified, API to the previous version. However, it has been extended to support hierarchical organization of data. This means any Section or node can contain other Sections, much like a directory on a filesystem can contain other directories. The persistent subsystem also supports the plugging in of different backends using databases like SQL, LDAP, etc. The provided backend uses the filesystem. More information about writing your own backend is available. Table of Contents
A simple exampleThe plugin developer point-of-entry into the persistence subsystem is with the getHomeSection() method of Plugin. For typical configuration purposes, this is essentially all you need to know. For example, one might set up a debugging flag as follows:
public class MyPlugin extends HttpPlugin {
private enableDebugging;
public void initialize() {
enableDebugging =
getHomeSection().getBooleanValue("debugging", false);
// ...
}
// ...
}
The getHomeSection() method returns a section based upon the name of your plugin. This means if you rename your plugin, any persistent data will no longer be available. Likewise if you develop a second plugin with the same name as the first, the data will still be there. Please do not rely on the actual layout or location of the data on the physical filesystem. You might, however, need to know this in order to set the debugging flag in the example. Let's say this plugin was called "myplugin", the file accessed by getHomeSection() would be $WBIHOME/etc/plugins/myplugin/home.prop. While you might need to know these locations for your own development, please do not rely on them programmaticly -- i.e., make sure you plugin just uses the getHomeSection() API call, as the physical locations might change in a future release. It is also suggested that if you create an administration page for your plugin which can set and save configuration values if you anticipate others using it. The argument to getSection() or createSection() is a "/"-delimited path to the desired section. Just like with a filesystem, a path which is preceded by a "/" is absolute. Please be careful not to precede any of the paths you pass to these methods with a "/", otherwise your data will "escape" from the plugin namespace in which it belongs. Also, the location and behavior of the various WBI configuration data you will find up there is to be considered undocumented, and it may change from release to release. For example, a section with the path "http://ibm.com/index.html" will create the following three nested sections "http:" / "ibm.com" / "index.html", which is probably not what you intended. You should consider using java.net.URLEncoder to encode the "/"'s.
As with the previous system, the second argument to getBooleanValue() is a default value to use if a value is not found. Porting from the Previous APIWhile the API is similar to the previous one, there are significant changes and you will need to modify your code to compile with the new API.
Using hierarchical functionalityThe hierarchical extensions to the API allow the developer to organize data in a tree. For example, a plugin might have some configuration settings and may want to save other application-specific data. Let's say you're writing a plugin to keep track of the places you've visited on the web. You might want to keep a record of data associated with each URL encountered. That record might contain the number of visits and the last visit date for now, though you think you'll be extending that in the future. One might use the persistence API to save this kind of data as in the following example:
public class MyPlugin extends HttpPlugin {
String foo, bar; // configuration options
Section home;
public void initialize() {
home = getHomeSection();
foo = home.getValue("foo");
bar = home.getValue("bar");
// ...
Monitor m = new MyMonitor();
m.setup("my monitor", "content-type=text/html", 10);
addMeg(m);
// ...
}
class MyMonitor extends HttpMonitor {
// ...
public void handleRequest(RequestEvent e) {
DocumentInfo di = (DocumentInfo)e.getRequestInfo();
String url = di.getUrl();
// we want to create a new section if necessary,
// so use createSection(), not getSection()
Section s = home.createSection(URLEncoder.encode(url));
int visits = s.getIntegerValue("visits", 0) + 1;
s.setValue("visits", visits);
s.setValue("lastvisit", new Date().getTime());
s.save();
}
}
// ...
}
Note that in addition to illustrating hierarchical functionality, this example introduced the save() method. Save() will commit any unsaved data in the Section on which it is called and its contained sections to persistent storage. Saving Raw ObjectsThe setValue() method is overloaded to take any java primitive type as well as any Object which implements Serializable. If the argument is non-String Object, it will be stored using the java serialization mechanism. While simple and convenient for some purposes, there are some issues introduced by using this feature.
Don't Try to Fit a Round Peg into a Square HoleThe persistence system is intended first and foremost as a simple system for storing configuration settings. While it is possible to store larger amounts of data with it, or to write a more scalable backend, please keep in mind that what you may really want is something like JDBC.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||