Index: trunk/src/org/openstreetmap/josm/data/Preferences.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 13019)
+++ trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 13021)
@@ -6,6 +6,4 @@
 
 import java.awt.Color;
-import java.awt.GraphicsEnvironment;
-import java.awt.Toolkit;
 import java.io.File;
 import java.io.IOException;
@@ -15,5 +13,4 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.lang.reflect.Field;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
@@ -28,5 +25,4 @@
 import java.util.Map.Entry;
 import java.util.Optional;
-import java.util.ResourceBundle;
 import java.util.Set;
 import java.util.SortedMap;
@@ -46,4 +42,5 @@
 import org.openstreetmap.josm.data.preferences.IntegerProperty;
 import org.openstreetmap.josm.data.preferences.ColorInfo;
+import org.openstreetmap.josm.data.preferences.JosmBaseDirectories;
 import org.openstreetmap.josm.data.preferences.LongProperty;
 import org.openstreetmap.josm.data.preferences.NamedColorProperty;
@@ -60,4 +57,5 @@
 import org.openstreetmap.josm.io.OfflineAccessException;
 import org.openstreetmap.josm.io.OnlineResource;
+import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.openstreetmap.josm.tools.ColorHelper;
@@ -90,5 +88,5 @@
  * @since 74
  */
-public class Preferences extends AbstractPreferences implements IBaseDirectories {
+public class Preferences extends AbstractPreferences {
 
     private static final String COLOR_PREFIX = "color.";
@@ -103,20 +101,5 @@
     private static final long MAX_AGE_DEFAULT_PREFERENCES = TimeUnit.DAYS.toSeconds(50);
 
-    /**
-     * Internal storage for the preference directory.
-     * Do not access this variable directly!
-     * @see #getPreferencesDirectory()
-     */
-    private File preferencesDir;
-
-    /**
-     * Internal storage for the cache directory.
-     */
-    private File cacheDir;
-
-    /**
-     * Internal storage for the user data directory.
-     */
-    private File userdataDir;
+    private final IBaseDirectories dirs;
 
     /**
@@ -246,5 +229,14 @@
      */
     public Preferences() {
-        // Default constructor
+        this.dirs = Config.getDirs();
+    }
+
+    /**
+     * Constructs a new {@code Preferences}.
+     *
+     * @param dirs the directories to use for saving the preferences
+     */
+    public Preferences(IBaseDirectories dirs) {
+        this.dirs = dirs;
     }
 
@@ -256,4 +248,5 @@
     @SuppressWarnings("deprecation")
     public Preferences(Preferences pref) {
+        this(pref.dirs);
         settingsMap.putAll(pref.settingsMap);
         defaultsMap.putAll(pref.defaultsMap);
@@ -420,4 +413,12 @@
 
     /**
+     * Get the base directories associated with this preference instance.
+     * @return the base directories
+     */
+    public IBaseDirectories getDirs() {
+        return dirs;
+    }
+
+    /**
      * Returns the user defined preferences directory, containing the preferences.xml file
      * @return The user defined preferences directory, containing the preferences.xml file
@@ -430,30 +431,10 @@
     }
 
-    @Override
+    /**
+     * @deprecated use {@link #getDirs()} or (more generally) {@link Config#getDirs()}
+     */
+    @Deprecated
     public File getPreferencesDirectory(boolean createIfMissing) {
-        if (preferencesDir == null) {
-            String path;
-            path = System.getProperty("josm.pref");
-            if (path != null) {
-                preferencesDir = new File(path).getAbsoluteFile();
-            } else {
-                path = System.getProperty("josm.home");
-                if (path != null) {
-                    preferencesDir = new File(path).getAbsoluteFile();
-                } else {
-                    preferencesDir = Main.platform.getDefaultPrefDirectory();
-                }
-            }
-        }
-        if (createIfMissing && !preferencesDir.exists() && !preferencesDir.mkdirs()) {
-            Logging.warn(tr("Failed to create missing preferences directory: {0}", preferencesDir.getAbsoluteFile()));
-            JOptionPane.showMessageDialog(
-                    Main.parent,
-                    tr("<html>Failed to create missing preferences directory: {0}</html>", preferencesDir.getAbsoluteFile()),
-                    tr("Error"),
-                    JOptionPane.ERROR_MESSAGE
-            );
-        }
-        return preferencesDir;
+        return dirs.getPreferencesDirectory(createIfMissing);
     }
 
@@ -470,30 +451,10 @@
     }
 
-    @Override
+    /**
+     * @deprecated use {@link #getDirs()} or (more generally) {@link Config#getDirs()}
+     */
+    @Deprecated
     public File getUserDataDirectory(boolean createIfMissing) {
-        if (userdataDir == null) {
-            String path;
-            path = System.getProperty("josm.userdata");
-            if (path != null) {
-                userdataDir = new File(path).getAbsoluteFile();
-            } else {
-                path = System.getProperty("josm.home");
-                if (path != null) {
-                    userdataDir = new File(path).getAbsoluteFile();
-                } else {
-                    userdataDir = Main.platform.getDefaultUserDataDirectory();
-                }
-            }
-        }
-        if (createIfMissing && !userdataDir.exists() && !userdataDir.mkdirs()) {
-            Logging.warn(tr("Failed to create missing user data directory: {0}", userdataDir.getAbsoluteFile()));
-            JOptionPane.showMessageDialog(
-                    Main.parent,
-                    tr("<html>Failed to create missing user data directory: {0}</html>", userdataDir.getAbsoluteFile()),
-                    tr("Error"),
-                    JOptionPane.ERROR_MESSAGE
-            );
-        }
-        return userdataDir;
+        return dirs.getUserDataDirectory(createIfMissing);
     }
 
@@ -535,34 +496,10 @@
     }
 
-    @Override
+    /**
+     * @deprecated use {@link #getDirs()} or (more generally) {@link Config#getDirs()}
+     */
+    @Deprecated
     public File getCacheDirectory(boolean createIfMissing) {
-        if (cacheDir == null) {
-            String path = System.getProperty("josm.cache");
-            if (path != null) {
-                cacheDir = new File(path).getAbsoluteFile();
-            } else {
-                path = System.getProperty("josm.home");
-                if (path != null) {
-                    cacheDir = new File(path, "cache");
-                } else {
-                    path = get("cache.folder", null);
-                    if (path != null) {
-                        cacheDir = new File(path).getAbsoluteFile();
-                    } else {
-                        cacheDir = Main.platform.getDefaultCacheDirectory();
-                    }
-                }
-            }
-        }
-        if (createIfMissing && !cacheDir.exists() && !cacheDir.mkdirs()) {
-            Logging.warn(tr("Failed to create missing cache directory: {0}", cacheDir.getAbsoluteFile()));
-            JOptionPane.showMessageDialog(
-                    Main.parent,
-                    tr("<html>Failed to create missing cache directory: {0}</html>", cacheDir.getAbsoluteFile()),
-                    tr("Error"),
-                    JOptionPane.ERROR_MESSAGE
-            );
-        }
-        return cacheDir;
+        return dirs.getCacheDirectory(createIfMissing);
     }
 
@@ -782,6 +719,4 @@
             /* currently unused, but may help to fix configuration issues in future */
             putInt("josm.version", Version.getInstance().getVersion());
-
-            updateSystemProperties();
         }
 
@@ -837,5 +772,4 @@
         settingsMap.clear();
         settingsMap.putAll(reader.getSettings());
-        updateSystemProperties();
         removeObsolete(reader.getVersion());
     }
@@ -984,7 +918,4 @@
     public void resetToInitialState() {
         resetToDefault();
-        preferencesDir = null;
-        cacheDir = null;
-        userdataDir = null;
         saveOnPut = true;
         initSuccessful = false;
@@ -1505,35 +1436,4 @@
 
     /**
-     * Updates system properties with the current values in the preferences.
-     */
-    public void updateSystemProperties() {
-        if ("true".equals(get("prefer.ipv6", "auto")) && !"true".equals(Utils.updateSystemProperty("java.net.preferIPv6Addresses", "true"))) {
-            // never set this to false, only true!
-            Logging.info(tr("Try enabling IPv6 network, prefering IPv6 over IPv4 (only works on early startup)."));
-        }
-        Utils.updateSystemProperty("http.agent", Version.getInstance().getAgentString());
-        Utils.updateSystemProperty("user.language", get("language"));
-        // Workaround to fix a Java bug. This ugly hack comes from Sun bug database: https://bugs.openjdk.java.net/browse/JDK-6292739
-        // Force AWT toolkit to update its internal preferences (fix #6345).
-        // Does not work anymore with Java 9, to remove with Java 9 migration
-        if (Utils.getJavaVersion() < 9 && !GraphicsEnvironment.isHeadless()) {
-            try {
-                Field field = Toolkit.class.getDeclaredField("resources");
-                Utils.setObjectsAccessible(field);
-                field.set(null, ResourceBundle.getBundle("sun.awt.resources.awt"));
-            } catch (ReflectiveOperationException | RuntimeException e) { // NOPMD
-                // Catch RuntimeException in order to catch InaccessibleObjectException, new in Java 9
-                Logging.warn(e);
-            }
-        }
-        // Possibility to disable SNI (not by default) in case of misconfigured https servers
-        // See #9875 + http://stackoverflow.com/a/14884941/2257172
-        // then https://josm.openstreetmap.de/ticket/12152#comment:5 for details
-        if (getBoolean("jdk.tls.disableSNIExtension", false)) {
-            Utils.updateSystemProperty("jsse.enableSNIExtension", "false");
-        }
-    }
-
-    /**
      * Replies the collection of plugin site URLs from where plugin lists can be downloaded.
      * @return the collection of plugin site URLs
Index: trunk/src/org/openstreetmap/josm/data/preferences/JosmBaseDirectories.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/JosmBaseDirectories.java	(revision 13021)
+++ trunk/src/org/openstreetmap/josm/data/preferences/JosmBaseDirectories.java	(revision 13021)
@@ -0,0 +1,135 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.preferences;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.File;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.spi.preferences.Config;
+import org.openstreetmap.josm.spi.preferences.IBaseDirectories;
+import org.openstreetmap.josm.tools.Logging;
+
+/**
+ * Class provides base directory locations for JOSM.
+ * @since 13021
+ */
+public final class JosmBaseDirectories implements IBaseDirectories {
+
+    private JosmBaseDirectories() {
+        // hide constructor
+    }
+
+    private static class InstanceHolder {
+        static final JosmBaseDirectories INSTANCE = new JosmBaseDirectories();
+    }
+
+    public static JosmBaseDirectories getInstance() {
+        return InstanceHolder.INSTANCE;
+    }
+
+    /**
+     * Internal storage for the preference directory.
+     */
+    private File preferencesDir;
+
+    /**
+     * Internal storage for the cache directory.
+     */
+    private File cacheDir;
+
+    /**
+     * Internal storage for the user data directory.
+     */
+    private File userdataDir;
+
+    @Override
+    public File getPreferencesDirectory(boolean createIfMissing) {
+        if (preferencesDir == null) {
+            String path;
+            path = System.getProperty("josm.pref");
+            if (path != null) {
+                preferencesDir = new File(path).getAbsoluteFile();
+            } else {
+                path = System.getProperty("josm.home");
+                if (path != null) {
+                    preferencesDir = new File(path).getAbsoluteFile();
+                } else {
+                    preferencesDir = Main.platform.getDefaultPrefDirectory();
+                }
+            }
+        }
+        if (createIfMissing && !preferencesDir.exists() && !preferencesDir.mkdirs()) {
+            Logging.warn(tr("Failed to create missing preferences directory: {0}", preferencesDir.getAbsoluteFile()));
+            JOptionPane.showMessageDialog(
+                    Main.parent,
+                    tr("<html>Failed to create missing preferences directory: {0}</html>", preferencesDir.getAbsoluteFile()),
+                    tr("Error"),
+                    JOptionPane.ERROR_MESSAGE
+            );
+        }
+        return preferencesDir;
+    }
+
+    @Override
+    public File getUserDataDirectory(boolean createIfMissing) {
+        if (userdataDir == null) {
+            String path;
+            path = System.getProperty("josm.userdata");
+            if (path != null) {
+                userdataDir = new File(path).getAbsoluteFile();
+            } else {
+                path = System.getProperty("josm.home");
+                if (path != null) {
+                    userdataDir = new File(path).getAbsoluteFile();
+                } else {
+                    userdataDir = Main.platform.getDefaultUserDataDirectory();
+                }
+            }
+        }
+        if (createIfMissing && !userdataDir.exists() && !userdataDir.mkdirs()) {
+            Logging.warn(tr("Failed to create missing user data directory: {0}", userdataDir.getAbsoluteFile()));
+            JOptionPane.showMessageDialog(
+                    Main.parent,
+                    tr("<html>Failed to create missing user data directory: {0}</html>", userdataDir.getAbsoluteFile()),
+                    tr("Error"),
+                    JOptionPane.ERROR_MESSAGE
+            );
+        }
+        return userdataDir;
+    }
+
+    @Override
+    public File getCacheDirectory(boolean createIfMissing) {
+        if (cacheDir == null) {
+            String path = System.getProperty("josm.cache");
+            if (path != null) {
+                cacheDir = new File(path).getAbsoluteFile();
+            } else {
+                path = System.getProperty("josm.home");
+                if (path != null) {
+                    cacheDir = new File(path, "cache");
+                } else {
+                    path = Config.getPref().get("cache.folder", null);
+                    if (path != null) {
+                        cacheDir = new File(path).getAbsoluteFile();
+                    } else {
+                        cacheDir = Main.platform.getDefaultCacheDirectory();
+                    }
+                }
+            }
+        }
+        if (createIfMissing && !cacheDir.exists() && !cacheDir.mkdirs()) {
+            Logging.warn(tr("Failed to create missing cache directory: {0}", cacheDir.getAbsoluteFile()));
+            JOptionPane.showMessageDialog(
+                    Main.parent,
+                    tr("<html>Failed to create missing cache directory: {0}</html>", cacheDir.getAbsoluteFile()),
+                    tr("Error"),
+                    JOptionPane.ERROR_MESSAGE
+            );
+        }
+        return cacheDir;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/MainApplication.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MainApplication.java	(revision 13019)
+++ trunk/src/org/openstreetmap/josm/gui/MainApplication.java	(revision 13021)
@@ -11,8 +11,10 @@
 import java.awt.GraphicsEnvironment;
 import java.awt.GridBagLayout;
+import java.awt.Toolkit;
 import java.awt.event.KeyEvent;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.reflect.Field;
 import java.net.Authenticator;
 import java.net.Inet6Address;
@@ -38,4 +40,5 @@
 import java.util.Objects;
 import java.util.Optional;
+import java.util.ResourceBundle;
 import java.util.Set;
 import java.util.TreeSet;
@@ -90,4 +93,5 @@
 import org.openstreetmap.josm.data.osm.UserInfo;
 import org.openstreetmap.josm.data.osm.search.SearchMode;
+import org.openstreetmap.josm.data.preferences.JosmBaseDirectories;
 import org.openstreetmap.josm.data.preferences.sources.SourceType;
 import org.openstreetmap.josm.data.projection.ProjectionCLI;
@@ -148,4 +152,6 @@
 import org.openstreetmap.josm.plugins.PluginInformation;
 import org.openstreetmap.josm.spi.preferences.Config;
+import org.openstreetmap.josm.spi.preferences.PreferenceChangeEvent;
+import org.openstreetmap.josm.spi.preferences.PreferenceChangedListener;
 import org.openstreetmap.josm.tools.FontsManager;
 import org.openstreetmap.josm.tools.GBC;
@@ -926,5 +932,5 @@
         Main.pref.init(args.hasOption(Option.RESET_PREFERENCES));
         Config.setPreferencesInstance(Main.pref);
-        Config.setBaseDirectoriesProvider(Main.pref);
+        Config.setBaseDirectoriesProvider(JosmBaseDirectories.getInstance());
 
         args.getPreferencesToSet().forEach(Main.pref::put);
@@ -933,5 +939,11 @@
             I18n.set(Config.getPref().get("language", null));
         }
-        Main.pref.updateSystemProperties();
+        updateSystemProperties();
+        Main.pref.addPreferenceChangeListener(new PreferenceChangedListener() {
+            @Override
+            public void preferenceChanged(PreferenceChangeEvent e) {
+                updateSystemProperties();
+            }
+        });
 
         checkIPv6();
@@ -1069,4 +1081,36 @@
             Logging.info("Enabled EDT checker, wrongful access to gui from non EDT thread will be printed to console");
             RepaintManager.setCurrentManager(new CheckThreadViolationRepaintManager());
+        }
+    }
+
+    /**
+     * Updates system properties with the current values in the preferences.
+     */
+    private static void updateSystemProperties() {
+        if ("true".equals(Config.getPref().get("prefer.ipv6", "auto"))
+                && !"true".equals(Utils.updateSystemProperty("java.net.preferIPv6Addresses", "true"))) {
+            // never set this to false, only true!
+            Logging.info(tr("Try enabling IPv6 network, prefering IPv6 over IPv4 (only works on early startup)."));
+        }
+        Utils.updateSystemProperty("http.agent", Version.getInstance().getAgentString());
+        Utils.updateSystemProperty("user.language", Config.getPref().get("language"));
+        // Workaround to fix a Java bug. This ugly hack comes from Sun bug database: https://bugs.openjdk.java.net/browse/JDK-6292739
+        // Force AWT toolkit to update its internal preferences (fix #6345).
+        // Does not work anymore with Java 9, to remove with Java 9 migration
+        if (Utils.getJavaVersion() < 9 && !GraphicsEnvironment.isHeadless()) {
+            try {
+                Field field = Toolkit.class.getDeclaredField("resources");
+                Utils.setObjectsAccessible(field);
+                field.set(null, ResourceBundle.getBundle("sun.awt.resources.awt"));
+            } catch (ReflectiveOperationException | RuntimeException e) { // NOPMD
+                // Catch RuntimeException in order to catch InaccessibleObjectException, new in Java 9
+                Logging.warn(e);
+            }
+        }
+        // Possibility to disable SNI (not by default) in case of misconfigured https servers
+        // See #9875 + http://stackoverflow.com/a/14884941/2257172
+        // then https://josm.openstreetmap.de/ticket/12152#comment:5 for details
+        if (Config.getPref().getBoolean("jdk.tls.disableSNIExtension", false)) {
+            Utils.updateSystemProperty("jsse.enableSNIExtension", "false");
         }
     }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/RenderingCLI.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/RenderingCLI.java	(revision 13019)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/RenderingCLI.java	(revision 13021)
@@ -24,5 +24,4 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.Preferences;
 import org.openstreetmap.josm.data.ProjectionBounds;
 import org.openstreetmap.josm.data.coor.EastNorth;
@@ -30,4 +29,5 @@
 import org.openstreetmap.josm.data.coor.conversion.LatLonParser;
 import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.preferences.JosmBaseDirectories;
 import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.data.projection.Projections;
@@ -419,5 +419,5 @@
         Logging.setLogLevel(getLogLevel());
 
-        Config.setBaseDirectoriesProvider(new Preferences()); // for right-left-hand traffic cache file
+        Config.setBaseDirectoriesProvider(JosmBaseDirectories.getInstance()); // for right-left-hand traffic cache file
         Config.setPreferencesInstance(new MemoryPreferences());
         Config.getPref().putBoolean("mappaint.auto_reload_local_styles", false); // unnecessary to listen for external changes
