diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index 8f1cf83b715aeb443360b5601407fa3ec77f5e8c..eede0c768db98e63cee52893f4541fc4cfe174fa 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -19,10 +19,12 @@ import java.util.GregorianCalendar; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.TimeZone; import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; import net.i2p.CoreVersion; import net.i2p.crypto.DHSessionKeyBuilder; @@ -57,7 +59,7 @@ import net.i2p.util.SimpleTimer; public class Router { private Log _log; private RouterContext _context; - private final Properties _config; + private final Map<String, String> _config; /** full path */ private String _configFilename; private RouterInfo _routerInfo; @@ -120,7 +122,7 @@ public class Router { public Router(String configFilename) { this(configFilename, null); } public Router(String configFilename, Properties envProps) { _gracefulExitCode = -1; - _config = new Properties(); + _config = new ConcurrentHashMap(); if (configFilename == null) { if (envProps != null) { @@ -168,15 +170,9 @@ public class Router { readConfig(); - if (envProps == null) { - envProps = _config; - } else { - for (Iterator iter = _config.keySet().iterator(); iter.hasNext(); ) { - String k = (String)iter.next(); - String v = _config.getProperty(k); - envProps.setProperty(k, v); - } - } + if (envProps == null) + envProps = new Properties(); + envProps.putAll(_config); // This doesn't work, guess it has to be in the static block above? // if (Boolean.valueOf(envProps.getProperty("router.disableIPv6")).booleanValue()) @@ -203,12 +199,12 @@ public class Router { System.exit(-1); } - if (_config.getProperty("router.firstVersion") == null) { + if (_config.get("router.firstVersion") == null) { // These may be useful someday. First added in 0.8.2 - _config.setProperty("router.firstVersion", RouterVersion.VERSION); + _config.put("router.firstVersion", RouterVersion.VERSION); String now = Long.toString(System.currentTimeMillis()); - _config.setProperty("router.firstInstalled", now); - _config.setProperty("router.updateLastInstalled", now); + _config.put("router.firstInstalled", now); + _config.put("router.updateLastInstalled", now); saveConfig(); } @@ -285,30 +281,20 @@ public class Router { public void setConfigFilename(String filename) { _configFilename = filename; } public String getConfigSetting(String name) { - synchronized (_config) { - return _config.getProperty(name); - } + return _config.get(name); } public void setConfigSetting(String name, String value) { - synchronized (_config) { - _config.setProperty(name, value); - } + _config.put(name, value); } public void removeConfigSetting(String name) { - synchronized (_config) { _config.remove(name); - } } public Set getConfigSettings() { - synchronized (_config) { return new HashSet(_config.keySet()); - } } public Properties getConfigMap() { Properties rv = new Properties(); - synchronized (_config) { - rv.putAll(_config); - } + rv.putAll(_config); return rv; } @@ -377,14 +363,19 @@ public class Router { _context.jobQueue().addJob(new StartupJob(_context)); } - public void readConfig() { + /** + * This updates the config with all settings found in the file. + * It does not clear the config first, so settings not found in + * the file will remain in the config. + * + * This is synchronized with saveConfig() + */ + public synchronized void readConfig() { String f = getConfigFilename(); Properties config = getConfig(_context, f); - for (Iterator iter = config.keySet().iterator(); iter.hasNext(); ) { - String name = (String)iter.next(); - String val = config.getProperty(name); - setConfigSetting(name, val); - } + // to avoid compiler errror + Map foo = _config; + foo.putAll(config); } /** this does not use ctx.getConfigDir(), must provide a full path in filename */ @@ -988,7 +979,7 @@ public class Router { */ public void shutdownGracefully(int exitCode) { _gracefulExitCode = exitCode; - _config.setProperty(PROP_SHUTDOWN_IN_PROGRESS, "true"); + _config.put(PROP_SHUTDOWN_IN_PROGRESS, "true"); synchronized (_gracefulShutdownDetector) { _gracefulShutdownDetector.notifyAll(); } @@ -1010,7 +1001,7 @@ public class Router { */ public int scheduledGracefulExitCode() { return _gracefulExitCode; } public boolean gracefulShutdownInProgress() { - return (null != _config.getProperty(PROP_SHUTDOWN_IN_PROGRESS)); + return (null != _config.get(PROP_SHUTDOWN_IN_PROGRESS)); } /** How long until the graceful shutdown will kill us? */ public long getShutdownTimeRemaining() { @@ -1033,7 +1024,7 @@ public class Router { private class GracefulShutdown implements Runnable { public void run() { while (true) { - boolean shutdown = (null != _config.getProperty(PROP_SHUTDOWN_IN_PROGRESS)); + boolean shutdown = (null != _config.get(PROP_SHUTDOWN_IN_PROGRESS)); if (shutdown) { if (_gracefulExitCode == EXIT_HARD || _gracefulExitCode == EXIT_HARD_RESTART || _context.tunnelManager().getParticipatingCount() <= 0) { @@ -1077,26 +1068,24 @@ public class Router { * this does escape the \r or \n that are unescaped in DataHelper.loadProps(). * Note that the escaping of \r or \n was probably a mistake and should be taken out. * - * FIXME Synchronize!! + * Synchronized with file read in getConfig() */ - public boolean saveConfig() { + public synchronized boolean saveConfig() { FileOutputStream fos = null; try { fos = new SecureFileOutputStream(_configFilename); StringBuilder buf = new StringBuilder(8*1024); buf.append("# NOTE: This I2P config file must use UTF-8 encoding\n"); - synchronized (_config) { - TreeSet ordered = new TreeSet(_config.keySet()); - for (Iterator iter = ordered.iterator() ; iter.hasNext(); ) { - String key = (String)iter.next(); - String val = _config.getProperty(key); + TreeSet ordered = new TreeSet(_config.keySet()); + for (Iterator iter = ordered.iterator() ; iter.hasNext(); ) { + String key = (String)iter.next(); + String val = _config.get(key); // Escape line breaks before saving. // Remember: "\" needs escaping both for regex and string. // NOOO - see comments in DataHelper //val = val.replaceAll("\\r","\\\\r"); //val = val.replaceAll("\\n","\\\\n"); - buf.append(key).append('=').append(val).append('\n'); - } + buf.append(key).append('=').append(val).append('\n'); } fos.write(buf.toString().getBytes("UTF-8")); } catch (IOException ioe) { @@ -1193,7 +1182,7 @@ public class Router { } if (ok) { // This may be useful someday. First added in 0.8.2 - _config.setProperty("router.updateLastInstalled", "" + System.currentTimeMillis()); + _config.put("router.updateLastInstalled", "" + System.currentTimeMillis()); saveConfig(); boolean deleted = updateFile.delete(); if (!deleted) {