java.util.prefsパッケージの基本的な使い方
なかなか使う機会もないパッケージです。
JDK1.4からと、思ったよりも古くからあるようです。
Windowsではレジストリが使われてます。
システムルート
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs
ユーザールート
HKEY_CURRENT_USER\Software\Java Soft\Prefs
Windowsの場合は、
java.util.prefs.WindowsPreferencesFactoryから生成されたもので
java.util.prefs.WindowsPreferencesというクラスが
java.util.prefs.Preferenceのインスタンスとして使われます。
上記のファクトリは次のファイルを作成して実装を差し替え可能です。
META-INF/services/java.util.prefs.PreferencesFactory
普通は自分で登録する必要はないです。
でもあのシステムルート/ユーザールートの配下しかいじれないのだと意味がない人が、その実装(レジストリをいじれるJNIコード含む)を用意して差し替えるということじゃないでしょうか。
ええ、ただのJavaエンジニアにはハードル高いですよ。
-システムプロパティ
-META-INF/services/java.util.prefs.PreferencesFactory
その他のプラットフォームではレジストリなんてないので、
java.util.prefs.FileSystemPreferencesという実装が使われてるみたいで、
ファイルシステム上にXMLファイルでストアされるっぽいです。
z/OS上でもそうだった。妙なWarningが出るので、今後使う気はないですが。
WARNING: Could not create system preferences directory. System preferences are unusable.
だとか
WARNING: Prefs file removed in background /パス名は臥せる/.systemPrefs/prefs.xml
それに
WARNING: Prefs file removed in background /.java/.userPrefs/prefs.xml
スーパーユーザーで動かしていて、
ホームディレクトリがルートっぽかったので確証持てませんが、
きっとユーザーホームを意識してファイルが出来ます。
ユーザーホーム/.java/.userPrefs/prefs.xml
ノードは、ファイルシステムのディレクトリとして機能します。
ユーザーホーム/.java/.userPrefs/test/prefs.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE map SYSTEM "http://java.sun.com/dtd/preferences.dtd">
<map MAP_XML_VERSION="1.0">
<entry key="testKey" value="testValue"/>
</map>
ざっくりとした使い方(申し訳ないが例外は全部スローさせてる)
まずはこういう感じでユーザールートを取得します。
※)システムルートは恐いからいじらない
Preferences userRoot = Preferences.userRoot();
1つ階層を作りたいのであればノードを掘る。
Preferences child = userRoot.node("child");
設定を残したいのならばputする。
child.put("key","value");
キーは必ずString、バリューは様々な型を使えるようになっています。
Windowsで試してみて気に食わなかった点がある。
ここでこんな名前でノードを作ったり、
キーやバリューを設定した時に嫌な感じに保存される。
Preferences child = userRoot.node("testChild");
child.put("testKey","testValue");
見た目が醜くなるので大文字は使わない方がいいですね。
NodeChangeListenerとPreferenceChangeListener
NodeChangeListenerの実装を用意して
node.addNodeChangeListener(new NodeChangeListenerImpl();
という風にリスナーを登録しておくと、
ノードの追加・削除の際に動かしてくれます。
NodeEventChangeが引数で渡ってくるので、
どういうノードが追加されたかを見ることができます。
ただし、追加されたノード(Preferences)がすぐに削除されていた場合、
そのPreferencesへの操作でIllegalStateExceptionが発生することがあります。
新しいノードに対して新しいリスナーを登録したい場合に注意が必要です。
このリスナーは、子ノードの追加・削除が対象で、
自ノードの削除には反応しません。
PreferenceChangeListenerの実装を用意して
node.addPreferenceChangeListener(new PrefenceChangeListenerImpl();
systemNodeForPackageとuserNodeForPackage
引数にクラスを渡すことで、パッケージ名(クラス名は使わない)から、
深くまでノードを掘ってくれるものです。
実際、私のPCには、これで作ったと思われるレジストリがありました。
ただ残念なことに、パッケージ名の先頭のJPだけ大文字で"/J/P"というのなってます。
nodeメソッドに渡すパス名のコンベンション
node.node("jp.co.hoge");
この場合は、そのままの名前でレジストリにキーができます。
node.node("jp/co/hoge");
この場合は、階層になってレジストリにキーができます。
さきほどのuserNodeForPackageなどは、
クラスからパッケージ名を取り出して、
ピリオドをスラッシュに変えてるのだと言えます。
パッケージに基づきたいが、階層にするのが嫌だと思う人は、
node.node(Hoge.class.getPackage().getName());
という風に作ることで階層なしでいけます。
他にもメソッドがあって考える必要がありますが、
主だった使い方はここに書けたかと思います。
いちおうWindows7 64bitで動かしてました。