-PluginPreferences
さて、ProjectPreferencesがどうも動きが悪いみたいなのと、設定を\workspace\
EclipseのPreferences仕様では、ExtensionPointを用いてプロトコル風に用いることができるように、IScopeContextを実装することになっています。IContextScope#getName()で返す名前がパスの第一ノードとなります。たとえば/plugin/hogehogeや、/instance/gehogehoというようになります。Preferencesはツリー上になってますから、あるPreferencesからparentやchildといったWalkerメソッドによって移動することができるのです。第一ノードごとに永続化方法が変り、以下のノードごとに永続化ファイルが異なるのです。DBに永続化するPreferencesとかも作れますね。一点残念なのは、Preferencesの仕様(OSGi仕様)で、パス+パラメータの仕組みがなかったこと。たとえば、/plugin/dicon?key1=value1とやると設定できちゃったりとかね。ここまでやるならDAPっぽい仕組みにしてもよかったかな〜と。ま、実装上乗せすればすぐ作れる機能ですが。
public class PluginScope implements IScopeContext { public static final String SCOPE = "plugin"; private Plugin plugin; private String qualifier; public PluginScope(Plugin plugin) { super(); if(plugin == null) { throw new IllegalArgumentException(); } this.plugin = plugin; } public IPath getLocation() { IPath path = ResourcesPlugin.getPlugin().getStateLocation(); String pluginID = plugin.getBundle().getSymbolicName(); path = path.removeLastSegments(1).append(pluginID); return path; } public String getName() { return SCOPE; } public IEclipsePreferences getNode(String qualifier) { if (qualifier == null) { throw new IllegalArgumentException(); } if (plugin == null) { return null; } IEclipsePreferences root = Platform.getPreferencesService().getRootNode(); String pluginID = plugin.getBundle().getSymbolicName(); return (IEclipsePreferences)root.node(SCOPE).node(pluginID).node(qualifier); } }
Preferencesは、複数ノードがツリー上になっているので赤字のところのようなノードの数を数える処理が必要です。基本的な機能は基底のEclipsePreferencesで実装されているので、オーバーライドするべきJavaDocが書かれているメソッドを実装しなおすだけでOK。ちょっと分かりにくいのは、Preferences自体がPreferencesのファクトリーとなっているところです。privateコンストラクターと、internalCreate()メソッドは、PluginScope#getNode()で利用している、Preferences#node()メソッドより呼び出されます。
public class PluginPreferences extends EclipsePreferences { private static Set loadedNodes = new HashSet(); private String pluginID; private String qualifier; private IEclipsePreferences loadLevel; private int segmentCount; private boolean initialized; public PluginPreferences() { super(null, null); } private PluginPreferences(IEclipsePreferences parent, String name) { super(parent, name); String path = absolutePath(); segmentCount = getSegmentCount(path); if (segmentCount < 2) { return; } pluginID = getSegment(path, 1); if (segmentCount > 2) { qualifier = getSegment(path, 2); } } protected EclipsePreferences internalCreate( IEclipsePreferences nodeParent, String nodeName, Plugin context) { return new PluginPreferences(nodeParent, nodeName); } protected IPath getLocation() { if (pluginID == null || qualifier == null) { return null; } IPath path = ResourcesPlugin.getPlugin().getStateLocation(); path = path.removeLastSegments(1).append(pluginID); return computeLocation(path, qualifier); } protected IEclipsePreferences getLoadLevel() { if (loadLevel == null) { if (pluginID == null || qualifier == null) { return null; } IEclipsePreferences node = this; for (int i = 3; i < segmentCount; i++) { node = (IEclipsePreferences) node.parent(); } loadLevel = node; } return loadLevel; } protected void loaded() { loadedNodes.add(name()); } protected boolean isAlreadyLoaded(IEclipsePreferences node) { return loadedNodes.contains(node.name()); } }
Plugin.xmlは。。。
<extension point="org.eclipse.core.runtime.preferences"> <scope class="org.seasar.kijimuna.core.preferences.PluginPreferences" name="plugin"/> </extension>