I am using Preferences
to store application settings. My java class reads the settings at program start and then the data is available with simple getters for other classes.
Now I also want to implement setters because the user can change some Preferences in the program and therefore calling a setter from another java class is an easy method to change the preferences.
If I change a value in my Preferences, how can I ensure, that the data in the Preferences and in the class are consistent? Should I just store the data within the setter in the runtime object and in the Preferences?
And most importantly: How can I ensure, that no getter is called, before the data is written into the preferences? How do I need to synchronize them?
Here is just a really simple example to display the issue:
private static final Preferences PREFERENCES = //here are valid preferences
private static final String KEY = //Some path to the attribute
private static PrefManager prefManager = new PrefManager();
private String serverIP;
private PrefManager() {
this.serverIP = PREFERENCES.get(KEY, "");
}
public static void setServerIP(String serverIP) {
// How do I synchronize the PREFERENCE object and this setter to prevent getter
// calls between put and = call here?
PREFERENCES.put(KEY, serverIP);
prefManager.serverIP = serverIP;
}
In terms of solving your race condition, you can create your own Preferences extension and add synchronized
to set and get. There are two ways to create a preference extension: use a map internally and copy all key - values there, or create a facade.
In terms of how do you keep your application consistent: The answer to this is the Controller piece of MVC
Example of facade
I've copied all of the methods from Preferences and added them here. You can see that the constructor takes a Preferences parameter, which is going to be the reference implementing all methods in this facade (see the first two methods absolutePath() and addNodeChangeListener(...) for examples of how this should be implemented) Also note that the methods put
and get
have been synchronized. So if any thread is calling put, any other thread calling get will wait until put is done. (You may want to add synchronized to other methods as well)
===================
public class MyPrefsFacade extends Preferences {
private Preferences p;
public MyPrefsFacade(Preferences prefs) {
p = prefs;
}
public String absolutePath() { return p.absolutePath(); }
public void addNodeChangeListener(NodeChangeListener ncl) { p.addNodeChangeListener(ncl); }
public void addPreferenceChangeListener(PreferenceChangeListener pcl)
public String[] childrenNames()
public void clear()
public void exportNode(OutputStream os)
public void exportSubtree(OutputStream os)
public void flush()
public synchronized String get(String key, String def)
public boolean getBoolean(String key, boolean def)
public byte[] getByteArray(String key, byte[] def)
public double getDouble(String key, double def)
public float getFloat(String key, float def)
public int getInt(String key, int def)
public long getLong(String key, long def)
public boolean isUserNode()
public String[] keys()
public String name()
public Preferences node(String pathName)
public boolean nodeExists(String pathName)
public Preferences parent()
public synchronized void put(String key, String value)
public void putBoolean(String key, boolean value)
public void putByteArray(String key, byte[] value)
public void putDouble(String key, double value)
public void putFloat(String key, float value)
public void putInt(String key, int value)
public void putLong(String key, long value)
public void remove(String key)
public void removeNode()
public void removeNodeChangeListener(NodeChangeListener ncl)
public void sync()
public String toString()
}