diff --git a/src/java/com/threerings/getdown/data/Application.java b/src/java/com/threerings/getdown/data/Application.java
index 4e9496f..2aac61a 100644
--- a/src/java/com/threerings/getdown/data/Application.java
+++ b/src/java/com/threerings/getdown/data/Application.java
@@ -1,5 +1,5 @@
//
-// $Id: Application.java,v 1.8 2004/07/07 16:18:23 mdb Exp $
+// $Id: Application.java,v 1.9 2004/07/13 02:42:52 mdb Exp $
package com.threerings.getdown.data;
@@ -83,7 +83,7 @@ public class Application
try {
return createResource(CONFIG_FILE);
} catch (Exception e) {
- throw new RuntimeException("Booched appbase '" + _appbase + "'!?");
+ throw new RuntimeException("Booched appbase '" + _vappbase + "'!?");
}
}
@@ -105,6 +105,32 @@ public class Application
return _resources;
}
+ /**
+ * Returns a resource that can be used to download a patch file that
+ * will bring this application from its current version to the target
+ * version.
+ */
+ public Resource getPatchResource ()
+ {
+ if (_targetVersion <= _version) {
+ Log.warning("Requested patch resource for up-to-date or " +
+ "non-versioned appliation [cvers=" + _version +
+ ", tvers=" + _targetVersion + "].");
+ return null;
+ }
+
+ String pfile = "patch" + _version + ".dat";
+ try {
+ URL remote = new URL(createVAppBase(_targetVersion), pfile);
+ return new Resource(pfile, remote, getLocalPath(pfile));
+ } catch (Exception e) {
+ Log.warning("Failed to create patch resource path [pfile=" + pfile +
+ ", appbase=" + _appbase + ", tvers=" + _targetVersion +
+ ", error=" + e + "].");
+ return null;
+ }
+ }
+
/**
* Instructs the application to parse its getdown.txt
* configuration and prepare itself for operation. The application
@@ -140,19 +166,13 @@ public class Application
// first determine our application base, this way if anything goes
// wrong later in the process, our caller can use the appbase to
// download a new configuration file
- String appbase = (String)cdata.get("appbase");
- if (appbase == null) {
+ _appbase = (String)cdata.get("appbase");
+ if (_appbase == null) {
throw new IOException("m.missing_appbase");
}
- try {
- // make sure there's a trailing slash
- if (!appbase.endsWith("/")) {
- appbase = appbase + "/";
- }
- _appbase = new URL(appbase);
- } catch (Exception e) {
- String err = MessageUtil.tcompose("m.invalid_appbase", appbase);
- throw new NestableIOException(err, e);
+ // make sure there's a trailing slash
+ if (!_appbase.endsWith("/")) {
+ _appbase = _appbase + "/";
}
// extract our version information
@@ -167,16 +187,15 @@ public class Application
}
// if we are a versioned deployment, create a versioned appbase
- if (_version < 0) {
- _vappbase = _appbase;
- } else {
- try {
- _vappbase = new URL(
- StringUtil.replace(_appbase.toString(), "%VERSION%", vstr));
- } catch (MalformedURLException mue) {
- String err = MessageUtil.tcompose("m.invalid_appbase", appbase);
- throw new NestableIOException(err, mue);
+ try {
+ if (_version < 0) {
+ _vappbase = new URL(_appbase);
+ } else {
+ _vappbase = createVAppBase(_version);
}
+ } catch (MalformedURLException mue) {
+ String err = MessageUtil.tcompose("m.invalid_appbase", _appbase);
+ throw new NestableIOException(err, mue);
}
// determine our application class name
@@ -271,6 +290,30 @@ public class Application
downloadControlFile(CONFIG_FILE);
}
+ /**
+ * Downloads and replaces the getdown.txt and
+ * digest.txt files with those for the target version of
+ * our application.
+ */
+ public void updateMetadata ()
+ throws IOException
+ {
+ try {
+ // update our versioned application base with the target version
+ _vappbase = createVAppBase(_targetVersion);
+ } catch (MalformedURLException mue) {
+ String err = MessageUtil.tcompose("m.invalid_appbase", _appbase);
+ throw new NestableIOException(err, mue);
+ }
+
+ // now re-download our control files; we download the digest first
+ // so that if it fails, our config file will still reference the
+ // old version and re-running the updater will start the whole
+ // process over again
+ downloadControlFile(Digest.DIGEST_FILE);
+ downloadControlFile(CONFIG_FILE);
+ }
+
/**
* Invokes the process associated with this application definition.
*/
@@ -345,7 +388,7 @@ public class Application
public boolean verifyMetadata ()
throws IOException
{
- Log.info("Verifying application: " + _appbase);
+ Log.info("Verifying application: " + _vappbase);
Log.info("Version: " + _version);
Log.info("Class: " + _class);
// Log.info("Code: " + StringUtil.toString(_codes.iterator()));
@@ -439,6 +482,25 @@ public class Application
return (failures.size() == 0) ? null : failures;
}
+ /**
+ * Clears all validation marker files.
+ */
+ public void clearValidationMarkers ()
+ {
+ clearValidationMarkers(_codes.iterator());
+ clearValidationMarkers(_resources.iterator());
+ }
+
+ /**
+ * Creates a versioned application base URL for the specified version.
+ */
+ protected URL createVAppBase (int version)
+ throws MalformedURLException
+ {
+ return new URL(
+ StringUtil.replace(_appbase, "%VERSION%", "" + version));
+ }
+
/** A helper function used by {@link #verifyResources()}. */
protected void verifyResources (Iterator rsrcs, List failures)
{
@@ -463,13 +525,6 @@ public class Application
}
}
- /** Clears all validation marker files. */
- protected void clearValidationMarkers ()
- {
- clearValidationMarkers(_codes.iterator());
- clearValidationMarkers(_resources.iterator());
- }
-
/** Clears all validation marker files for the resources in the
* supplied iterator. */
protected void clearValidationMarkers (Iterator iter)
@@ -493,7 +548,7 @@ public class Application
targetURL = getRemoteURL(path);
} catch (Exception e) {
Log.warning("Requested to download invalid control file " +
- "[appbase=" + _appbase + ", path=" + path +
+ "[appbase=" + _vappbase + ", path=" + path +
", error=" + e + "].");
throw new NestableIOException("Invalid path '" + path + "'.", e);
}
@@ -567,7 +622,8 @@ public class Application
protected int _version = -1;
protected int _targetVersion = -1;
- protected URL _appbase, _vappbase;
+ protected String _appbase;
+ protected URL _vappbase;
protected String _class;
protected ArrayList _codes = new ArrayList();
diff --git a/src/java/com/threerings/getdown/launcher/Getdown.java b/src/java/com/threerings/getdown/launcher/Getdown.java
index 75a0088..eec17b9 100644
--- a/src/java/com/threerings/getdown/launcher/Getdown.java
+++ b/src/java/com/threerings/getdown/launcher/Getdown.java
@@ -1,5 +1,5 @@
//
-// $Id: Getdown.java,v 1.6 2004/07/07 10:45:20 mdb Exp $
+// $Id: Getdown.java,v 1.7 2004/07/13 02:42:52 mdb Exp $
package com.threerings.getdown.launcher;
@@ -16,6 +16,7 @@ import java.io.IOException;
import java.io.PrintStream;
import java.text.MessageFormat;
+import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
@@ -43,6 +44,7 @@ public class Getdown
public void run ()
{
try {
+ // first parses our application deployment file
try {
_ifc = _app.init();
} catch (IOException ioe) {
@@ -52,29 +54,35 @@ public class Getdown
}
for (int ii = 0; ii < MAX_LOOPS; ii++) {
+ // make sure we have the desired version and that the
+ // metadata files are valid...
if (_app.verifyMetadata()) {
Log.info("Application requires update.");
update();
-
- } else {
- Log.info("Metadata verified.");
- List failures = _app.verifyResources();
- if (failures == null) {
- Log.info("Resources verified.");
- launch();
- return;
-
- } else {
- Log.info(failures.size() + " rsrcs require update.");
- download(failures);
- // now we'll loop back and try it all again
- }
+ // loop back again and reverify the metadata
+ continue;
}
+
+ // now verify our resources...
+ List failures = _app.verifyResources();
+ if (failures == null) {
+ Log.info("Resources verified.");
+ launch();
+ return;
+ }
+
+ // redownload any that are corrupt or invalid...
+ Log.info(failures.size() + " rsrcs require update.");
+ download(failures);
+ // now we'll loop back and try it all again
}
+
Log.warning("Pants! We couldn't get the job done.");
+ // TODO: throw exception
} catch (Exception e) {
Log.logStackTrace(e);
+ // TODO: display error to user
}
}
@@ -82,7 +90,30 @@ public class Getdown
* Called if the application is determined to be of an old version.
*/
protected void update ()
+ throws IOException
{
+ // first clear all validation markers
+ _app.clearValidationMarkers();
+
+ // attempt to download the patch file
+ Resource patch = _app.getPatchResource();
+ if (patch != null) {
+ // download the patch file...
+ ArrayList list = new ArrayList();
+ list.add(patch);
+ download(list);
+
+ // and apply it...
+ // TODO
+ }
+ // if the patch resource is null, that means something was booched
+ // in the application, so we skip the patching process but update
+ // the metadata which will result in a "brute force" upgrade
+
+ // finally update our metadata files...
+ _app.updateMetadata();
+ // ...and reinitialize the application
+ _ifc = _app.init();
}
/**
@@ -196,16 +227,21 @@ public class Getdown
public static void main (String[] args)
{
- // ensure the proper parameters are passed
- if (args.length != 1) {
- System.err.println("Usage: java -jar getdown.jar app_dir");
- System.exit(-1);
+ // maybe they specified the appdir in a system property
+ String adarg = System.getProperty("appdir");
+ // if not, check for a command line argument
+ if (StringUtil.blank(adarg)) {
+ if (args.length != 1) {
+ System.err.println("Usage: java -jar getdown.jar app_dir");
+ System.exit(-1);
+ }
+ adarg = args[0];
}
// ensure a valid directory was supplied
- File appDir = new File(args[0]);
+ File appDir = new File(adarg);
if (!appDir.exists() || !appDir.isDirectory()) {
- Log.warning("Invalid app_dir '" + args[0] + "'.");
+ Log.warning("Invalid app_dir '" + adarg + "'.");
System.exit(-1);
}