Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDJ Houghton2012-01-19 20:11:44 +0000
committerDJ Houghton2012-01-19 20:11:44 +0000
commita20fbc2f08d5e536c959b5590ce19179e708dbc4 (patch)
tree36b07cffac14d2177da33fe9b312edabc4e14032 /bundles/org.eclipse.equinox.preferences
parentf9e9301010b0f1452ffb5c7e930f02697308c2ab (diff)
downloadrt.equinox.bundles-a20fbc2f08d5e536c959b5590ce19179e708dbc4.tar.gz
rt.equinox.bundles-a20fbc2f08d5e536c959b5590ce19179e708dbc4.tar.xz
rt.equinox.bundles-a20fbc2f08d5e536c959b5590ce19179e708dbc4.zip
Bug 172096 - [prefs] Ensure pluggability of backing storev20120119-2011
Diffstat (limited to 'bundles/org.eclipse.equinox.preferences')
-rw-r--r--bundles/org.eclipse.equinox.preferences/META-INF/MANIFEST.MF2
-rw-r--r--bundles/org.eclipse.equinox.preferences/schema/preferences.exsd25
-rw-r--r--bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/EclipsePreferences.java72
-rw-r--r--bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferenceServiceRegistryHelper.java39
-rw-r--r--bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PrefsMessages.java6
-rw-r--r--bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/RootPreferences.java33
-rw-r--r--bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/ScopeDescriptor.java141
-rw-r--r--bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/TestHelper.java26
-rw-r--r--bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/messages.properties6
-rw-r--r--bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/runtime/preferences/AbstractPreferenceStorage.java135
10 files changed, 433 insertions, 52 deletions
diff --git a/bundles/org.eclipse.equinox.preferences/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.preferences/META-INF/MANIFEST.MF
index f2e35012..2d704ff5 100644
--- a/bundles/org.eclipse.equinox.preferences/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.preferences/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.equinox.preferences; singleton:=true
-Bundle-Version: 3.4.100.qualifier
+Bundle-Version: 3.5.0.qualifier
Bundle-Activator: org.eclipse.core.internal.preferences.Activator
Bundle-Vendor: %providerName
Bundle-Localization: plugin
diff --git a/bundles/org.eclipse.equinox.preferences/schema/preferences.exsd b/bundles/org.eclipse.equinox.preferences/schema/preferences.exsd
index 6173800b..3f253143 100644
--- a/bundles/org.eclipse.equinox.preferences/schema/preferences.exsd
+++ b/bundles/org.eclipse.equinox.preferences/schema/preferences.exsd
@@ -63,7 +63,7 @@
</documentation>
</annotation>
</attribute>
- <attribute name="class" type="string" use="required">
+ <attribute name="class" type="string">
<annotation>
<documentation>
The name of the class.
@@ -73,6 +73,16 @@
</appInfo>
</annotation>
</attribute>
+ <attribute name="storage" type="string">
+ <annotation>
+ <documentation>
+ The class which implements the preference storage.
+ </documentation>
+ <appInfo>
+ <meta.attribute kind="java" basedOn="org.eclipse.core.runtime.preferences.AbstractPreferenceStorage:"/>
+ </appInfo>
+ </annotation>
+ </attribute>
</complexType>
</element>
@@ -140,6 +150,17 @@
&lt;/extension&gt;
&lt;/pre&gt;
&lt;/p&gt;
+
+If the client chooses let the Eclipse Platform handle the preference nodes but wishes to define a custom location/mechanism for persisting the data, then they are able to set the &quot;storage&quot; attribute on the &quot;scope&quot; element. Note that only one of the &quot;class&quot; and &quot;storage&quot; attributes can be defined at the same time. The class referenced in the &quot;storage&quot; attribute must extend the AbstractPreferenceStorage class. In the following example the &quot;FooStorage&quot; class handles the loading/saving for the &quot;foo&quot; preferences.
+&lt;p&gt;
+ &lt;pre&gt;
+ &lt;extension point=&quot;org.eclipse.equinox.preferences.preferences&quot;&gt;
+ &lt;scope name=&quot;foo&quot; storage=&quot;com.example.FooStorage&quot;/&gt;
+ &lt;initializer class=&quot;com.example.MyPreferenceInitializer&quot;/&gt;
+ &lt;modifier class=&quot;com.example.MyModifyListener&quot;/&gt;
+ &lt;/extension&gt;
+ &lt;/pre&gt;
+&lt;/p&gt;
</documentation>
</annotation>
@@ -166,7 +187,7 @@
<meta.section type="copyright"/>
</appInfo>
<documentation>
- Copyright (c) 2004, 2009 IBM Corporation and others.&lt;br&gt;
+ Copyright (c) 2004, 2012 IBM Corporation and others.&lt;br&gt;
All rights reserved. This program and the accompanying materials are made
available under the terms of the Eclipse Public License v1.0 which
accompanies this distribution, and is available at
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/EclipsePreferences.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/EclipsePreferences.java
index ee30ae8a..200d5d93 100644
--- a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/EclipsePreferences.java
+++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/EclipsePreferences.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2011 IBM Corporation and others.
+ * Copyright (c) 2004, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -58,6 +58,7 @@ public class EclipsePreferences implements IEclipsePreferences, IScope {
protected boolean removed = false;
private ListenerList nodeChangeListeners;
private ListenerList preferenceChangeListeners;
+ private ScopeDescriptor descriptor;
public static boolean DEBUG_PREFERENCE_GENERAL = false;
public static boolean DEBUG_PREFERENCE_SET = false;
@@ -196,10 +197,18 @@ public class EclipsePreferences implements IEclipsePreferences, IScope {
/*
* @see org.osgi.service.prefs.Preferences#childrenNames()
*/
- public String[] childrenNames() {
+ public String[] childrenNames() throws BackingStoreException {
// illegal state if this node has been removed
checkRemoved();
- return internalChildNames();
+ String[] internal = internalChildNames();
+ // if we are != 0 then we have already been initialized
+ if (internal.length != 0)
+ return internal;
+ // we only want to query the descriptor for the child names if
+ // this node is the scope root
+ if (descriptor != null && getSegmentCount(absolutePath()) == 1)
+ return descriptor.childrenNames(absolutePath());
+ return internal;
}
protected String[] internalChildNames() {
@@ -560,7 +569,7 @@ public class EclipsePreferences implements IEclipsePreferences, IScope {
}
protected IEclipsePreferences getLoadLevel() {
- return null;
+ return descriptor == null ? null : descriptor.getLoadLevel(this);
}
/*
@@ -586,7 +595,9 @@ public class EclipsePreferences implements IEclipsePreferences, IScope {
}
protected EclipsePreferences internalCreate(EclipsePreferences nodeParent, String nodeName, Object context) {
- return new EclipsePreferences(nodeParent, nodeName);
+ EclipsePreferences result = new EclipsePreferences(nodeParent, nodeName);
+ result.descriptor = this.descriptor;
+ return result;
}
/**
@@ -658,7 +669,7 @@ public class EclipsePreferences implements IEclipsePreferences, IScope {
* Subclasses to over-ride.
*/
protected boolean isAlreadyLoaded(IEclipsePreferences node) {
- return true;
+ return descriptor == null ? true : descriptor.isAlreadyLoaded(node.absolutePath());
}
/*
@@ -678,7 +689,15 @@ public class EclipsePreferences implements IEclipsePreferences, IScope {
* could not be loaded
*/
protected void load() throws BackingStoreException {
- load(getLocation());
+ if (descriptor == null) {
+ load(getLocation());
+ } else {
+ // load the properties then set them without sending out change events
+ Properties props = descriptor.load(absolutePath());
+ if (props == null || props.isEmpty())
+ return;
+ convertFromProperties(this, props, false);
+ }
}
protected static Properties loadProperties(IPath location) throws BackingStoreException {
@@ -720,7 +739,11 @@ public class EclipsePreferences implements IEclipsePreferences, IScope {
}
protected void loaded() {
- // do nothing
+ if (descriptor == null) {
+ // do nothing
+ } else {
+ descriptor.loaded(absolutePath());
+ }
}
protected void loadLegacy() {
@@ -989,33 +1012,28 @@ public class EclipsePreferences implements IEclipsePreferences, IScope {
* was actually removed.
*/
protected void removeNode(IEclipsePreferences child) {
- boolean wasRemoved = false;
- synchronized (this) {
- if (children != null) {
- wasRemoved = children.remove(child.name()) != null;
- if (wasRemoved)
- makeDirty();
- if (children.isEmpty())
- children = null;
- }
- }
- if (wasRemoved)
+ if (removeNode(child.name()) != null) {
fireNodeEvent(new NodeChangeEvent(this, child), false);
+ if (descriptor != null)
+ descriptor.removed(child.absolutePath());
+ }
}
/*
* Remove non-initialized node from the collection.
*/
- protected void removeNode(String key) {
+ protected Object removeNode(String key) {
synchronized (this) {
if (children != null) {
- boolean wasRemoved = children.remove(key) != null;
- if (wasRemoved)
+ Object result = children.remove(key);
+ if (result != null)
makeDirty();
if (children.isEmpty())
children = null;
+ return result;
}
}
+ return null;
}
/*
@@ -1054,7 +1072,11 @@ public class EclipsePreferences implements IEclipsePreferences, IScope {
* could not be saved
*/
protected void save() throws BackingStoreException {
- save(getLocation());
+ if (descriptor == null) {
+ save(getLocation());
+ } else {
+ descriptor.save(absolutePath(), convertToProperties(new Properties(), "")); //$NON-NLS-1$
+ }
}
protected void save(IPath location) throws BackingStoreException {
@@ -1243,4 +1265,8 @@ public class EclipsePreferences implements IEclipsePreferences, IScope {
public String toString() {
return absolutePath();
}
+
+ void setDescriptor(ScopeDescriptor descriptor) {
+ this.descriptor = descriptor;
+ }
}
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferenceServiceRegistryHelper.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferenceServiceRegistryHelper.java
index a4dee274..c01a6213 100644
--- a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferenceServiceRegistryHelper.java
+++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferenceServiceRegistryHelper.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2010 IBM Corporation and others.
+ * Copyright (c) 2006, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -29,6 +29,7 @@ public class PreferenceServiceRegistryHelper implements IRegistryChangeListener
private static final String ELEMENT_INITIALIZER = "initializer"; //$NON-NLS-1$
private static final String ATTRIBUTE_NAME = "name"; //$NON-NLS-1$
private static final String ATTRIBUTE_CLASS = "class"; //$NON-NLS-1$
+ private static final String ATTRIBUTE_STORAGE = "storage"; //$NON-NLS-1$
private static final String ELEMENT_SCOPE = "scope"; //$NON-NLS-1$
private static final String ELEMENT_MODIFIER = "modifier"; //$NON-NLS-1$
// Store this around for performance
@@ -156,15 +157,33 @@ public class PreferenceServiceRegistryHelper implements IRegistryChangeListener
IScope scope = null;
Object value = scopeRegistry.get(name);
if (value instanceof IConfigurationElement) {
- try {
- scope = (IScope) ((IConfigurationElement) value).createExecutableExtension(ATTRIBUTE_CLASS);
- scopeRegistry.put(name, scope);
- } catch (ClassCastException e) {
- log(createStatusError(PrefsMessages.preferences_classCastScope, e));
- return new EclipsePreferences(parent, name);
- } catch (CoreException e) {
- log(e.getStatus());
- return new EclipsePreferences(parent, name);
+ // did the user define their own class?
+ if (((IConfigurationElement) value).getAttribute(ATTRIBUTE_CLASS) != null) {
+ try {
+ scope = (IScope) ((IConfigurationElement) value).createExecutableExtension(ATTRIBUTE_CLASS);
+ scopeRegistry.put(name, scope);
+ } catch (ClassCastException e) {
+ log(createStatusError(PrefsMessages.preferences_classCastScope, e));
+ return new EclipsePreferences(parent, name);
+ } catch (CoreException e) {
+ log(e.getStatus());
+ return new EclipsePreferences(parent, name);
+ }
+ } else if (((IConfigurationElement) value).getAttribute(ATTRIBUTE_STORAGE) != null) {
+ // or if they defined a storage class then use EclipsePreferences to model the prefs.
+ try {
+ AbstractPreferenceStorage storage = (AbstractPreferenceStorage) ((IConfigurationElement) value).createExecutableExtension(ATTRIBUTE_STORAGE);
+ ScopeDescriptor descriptor = new ScopeDescriptor(storage);
+ EclipsePreferences result = new EclipsePreferences(parent, name);
+ result.setDescriptor(descriptor);
+ return result;
+ } catch (ClassCastException e) {
+ log(createStatusError(PrefsMessages.preferences_classCastStorage, e));
+ return new EclipsePreferences(parent, name);
+ } catch (CoreException e) {
+ log(e.getStatus());
+ return new EclipsePreferences(parent, name);
+ }
}
} else
scope = (IScope) value;
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PrefsMessages.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PrefsMessages.java
index 6781e95f..f3fc8dfa 100644
--- a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PrefsMessages.java
+++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PrefsMessages.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2009 IBM Corporation and others.
+ * Copyright (c) 2005, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -25,6 +25,7 @@ public class PrefsMessages extends NLS {
// Preferences
public static String preferences_applyProblems;
public static String preferences_classCastScope;
+ public static String preferences_classCastStorage;
public static String preferences_classCastListener;
public static String preferences_classCastFilterEntry;
@@ -38,6 +39,7 @@ public class PrefsMessages extends NLS {
public static String preferences_invalidExtensionSuperclass;
public static String preferences_invalidFileFormat;
public static String preferences_loadException;
+ public static String preferences_loadProblems;
public static String preferences_matching;
public static String preferences_missingClassAttribute;
public static String preferences_missingScopeAttribute;
@@ -47,6 +49,8 @@ public class PrefsMessages extends NLS {
public static String preferences_saveProblems;
public static String preferences_validate;
public static String preferences_validationException;
+ public static String childrenNames;
+ public static String childrenNames2;
static {
// load message values from bundle file
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/RootPreferences.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/RootPreferences.java
index 26e59a1e..74ebd74d 100644
--- a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/RootPreferences.java
+++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/RootPreferences.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2006 IBM Corporation and others.
+ * Copyright (c) 2004, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipse.core.internal.preferences;
-import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
@@ -52,17 +52,16 @@ public class RootPreferences extends EclipsePreferences {
* @see EclipsePreferences#getChild(String, Plugin)
*/
protected synchronized IEclipsePreferences getChild(String key, Object context) {
- Object value = null;
- IEclipsePreferences child = null;
- if (children != null)
- value = children.get(key);
- if (value != null) {
- if (value instanceof IEclipsePreferences)
- return (IEclipsePreferences) value;
- //lazy initialization
- child = PreferencesService.getDefault().createNode(key);
- addChild(key, child);
- }
+ if (children == null)
+ return null;
+ Object value = children.get(key);
+ if (value == null)
+ return null;
+ if (value instanceof IEclipsePreferences)
+ return (IEclipsePreferences) value;
+ //lazy initialization
+ IEclipsePreferences child = PreferencesService.getDefault().createNode(key);
+ addChild(key, child);
return child;
}
@@ -71,7 +70,13 @@ public class RootPreferences extends EclipsePreferences {
*/
protected synchronized IEclipsePreferences[] getChildren() {
//must perform lazy initialization of child nodes
- String[] childNames = childrenNames();
+ String[] childNames = new String[0];
+ try {
+ childNames = childrenNames();
+ } catch (BackingStoreException e) {
+ log(new Status(IStatus.ERROR, Activator.PI_PREFERENCES, PrefsMessages.childrenNames, e));
+ return new IEclipsePreferences[0];
+ }
IEclipsePreferences[] childNodes = new IEclipsePreferences[childNames.length];
for (int i = 0; i < childNames.length; i++)
childNodes[i] = getChild(childNames[i], null);
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/ScopeDescriptor.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/ScopeDescriptor.java
new file mode 100644
index 00000000..e5e3889d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/ScopeDescriptor.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.core.internal.preferences;
+
+import java.util.*;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.preferences.AbstractPreferenceStorage;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.osgi.util.NLS;
+import org.osgi.service.prefs.BackingStoreException;
+
+public class ScopeDescriptor {
+
+ String name;
+ AbstractPreferenceStorage storage;
+ Set loadedNodes = Collections.synchronizedSet(new HashSet());
+
+ public ScopeDescriptor(AbstractPreferenceStorage storage) {
+ super();
+ this.storage = storage;
+ }
+
+ String getName() {
+ return name;
+ }
+
+ /*
+ * For now the default behaviour is that we flush/load at the second level.
+ */
+ IEclipsePreferences getLoadLevel(IEclipsePreferences node) {
+ String path = node.absolutePath();
+ int count = EclipsePreferences.getSegmentCount(path);
+ // root or scope root
+ if (count == 1 || count == 0)
+ return null;
+ // the load level we want
+ if (count == 2)
+ return node;
+ for (int i = count; i > 2 && node.parent() != null; i--)
+ node = (IEclipsePreferences) node.parent();
+ return node;
+ }
+
+ String[] childrenNames(final String path) throws BackingStoreException {
+ if (storage == null)
+ return new String[0];
+ final String[][] result = new String[1][];
+ final BackingStoreException[] bse = new BackingStoreException[1];
+ ISafeRunnable code = new ISafeRunnable() {
+ public void run() throws Exception {
+ result[0] = storage.childrenNames(path);
+ }
+
+ public void handleException(Throwable exception) {
+ if (exception instanceof BackingStoreException)
+ bse[0] = (BackingStoreException) exception;
+ else
+ bse[0] = new BackingStoreException(NLS.bind(PrefsMessages.childrenNames2, path), exception);
+ }
+ };
+ SafeRunner.run(code);
+ if (bse[0] != null)
+ throw bse[0];
+ return result[0] == null ? new String[0] : result[0];
+ }
+
+ Properties load(final String path) throws BackingStoreException {
+ if (storage == null)
+ return null;
+ final Properties[] result = new Properties[1];
+ final BackingStoreException[] bse = new BackingStoreException[1];
+ ISafeRunnable code = new ISafeRunnable() {
+ public void run() throws Exception {
+ result[0] = storage.load(path);
+ }
+
+ public void handleException(Throwable exception) {
+ if (exception instanceof BackingStoreException)
+ bse[0] = (BackingStoreException) exception;
+ else
+ bse[0] = new BackingStoreException(NLS.bind(PrefsMessages.preferences_loadException, path), exception);
+ }
+ };
+ SafeRunner.run(code);
+ if (bse[0] != null)
+ throw bse[0];
+ return result[0] == null ? null : result[0];
+ }
+
+ void save(final String path, final Properties properties) throws BackingStoreException {
+ if (storage == null)
+ return;
+ final BackingStoreException[] bse = new BackingStoreException[1];
+ ISafeRunnable code = new ISafeRunnable() {
+ public void run() throws Exception {
+ storage.save(path, properties);
+ }
+
+ public void handleException(Throwable exception) {
+ if (exception instanceof BackingStoreException)
+ bse[0] = (BackingStoreException) exception;
+ else
+ bse[0] = new BackingStoreException(NLS.bind(PrefsMessages.preferences_saveException, path), exception);
+ }
+ };
+ SafeRunner.run(code);
+ if (bse[0] != null)
+ throw bse[0];
+ }
+
+ boolean isAlreadyLoaded(String node) {
+ return loadedNodes.contains(node);
+ }
+
+ void loaded(String node) {
+ loadedNodes.add(node);
+ }
+
+ void removed(final String path) {
+ if (storage == null)
+ return;
+ SafeRunner.run(new ISafeRunnable() {
+ public void run() throws Exception {
+ storage.removed(path);
+ }
+
+ public void handleException(Throwable exception) {
+ // ignore here, error will be logged in saferunner
+ }
+ });
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/TestHelper.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/TestHelper.java
new file mode 100644
index 00000000..6574dc00
--- /dev/null
+++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/TestHelper.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.core.internal.preferences;
+
+import java.util.Properties;
+import org.osgi.service.prefs.BackingStoreException;
+
+public class TestHelper {
+
+ public static Properties convertToProperties(EclipsePreferences node, String prefix) throws BackingStoreException {
+ return node.convertToProperties(new Properties(), prefix);
+ }
+
+ // TODO
+ //public static IPath getInstanceBaseLocation() {
+ // return InstancePreferences.getBaseLocation();
+ //}
+}
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/messages.properties b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/messages.properties
index d88a4423..717aaf88 100644
--- a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/messages.properties
+++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/messages.properties
@@ -1,5 +1,5 @@
###############################################################################
-# Copyright (c) 2000, 2009 IBM Corporation and others.
+# Copyright (c) 2000, 2012 IBM Corporation and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
@@ -13,6 +13,7 @@
### Preferences
preferences_applyProblems=Problems applying preference changes.
preferences_classCastScope=Extensions to org.eclipse.core.runtime.preferences extension point must implement the IScope interface.
+preferences_classCastStorage=Preference storage extensions must extend the AbstractPreferenceStorage class.
preferences_classCastListener=Preference modify listeners must subclass the PreferenceModifyListener class.
preferences_classCastFilterEntry=Preference filter mappings must be instances of the class PreferenceFilterEntry.
preferences_contextError=Error occurred while accessing preference scope.
@@ -25,6 +26,7 @@ preferences_incompatible=The preference file contains preferences for version \"
preferences_invalidExtensionSuperclass=Extension does not extend class AbstractPreferenceInitializer.
preferences_invalidFileFormat=Invalid preference file format.
preferences_loadException=Exception loading preferences from: {0}.
+preferences_loadProblems=Problems loading preferences.
preferences_matching=Exception while matching preference filters.
preferences_missingClassAttribute= Missing \"class\" attribute in \"preference\" element in extension declaration for: {0}.
preferences_missingScopeAttribute= Missing \"scope\" attribute in \"preference\" element in extension declaration for: {0}.
@@ -34,3 +36,5 @@ preferences_saveException=Exception saving preferences to: {0}.
preferences_saveProblems=Problems saving preferences.
preferences_validate=Some preferences may not be compatible with the currently installed plug-ins.
preferences_validationException=Exception while validating bundle versions.
+childrenNames=Error occurred while retrieving children names.
+childrenNames2=Error occurred while retrieving children names for preference node: {0}.
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/runtime/preferences/AbstractPreferenceStorage.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/runtime/preferences/AbstractPreferenceStorage.java
new file mode 100644
index 00000000..9d44265e
--- /dev/null
+++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/runtime/preferences/AbstractPreferenceStorage.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.core.runtime.preferences;
+
+import java.io.*;
+import java.util.Properties;
+import org.eclipse.core.internal.preferences.PrefsMessages;
+import org.osgi.service.prefs.BackingStoreException;
+
+/**
+ * Abstract class which can be used to help provide an alternate storage mechanism
+ * for Eclipse preferences. Clients can over-ride this class and implement the appropriate
+ * methods to read/persist preferences.
+ *
+ * @since 3.5
+ */
+public abstract class AbstractPreferenceStorage {
+
+ /**
+ * Return a <code>java.util.Properties</code> object containing the preference
+ * key/value pairs for the preference node with the specified path, and its children.
+ * <p>
+ * The table keys consist of an optional child node path and separator, followed by
+ * the property key. The table values are the values of the properties.
+ * <pre>
+ * [childNodePath/]propertyKey=propertyValue
+ * </pre>
+ * </p>
+ * <p>
+ * Note: Whether they are absolute or relative, the paths in the returned Properties
+ * object are always interpreted as relative to the node specified by nodePath.
+ * </p>
+ * @param nodePath the absolute path of the preference node
+ * @return a <code>java.util.Properties</code> object or <code>null</code>
+ * @throws BackingStoreException if there was a problem loading the properties
+ */
+ public abstract Properties load(String nodePath) throws BackingStoreException;
+
+ /**
+ * Save the given <code>java.util.Properties</code> object which represents
+ * preference key/value pairs for the preference node represented by the given
+ * path.
+ * <p>
+ * Clients are reminded that if the given properties object is empty then
+ * the preference node has been removed and they should react
+ * accordingly (e.g. for instance by removing the file on disk)
+ * </p>
+ *
+ * @param nodePath the absolute path of the preference node
+ * @param properties the <code>java.util.Properties</code> object to store
+ * @throws BackingStoreException if there was a problem saving the properties
+ */
+ public abstract void save(String nodePath, Properties properties) throws BackingStoreException;
+
+ /**
+ * Helper method to load a <code>java.util.Properties</code> file from the given
+ * input stream. The stream will be closed on completion of the operation.
+ *
+ * @param input the stream to load from
+ * @return the <code>java.util.Properties</code> object loaded from the stream
+ * @throws BackingStoreException if there was a problem loading the file
+ */
+ protected Properties loadProperties(InputStream input) throws BackingStoreException {
+ Properties result = new Properties();
+ try {
+ input = new BufferedInputStream(input);
+ result.load(input);
+ } catch (IOException e) {
+ throw new BackingStoreException(PrefsMessages.preferences_loadProblems, e);
+ } finally {
+ if (input != null)
+ try {
+ input.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Helper method to save the given <code>java.util.Properties</code> object
+ * to the given output stream. The stream will be closed at the end of the operation.
+ *
+ * @param output the stream to store the object to
+ * @param properties the object to store
+ * @throws BackingStoreException if there was a problem saving the object
+ */
+ protected void saveProperties(OutputStream output, Properties properties) throws BackingStoreException {
+ try {
+ output = new BufferedOutputStream(output);
+ properties.store(output, null);
+ output.flush();
+ } catch (IOException e) {
+ throw new BackingStoreException(PrefsMessages.preferences_saveProblems, e);
+ } finally {
+ if (output != null)
+ try {
+ output.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+
+ /**
+ * Return a string array containing the names of the children for the node
+ * with the given path. If there are no children then an empty array is returned.
+ * One example where this method is commonly called, is at the scope root
+ * when discovering the initial children.
+ *
+ * @param nodePath the path for the preference node
+ * @return the array of children names
+ * @throws BackingStoreException if there was a problem retrieving the child names
+ */
+ public abstract String[] childrenNames(String nodePath) throws BackingStoreException;
+
+ /**
+ * Callback to inform the client that the preference node with the specified
+ * path has been deleted and the client should react accordingly and make
+ * the appropriate changes to the storage. (e.g. delete the file/information
+ * associated with that node)
+ *
+ * @param nodePath the absolute path of the preference node
+ */
+ public abstract void removed(String nodePath);
+} \ No newline at end of file

Back to the top