Disabling Sun’s Java 1.4.x Preferences Subsystem

Introduction

With the release of Java 1.4, Sun introduced a Preferences subsystem that is platform and JVM dependant. The motivation appeared to be the provision of a Windows-registry-like backing store for Java applications. This storage exists on a per-user and per-system called “user preferences” and “systems preferences”, respectively. If you’ve ever written a Windows application, you’ll know that the registry comes in extremely handy for a number of reasons – it’s a backing store that always exists, is always in-core and always writeable (at least HKCU).

The Preferences subsystem has default implementations for each platform. As of this writing, there are two: Windows – the registry, L/Unix – the file system. My usage of the word “default” is significant as it is entirely possible to supply your own preferences implementation that uses a database or some other persistence mechanism.

Chances are you’re reading this page because you’re having difficulty with the preferences subsystem, and an even better chance your problem(s) arise from the unconditional activation of said subsystem. For Unix and Linux developers who don’t run the JVM with root access, this is a problem. The default implementation on Unix-based OSs is java.util.prefs.FileSystemPreferences. It uses three JVM arguments to determine where to place the preferences, with defaults listed parenthetically:

  • java.util.prefs.systemRoot (/etc/.java)
  • java.util.prefs.userRoot (user.home / “.userPrefs”)
  • java.util.prefs.syncInterval (30)

What if you’re not running as root and Java attempts to create a file under /etc? The first “sync” attempt fails, and so on. Failure is OK, but unfortunately an uncatchable SecurityException is thrown. There are several variations of the following stack trace that users of 1.4.x have come across. One particularly uncatchable example, thrown from within a Timer:

java.lang.SecurityException: Could not lockSystem prefs.Lock file access denied.   at 
java.util.prefs.FileSystemPreferences.checkLockFile0ErrorCode (FileSystemPreferences.java:926)   at
java.util.prefs.FileSystemPreferences.lockFile (FileSystemPreferences.java:915)   at
java.util.prefs.FileSystemPreferences.sync (FileSystemPreferences.java:723)   at
java.util.prefs.FileSystemPreferences.flush (FileSystemPreferences.java:814)   at
java.util.prefs.FileSystemPreferences.syncWorld (FileSystemPreferences.java:475)   at
java.util.prefs.FileSystemPreferences.access$1200 (FileSystemPreferences.java:33)   at
java.util.prefs.FileSystemPreferences$10.run (FileSystemPreferences.java:449)   at
java.util.TimerThread.mainLoop (Timer.java:432)   at
java.util.TimerThread.run(Timer.java:382)

Some log file output I copied from the java.sun.com forums:

Mar 18, 2002 5:09:33 PM java.util.prefs.FileSystemPreferences checkLockFile0ErrorCodeWARNING: Could not lock User prefs. Unix error code 37.
Mar 18, 2002 5:09:33 PM java.util.prefs.FileSystemPreferences syncWorldWARNING: Couldn't flush user prefs: java.util.prefs.BackingStoreException: Couldn't get file lock.
Apr 29, 2002 3:40:00 PM java.util.prefs.FileSystemPreferences syncWorld
WARNING: Couldn't flush user prefs:
java.util.prefs.BackingStoreException: Couldn't get file lock

From this search result, you can see that this is a problem plaguing several Java users, and that there’s a bug addressing a related issue.

Proposed Solutions

  1. Give temporary write access to the directories in question (either for one execution or long term), so that the program can initialize, preventing it from throwing exceptions in the future.
  2. Set –Djava.util.prefs.syncInterval to a very large number. Works great until the interval is hit or you exit your application. Sooner or later, the preferences are going to want to persist.
  3. Set –Djava.util.prefs.userRoot and systemRoot properties. Certainly I could set these preference values and be done with it. But a more important question remains – why am I bending over backwards for code I don’t even use? Telling me I have to create directories on a client’s machine for no good reason is an amateurish suggestion, not to mention that it’s a catch-22: I can’t create the directories with a Java app, because running it the first time will cause the SecurityException to be thrown!

Analysis

After running through the implementation-dependant classes (FileSystemPreferences on *nix and WindowsPreferences on Windows), I realized that only FileSystemPreferences exhibited this problem. It would throw SecurityExceptionS when you weren’t using the preferences subsystem at all.

Surprisingly, the Preferences code was written (and architected?) by Joshua Bloch, the author of Effective Java, one of my favourite books and someone I briefly corresponded with via email – a very nice and most excellent engineer in lieu of this one oversight. Josh, we love ya but this default implementation is not your best work ;-)

Here is the core bit of code causing all of these issues, found in java.util.prefs.FileSystemPreferences.java:

private static Timer syncTimer = new Timer(true); // Daemon Thread static {
// Add periodic timer task to periodically sync cached prefs    syncTimer.schedule(new TimerTask() {
public void run() {
syncWorld();
}
}, SYNC_INTERVAL*1000, SYNC_INTERVAL*1000);
// Add shutdown hook to flush cached prefs on normal termination
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
syncTimer.cancel();
syncWorld();
}
});
return null;
}
});
}

There are two problems here. One is that this is done inside of a static initializer meaning you cannot catch it as the JVM initializes static blocks (versus a constructor, whose <init> you can catch) and second is that syncWorld() call is twice removed. It’s called from inside of a timer (meaning you can’t catch it as the JVM shoots it off) and that that timer is also instantiated by the JVM inside the static initialization block, again meaning you can’t catch it.

Solution

Fortunately for us, Mr. Bloch designed the Preferences subsystem with the ability to have new implementations plugged into it. I told you he was good, didn’t I?

In the JavaDoc for java.util.prefs.Preferences he points out that if you implement your own preferences subsystem, you can specify it with this argument:

-Djava.util.prefs.PreferencesFactory=<a class that implements PreferencesFactory>

And therein lies the solution: implement your own preferences classes that do nothing. Sounds hard? Not when you’ve got Joshua designing! Thankfully, AbstractPreferences does most of what you want. You have to write 3 lines of code – a constructor for your new class. I’ve done that for you. And I’ve outlined the solution in a two-step process:

  1. Download DisabledPreferences.java and DisabledPreferencesFactory.java, and add them to your implementation.
  2. When you start your JVM, supply this argument (make sure that if you put it in a package, you qualify the class name):

    -Djava.util.prefs.PreferencesFactory=DisabledPreferencesFactory

The next time you start an application, my DisabledPreferences will kick in. Because Mr. Bloch wrote the Preferences system, it’s extremely robust and all internal calls will fail (or succeed) quietly.

Thanks for reading, and I hope this helped you! Have a look at my pictures and take a break from pounding your head against your keyboard :-)

Rob Slifka

Reader Feedback

April 5, 2003 – Knut writes…

If you write your own application, you can disable the Preferences Subsystem using this command at an early stage in your program (that is, before you use any preferences):

System.setProperty(“java.util.prefs.PreferencesFactory”, “DisabledPreferencesFactory”);

This way you don’t need to use the ugly command-line option every time. Naturally, you still need the dummy-classes.

March 15, 2005 – Kumar writes…

I am being bugged by the Preferences API exceptions. I found your web page very useful in understanding what’s going on. I am using the method call,

Preferences.systemNodeForPackage( userNodeName )

where userNodeName is a Java Class to instantiate the Preferences before I store data. [rest of email removed, where NullPointerExceptionS were mentioned while using the Preferences API]Response

The name of the class is “DisabledPreferencesFactory” with emphasis on the word “disabled”. That is, use of the preferences system will be “disabled” after installing my class, so your NPE should come as no surprise ;-)

August 19, 2005 – Richard writes…

The .systemPrefs subdirectory is required to exist before it is first accessed by the Preferences subsystem, but it is not part of the property value. This subtle distinction is important when trying to override the default. One can pass:”-Djava.util.prefs.systemRoot=/home/user/.java”

with /home/user/.java/.systemPrefs already existing, but one cannot pass “-Djava.util.prefs.systemRoot=/home/user/.java/.systemPrefs”

[Richard also provided several corrections and some insight as well. Thanks!]

September 26, 2005 – Pete writes…

You say in that web page that it is only the *nix implementation that gives grief.The application that I’m writing is giving warnings when run on Windows. A component that I make use of is storing an item in User Preferences. That much works.

The warnings are seen when run by a non-privileged user. Presumably they arise because that user is not allowed to access HKEY_LOCAL_MACHINE. I did not spot the problems when developing because I have local administration privileges.

My suggestion to Sun for both WindowsPreferences and FileSystemPreferences would be defer access to SystemRoot until it is first used by the caller. The majority of programs that use the User Preferences only would then avoid these spurious errors. This comment applies to JRE 1.4, I’ve not yet researched 5.0 to see whether it has improved.

Here is an example warning.

26-Sep-2005 11:32:52 java.util.prefs.WindowsPreferences <init> WARNING: Could not open/create prefs root node Software\JavaSoft\Prefs at root 0×80000002. Windows RegCreateKeyEx(…) returned error code 5.

November 4, 2005 – David writes…

Thanks for your web page about these infamous Java prefs.FYI. I have hit a problem on Windows that lead me to a similar approach. At one of my clients site, developers are not administrators of their Windows workstations. Hence the default implementation of Sun’s JDK fails miserably.

I first thought to use your disabled implementation but that was not an option because the product that was using the prefs (Apache Jetspeed 2) was actually needing to re-read them afterwards.

So I came to the (attached hereto) implementation, based on Preferences for the backed store, not production grade because it very inefficiently reads/writes the store on every access (for obvious reasons of simplicity); but useful enough to allow developers to work!

It might be useful for your readers?