[freenet-cvs] r13181 - in trunk/freenet/src/freenet/node: . updater useralerts

toad at freenetproject.org toad at freenetproject.org
Wed May 9 21:12:03 UTC 2007


Author: toad
Date: 2007-05-09 21:12:03 +0000 (Wed, 09 May 2007)
New Revision: 13181

Added:
   trunk/freenet/src/freenet/node/updater/NodeUpdateManager.java
Removed:
   trunk/freenet/src/freenet/node/updater/NodeUpdaterManager.java
Modified:
   trunk/freenet/src/freenet/node/Node.java
   trunk/freenet/src/freenet/node/updater/NodeUpdater.java
   trunk/freenet/src/freenet/node/updater/RevocationChecker.java
   trunk/freenet/src/freenet/node/useralerts/UpdatedVersionAvailableUserAlert.java
Log:
NodeUpdaterManager -> NodeUpdateManager
(it's the latter in the l10n files already...)

Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java	2007-05-09 21:10:48 UTC (rev 13180)
+++ trunk/freenet/src/freenet/node/Node.java	2007-05-09 21:12:03 UTC (rev 13181)
@@ -82,7 +82,7 @@
 import freenet.keys.SSKBlock;
 import freenet.keys.SSKVerifyException;
 import freenet.l10n.L10n;
-import freenet.node.updater.NodeUpdaterManager;
+import freenet.node.updater.NodeUpdateManager;
 import freenet.node.useralerts.BuildOldAgeUserAlert;
 import freenet.node.useralerts.ExtOldAgeUserAlert;
 import freenet.node.useralerts.MeaningfulNodeNameUserAlert;
@@ -428,7 +428,7 @@
 	public int lastVersion;
 	
 	/** NodeUpdater **/
-	public NodeUpdaterManager nodeUpdater;
+	public NodeUpdateManager nodeUpdater;
 	
 	// Things that's needed to keep track of
 	public final PluginManager pluginManager;
@@ -1400,7 +1400,7 @@
 
 		// Node Updater
 		try{
-			nodeUpdater = NodeUpdaterManager.maybeCreate(this, config);
+			nodeUpdater = NodeUpdateManager.maybeCreate(this, config);
 			Logger.normal(this, "Starting the node updater");
 			nodeUpdater.start();
 		}catch (Exception e) {
@@ -2480,7 +2480,7 @@
 		config.store();
 	}
 
-	public NodeUpdaterManager getNodeUpdater(){
+	public NodeUpdateManager getNodeUpdater(){
 		return nodeUpdater;
 	}
 	

Copied: trunk/freenet/src/freenet/node/updater/NodeUpdateManager.java (from rev 13180, trunk/freenet/src/freenet/node/updater/NodeUpdaterManager.java)
===================================================================
--- trunk/freenet/src/freenet/node/updater/NodeUpdateManager.java	                        (rev 0)
+++ trunk/freenet/src/freenet/node/updater/NodeUpdateManager.java	2007-05-09 21:12:03 UTC (rev 13181)
@@ -0,0 +1,760 @@
+package freenet.node.updater;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import org.tanukisoftware.wrapper.WrapperManager;
+
+import freenet.config.Config;
+import freenet.config.InvalidConfigValueException;
+import freenet.config.SubConfig;
+import freenet.keys.FreenetURI;
+import freenet.l10n.L10n;
+import freenet.node.Node;
+import freenet.node.NodeStarter;
+import freenet.node.Version;
+import freenet.node.updater.UpdateDeployContext.UpdateCatastropheException;
+import freenet.node.useralerts.RevocationKeyFoundUserAlert;
+import freenet.node.useralerts.SimpleUserAlert;
+import freenet.node.useralerts.UpdatedVersionAvailableUserAlert;
+import freenet.node.useralerts.UserAlert;
+import freenet.support.Logger;
+import freenet.support.api.BooleanCallback;
+import freenet.support.api.StringCallback;
+
+/**
+ * Supervises NodeUpdater's. Enables us to easily update multiple files, 
+ * change the URI's on the fly, eliminates some messy code in the 
+ * callbacks etc.
+ */
+public class NodeUpdateManager {
+
+	public final static String UPDATE_URI = "freenet:USK at BFa1voWr5PunINSZ5BGMqFwhkJTiDBBUrOZ0MYBXseg,BOrxeLzUMb6R9tEZzexymY0zyKAmBNvrU4A9Q0tAqu0,AQACAAE/update/"+Version.buildNumber();
+	public final static String REVOCATION_URI = "SSK at tHlY8BK2KFB7JiO2bgeAw~e4sWU43YdJ6kmn73gjrIw,DnQzl0BYed15V8WQn~eRJxxIA-yADuI8XW7mnzEbut8,AQACAAE/revoked";
+	public final static String EXT_URI = "freenet:USK at BFa1voWr5PunINSZ5BGMqFwhkJTiDBBUrOZ0MYBXseg,BOrxeLzUMb6R9tEZzexymY0zyKAmBNvrU4A9Q0tAqu0,AQACAAE/ext/"+NodeStarter.extBuildNumber;
+	
+	FreenetURI updateURI;
+	FreenetURI extURI;
+	FreenetURI revocationURI;
+	
+	NodeUpdater mainUpdater;
+	NodeUpdater extUpdater;
+	
+	boolean wasEnabledOnStartup;
+	/** Is auto-update enabled? */
+	boolean isAutoUpdateAllowed;
+	/** Has the user given the go-ahead? */
+	boolean armed;
+	/** Should we check for freenet-ext.jar updates? 
+	 * Normally set only when our freenet-ext.jar is known to be out of date. */
+	final boolean shouldUpdateExt;
+	/** Currently deploying an update? */
+	boolean isDeployingUpdate;
+	
+	Node node;
+	
+	final RevocationChecker revocationChecker;
+	private String revocationMessage;
+	private boolean hasBeenBlown;
+	
+	/** Is there a new main jar ready to deploy? */
+	private boolean hasNewMainJar;
+	/** Is there a new ext jar ready to deploy? */
+	private boolean hasNewExtJar;
+	/** If another main jar is being fetched, when did the fetch start? */
+	private long startedFetchingNextMainJar;
+	/** If another ext jar is being fetched, when did the fetch start? */
+	private long startedFetchingNextExtJar;
+
+	// Revocation alert
+	private RevocationKeyFoundUserAlert revocationAlert;
+	// Update alert
+	private final UpdatedVersionAvailableUserAlert alert;
+
+	private boolean logMINOR;
+	
+	public NodeUpdateManager(Node node, Config config) throws InvalidConfigValueException {
+		logMINOR = Logger.shouldLog(Logger.MINOR, this);
+		this.node = node;
+		this.hasBeenBlown = false;
+		shouldUpdateExt = NodeStarter.extBuildNumber < NodeStarter.RECOMMENDED_EXT_BUILD_NUMBER;
+		this.alert= new UpdatedVersionAvailableUserAlert(this);
+		alert.isValid(false);
+		
+        SubConfig updaterConfig = new SubConfig("node.updater", config);
+        
+        updaterConfig.register("enabled", WrapperManager.isControlledByNativeWrapper(), 1, true, false, "NodeUpdateManager.enabled",
+        		"NodeUpdateManager.enabledLong",
+        		new UpdaterEnabledCallback());
+        
+        wasEnabledOnStartup = updaterConfig.getBoolean("enabled");
+
+        // is the auto-update allowed ?
+        updaterConfig.register("autoupdate", false, 2, false, true, "NodeUpdateManager.installNewVersions", "NodeUpdateManager.installNewVersionsLong",
+        		new AutoUpdateAllowedCallback());
+        isAutoUpdateAllowed = updaterConfig.getBoolean("autoupdate");
+
+        updaterConfig.register("URI", UPDATE_URI, 3,
+        		true, false, "NodeUpdateManager.updateURI",
+        		"NodeUpdateManager.updateURILong",
+        		new UpdateURICallback(false));
+
+        // FIXME remove when 101X is long gone
+        updaterConfig.fixOldDefaultRegex("URI", "USK at SIDKS6l-eOU8IQqDo03d~3qqBd-69WG60aDgg4nWqss,CPFqYi95Is3GwzAdAKtAuFMCXDZFFWC3~uPoidCD67s,AQABAAE/update/[0-9]++");
+        
+        try {
+			updateURI = new FreenetURI(updaterConfig.getString("URI"));
+		} catch (MalformedURLException e) {
+			throw new InvalidConfigValueException("Invalid updateURI: "+e);
+		}
+
+		if(updateURI.lastMetaString() != null && updateURI.lastMetaString().length() == 0) {
+			// FIXME remove this hack, put in because of bad default
+			System.err.println("Correcting auto-update URI: Removing extra /");
+			updateURI = updateURI.popMetaString();
+		}
+		
+        updaterConfig.register("revocationURI",	REVOCATION_URI,4,
+        		true, false, "NodeUpdateManager.revocationURI",
+        		"NodeUpdateManager.revocationURILong",
+        		new UpdateRevocationURICallback());
+        
+        // FIXME remove
+        updaterConfig.fixOldDefault("revocationURI", "freenet:SSK at VOfCZVTYPaatJ~eB~4lu2cPrWEmGyt4bfbB1v15Z6qQ,B6EynLhm7QE0se~rMgWWhl7wh3rFWjxJsEUcyohAm8A,AQABAAE/revoked");
+        updaterConfig.fixOldDefault("revocationURI", "freenet:SSK at i1F0GnBgMHNLZC~KrI8IiMCnDZeIy2YaLGsX~C0Mgv0,NlgBgblPys8YINj8CXabLW6AtUlWvZYNpYfNV08aoPo,AQACAAE/revoked");
+        
+        try {
+			revocationURI = new FreenetURI(updaterConfig.getString("revocationURI"));
+		} catch (MalformedURLException e) {
+			throw new InvalidConfigValueException("Invalid revocationURI: "+e);
+		}
+
+		if(revocationURI.lastMetaString() != null && revocationURI.lastMetaString().length() == 0) {
+			// FIXME remove this hack, put in because of bad default
+			System.err.println("Correcting auto-update revocation URI: Removing extra /");
+			revocationURI = revocationURI.popMetaString();
+		}
+		
+        updaterConfig.register("extURI", EXT_URI, 5, true, false, "NodeUpdateManager.extURI", "NodeUpdateManager.extURILong", new UpdateURICallback(true));
+        
+        // FIXME remove
+		updaterConfig.fixOldDefaultRegex("extURI", "USK at SIDKS6l-eOU8IQqDo03d~3qqBd-69WG60aDgg4nWqss,CPFqYi95Is3GwzAdAKtAuFMCXDZFFWC3~uPoidCD67s,AQABAAE/ext/[0-9]++");
+		
+        try {
+			extURI = new FreenetURI(updaterConfig.getString("extURI"));
+		} catch (MalformedURLException e) {
+			throw new InvalidConfigValueException("Invalid extURI: "+e);
+		}
+
+        updaterConfig.finishedInitialization();
+        
+        this.revocationChecker = new RevocationChecker(this);
+        
+	}
+
+	public void start() throws InvalidConfigValueException {
+		
+		node.clientCore.alerts.register(alert);
+        
+        enable(wasEnabledOnStartup);
+		
+	}
+	
+	/**
+	 * Is auto-update enabled?
+	 */
+	public boolean isEnabled() {
+		synchronized(this) {
+			return mainUpdater != null && mainUpdater.isRunning();
+		}
+	}
+
+	/**
+	 * Enable or disable auto-update.
+	 * @param enable Whether auto-update should be enabled.
+	 * @throws InvalidConfigValueException If enable=true and we are not running under the wrapper.
+	 */
+	void enable(boolean enable) throws InvalidConfigValueException {
+		logMINOR = Logger.shouldLog(Logger.MINOR, this);
+		if(!node.isUsingWrapper()){
+			Logger.normal(this, "Don't try to start the updater as we are not running under the wrapper.");
+			return;
+		}
+		NodeUpdater main = null, ext = null;
+		synchronized(this) {
+			boolean enabled = (mainUpdater != null && mainUpdater.isRunning());
+			if(enabled == enable) return;
+			if(!enable) {
+				// Kill it
+				mainUpdater.preKill();
+				main = mainUpdater;
+				mainUpdater = null;
+				if(extUpdater != null)
+					extUpdater.preKill();
+				ext = extUpdater;
+				extUpdater = null;
+			} else {
+				if((!WrapperManager.isControlledByNativeWrapper()) || (NodeStarter.extBuildNumber == -1)) {
+					Logger.error(this, "Cannot update because not running under wrapper");
+					throw new InvalidConfigValueException("Cannot update because not running under wrapper");
+				}
+				// Start it
+				mainUpdater = new NodeUpdater(this, updateURI, false, Version.buildNumber());
+				if(shouldUpdateExt)
+					extUpdater = new NodeUpdater(this, extURI, true, NodeStarter.extBuildNumber);
+			}
+		}
+		if(!enable) {
+			if(main != null) main.kill();
+			if(ext != null) ext.kill();
+			revocationChecker.kill();
+		} else {
+			mainUpdater.start();
+			if(extUpdater != null)
+				extUpdater.start();
+			revocationChecker.start(false);
+		}
+	}
+	
+	/**
+	 * Create a NodeUpdateManager. Called by node constructor.
+	 * @param node The node object.
+	 * @param config The global config object. Options will be added to a subconfig called node.updater.
+	 * @return A new NodeUpdateManager
+	 * @throws InvalidConfigValueException If there is an error in the config.
+	 */
+	public static NodeUpdateManager maybeCreate(Node node, Config config) throws InvalidConfigValueException {
+		return new NodeUpdateManager(node, config);
+	}
+
+	/**
+	 * Get the URI for either the freenet.jar updater or the freenet-ext.jar updater.
+	 * @param isExt If true, return the freenet-ext.jar update URI; if false, return the freenet.jar URI.
+	 * @return See above.
+	 */
+	public synchronized FreenetURI getURI(boolean isExt) {
+		return isExt ? extURI : updateURI;
+	}
+
+	/**
+	 * Set the URI for either the freenet.jar updater or the freenet-ext.jar updater.
+	 * @param isExt If true, set the freenet-ext.jar update URI; if false, set the freenet.jar update URI.
+	 * @param uri The URI to set.
+	 */
+	public void setURI(boolean isExt, FreenetURI uri) {
+		NodeUpdater updater;
+		synchronized(this) {
+			if(isExt) {
+				if(extURI.equals(uri)) return;
+				extURI = uri;
+				updater = extUpdater;
+			} else {
+				if(updateURI.equals(uri)) return;
+				updateURI = uri;
+				updater = mainUpdater;
+			}
+		}
+		if(updater == null) return;
+		if(updater.isRunning()) return;
+		updater.onChangeURI(uri);
+	}
+
+	/** @return The revocation URI. */
+	public synchronized FreenetURI getRevocationURI() {
+		return revocationURI;
+	}
+	
+	/**
+	 * Set the revocation URI.
+	 * @param uri The new revocation URI.
+	 */
+	public void setRevocationURI(FreenetURI uri) {
+		synchronized(this) {
+			if(revocationURI.equals(uri)) return;
+			this.revocationURI = uri;
+		}
+		revocationChecker.onChangeRevocationURI();
+	}
+	
+	/**
+	 * @return Is auto-update currently enabled?
+	 */
+	public synchronized boolean isAutoUpdateAllowed() {
+		return isAutoUpdateAllowed;
+	}
+
+	/**
+	 * Enable or disable auto-update.
+	 * @param val If true, enable auto-update (and immediately update if an update is ready). If false, disable it.
+	 */
+	public void setAutoUpdateAllowed(boolean val) {
+		synchronized(this) {
+			if(val == isAutoUpdateAllowed) return;
+			isAutoUpdateAllowed = val;
+			if(val) {
+				if(!isReadyToDeployUpdate(false)) return;
+			} else return;
+		}
+		deployOffThread(0);
+	}
+
+	private static final int WAIT_FOR_SECOND_FETCH_TO_COMPLETE = 240*1000;
+	private static final int RECENT_REVOCATION_INTERVAL = 120*1000;
+	
+	/** Does the updater have an update ready to deploy? May be called synchronized(this) */
+	private boolean isReadyToDeployUpdate(boolean ignoreRevocation) {
+		long now = System.currentTimeMillis();
+		long startedMillisAgo;
+		synchronized(this) {
+			if(!(hasNewMainJar || hasNewExtJar)) return false; // no jar
+			if(hasBeenBlown) return false; // Duh
+			// Don't immediately deploy if still fetching
+			startedMillisAgo = now - Math.max(startedFetchingNextMainJar, startedFetchingNextExtJar);
+			if(startedMillisAgo < WAIT_FOR_SECOND_FETCH_TO_COMPLETE)
+				return false; // Wait for running fetch to complete
+			if(!ignoreRevocation) {
+				if(now - revocationChecker.lastSucceeded() < RECENT_REVOCATION_INTERVAL)
+					return true;
+			}
+		}
+		revocationChecker.start(true);
+		if(ignoreRevocation) return true;
+		deployOffThread(WAIT_FOR_SECOND_FETCH_TO_COMPLETE - startedMillisAgo);
+		return false;
+	}
+
+	/** Check whether there is an update to deploy. If there is, do it. */
+	private void deployUpdate() {
+		logMINOR = Logger.shouldLog(Logger.MINOR, this);
+		try {
+			synchronized(this) {
+				if(hasBeenBlown) {
+					String msg = "Trying to update but key has been blown! Message was "+revocationMessage;
+					Logger.error(this, msg);
+					System.err.println(msg);
+					return;
+				}
+				if(!isEnabled()) return;
+				if(!(isAutoUpdateAllowed || armed)) return;
+				if(!isReadyToDeployUpdate(false)) return;
+				if(isDeployingUpdate) return;
+				isDeployingUpdate = true;
+			}
+			
+			innerDeployUpdate();
+		} catch (Throwable t) {
+			synchronized(this) {
+				isDeployingUpdate = false;
+			}
+		}
+	}
+	
+	/**
+	 * Deploy the update. Inner method. Doesn't check anything, just does it.
+	 */
+	private void innerDeployUpdate() {
+		// Write the jars, config etc.
+		// Then restart
+
+		UpdateDeployContext ctx;
+		try {
+			ctx = new UpdateDeployContext();
+		} catch (UpdaterParserException e) {
+			failUpdate("Could not determine which jars are in use: "+e.getMessage());
+			return;
+		}
+
+		if(writeJars(ctx)) 
+			restart(ctx);
+	}
+
+	/**
+	 * Write the updated jars, if necessary rewrite the wrapper.conf.
+	 * @return True if this part of the update succeeded.
+	 */
+	private boolean writeJars(UpdateDeployContext ctx) {
+		/**
+		 * What do we want to do here?
+		 * 1. If we have a new main jar:
+		 * - If on Windows, write it to a new jar file, update the wrapper.conf to point to it.
+		 * - Otherwise, write to a new jar file, then move the new jar file over the old jar file.
+		 * 2. If we have a new ext jar:
+		 * - Write it to a new jar file, update the wrapper.conf to point to it.
+		 */
+
+		boolean writtenNewJar = false;
+		boolean writtenNewExt = false;
+		
+		boolean tryEasyWay = File.pathSeparatorChar == '/' && !hasNewExtJar;
+
+		File mainJar = ctx.getMainJar();
+		File newMainJar = ctx.getNewMainJar();
+		
+		if(hasNewMainJar) {
+			writtenNewJar = true;
+			boolean writtenToTempFile = false;
+			try {
+				if(newMainJar.exists()) {
+					if(!newMainJar.delete()) {
+						if(newMainJar.exists()) {
+							System.err.println("Cannot write to preferred new jar location "+newMainJar);
+							if(tryEasyWay) {
+								try {
+									newMainJar = File.createTempFile("freenet", ".jar", mainJar.getParentFile());
+								} catch (IOException e) {
+									failUpdate("Cannot write to any other location either - disk full? "+e);
+									return false;
+								}
+								// Try writing to it
+								try {
+									mainUpdater.writeJarTo(newMainJar);
+									writtenToTempFile = true;
+								} catch (IOException e) {
+									newMainJar.delete();
+									failUpdate("Cannot write new jar - disk full? "+e);
+									return false;
+								}
+							} else {
+								// Try writing it to the new one even though we can't delete it.
+								mainUpdater.writeJarTo(newMainJar);
+							}
+						} else {
+							mainUpdater.writeJarTo(newMainJar);
+						}
+					} else {
+						if(logMINOR) Logger.minor(this, "Deleted old jar "+newMainJar);
+						mainUpdater.writeJarTo(newMainJar);
+					}
+				} else {
+					mainUpdater.writeJarTo(newMainJar);
+				}
+			} catch (IOException e) {
+				failUpdate("Cannot update: Cannot write to " + (tryEasyWay ? " temp file " : "new jar ")+newMainJar);
+				return false;
+			}
+			
+			if(tryEasyWay) {
+				// Do it the easy way. Just rewrite the main jar.
+				if(!newMainJar.renameTo(mainJar)) {
+					Logger.error(this, "Cannot rename temp file "+newMainJar+" over original jar "+mainJar);
+					if(writtenToTempFile) {
+						// Fail the update - otherwise we will leak disk space
+						newMainJar.delete();
+						failUpdate("Cannot write to preferred new jar location and cannot rename temp file over old jar, update failed");
+						return false;
+					}
+					// Try the hard way
+				} else {
+					System.err.println("Written new Freenet jar: "+mainUpdater.getWrittenVersion());
+					return true;
+				}
+			}
+			
+		}
+		
+		// Easy way didn't work or we can't do the easy way. Try the hard way.
+		
+		if(hasNewExtJar) {
+			
+			writtenNewExt = true;
+			
+			// Write the new ext jar
+			
+			File newExtJar = ctx.getNewExtJar();
+			
+			try {
+				extUpdater.writeJarTo(newExtJar);
+			} catch (IOException e) {
+				failUpdate("Cannot write new ext jar to "+newExtJar);
+				return false;
+			}
+			
+		}
+		
+		try {
+			ctx.rewriteWrapperConf(writtenNewJar, writtenNewExt);
+		} catch (IOException e) {
+			failUpdate("Cannot rewrite wrapper.conf: "+e);
+			return false;
+		} catch (UpdateCatastropheException e) {
+			failUpdate(e.getMessage());
+			node.clientCore.alerts.register(new SimpleUserAlert(false, l10n("updateCatastropheTitle"), e.getMessage(), UserAlert.CRITICAL_ERROR));
+			return false;
+		} catch (UpdaterParserException e) {
+			node.clientCore.alerts.register(new SimpleUserAlert(false, l10n("updateFailedTitle"), e.getMessage(), UserAlert.CRITICAL_ERROR));
+			return false;
+		}
+		
+		return true;
+	}
+
+	/** Restart the node. Does not return. */
+	private void restart(UpdateDeployContext ctx) {
+		node.getNodeStarter().restart();
+		try {
+			Thread.sleep(5*60*1000);
+		} catch (InterruptedException e) {
+			// Break
+		} // in case it's still restarting
+		System.err.println("Failed to restart. Exiting, please restart the node.");
+		System.exit(Node.EXIT_RESTART_FAILED);
+	}
+
+	private void failUpdate(String reason) {
+		Logger.error(this, "Update failed: "+reason);
+		System.err.println("Update failed: "+reason);
+		this.killUpdateAlerts();
+		node.clientCore.alerts.register(new SimpleUserAlert(true, l10n("updateFailedTitle"), l10n("updateFailed", "reason", reason), UserAlert.ERROR));
+	}
+
+	private String l10n(String key) {
+		return L10n.getString("NodeUpdateManager."+key);
+	}
+
+	private String l10n(String key, String pattern, String value) {
+		return L10n.getString("NodeUpdateManager."+key, pattern, value);
+	}
+
+	/**
+	 * Called when a new jar has been downloaded.
+	 * @param isExt If true, the new jar is the ext jar; if false, it is the main jar.
+	 */
+	void onDownloadedNewJar(boolean isExt) {
+		synchronized(this) {
+			if(isExt) {
+				hasNewExtJar = true;
+				startedFetchingNextExtJar = -1;
+			} else {
+				hasNewMainJar = true;
+				startedFetchingNextMainJar = -1;
+			}
+		}
+		revocationChecker.start(true);
+	}
+
+	/**
+	 * Called when the NodeUpdater starts to fetch a new version of the jar.
+	 * @param isExt If true, the new jar is the ext jar; if false, it is the main jar.
+	 */
+	void onStartFetching(boolean isExt) {
+		long now = System.currentTimeMillis();
+		synchronized(this) {
+			if(isExt) {
+				startedFetchingNextExtJar = now;
+			} else {
+				startedFetchingNextMainJar = now;
+			}
+		}
+	}
+	
+	public void blow(String msg){
+		NodeUpdater main, ext;
+		synchronized(this) {
+			if(hasBeenBlown){
+				Logger.error(this, "The key has ALREADY been marked as blown! Message was "+revocationMessage+" new message "+msg);
+				return;
+			}else{
+				this.revocationMessage = msg;
+				this.hasBeenBlown = true;
+				// We must get to the lower part, and show the user the message
+				try {
+					System.err.println("THE AUTO-UPDATING SYSTEM HAS BEEN COMPROMIZED!");
+					System.err.println("The auto-updating system revocation key has been inserted. It says: "+revocationMessage);
+				} catch (Throwable t) {
+					try {
+						Logger.error(this, "Caught "+t, t);
+					} catch (Throwable t1) {}
+				}
+			}
+			main = mainUpdater;
+			ext = extUpdater;
+			if(main != null) main.preKill();
+			if(ext != null) ext.preKill();
+			mainUpdater = null;
+			extUpdater = null;
+		}
+		if(main != null) main.kill();
+		if(ext != null) ext.kill();
+		if(revocationAlert==null){
+			revocationAlert = new RevocationKeyFoundUserAlert(msg);
+			node.clientCore.alerts.register(revocationAlert);
+			// we don't need to advertize updates : we are not going to do them
+			killUpdateAlerts();
+		}
+	}
+
+	/**
+	 * Kill all UserAlerts asking the user whether he wants to update.
+	 */
+	private void killUpdateAlerts() {
+		node.clientCore.alerts.unregister(alert);
+	}
+
+	/** Called when the RevocationChecker has got 3 DNFs on the revocation key */
+	public void noRevocationFound() {
+		deployUpdate(); // May have been waiting for the revocation.
+		// If we're still here, we didn't update.
+		node.ps.queueTimedJob(new Runnable() {
+			public void run() {
+				revocationChecker.start(false);
+			}
+		}, node.random.nextInt(24*60*60*1000)); 
+	}
+	
+	public void arm() {
+		synchronized(this) {
+			armed = true;
+		}
+		deployOffThread(0);
+	}
+	
+	void deployOffThread(long delay) {
+		node.ps.queueTimedJob(new Runnable() {
+			public void run() {
+				deployUpdate();
+			}
+		}, delay);
+	}
+
+	/**
+	 * Has the private key been revoked?
+	 */
+	public boolean isBlown() {
+		return hasBeenBlown;
+	}
+	
+	public synchronized boolean hasNewMainJar() {
+		return hasNewMainJar;
+	}
+
+	public synchronized boolean hasNewExtJar() {
+		return hasNewExtJar;
+	}
+
+	public int newMainJarVersion() {
+		if(mainUpdater == null) return -1;
+		return mainUpdater.getFetchedVersion();
+	}
+
+	public int newExtJarVersion() {
+		if(extUpdater == null) return -1;
+		return extUpdater.getFetchedVersion();
+	}
+
+	public boolean fetchingNewMainJar() {
+		return mainUpdater != null && mainUpdater.isFetching();
+	}
+
+	public boolean fetchingNewExtJar() {
+		return extUpdater != null && extUpdater.isFetching();
+	}
+
+	public int fetchingNewMainJarVersion() {
+		if(mainUpdater == null) return -1;
+		return mainUpdater.fetchingVersion();
+	}
+
+	public int fetchingNewExtJarVersion() {
+		if(extUpdater == null) return -1;
+		return extUpdater.fetchingVersion();
+	}
+
+	public boolean inFinalCheck() {
+		return isReadyToDeployUpdate(true) && !isReadyToDeployUpdate(false);
+	}
+
+	public int getRevocationDNFCounter() {
+		return revocationChecker.getRevocationDNFCounter();
+	}
+
+	public int getMainVersion() {
+		return Version.buildNumber();
+	}
+	
+	public int getExtVersion() {
+		return NodeStarter.extBuildNumber;
+	}
+
+	public boolean isArmed() {
+		return armed || isAutoUpdateAllowed;
+	}
+
+	/** Is the node able to update as soon as the revocation fetch has been completed? */
+	public boolean canUpdateNow() {
+		return isReadyToDeployUpdate(true);
+	}
+
+	/** Is the node able to update *immediately*? (i.e. not only is it ready in every other sense, but also a revocation
+	 * fetch has completed recently enough not to need another one) */
+	public boolean canUpdateImmediately() {
+		return isReadyToDeployUpdate(false);
+	}
+
+	// Config callbacks
+	
+	class UpdaterEnabledCallback implements BooleanCallback {
+		
+		public boolean get() {
+			return isEnabled();
+		}
+		
+		public void set(boolean val) throws InvalidConfigValueException {
+			enable(val);
+		}
+	}
+	
+	class AutoUpdateAllowedCallback implements BooleanCallback {
+		
+		public boolean get() {
+			return isAutoUpdateAllowed();
+		}
+		
+		public void set(boolean val) throws InvalidConfigValueException {
+			setAutoUpdateAllowed(val);
+		}
+	}
+
+	class UpdateURICallback implements StringCallback {
+
+		boolean isExt;
+		
+		UpdateURICallback(boolean isExt) {
+			this.isExt = isExt;
+		}
+		
+		public String get() {
+			return getURI(isExt).toString(false, false);
+		}
+
+		public void set(String val) throws InvalidConfigValueException {
+			FreenetURI uri;
+			try {
+				uri = new FreenetURI(val);
+			} catch (MalformedURLException e) {
+				throw new InvalidConfigValueException("Invalid key: "+val+" : "+e);
+			}
+			setURI(isExt, uri);
+		}
+
+	}
+
+	public class UpdateRevocationURICallback implements StringCallback {
+
+		public String get() {
+			return getRevocationURI().toString(false, false);
+		}
+
+		public void set(String val) throws InvalidConfigValueException {
+			FreenetURI uri;
+			try {
+				uri = new FreenetURI(val);
+			} catch (MalformedURLException e) {
+				throw new InvalidConfigValueException("Invalid key: "+val+" : "+e);
+			}
+			setRevocationURI(uri);
+		}
+		
+	}
+
+}

Modified: trunk/freenet/src/freenet/node/updater/NodeUpdater.java
===================================================================
--- trunk/freenet/src/freenet/node/updater/NodeUpdater.java	2007-05-09 21:10:48 UTC (rev 13180)
+++ trunk/freenet/src/freenet/node/updater/NodeUpdater.java	2007-05-09 21:12:03 UTC (rev 13181)
@@ -33,7 +33,7 @@
 	private final Ticker ticker;
 	public final NodeClientCore core;
 	private final Node node;
-	public final NodeUpdaterManager manager;
+	public final NodeUpdateManager manager;
 	
 	private final int currentVersion;
 	private int availableVersion;
@@ -46,7 +46,7 @@
 	
 	public final boolean extUpdate;
 	
-	NodeUpdater(NodeUpdaterManager manager, FreenetURI URI, boolean extUpdate, int current) {
+	NodeUpdater(NodeUpdateManager manager, FreenetURI URI, boolean extUpdate, int current) {
 		logMINOR = Logger.shouldLog(Logger.MINOR, this);
 		this.manager = manager;
 		this.node = manager.node;

Deleted: trunk/freenet/src/freenet/node/updater/NodeUpdaterManager.java
===================================================================
--- trunk/freenet/src/freenet/node/updater/NodeUpdaterManager.java	2007-05-09 21:10:48 UTC (rev 13180)
+++ trunk/freenet/src/freenet/node/updater/NodeUpdaterManager.java	2007-05-09 21:12:03 UTC (rev 13181)
@@ -1,760 +0,0 @@
-package freenet.node.updater;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.MalformedURLException;
-
-import org.tanukisoftware.wrapper.WrapperManager;
-
-import freenet.config.Config;
-import freenet.config.InvalidConfigValueException;
-import freenet.config.SubConfig;
-import freenet.keys.FreenetURI;
-import freenet.l10n.L10n;
-import freenet.node.Node;
-import freenet.node.NodeStarter;
-import freenet.node.Version;
-import freenet.node.updater.UpdateDeployContext.UpdateCatastropheException;
-import freenet.node.useralerts.RevocationKeyFoundUserAlert;
-import freenet.node.useralerts.SimpleUserAlert;
-import freenet.node.useralerts.UpdatedVersionAvailableUserAlert;
-import freenet.node.useralerts.UserAlert;
-import freenet.support.Logger;
-import freenet.support.api.BooleanCallback;
-import freenet.support.api.StringCallback;
-
-/**
- * Supervises NodeUpdater's. Enables us to easily update multiple files, 
- * change the URI's on the fly, eliminates some messy code in the 
- * callbacks etc.
- */
-public class NodeUpdaterManager {
-
-	public final static String UPDATE_URI = "freenet:USK at BFa1voWr5PunINSZ5BGMqFwhkJTiDBBUrOZ0MYBXseg,BOrxeLzUMb6R9tEZzexymY0zyKAmBNvrU4A9Q0tAqu0,AQACAAE/update/"+Version.buildNumber();
-	public final static String REVOCATION_URI = "SSK at tHlY8BK2KFB7JiO2bgeAw~e4sWU43YdJ6kmn73gjrIw,DnQzl0BYed15V8WQn~eRJxxIA-yADuI8XW7mnzEbut8,AQACAAE/revoked";
-	public final static String EXT_URI = "freenet:USK at BFa1voWr5PunINSZ5BGMqFwhkJTiDBBUrOZ0MYBXseg,BOrxeLzUMb6R9tEZzexymY0zyKAmBNvrU4A9Q0tAqu0,AQACAAE/ext/"+NodeStarter.extBuildNumber;
-	
-	FreenetURI updateURI;
-	FreenetURI extURI;
-	FreenetURI revocationURI;
-	
-	NodeUpdater mainUpdater;
-	NodeUpdater extUpdater;
-	
-	boolean wasEnabledOnStartup;
-	/** Is auto-update enabled? */
-	boolean isAutoUpdateAllowed;
-	/** Has the user given the go-ahead? */
-	boolean armed;
-	/** Should we check for freenet-ext.jar updates? 
-	 * Normally set only when our freenet-ext.jar is known to be out of date. */
-	final boolean shouldUpdateExt;
-	/** Currently deploying an update? */
-	boolean isDeployingUpdate;
-	
-	Node node;
-	
-	final RevocationChecker revocationChecker;
-	private String revocationMessage;
-	private boolean hasBeenBlown;
-	
-	/** Is there a new main jar ready to deploy? */
-	private boolean hasNewMainJar;
-	/** Is there a new ext jar ready to deploy? */
-	private boolean hasNewExtJar;
-	/** If another main jar is being fetched, when did the fetch start? */
-	private long startedFetchingNextMainJar;
-	/** If another ext jar is being fetched, when did the fetch start? */
-	private long startedFetchingNextExtJar;
-
-	// Revocation alert
-	private RevocationKeyFoundUserAlert revocationAlert;
-	// Update alert
-	private final UpdatedVersionAvailableUserAlert alert;
-
-	private boolean logMINOR;
-	
-	public NodeUpdaterManager(Node node, Config config) throws InvalidConfigValueException {
-		logMINOR = Logger.shouldLog(Logger.MINOR, this);
-		this.node = node;
-		this.hasBeenBlown = false;
-		shouldUpdateExt = NodeStarter.extBuildNumber < NodeStarter.RECOMMENDED_EXT_BUILD_NUMBER;
-		this.alert= new UpdatedVersionAvailableUserAlert(this);
-		alert.isValid(false);
-		
-        SubConfig updaterConfig = new SubConfig("node.updater", config);
-        
-        updaterConfig.register("enabled", WrapperManager.isControlledByNativeWrapper(), 1, true, false, "NodeUpdateManager.enabled",
-        		"NodeUpdateManager.enabledLong",
-        		new UpdaterEnabledCallback());
-        
-        wasEnabledOnStartup = updaterConfig.getBoolean("enabled");
-
-        // is the auto-update allowed ?
-        updaterConfig.register("autoupdate", false, 2, false, true, "NodeUpdateManager.installNewVersions", "NodeUpdateManager.installNewVersionsLong",
-        		new AutoUpdateAllowedCallback());
-        isAutoUpdateAllowed = updaterConfig.getBoolean("autoupdate");
-
-        updaterConfig.register("URI", UPDATE_URI, 3,
-        		true, false, "NodeUpdateManager.updateURI",
-        		"NodeUpdateManager.updateURILong",
-        		new UpdateURICallback(false));
-
-        // FIXME remove when 101X is long gone
-        updaterConfig.fixOldDefaultRegex("URI", "USK at SIDKS6l-eOU8IQqDo03d~3qqBd-69WG60aDgg4nWqss,CPFqYi95Is3GwzAdAKtAuFMCXDZFFWC3~uPoidCD67s,AQABAAE/update/[0-9]++");
-        
-        try {
-			updateURI = new FreenetURI(updaterConfig.getString("URI"));
-		} catch (MalformedURLException e) {
-			throw new InvalidConfigValueException("Invalid updateURI: "+e);
-		}
-
-		if(updateURI.lastMetaString() != null && updateURI.lastMetaString().length() == 0) {
-			// FIXME remove this hack, put in because of bad default
-			System.err.println("Correcting auto-update URI: Removing extra /");
-			updateURI = updateURI.popMetaString();
-		}
-		
-        updaterConfig.register("revocationURI",	REVOCATION_URI,4,
-        		true, false, "NodeUpdateManager.revocationURI",
-        		"NodeUpdateManager.revocationURILong",
-        		new UpdateRevocationURICallback());
-        
-        // FIXME remove
-        updaterConfig.fixOldDefault("revocationURI", "freenet:SSK at VOfCZVTYPaatJ~eB~4lu2cPrWEmGyt4bfbB1v15Z6qQ,B6EynLhm7QE0se~rMgWWhl7wh3rFWjxJsEUcyohAm8A,AQABAAE/revoked");
-        updaterConfig.fixOldDefault("revocationURI", "freenet:SSK at i1F0GnBgMHNLZC~KrI8IiMCnDZeIy2YaLGsX~C0Mgv0,NlgBgblPys8YINj8CXabLW6AtUlWvZYNpYfNV08aoPo,AQACAAE/revoked");
-        
-        try {
-			revocationURI = new FreenetURI(updaterConfig.getString("revocationURI"));
-		} catch (MalformedURLException e) {
-			throw new InvalidConfigValueException("Invalid revocationURI: "+e);
-		}
-
-		if(revocationURI.lastMetaString() != null && revocationURI.lastMetaString().length() == 0) {
-			// FIXME remove this hack, put in because of bad default
-			System.err.println("Correcting auto-update revocation URI: Removing extra /");
-			revocationURI = revocationURI.popMetaString();
-		}
-		
-        updaterConfig.register("extURI", EXT_URI, 5, true, false, "NodeUpdateManager.extURI", "NodeUpdateManager.extURILong", new UpdateURICallback(true));
-        
-        // FIXME remove
-		updaterConfig.fixOldDefaultRegex("extURI", "USK at SIDKS6l-eOU8IQqDo03d~3qqBd-69WG60aDgg4nWqss,CPFqYi95Is3GwzAdAKtAuFMCXDZFFWC3~uPoidCD67s,AQABAAE/ext/[0-9]++");
-		
-        try {
-			extURI = new FreenetURI(updaterConfig.getString("extURI"));
-		} catch (MalformedURLException e) {
-			throw new InvalidConfigValueException("Invalid extURI: "+e);
-		}
-
-        updaterConfig.finishedInitialization();
-        
-        this.revocationChecker = new RevocationChecker(this);
-        
-	}
-
-	public void start() throws InvalidConfigValueException {
-		
-		node.clientCore.alerts.register(alert);
-        
-        enable(wasEnabledOnStartup);
-		
-	}
-	
-	/**
-	 * Is auto-update enabled?
-	 */
-	public boolean isEnabled() {
-		synchronized(this) {
-			return mainUpdater != null && mainUpdater.isRunning();
-		}
-	}
-
-	/**
-	 * Enable or disable auto-update.
-	 * @param enable Whether auto-update should be enabled.
-	 * @throws InvalidConfigValueException If enable=true and we are not running under the wrapper.
-	 */
-	void enable(boolean enable) throws InvalidConfigValueException {
-		logMINOR = Logger.shouldLog(Logger.MINOR, this);
-		if(!node.isUsingWrapper()){
-			Logger.normal(this, "Don't try to start the updater as we are not running under the wrapper.");
-			return;
-		}
-		NodeUpdater main = null, ext = null;
-		synchronized(this) {
-			boolean enabled = (mainUpdater != null && mainUpdater.isRunning());
-			if(enabled == enable) return;
-			if(!enable) {
-				// Kill it
-				mainUpdater.preKill();
-				main = mainUpdater;
-				mainUpdater = null;
-				if(extUpdater != null)
-					extUpdater.preKill();
-				ext = extUpdater;
-				extUpdater = null;
-			} else {
-				if((!WrapperManager.isControlledByNativeWrapper()) || (NodeStarter.extBuildNumber == -1)) {
-					Logger.error(this, "Cannot update because not running under wrapper");
-					throw new InvalidConfigValueException("Cannot update because not running under wrapper");
-				}
-				// Start it
-				mainUpdater = new NodeUpdater(this, updateURI, false, Version.buildNumber());
-				if(shouldUpdateExt)
-					extUpdater = new NodeUpdater(this, extURI, true, NodeStarter.extBuildNumber);
-			}
-		}
-		if(!enable) {
-			if(main != null) main.kill();
-			if(ext != null) ext.kill();
-			revocationChecker.kill();
-		} else {
-			mainUpdater.start();
-			if(extUpdater != null)
-				extUpdater.start();
-			revocationChecker.start(false);
-		}
-	}
-	
-	/**
-	 * Create a NodeUpdaterManager. Called by node constructor.
-	 * @param node The node object.
-	 * @param config The global config object. Options will be added to a subconfig called node.updater.
-	 * @return A new NodeUpdaterManager
-	 * @throws InvalidConfigValueException If there is an error in the config.
-	 */
-	public static NodeUpdaterManager maybeCreate(Node node, Config config) throws InvalidConfigValueException {
-		return new NodeUpdaterManager(node, config);
-	}
-
-	/**
-	 * Get the URI for either the freenet.jar updater or the freenet-ext.jar updater.
-	 * @param isExt If true, return the freenet-ext.jar update URI; if false, return the freenet.jar URI.
-	 * @return See above.
-	 */
-	public synchronized FreenetURI getURI(boolean isExt) {
-		return isExt ? extURI : updateURI;
-	}
-
-	/**
-	 * Set the URI for either the freenet.jar updater or the freenet-ext.jar updater.
-	 * @param isExt If true, set the freenet-ext.jar update URI; if false, set the freenet.jar update URI.
-	 * @param uri The URI to set.
-	 */
-	public void setURI(boolean isExt, FreenetURI uri) {
-		NodeUpdater updater;
-		synchronized(this) {
-			if(isExt) {
-				if(extURI.equals(uri)) return;
-				extURI = uri;
-				updater = extUpdater;
-			} else {
-				if(updateURI.equals(uri)) return;
-				updateURI = uri;
-				updater = mainUpdater;
-			}
-		}
-		if(updater == null) return;
-		if(updater.isRunning()) return;
-		updater.onChangeURI(uri);
-	}
-
-	/** @return The revocation URI. */
-	public synchronized FreenetURI getRevocationURI() {
-		return revocationURI;
-	}
-	
-	/**
-	 * Set the revocation URI.
-	 * @param uri The new revocation URI.
-	 */
-	public void setRevocationURI(FreenetURI uri) {
-		synchronized(this) {
-			if(revocationURI.equals(uri)) return;
-			this.revocationURI = uri;
-		}
-		revocationChecker.onChangeRevocationURI();
-	}
-	
-	/**
-	 * @return Is auto-update currently enabled?
-	 */
-	public synchronized boolean isAutoUpdateAllowed() {
-		return isAutoUpdateAllowed;
-	}
-
-	/**
-	 * Enable or disable auto-update.
-	 * @param val If true, enable auto-update (and immediately update if an update is ready). If false, disable it.
-	 */
-	public void setAutoUpdateAllowed(boolean val) {
-		synchronized(this) {
-			if(val == isAutoUpdateAllowed) return;
-			isAutoUpdateAllowed = val;
-			if(val) {
-				if(!isReadyToDeployUpdate(false)) return;
-			} else return;
-		}
-		deployOffThread(0);
-	}
-
-	private static final int WAIT_FOR_SECOND_FETCH_TO_COMPLETE = 240*1000;
-	private static final int RECENT_REVOCATION_INTERVAL = 120*1000;
-	
-	/** Does the updater have an update ready to deploy? May be called synchronized(this) */
-	private boolean isReadyToDeployUpdate(boolean ignoreRevocation) {
-		long now = System.currentTimeMillis();
-		long startedMillisAgo;
-		synchronized(this) {
-			if(!(hasNewMainJar || hasNewExtJar)) return false; // no jar
-			if(hasBeenBlown) return false; // Duh
-			// Don't immediately deploy if still fetching
-			startedMillisAgo = now - Math.max(startedFetchingNextMainJar, startedFetchingNextExtJar);
-			if(startedMillisAgo < WAIT_FOR_SECOND_FETCH_TO_COMPLETE)
-				return false; // Wait for running fetch to complete
-			if(!ignoreRevocation) {
-				if(now - revocationChecker.lastSucceeded() < RECENT_REVOCATION_INTERVAL)
-					return true;
-			}
-		}
-		revocationChecker.start(true);
-		if(ignoreRevocation) return true;
-		deployOffThread(WAIT_FOR_SECOND_FETCH_TO_COMPLETE - startedMillisAgo);
-		return false;
-	}
-
-	/** Check whether there is an update to deploy. If there is, do it. */
-	private void deployUpdate() {
-		logMINOR = Logger.shouldLog(Logger.MINOR, this);
-		try {
-			synchronized(this) {
-				if(hasBeenBlown) {
-					String msg = "Trying to update but key has been blown! Message was "+revocationMessage;
-					Logger.error(this, msg);
-					System.err.println(msg);
-					return;
-				}
-				if(!isEnabled()) return;
-				if(!(isAutoUpdateAllowed || armed)) return;
-				if(!isReadyToDeployUpdate(false)) return;
-				if(isDeployingUpdate) return;
-				isDeployingUpdate = true;
-			}
-			
-			innerDeployUpdate();
-		} catch (Throwable t) {
-			synchronized(this) {
-				isDeployingUpdate = false;
-			}
-		}
-	}
-	
-	/**
-	 * Deploy the update. Inner method. Doesn't check anything, just does it.
-	 */
-	private void innerDeployUpdate() {
-		// Write the jars, config etc.
-		// Then restart
-
-		UpdateDeployContext ctx;
-		try {
-			ctx = new UpdateDeployContext();
-		} catch (UpdaterParserException e) {
-			failUpdate("Could not determine which jars are in use: "+e.getMessage());
-			return;
-		}
-
-		if(writeJars(ctx)) 
-			restart(ctx);
-	}
-
-	/**
-	 * Write the updated jars, if necessary rewrite the wrapper.conf.
-	 * @return True if this part of the update succeeded.
-	 */
-	private boolean writeJars(UpdateDeployContext ctx) {
-		/**
-		 * What do we want to do here?
-		 * 1. If we have a new main jar:
-		 * - If on Windows, write it to a new jar file, update the wrapper.conf to point to it.
-		 * - Otherwise, write to a new jar file, then move the new jar file over the old jar file.
-		 * 2. If we have a new ext jar:
-		 * - Write it to a new jar file, update the wrapper.conf to point to it.
-		 */
-
-		boolean writtenNewJar = false;
-		boolean writtenNewExt = false;
-		
-		boolean tryEasyWay = File.pathSeparatorChar == '/' && !hasNewExtJar;
-
-		File mainJar = ctx.getMainJar();
-		File newMainJar = ctx.getNewMainJar();
-		
-		if(hasNewMainJar) {
-			writtenNewJar = true;
-			boolean writtenToTempFile = false;
-			try {
-				if(newMainJar.exists()) {
-					if(!newMainJar.delete()) {
-						if(newMainJar.exists()) {
-							System.err.println("Cannot write to preferred new jar location "+newMainJar);
-							if(tryEasyWay) {
-								try {
-									newMainJar = File.createTempFile("freenet", ".jar", mainJar.getParentFile());
-								} catch (IOException e) {
-									failUpdate("Cannot write to any other location either - disk full? "+e);
-									return false;
-								}
-								// Try writing to it
-								try {
-									mainUpdater.writeJarTo(newMainJar);
-									writtenToTempFile = true;
-								} catch (IOException e) {
-									newMainJar.delete();
-									failUpdate("Cannot write new jar - disk full? "+e);
-									return false;
-								}
-							} else {
-								// Try writing it to the new one even though we can't delete it.
-								mainUpdater.writeJarTo(newMainJar);
-							}
-						} else {
-							mainUpdater.writeJarTo(newMainJar);
-						}
-					} else {
-						if(logMINOR) Logger.minor(this, "Deleted old jar "+newMainJar);
-						mainUpdater.writeJarTo(newMainJar);
-					}
-				} else {
-					mainUpdater.writeJarTo(newMainJar);
-				}
-			} catch (IOException e) {
-				failUpdate("Cannot update: Cannot write to " + (tryEasyWay ? " temp file " : "new jar ")+newMainJar);
-				return false;
-			}
-			
-			if(tryEasyWay) {
-				// Do it the easy way. Just rewrite the main jar.
-				if(!newMainJar.renameTo(mainJar)) {
-					Logger.error(this, "Cannot rename temp file "+newMainJar+" over original jar "+mainJar);
-					if(writtenToTempFile) {
-						// Fail the update - otherwise we will leak disk space
-						newMainJar.delete();
-						failUpdate("Cannot write to preferred new jar location and cannot rename temp file over old jar, update failed");
-						return false;
-					}
-					// Try the hard way
-				} else {
-					System.err.println("Written new Freenet jar: "+mainUpdater.getWrittenVersion());
-					return true;
-				}
-			}
-			
-		}
-		
-		// Easy way didn't work or we can't do the easy way. Try the hard way.
-		
-		if(hasNewExtJar) {
-			
-			writtenNewExt = true;
-			
-			// Write the new ext jar
-			
-			File newExtJar = ctx.getNewExtJar();
-			
-			try {
-				extUpdater.writeJarTo(newExtJar);
-			} catch (IOException e) {
-				failUpdate("Cannot write new ext jar to "+newExtJar);
-				return false;
-			}
-			
-		}
-		
-		try {
-			ctx.rewriteWrapperConf(writtenNewJar, writtenNewExt);
-		} catch (IOException e) {
-			failUpdate("Cannot rewrite wrapper.conf: "+e);
-			return false;
-		} catch (UpdateCatastropheException e) {
-			failUpdate(e.getMessage());
-			node.clientCore.alerts.register(new SimpleUserAlert(false, l10n("updateCatastropheTitle"), e.getMessage(), UserAlert.CRITICAL_ERROR));
-			return false;
-		} catch (UpdaterParserException e) {
-			node.clientCore.alerts.register(new SimpleUserAlert(false, l10n("updateFailedTitle"), e.getMessage(), UserAlert.CRITICAL_ERROR));
-			return false;
-		}
-		
-		return true;
-	}
-
-	/** Restart the node. Does not return. */
-	private void restart(UpdateDeployContext ctx) {
-		node.getNodeStarter().restart();
-		try {
-			Thread.sleep(5*60*1000);
-		} catch (InterruptedException e) {
-			// Break
-		} // in case it's still restarting
-		System.err.println("Failed to restart. Exiting, please restart the node.");
-		System.exit(Node.EXIT_RESTART_FAILED);
-	}
-
-	private void failUpdate(String reason) {
-		Logger.error(this, "Update failed: "+reason);
-		System.err.println("Update failed: "+reason);
-		this.killUpdateAlerts();
-		node.clientCore.alerts.register(new SimpleUserAlert(true, l10n("updateFailedTitle"), l10n("updateFailed", "reason", reason), UserAlert.ERROR));
-	}
-
-	private String l10n(String key) {
-		return L10n.getString("NodeUpdateManager."+key);
-	}
-
-	private String l10n(String key, String pattern, String value) {
-		return L10n.getString("NodeUpdateManager."+key, pattern, value);
-	}
-
-	/**
-	 * Called when a new jar has been downloaded.
-	 * @param isExt If true, the new jar is the ext jar; if false, it is the main jar.
-	 */
-	void onDownloadedNewJar(boolean isExt) {
-		synchronized(this) {
-			if(isExt) {
-				hasNewExtJar = true;
-				startedFetchingNextExtJar = -1;
-			} else {
-				hasNewMainJar = true;
-				startedFetchingNextMainJar = -1;
-			}
-		}
-		revocationChecker.start(true);
-	}
-
-	/**
-	 * Called when the NodeUpdater starts to fetch a new version of the jar.
-	 * @param isExt If true, the new jar is the ext jar; if false, it is the main jar.
-	 */
-	void onStartFetching(boolean isExt) {
-		long now = System.currentTimeMillis();
-		synchronized(this) {
-			if(isExt) {
-				startedFetchingNextExtJar = now;
-			} else {
-				startedFetchingNextMainJar = now;
-			}
-		}
-	}
-	
-	public void blow(String msg){
-		NodeUpdater main, ext;
-		synchronized(this) {
-			if(hasBeenBlown){
-				Logger.error(this, "The key has ALREADY been marked as blown! Message was "+revocationMessage+" new message "+msg);
-				return;
-			}else{
-				this.revocationMessage = msg;
-				this.hasBeenBlown = true;
-				// We must get to the lower part, and show the user the message
-				try {
-					System.err.println("THE AUTO-UPDATING SYSTEM HAS BEEN COMPROMIZED!");
-					System.err.println("The auto-updating system revocation key has been inserted. It says: "+revocationMessage);
-				} catch (Throwable t) {
-					try {
-						Logger.error(this, "Caught "+t, t);
-					} catch (Throwable t1) {}
-				}
-			}
-			main = mainUpdater;
-			ext = extUpdater;
-			if(main != null) main.preKill();
-			if(ext != null) ext.preKill();
-			mainUpdater = null;
-			extUpdater = null;
-		}
-		if(main != null) main.kill();
-		if(ext != null) ext.kill();
-		if(revocationAlert==null){
-			revocationAlert = new RevocationKeyFoundUserAlert(msg);
-			node.clientCore.alerts.register(revocationAlert);
-			// we don't need to advertize updates : we are not going to do them
-			killUpdateAlerts();
-		}
-	}
-
-	/**
-	 * Kill all UserAlerts asking the user whether he wants to update.
-	 */
-	private void killUpdateAlerts() {
-		node.clientCore.alerts.unregister(alert);
-	}
-
-	/** Called when the RevocationChecker has got 3 DNFs on the revocation key */
-	public void noRevocationFound() {
-		deployUpdate(); // May have been waiting for the revocation.
-		// If we're still here, we didn't update.
-		node.ps.queueTimedJob(new Runnable() {
-			public void run() {
-				revocationChecker.start(false);
-			}
-		}, node.random.nextInt(24*60*60*1000)); 
-	}
-	
-	public void arm() {
-		synchronized(this) {
-			armed = true;
-		}
-		deployOffThread(0);
-	}
-	
-	void deployOffThread(long delay) {
-		node.ps.queueTimedJob(new Runnable() {
-			public void run() {
-				deployUpdate();
-			}
-		}, delay);
-	}
-
-	/**
-	 * Has the private key been revoked?
-	 */
-	public boolean isBlown() {
-		return hasBeenBlown;
-	}
-	
-	public synchronized boolean hasNewMainJar() {
-		return hasNewMainJar;
-	}
-
-	public synchronized boolean hasNewExtJar() {
-		return hasNewExtJar;
-	}
-
-	public int newMainJarVersion() {
-		if(mainUpdater == null) return -1;
-		return mainUpdater.getFetchedVersion();
-	}
-
-	public int newExtJarVersion() {
-		if(extUpdater == null) return -1;
-		return extUpdater.getFetchedVersion();
-	}
-
-	public boolean fetchingNewMainJar() {
-		return mainUpdater != null && mainUpdater.isFetching();
-	}
-
-	public boolean fetchingNewExtJar() {
-		return extUpdater != null && extUpdater.isFetching();
-	}
-
-	public int fetchingNewMainJarVersion() {
-		if(mainUpdater == null) return -1;
-		return mainUpdater.fetchingVersion();
-	}
-
-	public int fetchingNewExtJarVersion() {
-		if(extUpdater == null) return -1;
-		return extUpdater.fetchingVersion();
-	}
-
-	public boolean inFinalCheck() {
-		return isReadyToDeployUpdate(true) && !isReadyToDeployUpdate(false);
-	}
-
-	public int getRevocationDNFCounter() {
-		return revocationChecker.getRevocationDNFCounter();
-	}
-
-	public int getMainVersion() {
-		return Version.buildNumber();
-	}
-	
-	public int getExtVersion() {
-		return NodeStarter.extBuildNumber;
-	}
-
-	public boolean isArmed() {
-		return armed || isAutoUpdateAllowed;
-	}
-
-	/** Is the node able to update as soon as the revocation fetch has been completed? */
-	public boolean canUpdateNow() {
-		return isReadyToDeployUpdate(true);
-	}
-
-	/** Is the node able to update *immediately*? (i.e. not only is it ready in every other sense, but also a revocation
-	 * fetch has completed recently enough not to need another one) */
-	public boolean canUpdateImmediately() {
-		return isReadyToDeployUpdate(false);
-	}
-
-	// Config callbacks
-	
-	class UpdaterEnabledCallback implements BooleanCallback {
-		
-		public boolean get() {
-			return isEnabled();
-		}
-		
-		public void set(boolean val) throws InvalidConfigValueException {
-			enable(val);
-		}
-	}
-	
-	class AutoUpdateAllowedCallback implements BooleanCallback {
-		
-		public boolean get() {
-			return isAutoUpdateAllowed();
-		}
-		
-		public void set(boolean val) throws InvalidConfigValueException {
-			setAutoUpdateAllowed(val);
-		}
-	}
-
-	class UpdateURICallback implements StringCallback {
-
-		boolean isExt;
-		
-		UpdateURICallback(boolean isExt) {
-			this.isExt = isExt;
-		}
-		
-		public String get() {
-			return getURI(isExt).toString(false, false);
-		}
-
-		public void set(String val) throws InvalidConfigValueException {
-			FreenetURI uri;
-			try {
-				uri = new FreenetURI(val);
-			} catch (MalformedURLException e) {
-				throw new InvalidConfigValueException("Invalid key: "+val+" : "+e);
-			}
-			setURI(isExt, uri);
-		}
-
-	}
-
-	public class UpdateRevocationURICallback implements StringCallback {
-
-		public String get() {
-			return getRevocationURI().toString(false, false);
-		}
-
-		public void set(String val) throws InvalidConfigValueException {
-			FreenetURI uri;
-			try {
-				uri = new FreenetURI(val);
-			} catch (MalformedURLException e) {
-				throw new InvalidConfigValueException("Invalid key: "+val+" : "+e);
-			}
-			setRevocationURI(uri);
-		}
-		
-	}
-
-}

Modified: trunk/freenet/src/freenet/node/updater/RevocationChecker.java
===================================================================
--- trunk/freenet/src/freenet/node/updater/RevocationChecker.java	2007-05-09 21:10:48 UTC (rev 13180)
+++ trunk/freenet/src/freenet/node/updater/RevocationChecker.java	2007-05-09 21:12:03 UTC (rev 13181)
@@ -14,7 +14,7 @@
 
 /**
  * Fetches the revocation key. Each time it starts, it will try to fetch it until it has 3 DNFs. If it ever finds it, it will
- * be immediately fed to the NodeUpdaterManager.
+ * be immediately fed to the NodeUpdateManager.
  */
 public class RevocationChecker implements ClientCallback {
 
@@ -22,7 +22,7 @@
 	
 	private boolean logMINOR;
 
-	private NodeUpdaterManager manager;
+	private NodeUpdateManager manager;
 	private NodeClientCore core;
 	private int revocationDNFCounter;
 	private FetchContext ctxRevocation;
@@ -31,7 +31,7 @@
 	/** Last time at which we got 3 DNFs on the revocation key */
 	private long lastSucceeded;
 
-	public RevocationChecker(NodeUpdaterManager manager) {
+	public RevocationChecker(NodeUpdateManager manager) {
 		this.manager = manager;
 		core = manager.node.clientCore;
 		this.revocationDNFCounter = 0;

Modified: trunk/freenet/src/freenet/node/useralerts/UpdatedVersionAvailableUserAlert.java
===================================================================
--- trunk/freenet/src/freenet/node/useralerts/UpdatedVersionAvailableUserAlert.java	2007-05-09 21:10:48 UTC (rev 13180)
+++ trunk/freenet/src/freenet/node/useralerts/UpdatedVersionAvailableUserAlert.java	2007-05-09 21:12:03 UTC (rev 13181)
@@ -4,14 +4,14 @@
 package freenet.node.useralerts;
 
 import freenet.l10n.L10n;
-import freenet.node.updater.NodeUpdaterManager;
+import freenet.node.updater.NodeUpdateManager;
 import freenet.node.updater.RevocationChecker;
 import freenet.support.HTMLNode;
 
 public class UpdatedVersionAvailableUserAlert implements UserAlert {
-	private final NodeUpdaterManager updater;
+	private final NodeUpdateManager updater;
 
-	public UpdatedVersionAvailableUserAlert(NodeUpdaterManager updater){
+	public UpdatedVersionAvailableUserAlert(NodeUpdateManager updater){
 		this.updater = updater;
 	}
 	




More information about the cvs mailing list