From: <ka...@us...> - 2010-07-11 12:16:50
|
Revision: 3372 http://java-game-lib.svn.sourceforge.net/java-game-lib/?rev=3372&view=rev Author: kappa1 Date: 2010-07-11 12:13:34 +0000 (Sun, 11 Jul 2010) Log Message: ----------- Appletloader: Initial implementation of a proper caching system. Files will only be downloaded if lastModified time is different from when files were downloaded previously. al_cache parameter is used to disable and enable this caching (default: true). This caching will not be used if al_version parameter is used. Modified Paths: -------------- trunk/LWJGL/src/java/org/lwjgl/util/applet/AppletLoader.java Modified: trunk/LWJGL/src/java/org/lwjgl/util/applet/AppletLoader.java =================================================================== --- trunk/LWJGL/src/java/org/lwjgl/util/applet/AppletLoader.java 2010-07-10 11:56:55 UTC (rev 3371) +++ trunk/LWJGL/src/java/org/lwjgl/util/applet/AppletLoader.java 2010-07-11 12:13:34 UTC (rev 3372) @@ -48,6 +48,8 @@ import java.io.FilePermission; import java.io.IOException; import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; @@ -69,6 +71,7 @@ import java.security.SecureClassLoader; import java.security.cert.Certificate; import java.util.Enumeration; +import java.util.HashMap; import java.util.StringTokenizer; import java.util.Vector; import java.util.jar.JarEntry; @@ -107,6 +110,7 @@ * <ul> * <li>al_version - [int or float] Version of deployment. If this is specified, the jars will be cached and * reused if the version matches. If version doesn't match all of the files are reloaded.</li> + * <li>al_cache - [boolean] Whether to use cache system. If al_version is used then cache is not used. <i>Default: true</i>.</li> * <li>al_debug - [boolean] Whether to enable debug mode. <i>Default: false</i>.</li> * <li>al_prepend_host - [boolean] Whether to limit caching to this domain, disable if your applet is hosted on multple domains and needs to share the cache. <i>Default: true</i>.</li> * <ul> @@ -220,6 +224,15 @@ /** whether to prepend host to cache path */ protected boolean prependHost; + /** Used to store file names with lastModified time */ + protected HashMap filesLastModified; + + /** Sizes of files to download */ + protected int[] fileSizes; + + /** whether to use caching system, only download files that have changed */ + protected boolean cacheEnabled; + /** String to display as a subtask */ protected String subtaskMessage = ""; @@ -262,7 +275,10 @@ return; } } - + + // whether to use cache system + cacheEnabled = getBooleanParameter("al_cache", true); + // whether to run in debug mode debugMode = getBooleanParameter("al_debug", false); @@ -479,7 +495,7 @@ og.dispose(); - // finally draw it all + // finally draw it all centred g.drawImage(offscreen, (getWidth() - offscreen.getWidth(null))/2, (getHeight() - offscreen.getHeight(null))/2, null); } @@ -528,7 +544,7 @@ case STATE_DETERMINING_PACKAGES: return "Determining packages to load"; case STATE_CHECKING_CACHE: - return "Checking cache for existing files"; + return "Calculate download size and check cache"; case STATE_DOWNLOADING: return "Downloading packages"; case STATE_EXTRACTING_PACKAGES: @@ -681,11 +697,12 @@ if (!dir.exists()) { dir.mkdirs(); } - dir = new File(dir, "version"); + + File versionFile = new File(dir, "version"); + + // if specified applet version already available don't download anything + boolean versionAvailable = false; - // if applet already available don't download anything - boolean cacheAvailable = false; - // version of applet String version = getParameter("al_version"); float latestVersion = 0; @@ -696,10 +713,10 @@ latestVersion = Float.parseFloat(version); // if version file exists - if (dir.exists()) { + if (versionFile.exists()) { // compare to new version - if (latestVersion <= readVersionFile(dir)) { - cacheAvailable = true; + if (latestVersion <= readVersionFile(versionFile)) { + versionAvailable = true; percentage = 90; if(debugMode) { @@ -711,9 +728,12 @@ } // if jars not available or need updating download them - if (!cacheAvailable) { + if (!versionAvailable) { + // get jars file sizes and check cache + getJarInfo(dir); // 5-15% + // downloads jars from the server - downloadJars(path); // 10-55% + downloadJars(path); // 15-55% // Extract Pack and LZMA files extractJars(path); // 55-65% @@ -721,11 +741,14 @@ // Extracts Native Files extractNatives(path); // 65-85% - // add version information once jars downloaded successfully + // save version information once jars downloaded successfully if (version != null) { percentage = 90; writeVersionFile(dir, latestVersion); } + + // save file names with last modified info once downloaded successfully + writeCacheFile(new File(dir, "cache"), filesLastModified); } // add the downloaded jars and natives to classpath @@ -771,8 +794,35 @@ dos.writeFloat(version); dos.close(); } + + /** + * read the current cache file + * + * @param file the file to read + * @return the hashmap containing the files names and lastModified times + * @throws Exception if it fails to read hashmap + */ + protected HashMap readCacheFile(File file) throws Exception { + ObjectInputStream dis = new ObjectInputStream(new FileInputStream(file)); + HashMap hashMap = (HashMap)dis.readObject(); + dis.close(); + return hashMap; + } /** + * write out cache file of applet + * + * @param file the file to write out to + * @param filesLastModified the hashmap containing files names and lastModified times + * @throws Exception if it fails to write file + */ + protected void writeCacheFile(File file, HashMap filesLastModified) throws Exception { + ObjectOutputStream dos = new ObjectOutputStream(new FileOutputStream(file)); + dos.writeObject(filesLastModified); + dos.close(); + } + + /** * Edits the ClassPath at runtime to include the jars * that have just been downloaded and then adds the * lwjgl natives folder property. @@ -848,7 +898,7 @@ * Due to the way applets on plugin1 work, one jvm must * be used for all applets. We need to use multiple * classloaders in the same jvm due to LWJGL's static - * nature. I order to solver this we simply remove the + * nature. I order to solve this we simply remove the * natives from a previous classloader allowing a new * classloader to use those natives in the same jvm. * @@ -913,23 +963,33 @@ state = STATE_START_REAL_APPLET; lwjglApplet.start(); } - + /** - * Will download the jars from the server using the list of urls - * in urlList, while at the same time updating progress bar + * This method will get the files sizes of the files to download. + * It wil further get the lastModified time of files + * and save it in a hashmap, if cache is enabled it will mark + * those files that have not changed since last download to not + * redownloaded. * - * @param path location of the directory to save to - * @throws Exception if download fails + * @param dir - location to read cache file from + * @throws Exception - if fails to get infomation */ - protected void downloadJars(String path) throws Exception { + protected void getJarInfo(File dir) throws Exception { - state = STATE_DOWNLOADING; - + filesLastModified = new HashMap(); + + // store file sizes and mark which files not to download + fileSizes = new int[urlList.length]; + URLConnection urlconnection; - // store file sizes, used for download verification - int[] fileSizes = new int[urlList.length]; + File cacheFile = new File(dir, "cache"); + // if cache file exists, load it + if (cacheFile.exists()) { + filesLastModified = readCacheFile(cacheFile); + } + // calculate total size of jars to download for (int i = 0; i < urlList.length; i++) { urlconnection = urlList[i].openConnection(); @@ -937,16 +997,57 @@ if (urlconnection instanceof HttpURLConnection) { ((HttpURLConnection) urlconnection).setRequestMethod("HEAD"); } + fileSizes[i] = urlconnection.getContentLength(); - totalSizeDownload += fileSizes[i]; + + long lastModified = urlconnection.getLastModified(); + String fileName = getFileName(urlList[i]); + + + if (cacheEnabled && lastModified != 0 && + filesLastModified.containsKey(fileName)) { + long savedLastModified = (Long)filesLastModified.get(fileName); + + // if lastModifed time is the same, don't redownload + if (savedLastModified == lastModified) { + fileSizes[i] = -2; // mark it to not redownload + } + } + + if (fileSizes[i] >= 0) { + totalSizeDownload += fileSizes[i]; + } + + // put key and value in the hashmap + filesLastModified.put(fileName, lastModified); + + // update progress bar + percentage = 5 + (int)(10 * i/(float)urlList.length); } + } + + /** + * Will download the jars from the server using the list of urls + * in urlList, while at the same time updating progress bar + * + * @param path location of the directory to save to + * @throws Exception if download fails + */ + protected void downloadJars(String path) throws Exception { - int initialPercentage = percentage = 10; + state = STATE_DOWNLOADING; + URLConnection urlconnection; + + int initialPercentage = percentage = 15; + // download each jar byte buffer[] = new byte[65536]; for (int i = 0; i < urlList.length; i++) { + // skip file if marked as -2 (already downloaded and not changed) + if (fileSizes[i] == -2) continue; + int unsuccessfulAttempts = 0; int maxUnsuccessfulAttempts = 3; boolean downloadFile = true; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |