diff --git a/src/java/com/threerings/resource/DownloadManager.java b/src/java/com/threerings/resource/DownloadManager.java
deleted file mode 100644
index bebf77bc8..000000000
--- a/src/java/com/threerings/resource/DownloadManager.java
+++ /dev/null
@@ -1,390 +0,0 @@
-//
-// $Id: DownloadManager.java,v 1.15 2004/02/25 14:49:39 mdb Exp $
-
-package com.threerings.resource;
-
-import java.awt.EventQueue;
-import java.io.File;
-import java.io.IOException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-
-import com.samskivert.util.Queue;
-import com.samskivert.util.StringUtil;
-
-/**
- * Manages the asynchronous downloading of files that are usually located
- * on an HTTP server but that may also be located on the local filesystem.
- */
-public class DownloadManager
-{
- /** Indicates whether or not we're using versioned resources. */
- public static boolean VERSIONING = false;
-
- /**
- * Provides facilities for notifying an observer of file download
- * progress.
- */
- public interface DownloadObserver
- {
- /**
- * If this method returns true the download observer callbacks
- * will be called on the AWT thread, allowing the observer to do
- * things like safely update user interfaces, etc. If false, it
- * will be called on the download thread.
- */
- public boolean notifyOnAWTThread ();
-
- /**
- * Called when the download manager is about to check all
- * downloads to see whether they are in need of an update.
- */
- public void resolvingDownloads ();
-
- /**
- * Called to inform the observer of ongoing progress toward
- * completion of the overall downloading task. The caller is
- * guaranteed to get at least one call reporting 100% completion.
- *
- * @param percent the percent completion, in terms of total file
- * size, of the download request.
- * @param remaining the estimated download time remaining in
- * seconds, or -1 if the time can not yet be
- * determined.
- */
- public void downloadProgress (int percent, long remaining);
-
- /**
- * Called on the download thread when the patching of jar files
- * has begun.
- */
- public void patching ();
-
- /**
- * Called after the download and patching has completed on the
- * download manager thread.
- */
- public void postDownloadHook ();
-
- /**
- * Called on the preferred notification thread after the download
- * is complete and the post-download hook has run to completion.
- */
- public void downloadComplete ();
-
- /**
- * Called if a failure occurs while checking for an update or
- * downloading a file.
- *
- * @param desc the file that was being downloaded when the error
- * occurred, or null if the failure occurred while
- * resolving downloads.
- * @param e the exception detailing the failure.
- */
- public void downloadFailed (DownloadDescriptor desc, Exception e);
- }
-
- /**
- * Describes a single file to be downloaded.
- */
- public static class DownloadDescriptor
- {
- /** The URL from which the file is to be downloaded. */
- public URL sourceURL;
-
- /** The destination file to which the file is to be written. */
- public File destFile;
-
- /** The version of the file to be downloaded. */
- public String version;
-
- /** The last-modified timestamp of the source. */
- public long lastModified;
-
- /** The last-modified timestamp of the destination file. */
- public long destLastModified;
-
- /** The size in bytes of the destination file. */
- public long destFileSize;
-
- /**
- * Constructs a download descriptor to retrieve the specified
- * version of the given file from the given URL.
- */
- public DownloadDescriptor (URL url, File file, String version)
- {
- this.sourceURL = url;
- this.destFile = file;
- this.version = version;
- }
-
- /**
- * Creates the appropriate type of downloader for this descriptor.
- */
- public Downloader createDownloader ()
- throws IOException
- {
- String protocol = sourceURL.getProtocol();
- if (protocol.equals("file")) {
- return new FileDownloader();
- } else if (protocol.equals("http")) {
- return VERSIONING ? (Downloader)new JNLPDownloader() :
- (Downloader)new HTTPDownloader();
- } else {
- throw new IOException(
- "Unknown source file protocol " +
- "[protocol=" + protocol + ", desc=" + this + "].");
- }
- }
-
- /** Returns a string representation of this instance. */
- public String toString ()
- {
- return StringUtil.fieldsToString(this);
- }
- }
-
- /**
- * Downloads the supplied list of descriptors, notifying the given
- * download observer of download progress and status.
- *
- * @param descriptors the list of files to be downloaded.
- * @param fragile if true, reports failure and ceases any further
- * downloading if an error occurs; else will continue attempting to
- * download the remainder of the descriptors.
- * @param downloadObs the observer to notify of progress, success and
- * failure.
- */
- public void download (
- List descriptors, boolean fragile, DownloadObserver downloadObs)
- {
- // add the download request to the download queue
- DownloadRecord dlrec = new DownloadRecord();
- dlrec.descriptors = descriptors;
- dlrec.obs = downloadObs;
- dlrec.fragile = fragile;
- _dlqueue.append(dlrec);
-
- synchronized (this) {
- // if we've not yet got our downloading thread...
- if (_dlthread == null) {
- // create the thread
- _dlthread = new Thread() {
- public void run () {
- processDownloads();
- }
- };
- _dlthread.setDaemon(true);
- // and start it going
- _dlthread.start();
- }
- }
- }
-
- /**
- * Called by the download thread to process all download requests in
- * the download queue.
- */
- protected void processDownloads ()
- {
- // create the data buffer to be used when reading files
- _buffer = new byte[BUFFER_SIZE];
-
- DownloadRecord dlrec;
- while (true) {
- synchronized (this) {
- // kill the download thread if we have no remaining
- // download requests
- if (_dlqueue.size() == 0) {
- _dlthread = null;
- // free up the data buffer
- _buffer = null;
- return;
- }
-
- // pop download off the queue
- dlrec = (DownloadRecord)_dlqueue.getNonBlocking();
- }
-
- // handle the download request
- processDownloadRequest(dlrec.descriptors, dlrec.obs, dlrec.fragile);
- }
- }
-
- /**
- * Processes a single download request.
- */
- protected void processDownloadRequest (
- List descriptors, final DownloadObserver obs, boolean fragile)
- {
- // let the observer know that we're about to resolve all files to
- // be downloaded
- if (obs.notifyOnAWTThread()) {
- EventQueue.invokeLater(new Runnable() {
- public void run () {
- obs.resolvingDownloads();
- }
- });
- } else {
- obs.resolvingDownloads();
- }
-
- // check the size and last-modified information for each file to
- // ascertain whether our local copy needs to be refreshed
- ArrayList fetch = new ArrayList();
- ProgressInfo pinfo = new ProgressInfo();
- int size = descriptors.size();
- for (int ii = 0; ii < size; ii++) {
- DownloadDescriptor desc = (DownloadDescriptor)descriptors.get(ii);
-
- try {
- Downloader loader = desc.createDownloader();
- loader.init(desc);
- if (loader.checkUpdate(pinfo)) {
- fetch.add(loader);
- }
-
- } catch (final IOException ioe) {
- notifyFailed(obs, null, ioe);
- if (fragile) {
- return;
- }
- }
- }
-
- if (pinfo.totalSize > 0) {
- Log.info("Initiating download of " + pinfo.totalSize + " bytes.");
- }
-
- // download all stale files
- size = fetch.size();
- DownloadDescriptor fdesc = null;
- pinfo.start = System.currentTimeMillis();
- for (int ii = 0; ii < size; ii++) {
- Downloader loader = (Downloader)fetch.get(ii);
- try {
- loader.processDownload(this, obs, pinfo, _buffer);
- } catch (IOException ioe) {
- notifyFailed(obs, loader.getDescriptor(), ioe);
- if (fragile) {
- return;
- } else {
- continue; // skip the postDownload for that bundle.
- }
- }
-
- try {
- loader.postDownload(this, obs, pinfo);
- } catch (IOException ioe) {
- // we want to try to apply as many of the patches as we
- // can, so we don't fail entirely here, just keep track of
- // the last failure and report that when we're done
- fdesc = loader.getDescriptor();
- Log.warning("Downloader failed in postDownload hook " +
- "[desc=" + fdesc + "].");
- Log.logStackTrace(ioe);
- }
- }
-
- // if we had any failure, go ahead and report it now
- if (fdesc != null) {
- PatchException pe = new PatchException(
- "Failed to patch one or more updated bundles.");
- notifyFailed(obs, fdesc, pe);
-
- } else {
- // make sure to always let the observer know that we've
- // wrapped up by reporting 100% completion
- notifyProgress(obs, 100, 0L);
- }
- }
-
- /** Helper function. */
- protected void notifyProgress (final DownloadObserver obs,
- final int progress, final long remaining)
- {
- if (obs.notifyOnAWTThread()) {
- EventQueue.invokeLater(new Runnable() {
- public void run () {
- obs.downloadProgress(progress, remaining);
- }
- });
- } else {
- obs.downloadProgress(progress, remaining);
- }
-
- if (progress == 100) {
- // if we're at 100%, run the post-download hook
- try {
- obs.postDownloadHook();
- } catch (Exception e) {
- Log.warning("Observer choked in post-download hook.");
- Log.logStackTrace(e);
- }
-
- // notify of total and final download completion
- if (obs.notifyOnAWTThread()) {
- EventQueue.invokeLater(new Runnable() {
- public void run () {
- obs.downloadComplete();
- }
- });
- } else {
- obs.downloadComplete();
- }
- }
- }
-
- /** Helper function. */
- protected void notifyFailed (final DownloadObserver obs,
- final DownloadDescriptor desc,
- final Exception e)
- {
- if (obs.notifyOnAWTThread()) {
- EventQueue.invokeLater(new Runnable() {
- public void run () {
- obs.downloadFailed(desc, e);
- }
- });
- } else {
- obs.downloadFailed(desc, e);
- }
- }
-
- /**
- * A record describing a single download request.
- */
- protected static class DownloadRecord
- {
- /** The list of download descriptors to be downloaded. */
- public List descriptors;
-
- /** The download observer to notify of download progress. */
- public DownloadObserver obs;
-
- /** Whether to abort downloading if an error occurs. */
- public boolean fragile;
- }
-
- /** The downloading thread. */
- protected Thread _dlthread;
-
- /** The queue of download requests. */
- protected Queue _dlqueue = new Queue();
-
- /** The data buffer used when reading file data. */
- protected byte[] _buffer;
-
- /** The data buffer size for reading file data. */
- protected static final int BUFFER_SIZE = 2048;
-
- static {
- try {
- VERSIONING = "true".equalsIgnoreCase(
- System.getProperty("versioned_rsrcs"));
- } catch (Throwable t) {
- // no versioning, no problem
- }
- }
-}
diff --git a/src/java/com/threerings/resource/Downloader.java b/src/java/com/threerings/resource/Downloader.java
deleted file mode 100644
index e08965d81..000000000
--- a/src/java/com/threerings/resource/Downloader.java
+++ /dev/null
@@ -1,181 +0,0 @@
-//
-// $Id: Downloader.java,v 1.4 2004/06/16 09:44:23 mdb Exp $
-
-package com.threerings.resource;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URLConnection;
-
-import com.threerings.resource.DownloadManager.DownloadDescriptor;
-import com.threerings.resource.DownloadManager.DownloadObserver;
-
-/**
- * Does something extraordinary.
- */
-public abstract class Downloader
-{
- /**
- * Provides this downloader with a reference to the download
- * descriptor it needs to do its business.
- */
- public void init (DownloadDescriptor ddesc)
- {
- _desc = ddesc;
- _desc.destFileSize = _desc.destFile.length();
- _desc.destLastModified = _desc.destFile.lastModified();
- }
-
- /**
- * Returns a reference to the descriptor we are downloading.
- */
- public DownloadDescriptor getDescriptor ()
- {
- return _desc;
- }
-
- /**
- * Requests that this downloader determine whether it needs to be
- * updated and if so, it should add its total download requirement to
- * {@link ProgressInfo#totalSize} the supplied {@link ProgressInfo}
- * record.
- *
- * @return true if this downloader needs be updated, false if not.
- */
- public abstract boolean checkUpdate (ProgressInfo info)
- throws IOException;
-
- /**
- * Compares the supplied size and last modified time with the size and
- * last modified time of our local copy of the file.
- */
- protected boolean compareWithLocal (long fileSize, long lastModified)
- {
- // check to see whether we have a local copy at all, and if so,
- // whether its file size or last-modified time differs from the
- // source file modulo a delta to account for inexactness on the
- // part of the file-system (thanks Microsoft)
- return ((!_desc.destFile.exists()) ||
- (_desc.destFileSize != fileSize) ||
- (_desc.destLastModified < (lastModified - DELTA)) ||
- (_desc.destLastModified > (lastModified + DELTA)));
- }
-
- /**
- * Processes a single download descriptor.
- */
- public void processDownload (DownloadManager dmgr, DownloadObserver obs,
- ProgressInfo pinfo, byte[] buffer)
- throws IOException
- {
- // download the resource bundle from the specified URL
- URLConnection ucon = _desc.sourceURL.openConnection();
-
- // prepare to read the data from the URL into the cache file
- Log.info("Downloading file [url=" + _desc.sourceURL + "].");
- downloadContent(dmgr, obs, pinfo, buffer, ucon, _desc.destFile);
-
- // if we have a last modified time, we want to adjust our cache
- // file accordingly
- if (_desc.lastModified != 0) {
- if (!_desc.destFile.setLastModified(_desc.lastModified)) {
- Log.warning("Failed to set last-modified date " +
- "[file=" + _desc.destFile + "].");
- }
- }
- }
-
- /**
- * Called after the download phase has completed to allow patching or
- * other post-download activities.
- */
- public void postDownload (DownloadManager dmgr, DownloadObserver obs,
- ProgressInfo pinfo)
- throws IOException
- {
- // nothing to do by default
- }
-
- /**
- * Downloads the content from the supplied URL connection into the
- * specified destination file, informing the supplied download manager
- * and observer of our progress along the way.
- */
- protected void downloadContent (DownloadManager dmgr, DownloadObserver obs,
- ProgressInfo pinfo, byte[] buffer,
- URLConnection ucon, File destFile)
- throws IOException
- {
- InputStream in = ucon.getInputStream();
- FileOutputStream out = new FileOutputStream(destFile);
- int read;
-
- // TODO: look to see if we have a download info file containing
- // info on potentially partially downloaded data; if so, use a
- // "Range: bytes=HAVE-" header.
-
- // if we were unable to determine our content length, record a
- // single "byte" of progress to indicate that we've started to
- // download this file
- if (_contentLength <= 0) {
- pinfo.currentSize += 1;
- }
-
- // read in the file data
- while ((read = in.read(buffer)) != -1) {
- // write it out to our local copy
- out.write(buffer, 0, read);
-
- // if we know we added something to the total download size,
- // then report our progress to the download observer as a
- // percentage of the total file data to be transferred
- if (_contentLength > 0) {
- pinfo.currentSize += read;
- }
-
- // update our percent completion; if we're totally done, hold
- // off on notifying the observer until the download manager
- // finishes fiddling to ensure that any action the observer
- // may take on the downloaded files can be safely undertaken
- int pctdone = pinfo.getPercentDone();
- pinfo.complete = (pctdone >= 100);
- if (pinfo.complete) {
- continue;
- }
-
- // update the transfer rate to reflect the bit of data we just
- // transferred
- long now = System.currentTimeMillis();
- pinfo.updateXferRate(now);
-
- // notify the progress observer if it's been sufficiently long
- // since our last notification
- if ((now - pinfo.lastUpdate) >= UPDATE_DELAY) {
- pinfo.lastUpdate = now;
- long remaining = pinfo.getXferTimeRemaining();
- dmgr.notifyProgress(obs, pctdone, remaining);
- }
- }
-
- // close the streams
- in.close();
- out.close();
- }
-
- /** The descriptor that we're downloading. */
- protected DownloadDescriptor _desc;
-
- /** We need this to cope gracefully with a missing content-length. */
- protected long _contentLength;
-
- /** The last-modified difference in milliseconds allowed between the
- * source and destination file without considering the destination
- * file to be out of date. */
- protected static final long DELTA = 5000L;
-
- /** The delay in milliseconds between notifying progress observers of
- * file download progress. */
- protected static final long UPDATE_DELAY = 2500L;
-}
diff --git a/src/java/com/threerings/resource/FileDownloader.java b/src/java/com/threerings/resource/FileDownloader.java
deleted file mode 100644
index 8ee914227..000000000
--- a/src/java/com/threerings/resource/FileDownloader.java
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-// $Id: FileDownloader.java,v 1.2 2004/06/16 09:44:23 mdb Exp $
-
-package com.threerings.resource;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * "Downloads" a file from a location on the filesystem.
- */
-public class FileDownloader extends Downloader
-{
- // documentation inherited
- public boolean checkUpdate (ProgressInfo info)
- throws IOException
- {
- // read the file information directly from the file system
- File tfile = new File(_desc.sourceURL.getPath());
- _contentLength = tfile.length();
- _desc.lastModified = tfile.lastModified();
-
- if (compareWithLocal(_contentLength, _desc.lastModified)) {
- // increment the total file size to be fetched
- info.totalSize += _contentLength;
- Log.debug("File deemed stale [url=" + _desc.sourceURL + "].");
- return true;
- } else {
- Log.debug("File deemed up-to-date [url=" + _desc.sourceURL + "].");
- return false;
- }
- }
-}
diff --git a/src/java/com/threerings/resource/HTTPDownloader.java b/src/java/com/threerings/resource/HTTPDownloader.java
deleted file mode 100644
index 9f5a00b5d..000000000
--- a/src/java/com/threerings/resource/HTTPDownloader.java
+++ /dev/null
@@ -1,78 +0,0 @@
-//
-// $Id: HTTPDownloader.java,v 1.4 2004/06/17 03:02:55 mdb Exp $
-
-package com.threerings.resource;
-
-import java.io.IOException;
-import java.net.HttpURLConnection;
-
-import com.threerings.resource.DownloadManager.DownloadObserver;
-
-/**
- * Downloads resources via HTTP using on last modification timestamps to
- * determine whether updates are needed.
- */
-public class HTTPDownloader extends Downloader
-{
- // documentation inherited
- public boolean checkUpdate (ProgressInfo info)
- throws IOException
- {
- // read the file information via an HTTP HEAD request
- HttpURLConnection ucon = (HttpURLConnection)
- _desc.sourceURL.openConnection();
- ucon.setRequestMethod("HEAD");
- ucon.connect();
-
- // make sure we got a satisfactory response code
- if (ucon.getResponseCode() != HttpURLConnection.HTTP_OK) {
- String errmsg = "Unable to check up-to-date for " +
- _desc.sourceURL + ": " + ucon.getResponseCode();
- throw new IOException(errmsg);
- }
-
- // read size and last modified information from the HEAD response
- _contentLength = ucon.getContentLength();
- _desc.lastModified = ucon.getLastModified();
-
- if (compareWithLocal(_contentLength, _desc.lastModified)) {
- // increment the total file size to be fetched
- info.totalSize += _contentLength;
- Log.debug("Resource deemed stale [url=" + _desc.sourceURL + "].");
- return true;
- } else {
- Log.debug("Resource up-to-date [url=" + _desc.sourceURL + "].");
- return false;
- }
- }
-
- // documentation inherited
- public void processDownload (DownloadManager dmgr, DownloadObserver obs,
- ProgressInfo pinfo, byte[] buffer)
- throws IOException
- {
- // download the resource bundle from the specified URL
- HttpURLConnection ucon = (HttpURLConnection)
- _desc.sourceURL.openConnection();
- ucon.connect();
-
- // make sure we got a satisfactory response code
- if (ucon.getResponseCode() != HttpURLConnection.HTTP_OK) {
- String errmsg = "Unable to download update for " +
- _desc.sourceURL + ": " + ucon.getResponseCode();
- throw new IOException(errmsg);
- }
-
- Log.info("Downloading updated jar [url=" + _desc.sourceURL + "].");
- downloadContent(dmgr, obs, pinfo, buffer, ucon, _desc.destFile);
-
- // if we have a last modified time, we want to adjust our cache
- // file accordingly
- if (_desc.lastModified != 0) {
- if (!_desc.destFile.setLastModified(_desc.lastModified)) {
- Log.warning("Failed to set last-modified date " +
- "[file=" + _desc.destFile + "].");
- }
- }
- }
-}
diff --git a/src/java/com/threerings/resource/JNLPDownloader.java b/src/java/com/threerings/resource/JNLPDownloader.java
deleted file mode 100644
index b1435a23d..000000000
--- a/src/java/com/threerings/resource/JNLPDownloader.java
+++ /dev/null
@@ -1,307 +0,0 @@
-//
-// $Id: JNLPDownloader.java,v 1.18 2004/06/16 09:44:23 mdb Exp $
-
-package com.threerings.resource;
-
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
-
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import com.sun.javaws.cache.Patcher;
-import com.sun.javaws.jardiff.JarDiffPatcher;
-
-import com.samskivert.io.StreamUtil;
-import com.samskivert.util.FileUtil;
-import com.samskivert.util.StringUtil;
-
-import com.threerings.resource.DownloadManager.DownloadDescriptor;
-import com.threerings.resource.DownloadManager.DownloadObserver;
-
-/**
- * Does something extraordinary.
- */
-public class JNLPDownloader extends Downloader
-{
- // documentation inherited
- public void init (DownloadDescriptor ddesc)
- {
- super.init(ddesc);
-
- String dpath = _desc.destFile.getPath();
-
- // determine the path of our version file before we version the
- // path of the destination file
- _vfile = new File(FileUtil.resuffix(_desc.destFile, ".jar", ".vers"));
-
- // if we're using a version, adjust our destination file path
- // based on said version
- if (!StringUtil.blank(_desc.version)) {
- _desc.destFile = new File(
- ResourceManager.versionPath(dpath, _desc.version, ".jar"));
- }
-
- // determine which version we already have, if any
- if (_vfile.exists()) {
- try {
- BufferedReader vin = new BufferedReader(new FileReader(_vfile));
- _cvers = vin.readLine();
-
- // make sure the version referenced by that file still
- // exists; if not ignore our "current version"
- _curFile = new File(ResourceManager.versionPath(
- dpath, _cvers, ".jar"));
- if (!_curFile.exists()) {
- _cvers = null;
- }
-
- } catch (IOException ioe) {
- Log.warning("Error reading version file [path=" + _vfile +
- ", error=" + ioe + "].");
- }
- }
- }
-
- // documentation inherited
- public boolean checkUpdate (ProgressInfo info)
- throws IOException
- {
- // if we're doing versioning and we have the appropriate version,
- // no need to update
- if (_desc.version != null && _desc.version.equals(_cvers)) {
- return false;
- }
-
- // read the file information via an HTTP HEAD request
- HttpURLConnection ucon = (HttpURLConnection)
- getResourceURL().openConnection();
- ucon.setRequestMethod("HEAD");
- ucon.connect();
-
- // make sure we got a satisfactory response code
- if (ucon.getResponseCode() != HttpURLConnection.HTTP_OK ||
- JNLP_ERROR_TYPE.equals(ucon.getContentType())) {
- String errmsg = "Unable to check up-to-date for " +
- getResourceURL() + ": " + ucon.getResponseCode();
- throw new IOException(errmsg);
- }
-
- // determine our content length
- _contentLength = ucon.getContentLength();
- if (_contentLength > 0) {
- // and record it to the total size if it is a sane value
- info.totalSize += _contentLength;
- } else {
- // if it's not sane, record a single byte which we will then
- // properly interepret later during actual downloading
- info.totalSize += 1;
- }
- Log.info(getResourceURL() + " requires " + _contentLength +
- " byte update.");
- return true;
- }
-
- // documentation inherited
- public void processDownload (DownloadManager dmgr, DownloadObserver obs,
- ProgressInfo pinfo, byte[] buffer)
- throws IOException
- {
- // download the resource bundle from the specified URL
- URL rsrcURL = getResourceURL();
- HttpURLConnection ucon = (HttpURLConnection)rsrcURL.openConnection();
- ucon.connect();
-
- // make sure we got a satisfactory response code
- if (ucon.getResponseCode() != HttpURLConnection.HTTP_OK ||
- JNLP_ERROR_TYPE.equals(ucon.getContentType())) {
- String errmsg = "Unable to download update for " +
- getResourceURL() + ": " + ucon.getResponseCode();
- throw new IOException(errmsg);
- }
-
- // determine whether or not this is a patch
- if (ucon.getContentType().equals(JARDIFF_TYPE)) {
- Log.info("Downloading patch [url=" + rsrcURL + "].");
- _patchFile = new File(
- FileUtil.resuffix(_curFile, ".jar", ".diff"));
- downloadContent(dmgr, obs, pinfo, buffer, ucon, _patchFile);
-
- } else {
- Log.info("Downloading whole jar [url=" + rsrcURL + "].");
- downloadContent(dmgr, obs, pinfo, buffer, ucon, _desc.destFile);
- }
- }
-
- // documentation inherited
- public void postDownload (DownloadManager dmgr, DownloadObserver obs,
- ProgressInfo pinfo)
- throws IOException
- {
- if (_patchFile != null) {
- // now apply the patch
- Log.info("Applying patch [old=" + _curFile +
- ", patch=" + _patchFile +
- ", new=" + _desc.destFile + "].");
- Patcher.PatchDelegate delegate = new Patcher.PatchDelegate() {
- public void patching (int value) {
- // System.out.println("Patching " + _desc.destFile + ": " +
- // value);
- }
- };
-
- JarDiffPatcher patcher = new JarDiffPatcher();
- BufferedOutputStream out = null;
- try {
- out = new BufferedOutputStream(
- new FileOutputStream(_desc.destFile));
- patcher.applyPatch(delegate, _curFile.getPath(),
- _patchFile.getPath(), out);
- out.close();
-
- } catch (IOException ioe) {
- Log.warning("Failure applying patch [rfile=" + _desc.destFile +
- ", error=" + ioe + "]. Cleaning up and failing.");
- StreamUtil.close(out);
- cleanUpAndFail(ioe);
- }
-
- // clean up the old jar and the patch file
- if (!_curFile.delete()) {
- Log.warning("Failed to delete old bundle " + _curFile + ".");
- }
- if (!_patchFile.delete()) {
- Log.warning("Failed to delete patch file " + _patchFile + ".");
- }
-
- // delete any old unversioned version of the .jar file
- File unverDest = new File(ResourceManager.unversionPath(
- _desc.destFile.getPath(), ".jar"));
- if (unverDest.exists()) {
- if (!unverDest.delete()) {
- Log.warning("Failed to delete old unversioned bundle '" +
- unverDest + "'.");
- }
- }
- }
-
- // attempt to delete any old stale bundles as well
- if (_desc.version != null) {
- try {
- String cpath = _desc.destFile.getPath();
- String pcpath = ResourceManager.unversionPath(cpath, ".jar");
- File pdir = _desc.destFile.getParentFile();
- File[] files = pdir.listFiles();
- for (int ii = 0; ii < files.length; ii++) {
- String path = files[ii].getPath();
- if (path.equals(cpath) || !path.endsWith(".jar")) {
- continue;
- }
- String ppath = ResourceManager.unversionPath(path, ".jar");
- if (!pcpath.equals(ppath)) {
- continue;
- }
- if (!files[ii].delete()) {
- Log.warning("Unable to delete stale bundle '" +
- files[ii].getPath() + "'.");
- } else {
- Log.info("Deleted stale bundle '" + files[ii] + "'.");
- }
- }
- } catch (Exception e) {
- Log.warning("Failure deleting stale bundles.");
- Log.logStackTrace(e);
- }
- }
-
- PrintWriter pout = new PrintWriter(
- new BufferedWriter(new FileWriter(_vfile)));
- pout.println(_desc.version);
- pout.close();
- // Log.info("Updated version to " + _desc.version + ".");
- }
-
- /**
- * Constructs the resource URL using the source URL supplied in the
- * download descriptor and any version information that is
- * appropriate.
- */
- protected URL getResourceURL ()
- {
- if (_desc.version == null) {
- return _desc.sourceURL;
- }
- URL rsrcURL = _desc.sourceURL;
- String vargs = _desc.sourceURL.getPath() +
- "?version-id=" + _desc.version;
- if (_cvers != null) {
- vargs += "¤t-version-id=" + _cvers;
- }
- try {
- rsrcURL = new URL(rsrcURL, vargs);
- } catch (MalformedURLException mue) {
- Log.warning("Error creating versioned resource URL " +
- "[url=" + rsrcURL + ", vargs=" + vargs + "].");
- }
- return rsrcURL;
- }
-
- /**
- * Attempts to wipe out everything relating to this resource so that
- * the next time we attempt to run the client we can download it
- * completely afresh.
- */
- protected void cleanUpAndFail (IOException cause)
- throws IOException
- {
- if (_curFile != null) {
- Log.warning("Failed to delete " + _desc.destFile +
- " in cleanUpAndFail().");
- }
- if (_patchFile != null) {
- _patchFile.delete();
- }
- if (_vfile != null) {
- if (!_vfile.delete()) {
- Log.warning("Failed to delete " + _vfile +
- " in cleanUpAndFail().");
- }
- }
-
- IOException failure = new IOException(
- "Failed to patch " + _desc.destFile + ".");
- if (cause != null) {
- failure.initCause(cause);
- }
- throw failure;
- }
-
- /** A file that contains the current resource version. */
- protected File _vfile;
-
- /** The file that contains our patch if we have one. */
- protected File _patchFile;
-
- /** The current version of the resource if we have one. */
- protected String _cvers;
-
- /** The existing version of our bundle file. */
- protected File _curFile;
-
- /** The mime-type of a jardiff patch file. */
- protected static final String JARDIFF_TYPE =
- "application/x-java-archive-diff";
-
- /** The mime-type indicating a jnlp-servlet error. Why they don't just
- * use an HTTP error response code, I dare not attempt to imagine. */
- protected static final String JNLP_ERROR_TYPE =
- "application/x-java-jnlp-error";
-}
diff --git a/src/java/com/threerings/resource/PatchException.java b/src/java/com/threerings/resource/PatchException.java
deleted file mode 100644
index e443c4fe0..000000000
--- a/src/java/com/threerings/resource/PatchException.java
+++ /dev/null
@@ -1,17 +0,0 @@
-//
-// $Id: PatchException.java,v 1.1 2003/08/09 00:31:27 mdb Exp $
-
-package com.threerings.resource;
-
-import java.io.IOException;
-
-/**
- * An exception thrown when we fail to patch one or more updated files.
- */
-public class PatchException extends IOException
-{
- public PatchException (String msg)
- {
- super(msg);
- }
-}
diff --git a/src/java/com/threerings/resource/ProgressInfo.java b/src/java/com/threerings/resource/ProgressInfo.java
deleted file mode 100644
index 68c7a6b82..000000000
--- a/src/java/com/threerings/resource/ProgressInfo.java
+++ /dev/null
@@ -1,60 +0,0 @@
-//
-// $Id: ProgressInfo.java,v 1.1 2003/08/05 01:33:20 mdb Exp $
-
-package com.threerings.resource;
-
-/**
- * Used to track download progress.
- */
-public class ProgressInfo
-{
- /** The total file size in bytes to be transferred. */
- public long totalSize;
-
- /** The file size in bytes transferred thus far. */
- public long currentSize;
-
- /** The time at which the file transfer began. */
- public long start;
-
- /** The current transfer rate in bytes per second. */
- public long bytesPerSecond;
-
- /** The time at which the last progress update was posted to the
- * progress observer. */
- public long lastUpdate;
-
- /** Whether the download has completed and the progress observer
- * notified. */
- public boolean complete;
-
- /**
- * Returns the percent completion, based on data size transferred,
- * of the file transfer.
- */
- public int getPercentDone ()
- {
- return (int)((currentSize / (float)totalSize) * 100f);
- }
-
- /**
- * Updates the bytes per second transfer rate for the download
- * associated with this progress info record.
- */
- public void updateXferRate (long now)
- {
- long secs = (now - start) / 1000L;
- bytesPerSecond = (secs == 0) ? 0 : (currentSize / secs);
- }
-
- /**
- * Returns the estimated transfer time remaining for the download
- * associated with this progress info record, or -1 if
- * the transfer time cannot currently be estimated.
- */
- public long getXferTimeRemaining ()
- {
- return (bytesPerSecond == 0) ? -1 :
- (totalSize - currentSize) / bytesPerSecond;
- }
-}
diff --git a/src/java/com/threerings/resource/ResourceBundle.java b/src/java/com/threerings/resource/ResourceBundle.java
index f67951243..eefaa13b6 100644
--- a/src/java/com/threerings/resource/ResourceBundle.java
+++ b/src/java/com/threerings/resource/ResourceBundle.java
@@ -1,5 +1,5 @@
//
-// $Id: ResourceBundle.java,v 1.29 2004/07/13 16:37:40 mdb Exp $
+// $Id: ResourceBundle.java,v 1.30 2004/07/14 14:06:46 mdb Exp $
package com.threerings.resource;
@@ -49,9 +49,7 @@ public class ResourceBundle
{
_source = source;
if (unpack) {
- String root = ResourceManager.unversionPath(
- source.getPath(), ".jar");
- root = stripSuffix(root);
+ String root = stripSuffix(source.getPath());
_unpacked = new File(root + ".stamp");
_cache = new File(root);
}
diff --git a/src/java/com/threerings/resource/ResourceManager.java b/src/java/com/threerings/resource/ResourceManager.java
index 6ab065a5e..13d79287c 100644
--- a/src/java/com/threerings/resource/ResourceManager.java
+++ b/src/java/com/threerings/resource/ResourceManager.java
@@ -1,5 +1,5 @@
//
-// $Id: ResourceManager.java,v 1.43 2004/07/13 16:37:40 mdb Exp $
+// $Id: ResourceManager.java,v 1.44 2004/07/14 14:06:46 mdb Exp $
package com.threerings.resource;
@@ -9,13 +9,11 @@ import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
@@ -28,14 +26,10 @@ import javax.imageio.stream.FileImageInputStream;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;
-import org.apache.commons.io.CopyUtils;
-
+import com.samskivert.net.PathUtil;
import com.samskivert.util.ResultListener;
import com.samskivert.util.StringUtil;
-import com.threerings.resource.DownloadManager.DownloadDescriptor;
-import com.threerings.resource.DownloadManager.DownloadObserver;
-
/**
* The resource manager is responsible for maintaining a repository of
* resources that are synchronized with a remote source. This is
@@ -53,10 +47,10 @@ import com.threerings.resource.DownloadManager.DownloadObserver;
*
*
Applications that wish to make use of resource sets and their
* associated bundles must call {@link #initBundles} after constructing
- * the resource manager, providing the URL of a resource definition file
+ * the resource manager, providing the path to a resource definition file
* which describes these resource sets. The definition file will be loaded
* and the resource bundles defined within will be loaded relative to the
- * resource definition URL. The bundles will be cached in the user's home
+ * resource directory. The bundles will be cached in the user's home
* directory and only reloaded when the source resources have been
* updated. The resource definition file looks something like the
* following:
@@ -86,64 +80,51 @@ import com.threerings.resource.DownloadManager.DownloadObserver;
public class ResourceManager
{
/**
- * Provides facilities for notifying an observer of resource bundle
- * download progress.
+ * Provides facilities for notifying an observer of the resource
+ * unpacking process.
*/
- public interface BundleDownloadObserver
+ public interface InitObserver
{
/**
- * If this method returns true the download observer callbacks
- * will be called on the AWT thread, allowing the observer to do
- * things like safely update user interfaces, etc. If false, it
- * will be called on a special download thread.
+ * Indicates a percent completion along with an estimated time
+ * remaining in seconds.
*/
- public boolean notifyOnAWTThread ();
+ public void progress (int percent, long remaining);
/**
- * Called when the resource manager is about to check for an
- * update of any of our resource sets.
+ * Indicates that there was a failure unpacking our resource
+ * bundles.
*/
- public void checkingForUpdate ();
+ public void initializationFailed (Exception e);
+ }
- /**
- * Called to inform the observer of ongoing progress toward
- * completion of the overall bundle downloading task. The caller
- * is guaranteed to get at least one call reporting 100%
- * completion.
- *
- * @param percent the percent completion of the download.
- * @param remaining the estimated download time remaining in
- * seconds, or -1 if the time can not yet be
- * determined.
- */
- public void downloadProgress (int percent, long remaining);
+ /**
+ * An adapter that wraps an {@link InitObserver} and routes all method
+ * invocations to the AWT thread.
+ */
+ public static class AWTInitObserver implements InitObserver
+ {
+ public AWTInitObserver (InitObserver obs) {
+ _obs = obs;
+ }
- /**
- * Called to inform the observer that the bundle patching process
- * has begun. This follows the download phase, but is optional.
- */
- public void patching ();
+ public void progress (final int percent, final long remaining) {
+ EventQueue.invokeLater(new Runnable() {
+ public void run () {
+ _obs.progress(percent, remaining);
+ }
+ });
+ }
- /**
- * Called to inform the observer that the bundle unpacking process
- * has begun. This follows the download or patching phase.
- */
- public void unpacking ();
+ public void initializationFailed (final Exception e) {
+ EventQueue.invokeLater(new Runnable() {
+ public void run () {
+ _obs.initializationFailed(e);
+ }
+ });
+ }
- /**
- * Called to indicate that we have validated and unpacked our
- * bundles and are fully ready to go. A call to {@link
- * #dowloadProgress} with 100 percent completion is guaranteed to
- * precede this call and optionally one to {@link #patching} and
- * {@link #unpacking}.
- */
- public void downloadComplete ();
-
- /**
- * Called if a failure occurs while checking for an update or
- * downloading all resource sets.
- */
- public void downloadFailed (Exception e);
+ protected InitObserver _obs;
}
/**
@@ -164,52 +145,12 @@ public class ResourceManager
// keep track of our root path
_rootPath = resourceRoot;
- // make root path end with a slash (not the platform dependent
- // file system separator character as resource paths are passed to
- // ClassLoader.getResource() which requires / as its separator)
- if (!_rootPath.endsWith("/")) {
- _rootPath = _rootPath + "/";
- }
-
// use the classloader that loaded us
_loader = getClass().getClassLoader();
// set up a URL handler so that things can be loaded via
// urls with the 'resource' protocol
Handler.registerHandler(this);
-
- // sort our our default cache path
- _baseCachePath = "";
- try {
- // first check for an explicitly specified cache directory
- _baseCachePath = System.getProperty("narya.resource.cache_dir");
- // if that's null, try putting it into their home directory
- if (_baseCachePath == null) {
- _baseCachePath = System.getProperty("user.home");
- }
- if (!_baseCachePath.endsWith(File.separator)) {
- _baseCachePath += File.separator;
- }
- _baseCachePath += (CACHE_PATH + File.separator);
- } catch (SecurityException se) {
- Log.info("Can't obtain user.home system property. Probably " +
- "won't be able to create our cache directory " +
- "either. [error=" + se + "].");
- }
- }
-
- /**
- * Instructs the resource manager to store cached resources in the
- * specified directory. This must be called before {@link
- * #initBundles} if it is going to be called at all. If it is not
- * called, the default cache directory will be used.
- */
- public void setCachePath (String cachePath)
- {
- if (!cachePath.endsWith(File.separator)) {
- cachePath += File.separator;
- }
- _baseCachePath = cachePath;
}
/**
@@ -217,100 +158,56 @@ public class ResourceManager
* manager. Applications that wish to make use of resource bundles
* should call this method after constructing the resource manager.
*
- * @param resourceURL the base URL from which resources are loaded.
- * Relative paths specified in the resource definition file will be
- * loaded relative to this path. If this is null, the system property
- * resource_url will be used, if available.
- * @param configPath the path (relative to the resource URL) of the
+ * @param resourceDir the base directory to which the paths in the
+ * supplied configuration file are relative. If this is null, the
+ * system property resource_dir will be used, if
+ * available.
+ * @param configPath the path (relative to the resource dir) of the
* resource definition file.
- * @param version the version of the resource bundles to be
- * downloaded.
- * @param downloadObs the bundle download observer to notify of
- * download progress and success or failure, or null if
+ * @param initObs a bundle initialization observer to notify of
+ * unpacking progress and success or failure, or null if
* the caller doesn't care to be informed; note that in the latter
- * case, the calling thread will block until bundle updating is
+ * case, the calling thread will block until bundle unpacking is
* complete.
*
- * @exception IOException thrown if we are unable to download our
- * resource manager configuration from the support resource URL.
+ * @exception IOException thrown if we are unable to read our resource
+ * manager configuration.
*/
- public void initBundles (String resourceURL, String configPath,
- String version, BundleDownloadObserver downloadObs)
+ public void initBundles (
+ String resourceDir, String configPath, InitObserver initObs)
throws IOException
{
- _version = version;
-
- // if the resource URL wasn't provided, we try to figure it out
- // for ourselves
- if (resourceURL == null) {
+ // if the resource directory wasn't provided, we try to figure it
+ // out for ourselves
+ if (resourceDir == null) {
try {
// first look for the explicit system property
- resourceURL = System.getProperty("resource_url");
-
+ resourceDir = System.getProperty("resource_dir");
// if that doesn't work, fall back to the current directory
- if (resourceURL == null) {
- resourceURL = "file:" + System.getProperty("user.dir");
+ if (resourceDir == null) {
+ resourceDir = System.getProperty("user.dir");
}
} catch (SecurityException se) {
- resourceURL = "file:" + File.separator;
+ resourceDir = File.separator;
}
}
- // make sure there's a slash at the end of the URL
- if (!resourceURL.endsWith("/")) {
- resourceURL += "/";
+ // make sure there's a trailing slash
+ if (!resourceDir.endsWith(File.separator)) {
+ resourceDir += File.separator;
}
-
- try {
- _rurl = new URL(resourceURL);
- } catch (MalformedURLException mue) {
- Log.warning("Invalid resource URL [url=" + resourceURL +
- ", error=" + mue + "].");
- throw new IOException("Invalid resource url '" + resourceURL + "'");
- }
-
- // if no dynamic resource URL has been specified, use the normal
- // resource URL in its stead
- if (_drurl == null) {
- _drurl = _rurl;
- }
-
- Log.debug("Resource manager ready [rurl=" + _rurl +
- ", drurl=" + _drurl + "].");
+ _rdir = new File(resourceDir);
// load up our configuration
Properties config = new Properties();
- URL curl = null;
try {
- if (configPath != null) {
- curl = new URL(_rurl, configPath);
- }
-
- } catch (MalformedURLException mue) {
- Log.warning("Unable to construct config URL [resourceURL=" + _rurl +
- ", configPath=" + configPath + ", error=" + mue + "].");
- String errmsg = "Invalid config url [resourceURL=" + _rurl +
- ", configPath=" + configPath + "]";
- throw new IOException(errmsg);
- }
-
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- try {
- if (curl != null) {
- // download the properties file into a buffer
- CopyUtils.copy(curl.openStream(), bout);
- config.load(new ByteArrayInputStream(bout.toByteArray()));
- }
-
+ config.load(new FileInputStream(new File(_rdir, configPath)));
} catch (Exception e) {
- Log.warning("Unable to load resource mgr properties " +
- "[resourceURL=" + _rurl + ", configPath=" + configPath +
- ", error=" + e + "].");
- Log.warning("Bogus properties: " + bout.toString("UTF-8"));
- Log.logStackTrace(e);
String errmsg = "Unable to load resource manager config " +
- "[resourceURL=" + _rurl + ", configPath=" + configPath + "]";
+ "[rdir=" + _rdir + ", cpath=" + configPath + "]";
+ Log.warning(errmsg + ".");
+ Log.logStackTrace(e);
throw new IOException(errmsg);
}
@@ -326,74 +223,62 @@ public class ResourceManager
resolveResourceSet(setName, config.getProperty(key), dlist);
}
- // start the download, blocking if we've no observer
- DownloadManager dlmgr = new DownloadManager();
- if (downloadObs == null) {
- downloadBlocking(dlmgr, dlist);
- } else {
- downloadNonBlocking(dlmgr, dlist, downloadObs);
+ // if there's no observer, we'll need to block the caller
+ if (initObs == null) {
+ initObs = BLOCKER;
+ }
+
+ // start a thread to unpack our bundles
+ Unpacker unpack = new Unpacker(dlist, initObs);
+ unpack.start();
+
+ if (initObs == BLOCKER) {
+ try {
+ synchronized (BLOCKER) {
+ initObs.wait();
+ }
+ } catch (InterruptedException ie) {
+ Log.warning("Interrupted while waiting for bundles to unpack.");
+ }
}
}
/**
- * Configures the resource manager with a custom dynamic resource
- * URL. If it is not thusly configured, it will use the normal
- * resource URL for dynamic resources.
+ * Given a path relative to the resource directory, the path is
+ * properly jimmied (assuming we always use /) and combined with the
+ * resource directory to yield a {@link File} object that can be used
+ * to access the resource.
*/
- public void setDynamicResourceURL (String dynResURL)
+ public File getResourceFile (String path)
{
- // make sure there's a slash at the end of the URL
- if (!dynResURL.endsWith("/")) {
- dynResURL += "/";
- }
-
- try {
- _drurl = new URL(dynResURL);
- } catch (MalformedURLException mue) {
- Log.warning("Invalid dynamic resource URL " +
- "[url=" + dynResURL + ", error=" + mue + "].");
+ if (!"/".equals(File.separator)) {
+ path = StringUtil.replace(path, "/", File.separator);
}
+ return new File(_rdir, path);
}
/**
- * Create the resource bundle for the specified set and path.
+ * Checks to see if the specified bundle exists, is unpacked and is
+ * ready to be used.
*/
- protected ResourceBundle createResourceBundle (String setName, String path)
+ public boolean checkBundle (String path)
{
- createCacheDirectory(setName);
- File cfile = new File(genCachePath(setName, path));
-
- return new ResourceBundle(cfile, true, true);
+ return new ResourceBundle(
+ getResourceFile(path), true, true).isUnpacked();
}
/**
- * Checks to see if the specified dynamic bundle is already here
- * and ready to roll.
+ * Resolve the specified bundle (the bundle file must already exist in
+ * the appropriate place on the file system) and return it on the
+ * specified result listener. Note that the result listener may be
+ * notified before this method returns on the caller's thread if the
+ * bundle is already resolved, or it may be notified on a brand new
+ * thread if the bundle requires unpacking.
*/
- public boolean checkDynamicBundle (String path)
+ public void resolveBundle (String path, final ResultListener listener)
{
- return createResourceBundle(_dnset, path).isUnpacked();
- }
-
- /**
- * Resolve the specified dynamic bundle and return it on the specified
- * result listener.
- */
- public void resolveDynamicBundle (String path, String version,
- final ResultListener listener)
- {
- URL burl;
- try {
- burl = new URL(_drurl, path);
- } catch (MalformedURLException mue) {
- listener.requestFailed(mue);
- return;
- }
-
- // note our dynamic bundle set
- _dnset = DYNAMIC_BUNDLE_SET + StringUtil.md5hex(_drurl.toString());
-
- final ResourceBundle bundle = createResourceBundle(_dnset, path);
+ final ResourceBundle bundle =
+ new ResourceBundle(getResourceFile(path), true, true);
if (bundle.isUnpacked()) {
if (bundle.sourceIsReady()) {
listener.requestCompleted(bundle);
@@ -404,319 +289,20 @@ public class ResourceManager
return;
}
- // slap this on the list for retrieval or update by the download
- // manager
+ // start a thread to unpack our bundles
ArrayList list = new ArrayList();
- list.add(new DownloadDescriptor(burl, bundle.getSource(), version));
-
- // TODO: There should only be one download manager for all dynamic
- // bundles, with each bundle waiting its turn to use it.
- DownloadObserver obs = new DownloadObserver() {
- public boolean notifyOnAWTThread () {
- return false;
- }
-
- public void resolvingDownloads () {
- }
-
- public void downloadProgress (int percent, long remaining) {
- }
-
- public void patching () {
- }
-
- public void postDownloadHook () {
- }
-
- public void downloadComplete ()
- {
- final boolean unpacked = bundle.sourceIsReady();
- EventQueue.invokeLater(new Runnable() {
- public void run () {
- if (unpacked) {
- listener.requestCompleted(bundle);
- } else {
- String errmsg = "Bundle initialization failed.";
- listener.requestFailed(new IOException(errmsg));
- }
- }
- });
- }
-
- public void downloadFailed (
- DownloadDescriptor desc, final Exception e)
- {
- Log.warning("Failed to download file " +
- "[desc=" + desc + ", e=" + e + "].");
- EventQueue.invokeLater(new Runnable() {
- public void run () {
- listener.requestFailed(e);
- }
- });
- }
- };
-
- DownloadManager dlmgr = new DownloadManager();
- dlmgr.download(list, true, obs);
- }
-
- /**
- * Downloads the files in the supplied download list, blocking the
- * calling thread until the download is complete or a failure has
- * occurred.
- */
- protected void downloadBlocking (DownloadManager dlmgr, List dlist)
- {
- // create an object to wait on while the download takes place
- final Object lock = new Object();
-
- // create the observer that will notify us when all is finished
- DownloadObserver obs = new DownloadObserver() {
- public boolean notifyOnAWTThread () {
- return false;
- }
-
- public void resolvingDownloads () {
- // nothing for now
- }
-
- public void downloadProgress (int percent, long remaining) {
- // nothing for now
- }
-
- public void patching () {
- // nothing for now
- }
-
- public void postDownloadHook () {
- bundlesDownloaded();
- }
-
- public void downloadComplete () {
- synchronized (lock) {
- // wake things up as the download is finished
- lock.notify();
+ list.add(bundle);
+ Unpacker unpack = new Unpacker(list, new InitObserver() {
+ public void progress (int percent, long remaining) {
+ if (percent == 100) {
+ listener.requestCompleted(bundle);
}
}
-
- public void downloadFailed (DownloadDescriptor desc, Exception e) {
- Log.warning("Failed to download file " +
- "[desc=" + desc + ", e=" + e + "].");
- synchronized (lock) {
- // wake things up since we're fragile and so a
- // single failure means all is booched
- lock.notify();
- }
+ public void initializationFailed (Exception e) {
+ listener.requestFailed(e);
}
- };
-
- synchronized (lock) {
- // pass the descriptors on to the download manager
- dlmgr.download(dlist, true, obs);
-
- try {
- // block until the download has completed
- lock.wait();
- } catch (InterruptedException ie) {
- Log.warning("Thread interrupted while waiting for download " +
- "to complete [ie=" + ie + "].");
- }
- }
- }
-
- /**
- * Downloads the files in the supplied download list asynchronously,
- * notifying the download observer of ongoing progress.
- */
- protected void downloadNonBlocking (
- DownloadManager dlmgr, List dlist, final BundleDownloadObserver obs)
- {
- // pass the descriptors on to the download manager
- dlmgr.download(dlist, true, new DownloadObserver() {
- public boolean notifyOnAWTThread () {
- return obs.notifyOnAWTThread();
- }
-
- public void resolvingDownloads () {
- obs.checkingForUpdate();
- }
-
- public void downloadProgress (int percent, long remaining) {
- obs.downloadProgress(percent, remaining);
- }
-
- public void patching () {
- obs.patching();
- }
-
- public void postDownloadHook () {
- obs.unpacking();
- _unpacked = bundlesDownloaded();
- }
-
- public void downloadComplete () {
- if (_unpacked) {
- obs.downloadComplete();
- } else {
- String errmsg = "Bundle(s) failed initialization.";
- obs.downloadFailed(new IOException(errmsg));
- }
- }
-
- public void downloadFailed (DownloadDescriptor desc, Exception e) {
- obs.downloadFailed(e);
- }
-
- protected boolean _unpacked;
});
- }
-
- /**
- * Called when our resource bundle downloads have completed.
- *
- * @return true if we are fully operational, false if one or more
- * bundles failed to initialize.
- */
- protected boolean bundlesDownloaded ()
- {
- // let our bundles know that it's ok for them to access their
- // resource files
- Iterator iter = _sets.values().iterator();
- boolean unpacked = true;
- while (iter.hasNext()) {
- ResourceBundle[] bundles = (ResourceBundle[])iter.next();
- for (int ii = 0; ii < bundles.length; ii++) {
- unpacked = bundles[ii].sourceIsReady() && unpacked;
- }
- }
- return unpacked;
- }
-
- /**
- * Ensures that the cache directory for the specified resource set is
- * created.
- *
- * @return true if the directory was successfully created (or was
- * already there), false if we failed to create it.
- */
- protected boolean createCacheDirectory (String setName)
- {
- // compute the path to the top-level cache directory if we haven't
- // already been so configured
- if (_cachePath == null) {
- // start with the base cache path
- _cachePath = _baseCachePath;
- if (!createDirectory(_cachePath)) {
- return false;
- }
-
- // next incorporate the resource URL into the cache path so
- // that files fetched from different resource roots do not
- // overwrite one another
- _cachePath += StringUtil.md5hex(_rurl.toString()) + File.separator;
- if (!createDirectory(_cachePath)) {
- return false;
- }
-
- Log.debug("Caching bundles in '" + _cachePath + "'.");
- }
-
- // ensure that the set-specific cache directory exists
- return createDirectory(_cachePath + setName);
- }
-
- /**
- * Creates the specified directory if it doesn't already exist.
- *
- * @return true if directory was created (or existed), false if not.
- */
- protected boolean createDirectory (String path)
- {
- File cdir = new File(path);
- if (cdir.exists()) {
- if (!cdir.isDirectory()) {
- Log.warning("Cache dir exists but isn't a directory?! " +
- "[path=" + path + "].");
- return false;
- }
-
- } else {
- if (!cdir.mkdirs()) {
- Log.warning("Unable to create cache dir. " +
- "[path=" + path + "].");
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Generates the name of the bundle cache file given the name of the
- * resource set to which it belongs and the relative path URL.
- */
- protected String genCachePath (String setName, String resourcePath)
- {
- return _cachePath + setName + File.separator +
- StringUtil.replace(resourcePath, "/", "-");
- }
-
- /**
- * Loads up a resource set based on the supplied definition
- * information.
- */
- protected void resolveResourceSet (
- String setName, String definition, List dlist)
- {
- StringTokenizer tok = new StringTokenizer(definition, ":");
- ArrayList set = new ArrayList();
-
- while (tok.hasMoreTokens()) {
- String path = tok.nextToken().trim();
- URL burl = null;
-
- try {
- burl = new URL(_rurl, path);
-
- // make sure the cache directory exists for this set
- createCacheDirectory(setName);
-
- // compute the versioned path for this bundle if we have a
- // version configured
- String vpath = path;
- if (DownloadManager.VERSIONING && !StringUtil.blank(_version)) {
- vpath = versionPath(
- path, _version, getSuffix(path, ".jar"));
- }
-
- // compute the path to the cache file for this bundle
- File cfile = new File(genCachePath(setName, path));
- File vfile = new File(genCachePath(setName, vpath));
-
- // slap this on the list for retrieval or update by the
- // download manager
- dlist.add(new DownloadDescriptor(burl, cfile, _version));
-
- // finally, add the file that will be cached to the set as
- // a resource bundle
- set.add(new ResourceBundle(vfile, true, true));
-
- } catch (MalformedURLException mue) {
- Log.warning("Unable to create URL for resource " +
- "[set=" + setName + ", path=" + path +
- ", error=" + mue + "].");
- }
- }
-
- // convert our array list into an array and stick it in the table
- ResourceBundle[] setvec = new ResourceBundle[set.size()];
- set.toArray(setvec);
- _sets.put(setName, setvec);
-
- // if this is our default resource bundle, keep a reference to it
- if (DEFAULT_RESOURCE_SET.equals(setName)) {
- _default = setvec;
- }
+ unpack.start();
}
/**
@@ -742,7 +328,7 @@ public class ResourceManager
}
// if we didn't find anything, try the classloader
- String rpath = _rootPath + path;
+ String rpath = PathUtil.appendPath(_rootPath, path);
in = _loader.getResourceAsStream(rpath);
if (in != null) {
return in;
@@ -776,7 +362,7 @@ public class ResourceManager
}
// if we didn't find anything, try the classloader
- String rpath = _rootPath + path;
+ String rpath = PathUtil.appendPath(_rootPath, path);
InputStream in = _loader.getResourceAsStream(rpath);
if (in != null) {
return new MemoryCacheImageInputStream(new BufferedInputStream(in));
@@ -880,87 +466,89 @@ public class ResourceManager
}
/**
- * Creates a versioned path using the supplied version string, path
- * and file suffix. For example foo/bar/baz.jar becomes
- * foo/bar/baz__Vversion.jar.
+ * Loads up a resource set based on the supplied definition
+ * information.
*/
- public static String versionPath (
- String path, String version, String suffix)
+ protected void resolveResourceSet (
+ String setName, String definition, List dlist)
{
- if (!suffix.startsWith(".")) {
- suffix = "." + suffix;
+ StringTokenizer tok = new StringTokenizer(definition, ":");
+ ArrayList set = new ArrayList();
+
+ while (tok.hasMoreTokens()) {
+ String path = tok.nextToken().trim();
+ ResourceBundle bundle =
+ new ResourceBundle(getResourceFile(path), true, true);
+ set.add(bundle);
+ if (bundle.isUnpacked() && bundle.sourceIsReady()) {
+ continue;
+ }
+ dlist.add(bundle);
}
- int sidx = path.lastIndexOf(suffix);
- if (sidx == -1) {
- Log.warning("Invalid unversioned path, missing suffix " +
- "[path=" + path + ", suffix=" + suffix + "].");
- return path;
+
+ // convert our array list into an array and stick it in the table
+ ResourceBundle[] setvec = new ResourceBundle[set.size()];
+ set.toArray(setvec);
+ _sets.put(setName, setvec);
+
+ // if this is our default resource bundle, keep a reference to it
+ if (DEFAULT_RESOURCE_SET.equals(setName)) {
+ _default = setvec;
}
- return path.substring(0, sidx) + "__V" + version + suffix;
}
- /**
- * Creates an unversioned version of the supplied path. If the path is
- * not versioned, the existing path will be returned.
- */
- public static String unversionPath (String path, String suffix)
+ /** Used to unpack bundles on a separate thread. */
+ protected static class Unpacker extends Thread
{
- if (!suffix.startsWith(".")) {
- suffix = "." + suffix;
+ public Unpacker (List bundles, InitObserver obs)
+ {
+ _bundles = bundles;
+ _obs = obs;
}
- int vidx = path.indexOf("__V");
- if (vidx == -1) {
- return path;
- }
- int sidx = path.lastIndexOf(suffix);
- if (sidx == -1) {
- Log.warning("Invalid versioned path, missing suffix " +
- "[path=" + path + ", suffix=" + suffix + "].");
- return path;
- }
- return path.substring(0, vidx) + suffix;
- }
- /**
- * Returns the suffix of the specified path, ie. .jar if
- * the path references a file that ends in .jar.
- */
- public static String getSuffix (String path, String defsuf)
- {
- int didx = path.lastIndexOf(".");
- if (didx == -1) {
- return defsuf;
- } else {
- return path.substring(didx);
+ public void run ()
+ {
+ try {
+ int count = 0;
+ for (Iterator iter = _bundles.iterator(); iter.hasNext(); ) {
+ ResourceBundle bundle = (ResourceBundle)iter.next();
+ if (!bundle.sourceIsReady()) {
+ Log.warning("Bundle failed to initialize " +
+ bundle + ".");
+ }
+ if (_obs != null) {
+ int pct = count*100/_bundles.size();
+ if (pct < 100) {
+ _obs.progress(pct, 1);
+ }
+ }
+ count++;
+ }
+ if (_obs != null) {
+ _obs.progress(100, 0);
+ }
+
+ } catch (Exception e) {
+ if (_obs != null) {
+ _obs.initializationFailed(e);
+ }
+ }
}
+
+ protected List _bundles;
+ protected InitObserver _obs;
}
/** The classloader we use for classpath-based resource loading. */
protected ClassLoader _loader;
- /** The version of the resource bundles we'll be downloading. */
- protected String _version;
-
- /** The url via which we download our bundles. */
- protected URL _rurl;
-
- /** The url via which we download our dynamically generated bundles. */
- protected URL _drurl;
-
- /** The resource set we use for dynamic resources from a particular
- * dynamic bundle URL. */
- protected String _dnset;
+ /** The directory that contains our resource bundles. */
+ protected File _rdir;
/** The prefix we prepend to resource paths before attempting to load
* them from the classpath. */
protected String _rootPath;
- /** The path to the directory that will contain our bundle cache. */
- protected String _baseCachePath;
-
- /** The path to our bundle cache directory. */
- protected String _cachePath;
-
/** Our default resource set. */
protected ResourceBundle[] _default = new ResourceBundle[0];
@@ -974,9 +562,15 @@ public class ResourceManager
/** The name of the default resource set. */
protected static final String DEFAULT_RESOURCE_SET = "default";
- /** The name of our resource bundle cache directory. */
- protected static final String CACHE_PATH = ".narya";
-
- /** The name of the resource set where we store dynamic bundles. */
- protected static final String DYNAMIC_BUNDLE_SET = "_dynamic";
+ /** Used to block observerless bundle unpacking. */
+ protected static InitObserver BLOCKER = new InitObserver() {
+ public void progress (int percent, long remaining) {
+ if (percent >= 100) {
+ synchronized (this) { notify(); }
+ }
+ }
+ public void initializationFailed (Exception e) {
+ synchronized (this) { notify(); }
+ }
+ };
}