This article describes the usage of Eclipse preferences for storing and retrieving user settings.
1. Using preferences to persist data
1.1. Preferences and scopes
Preference are used to store user settings and data like color preferences, runtime options, etc between application restarts.
Preferences are stored as key / value pairs, where the key is an arbitrary String
.
The value can be a boolean, String, int or another primitive type.
For example, the user key may point to the value vogella.
The preference support in Eclipse is based on the Preferences
class from the org.osgi.service.prefs
package.
Eclipse preferences are very similar to the standard Java preferences API, but also supports different scopes. The scope defines how the preference data is stored and how it is changeable. The Eclipse runtime defines three scopes as explained in the following table.
Scope | Description |
---|---|
Instance scope |
Preferences in this scope are specific to a single Eclipse workspace. If you start an Eclipse application these settings can be different for each workspace. |
Configuration scope |
Settings for identical for the same installation. Preferences stored in this scope are shared across all workspaces. |
Default scope |
Default values can not be changed. This scope can be used to store default values for all your keys. These preferences are supplied via configuration files in plug-ins and product definitions. |
BundleDefaultsScope |
Similar to the default scope, these values are not written to disk. They are read from a file, typically named preferences.ini. |
1.2. Storage of the preferences
Preferences are stored in the workspace of your application under the .metadata/.plugins/org.eclipse.core.runtime/.settings/ directory as <nodePath>.prefs files. By default, the <nodePath> corresponds to the Bundle-SymbolicName of the plugin but can be customized via the preferences API. Typically, the workspace is the directory from which the application is launched.
The storage location for preferences can be adjusted through the -data launch parameter in Eclipse. For instance, to direct preferences storage to the user’s home directory, you can use the -data @user.home parameter setting.
1.3. Working with Eclipse Preference API
You can create and manipulate preferences directly via Singletons
provided by the Eclipse runtime.
You have the InstanceScope
, ConfigurationScope
and DefaultScope
classes which give access to the corresponding instance via the INSTANCE
field.
Preference values are read and saved by get()
and put()
methods.
In the get()
method you specify a default value in case the key can not be found.
The clear()
method removes all preferences and the remove()
method allows you to delete a selected preference value.
Via the flush()
method you persist the preferences to the file system.
// We access the instanceScope
Preferences preferences = InstanceScope.INSTANCE.getNode("com.vogella.eclipse.preferences.test");
Preferences sub1 = preferences.node("node1");
Preferences sub2 = preferences.node("node2");
sub1.put("h1", "Hello");
sub1.put("h2", "Hello again");
sub2.put("h1", "Moin");
try {
// forces the application to save the preferences
preferences.flush();
} catch (BackingStoreException e) {
e.printStackTrace();
}
}
// read values from the instance scope
Preferences preferences = InstanceScope.INSTANCE.getNode("com.vogella.eclipse.preferences.test");
Preferences sub1 = preferences.node("node1");
Preferences sub2 = preferences.node("node2");
sub1.get("h1", "default");
sub1.get("h2", "default");
sub2.get("h1", "default");
1.4. Reacting to changes in the preferences
You can register IPropertyChangeListener
instances to changes in the preference values.
These listener are called by the Eclipse framework if the reference value changes.
Preferences preferences = InstanceScope.INSTANCE.getNode("com.vogella.eclipse.preferences.test");
preferences.addPropertyChangeListener(new IPropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent event) {
if (event.getProperty() == "MySTRING1") {
String value = event.getNewValue().toString()
// do something with the new value
}
}
});
1.5. Default preference values via plugin_customization.ini
You can use a file to set the default values of preferences. The file which contains these defaults is typically named plugin_customization.ini.
Such a file needs to be registered via the preferenceCustomization property on the product extension point in the plugin.xml file. This is demonstrated in the following screenshot.
The format to use is <plugin id>/<setting>=<value>
, e.g., com.vogella.tasks.ui/user=vogella.
2. Workspace Location
An Eclipse based application requires a place to stores its configuration data. This is called the workspace location. The default workspace location is the install location of the Eclipse application.
2.1. Using the osgi.instance.area.default property
The osgi.instance.area.default
property can be used to declaratively define an alternative workspace location.
The property can be specified in the config.ini file of the RCP application.
Usually properties of the config.ini file are specified in a product configuration:
It is also possible to use variables like |
2.2. Setting the workspace location programmatically
Many RCP applications have a login screen at startup and the actual workspace location should be set according to the user being logged in.
In E4 applications a login screen is usually created in a lifecycle class in the method annotated with @PostContextCreate
.
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import org.eclipse.core.runtime.Platform;
import org.eclipse.e4.ui.workbench.lifecycle.PostContextCreate;
public class LifeCycleManager {
@PostContextCreate
public void postContextCreate() throws IllegalStateException, IOException {
// Show login dialog to the user
String userName = // get username from login dialog;
// check if the instance location is already set,
// otherwise setting another one will throw an IllegalStateException
if (!Platform.getInstanceLocation().isSet()) {
String defaultPath = System.getProperty("user.home");
// build the desired path for the workspace
String path = defaultPath + "/" + userName + "/workspace/";
URL instanceLocationUrl = new URL("file", null, path);
Platform.getInstanceLocation().set(instanceLocationUrl, false);
}
}
}
The instance location can only be set once! Therefore the if statement with |
When running the RCP application during development from the Eclipse IDE there usually already is a workspace in the run configuration. To be able to set the location during development the Location field must be empty. |
3. Usage of persistence for Eclipse 4 API based applications
3.1. Working with preferences via dependency injection
The Eclipse platform allows you to use dependency injection for preferences handling.
To access preference you use the @Preference
annotation as qualifier for the dependency injection annotation.
This means that @Preference
must be used together with @Inject
or one of the other annotations which implies dependency injection, e.g., the @Execute
annotation.
The @Preference
annotation allows you to specify the nodePath and the value as optional parameters.
The nodePath is the file name used to save the preference values to disk. By default, this is the Bundle-SymbolicName of the plug-in. The value parameter specifies the preference key for the value which should be injected.
Eclipse can also inject the IEclipsePreference
object.
You can use this object for storing values.
If you use the value parameter, Eclipse injects the value directly.
Use the value parameter for read access, while for storing or changing values, use the IEclipsePreference
object.
The following code snippet demonstrates how to put values into the preferences store.
Please note that @Preference
is used in combination with @Execute
.
// get IEclipsePreferences injected to change a value
@Execute
public void execute
(@Preference(nodePath = "com.example.e4.rcp.todo") IEclipsePreferences prefs) {
// more stuff...
prefs.put("user", "TestUser");
prefs.put("password", "Password");
// Persists
try {
prefs.flush();
} catch (BackingStoreException e) {
e.printStackTrace();
}
}
The next snippet demonstrates the read access of preference values.
This time the preference annotation is used a qualifier for @Inject
.
@Inject
@Optional
public void trackUserSettings
(
@Preference(nodePath = "com.example.e4.rcp.todo",
value = "user")
String user) {
System.out.println("New user: " + user);
}
@Inject
@Optional
public void trackPasswordSettings
(
@Preference(nodePath = "com.example.e4.rcp.todo",
value = "password")
String password) {
System.out.println("New password: " + password);
}
The Eclipse platform automatically tracks the values and re-injects them into fields and methods if they change.
Eclipse tracks changes of preferences in the InstanceScope
scope.
Preference values in the ConfigurationScope
and DefaultScope
are not tracked.
If you use the injected IEclipsePreference
to store new preference values, these values are stored in the instance scope.
3.2. Persistence of part state
Eclipse provides the @PersistState
annotation for parts.
This annotation can be applied to a method in a class referred to a part.
Such an annotated method can be used to store the instance state of the part.
The Eclipse framework calls such a method whenever the part or the application closes.
The stored information can be used in the method annotated with the @PostConstruct
annotation.
A typical use case for such a method would be to store the state of a checkbox.
The usage of this annotation is demonstrated in the following example code.
@PostConstruct
public void createControl(MPart part) {
Map<String, String> state = part.getPersistedState();
String value = state.get("key");
...
}
@PersistState
public void persistState(MPart part) {
Map<String, String> state = part.getPersistedState();
state.put("key", "newValue");
...
}
3.3. Preference pages for e4
See http://www.opcoach.com/en/managing-preference-pages-with-eclipse-4/ for an introdution how to use preference pages in Eclipse RCP applications.
4. Preference handling in Eclipse 3.x
4.1. Preference Page
Eclipse 3.x provides a standard dialog to display and change preference values via a preference dialog.
To open the Preference dialog, you can use the org.eclipse.ui.window.preferences
command.
This functionality is specific to the Eclipse IDE and will not work for Eclipse 4 RCP applications. See e4 preferences for a pure e4 implementation. |
To add a new preference page a plug-in must provide an contribution to the org.eclipse.ui.preferencePages
extension point.
This extension point defines a class which is responsible for creating a user interface and storing the preference values.
This class must implement IWorkbenchPreferencePage
and must have a non-parameter constructor.
The keywordReference id attribute in this extension point can be used to define search terms for the preference page.
The PreferencePage
class or one of its subclasses can get extended; a good template is usually FieldEditorPreferencePage
.
4.2. Access Preferences in different plug-ins
You can access preferences in other plug-ins via the PreferenceService
service.
For example, to access the "MySTRING1" preference in the "de.vogella.preferences.page" plug-in, you can use the following:
String text = Platform.getPreferencesService().
getString("com.vogella.preferences.page", "MySTRING1", "hello", null);
4.3. Secure storage of preferences
Eclipse allows to encrypt preference values via the org.eclipse.equinox.security
plug-in.
The key / value pairs will be stored in the secure.storage file in the .eclipse/org.eclipse.equinox.security folder of the user’s home directory.
Eclipse uses a class of type PasswordProvider
for encrypting the preferences and has a default class registered.
Via the org.eclipse.equinox.security.secureStorage
extension point you can register your own PasswordProvider.
5. Rerequisites
The following assumes that you know how to create Eclipse plug-ins.
6. Tutorial: Preferences via code
You can create, store and retrieve preference values directly via your coding. The following gives an example for this.
Create the following custom composite for that. Use this composite in one of your parts.
The first Button
will set the preference values. The next will display the values and
the last will clear the preference values.
package de.vogella.preferences.test.ui;
import org.eclipse.core.runtime.preferences.ConfigurationScope;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
public class ButtonComposite extends Composite {
public ButtonComposite(Composite parent, int style) {
super(parent, style);
Button write = new Button(parent, SWT.PUSH);
write.setText("Write");
write.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Preferences preferences = ConfigurationScope.INSTANCE
.getNode("de.vogella.preferences.test");
Preferences sub1 = preferences.node("node1");
Preferences sub2 = preferences.node("node2");
sub1.put("h1", "Hello");
sub1.put("h2", "Hello again");
sub2.put("h1", "Moin");
try {
// forces the application to save the preferences
preferences.flush();
} catch (BackingStoreException e2) {
e2.printStackTrace();
}
}
});
Button read = new Button(parent, SWT.PUSH);
read.setText("Read");
read.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Preferences preferences = ConfigurationScope.INSTANCE
.getNode("de.vogella.preferences.test");
Preferences sub1 = preferences.node("node1");
Preferences sub2 = preferences.node("node2");
System.out.println(sub1.get("h1", "default"));
System.out.println(sub1.get("h2", "default"));
System.out.println(sub2.get("h1", "default"));
}
});
Button clear = new Button(parent, SWT.PUSH);
clear.setText("clear");
clear.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Preferences preferences = ConfigurationScope.INSTANCE
.getNode("de.vogella.preferences.test");
Preferences sub1 = preferences.node("node1");
Preferences sub2 = preferences.node("node2");
// Delete the existing settings
try {
sub1.clear();
sub2.clear();
preferences.flush();
} catch (BackingStoreException e1) {
e1.printStackTrace();
}
}
});
}
}
Run and test your program.
7. Exercise: Contribute a preference page to the Eclipse IDE
In this exercise, you create a plug-in with a preference pages which allows the user to enter certain settings.
Create a new simple plug-in project called com.vogella.preferences.page
.
No activator is needed and you do not have to use a template.
Open the MANIFEST.MF editor and add the following on the Dependencies tab.
-
org.eclipse.ui
-
org.eclipse.core.runtime
Open the MANIFEST.MF editor and click on the Extensions link on the Overview tab.
On this tab, add an extension for the org.eclipse.ui.preferencePages
extension point.
Enter the data in plugin.xml
similar to the following:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
<extension
point="org.eclipse.ui.preferencePages">
<page
class="com.vogella.preferences.page.VogellaPrefPage"
id="com.vogella.preferences.page.page1"
name="vogella Preferences">
</page>
</extension>
</plugin>
Enter the following code for your VogellaPrefPage
class.
Method init()
sets the preferences store and the method createFieldEditors()
registers editors for the values.
checkState()
allows to perform a validations.
To get notified about value changes you need to override the propertyChange method.
package com.vogella.preferences.page;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.DirectoryFieldEditor;
import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.preference.RadioGroupFieldEditor;
import org.eclipse.jface.preference.StringFieldEditor;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.preferences.ScopedPreferenceStore;
public class VogellaPrefPage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
public VogellaPrefPage() {
super(GRID);
}
public void createFieldEditors() {
addField(new DirectoryFieldEditor("PATH", "&Directory preference:", getFieldEditorParent()));
addField(new BooleanFieldEditor("BOOLEAN_VALUE", "&A boolean preference", getFieldEditorParent()));
addField(new RadioGroupFieldEditor("CHOICE", "A &multiple-choice preference", 1,
new String[][] { { "&Choice 1", "choice1" }, { "C&hoice 2", "choice2" } }, getFieldEditorParent()));
addField(new StringFieldEditor("MySTRING1", "A &text preference:", getFieldEditorParent()));
addField(new StringFieldEditor("MySTRING2", "A t&ext preference:", getFieldEditorParent()));
}
@Override
public void init(IWorkbench workbench) {
// second parameter is typically the plug-in id
setPreferenceStore(new ScopedPreferenceStore(InstanceScope.INSTANCE, "com.vogella.preferences.page"));
setDescription("A demonstration of a preference page implementation");
}
}
7.1. Add to your feature
Add your new plug-in to your feature.
7.2. Validate
Start a runtime Eclipse IDE via your product. Open the preference dialog via
.Ensure that you see your preference page in the preferences of the Eclipse IDE.
Validate that maintained values are stored if you restart your application.
7.3. Create preference initializer
Create the following class com.vogella.preferences.page.preferencepage.MyInitializer
.
package com.vogella.preferences.page;
import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.ui.preferences.ScopedPreferenceStore;
public class VogellaPrefInitializer extends AbstractPreferenceInitializer {
public VogellaPrefInitializer() {
System.out.println("Called");
}
@Override
public void initializeDefaultPreferences() {
ScopedPreferenceStore scopedPreferenceStore = new ScopedPreferenceStore(InstanceScope.INSTANCE, "com.vogella.preferences.page");
scopedPreferenceStore.setDefault("MySTRING1", "https://www.vogella.com/");
}
}
To set the default values for your preferences, define a new extension for the org.eclipse.core.runtime.preferences
extension point.
Right-click on it and select initializer
.
7.4. Use preference in one of your views
Ensure org.eclipse.ui
is available as dependency in the manifest of the plug-in in which you plan to use the preferences.
Create a new view or use an existing to show one of the preference values.
Also register a PropertyChangeListener
to the preferences store to get informed in case the preference
settings change.
package com.vogella.tasks.ui.parts;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import jakarta.annotation.PostConstruct;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.widgets.WidgetFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.preferences.ScopedPreferenceStore;
public class PlaygroundPart {
private Label label;
@PostConstruct
public void createPartControl(Composite parent) {
// more code
ScopedPreferenceStore scopedPreferenceStore = new ScopedPreferenceStore(InstanceScope.INSTANCE,
"com.vogella.preferences.page");
String string = scopedPreferenceStore.getString("MySTRING1");
label = WidgetFactory.label(SWT.NONE).layoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)).text(string).create(parent);
// add change listener to the node so that we are notified
// in case of changes
scopedPreferenceStore.addPropertyChangeListener(event -> {
if (event.getProperty().equals("MySTRING1")) {
label.setText(event.getNewValue().toString());
}
});
}
}
8. Tutorial: Secure storage of preferences
To test the secure storage of preferences create an new plug-in called com.vogella.preferences.security.
Add a new view.
Add the org.eclipse.equinox.security
plug-in as a dependency to it.
Change the code of your view to the following.
package de.vogella.preferences.security;
import org.eclipse.equinox.security.storage.ISecurePreferences;
import org.eclipse.equinox.security.storage.SecurePreferencesFactory;
import org.eclipse.equinox.security.storage.StorageException;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;
public class View extends ViewPart {
public void createPartControl(Composite parent) {
Button buttonPut = new Button(parent, SWT.PUSH);
buttonPut.setText("Save values");
buttonPut.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ISecurePreferences preferences = SecurePreferencesFactory
.getDefault();
ISecurePreferences node = preferences.node("info");
try {
node.put("user", "vogella", true);
node.put("password", "123", true);
} catch (StorageException e1) {
e1.printStackTrace();
}
}
});
Button buttonGet = new Button(parent, SWT.PUSH);
buttonGet.setText("Get values");
buttonGet.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ISecurePreferences preferences = SecurePreferencesFactory
.getDefault();
if (preferences.nodeExists("info")) {
ISecurePreferences node = preferences.node("info");
try {
String user = node.get("user", "n/a");
String password = node.get("password", "n/a");
System.out.println(user);
System.out.println(password);
} catch (StorageException e1) {
e1.printStackTrace();
}
}
}
});
}
/**
* Passing the focus request to the viewer's control.
*/
public void setFocus() {
}
}
9. Links and Literature
www.opcoach.com/en/managing-preference-pages-with-eclipse-4/ Managing preferences pages in e4 application
9.1. vogella Java example code
If you need more assistance we offer Online Training and Onsite training as well as consulting