2010-09-28 17:11:35 -04:00
|
|
|
/*
|
2008-04-07 14:36:09 -04:00
|
|
|
* Copyright (c) 2002-2008 LWJGL Project
|
2007-06-10 16:30:03 -04:00
|
|
|
* All rights reserved.
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2007-06-10 16:30:03 -04:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
2010-09-28 17:11:35 -04:00
|
|
|
* modification, are permitted provided that the following conditions are
|
2007-06-10 16:30:03 -04:00
|
|
|
* met:
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
|
|
|
* * Redistributions of source code must retain the above copyright
|
2007-06-10 16:30:03 -04:00
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
*
|
|
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
2010-09-28 17:11:35 -04:00
|
|
|
* * Neither the name of 'LWJGL' nor the names of
|
|
|
|
* its contributors may be used to endorse or promote products derived
|
2007-06-10 16:30:03 -04:00
|
|
|
* from this software without specific prior written permission.
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2007-06-10 16:30:03 -04:00
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
2010-09-28 17:11:35 -04:00
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
2007-06-10 16:30:03 -04:00
|
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
2010-09-28 17:11:35 -04:00
|
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
2007-06-10 16:30:03 -04:00
|
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
package org.lwjgl.util.applet;
|
|
|
|
|
|
|
|
import java.applet.Applet;
|
|
|
|
import java.applet.AppletStub;
|
2007-10-24 17:55:39 -04:00
|
|
|
import java.awt.BorderLayout;
|
2007-06-10 16:30:03 -04:00
|
|
|
import java.awt.Color;
|
2011-01-22 13:08:21 -05:00
|
|
|
import java.awt.EventQueue;
|
2007-06-10 16:30:03 -04:00
|
|
|
import java.awt.FontMetrics;
|
|
|
|
import java.awt.Graphics;
|
|
|
|
import java.awt.Image;
|
2009-07-01 14:05:44 -04:00
|
|
|
import java.awt.MediaTracker;
|
2010-07-10 07:56:55 -04:00
|
|
|
import java.awt.image.ImageObserver;
|
2007-06-10 16:30:03 -04:00
|
|
|
import java.io.DataInputStream;
|
|
|
|
import java.io.DataOutputStream;
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
import java.io.FileOutputStream;
|
2009-05-22 05:14:38 -04:00
|
|
|
import java.io.FilePermission;
|
2007-10-24 17:25:54 -04:00
|
|
|
import java.io.IOException;
|
2007-06-10 16:30:03 -04:00
|
|
|
import java.io.InputStream;
|
2010-07-11 08:13:34 -04:00
|
|
|
import java.io.ObjectInputStream;
|
|
|
|
import java.io.ObjectOutputStream;
|
2007-06-10 16:30:03 -04:00
|
|
|
import java.io.OutputStream;
|
2009-06-11 17:07:34 -04:00
|
|
|
import java.io.PrintWriter;
|
|
|
|
import java.io.StringWriter;
|
|
|
|
import java.io.Writer;
|
2008-04-18 18:34:11 -04:00
|
|
|
import java.lang.reflect.Constructor;
|
2010-04-01 17:01:51 -04:00
|
|
|
import java.lang.reflect.Field;
|
2007-06-10 16:30:03 -04:00
|
|
|
import java.lang.reflect.Method;
|
2009-10-07 20:03:55 -04:00
|
|
|
import java.net.HttpURLConnection;
|
2009-11-20 18:06:24 -05:00
|
|
|
import java.net.JarURLConnection;
|
2009-05-22 05:14:38 -04:00
|
|
|
import java.net.SocketPermission;
|
2007-06-10 16:30:03 -04:00
|
|
|
import java.net.URL;
|
|
|
|
import java.net.URLClassLoader;
|
|
|
|
import java.net.URLConnection;
|
|
|
|
import java.security.AccessControlException;
|
|
|
|
import java.security.AccessController;
|
2009-05-22 05:14:38 -04:00
|
|
|
import java.security.CodeSource;
|
|
|
|
import java.security.PermissionCollection;
|
2007-06-10 16:30:03 -04:00
|
|
|
import java.security.PrivilegedExceptionAction;
|
2009-05-22 05:14:38 -04:00
|
|
|
import java.security.SecureClassLoader;
|
2007-06-10 16:30:03 -04:00
|
|
|
import java.security.cert.Certificate;
|
|
|
|
import java.util.Enumeration;
|
2010-07-11 08:13:34 -04:00
|
|
|
import java.util.HashMap;
|
2007-06-10 16:30:03 -04:00
|
|
|
import java.util.StringTokenizer;
|
2010-04-01 17:01:51 -04:00
|
|
|
import java.util.Vector;
|
2007-06-10 16:30:03 -04:00
|
|
|
import java.util.jar.JarEntry;
|
|
|
|
import java.util.jar.JarFile;
|
2008-04-18 18:34:11 -04:00
|
|
|
import java.util.jar.JarOutputStream;
|
|
|
|
import java.util.jar.Pack200;
|
2007-06-10 16:30:03 -04:00
|
|
|
|
2009-05-22 05:14:38 -04:00
|
|
|
import sun.security.util.SecurityConstants;
|
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/**
|
|
|
|
* <p>
|
|
|
|
* The AppletLoader enables deployment of LWJGL to applets in an easy
|
|
|
|
* and polished way. The loader will display a configurable logo and progressbar
|
|
|
|
* while the relevant jars (generic and native) are downloaded from a specified source.
|
|
|
|
* </p>
|
|
|
|
* <p>
|
2010-09-28 17:11:35 -04:00
|
|
|
* The downloaded jars are extracted to the users temporary directory - and if enabled, cached for
|
2007-06-10 16:30:03 -04:00
|
|
|
* faster loading in future uses.
|
|
|
|
* </p>
|
|
|
|
* <p>
|
|
|
|
* The following applet parameters are required:
|
|
|
|
* <ul>
|
|
|
|
* <li>al_main - [String] Full package and class the applet to instantiate and display when loaded.</li>
|
|
|
|
* <li>al_logo - [String Path of of the logo resource to paint while loading.</li>
|
|
|
|
* <li>al_progressbar - [String] Path of the progressbar resource to paint on top of the logo, width clipped by percentage.</li>
|
|
|
|
* <li>al_jars - [String] Comma seperated list of jars to download.</li>
|
|
|
|
* <li>al_windows - [String] Jar containing native files for windows.</li>
|
|
|
|
* <li>al_linux - [String] Jar containing native files for linux.</li>
|
|
|
|
* <li>al_mac - [String] Jar containing native files for mac.</li>
|
2008-08-12 17:02:06 -04:00
|
|
|
* <li>al_solaris - [String] Jar containing native files for solaris.</li>
|
2010-04-01 14:27:51 -04:00
|
|
|
* <li>al_freebsd - [String] Jar containing native files for freebsd.</li>
|
2007-06-10 16:30:03 -04:00
|
|
|
* </ul>
|
|
|
|
* </p>
|
|
|
|
* <p>
|
|
|
|
* Additionally the following parameters can be supplied to tweak the behaviour of the AppletLoader.
|
|
|
|
* <ul>
|
2010-09-28 17:11:35 -04:00
|
|
|
* <li>al_version - [int or float] Version of deployment. If this is specified, the jars will be cached and
|
2007-06-10 16:30:03 -04:00
|
|
|
* reused if the version matches. If version doesn't match all of the files are reloaded.</li>
|
2010-07-12 16:01:56 -04:00
|
|
|
* <li>al_cache - [boolean] Whether to use cache system. <i>Default: true</i>.</li>
|
2010-07-04 07:03:20 -04:00
|
|
|
* <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>
|
|
|
|
* <li>al_windows64 - [String] If specified it will be used instead of al_windows on 64bit windows systems.</li>
|
|
|
|
* <li>al_windows32 - [String] If specifed it will be used instead of al_windows on 32bit windows systems.</li>
|
|
|
|
* <li>al_linux64 - [String] If specifed it will be used instead of al_linux on 64bit linux systems.</li>
|
|
|
|
* <li>al_linux32 - [String] If specifed it will be used instead of al_linux on 32bit linux systems.</li>
|
|
|
|
* <ul>
|
AppletLoader: Parameters boxbgcolor, boxfgcolor and boxerrorcolor have been added. Previous parameters al_bgcolor, al_fgcolor and al_errorcolor have been removed. Unlike the previous color support now you can specify the color as a string name of any AWT Color ("red", "blue", "yellow", etc), RGB format (0-255, e.g. "255,0,0") or html HEX color (must use leading #, previous didn't need to have the # e.g. "#FF0000"). This is to match the color support of boxbgcolor and boxfgcolor of the java plugin, so now the color is set and appears before the appletloader is even loaded.
2010-07-04 10:35:41 -04:00
|
|
|
* <li>boxbgcolor - [String] any String AWT color ("red", "blue", etc), RGB (0-255) or hex formated color (#RRGGBB) to use as background. <i>Default: #ffffff</i>.</li>
|
|
|
|
* <li>boxfgcolor - [String] any String AWT color ("red", "blue", etc), RGB (0-255) or hex formated color (#RRGGBB) to use as foreground. <i>Default: #000000</i>.</li>
|
2007-06-10 16:30:03 -04:00
|
|
|
* </ul>
|
|
|
|
* </p>
|
|
|
|
* @author kappaOne
|
|
|
|
* @author Brian Matzon <brian@matzon.dk>
|
|
|
|
* @version $Revision$
|
|
|
|
* $Id$
|
|
|
|
*/
|
|
|
|
public class AppletLoader extends Applet implements Runnable, AppletStub {
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** initializing */
|
|
|
|
public static final int STATE_INIT = 1;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** determining which packages that are required */
|
|
|
|
public static final int STATE_DETERMINING_PACKAGES = 2;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** checking for already downloaded files */
|
|
|
|
public static final int STATE_CHECKING_CACHE = 3;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** downloading packages */
|
|
|
|
public static final int STATE_DOWNLOADING = 4;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** extracting packages */
|
|
|
|
public static final int STATE_EXTRACTING_PACKAGES = 5;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** updating the classpath */
|
|
|
|
public static final int STATE_UPDATING_CLASSPATH = 6;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** switching to real applet */
|
|
|
|
public static final int STATE_SWITCHING_APPLET = 7;
|
|
|
|
|
|
|
|
/** initializing real applet */
|
|
|
|
public static final int STATE_INITIALIZE_REAL_APPLET = 8;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** stating real applet */
|
|
|
|
public static final int STATE_START_REAL_APPLET = 9;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** done */
|
|
|
|
public static final int STATE_DONE = 10;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** used to calculate length of progress bar */
|
|
|
|
protected int percentage;
|
|
|
|
|
|
|
|
/** current size of download in bytes */
|
2010-09-28 17:11:35 -04:00
|
|
|
protected int currentSizeDownload;
|
2007-06-10 16:30:03 -04:00
|
|
|
|
|
|
|
/** total size of download in bytes */
|
2010-09-28 17:11:35 -04:00
|
|
|
protected int totalSizeDownload;
|
2007-06-10 16:30:03 -04:00
|
|
|
|
|
|
|
/** current size of extracted in bytes */
|
2010-09-28 17:11:35 -04:00
|
|
|
protected int currentSizeExtract;
|
2007-06-10 16:30:03 -04:00
|
|
|
|
|
|
|
/** total size of extracted in bytes */
|
2010-09-28 17:11:35 -04:00
|
|
|
protected int totalSizeExtract;
|
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** logo to be shown while loading */
|
2010-07-10 07:56:55 -04:00
|
|
|
protected Image logo, logoBuffer;
|
2007-06-10 16:30:03 -04:00
|
|
|
|
|
|
|
/** progressbar to render while loading */
|
2010-07-10 07:56:55 -04:00
|
|
|
protected Image progressbar, progressbarBuffer;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** offscreen image used */
|
|
|
|
protected Image offscreen;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-10 07:56:55 -04:00
|
|
|
/** set to true while painting is done */
|
|
|
|
protected boolean painting;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** background color of applet */
|
|
|
|
protected Color bgColor = Color.white;
|
|
|
|
|
2009-05-28 14:17:04 -04:00
|
|
|
/** color to write foreground in */
|
2010-09-28 17:11:35 -04:00
|
|
|
protected Color fgColor = Color.black;
|
2007-06-10 16:30:03 -04:00
|
|
|
|
|
|
|
/** urls of the jars to download */
|
|
|
|
protected URL[] urlList;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-05-28 14:17:04 -04:00
|
|
|
/** classLoader used to add downloaded jars to the classpath */
|
2009-05-22 05:14:38 -04:00
|
|
|
protected ClassLoader classLoader;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** actual thread that does the loading */
|
|
|
|
protected Thread loaderThread;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-05-28 14:17:04 -04:00
|
|
|
/** animation thread that renders our load screen while loading */
|
2007-06-10 16:30:03 -04:00
|
|
|
protected Thread animationThread;
|
|
|
|
|
|
|
|
/** applet to load after all downloads are complete */
|
|
|
|
protected Applet lwjglApplet;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** whether a fatal error occured */
|
|
|
|
protected boolean fatalError;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** whether we're running in debug mode */
|
|
|
|
protected boolean debugMode;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-10 17:02:04 -04:00
|
|
|
/** whether to prepend host to cache path */
|
|
|
|
protected boolean prependHost;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
/** Used to store file names with lastModified time */
|
2010-09-28 17:11:35 -04:00
|
|
|
protected HashMap<String, Long> filesLastModified;
|
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
/** Sizes of files to download */
|
|
|
|
protected int[] fileSizes;
|
2011-01-24 17:35:11 -05:00
|
|
|
|
|
|
|
/** Number of native jars */
|
|
|
|
protected int nativeJarCount;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
/** whether to use caching system, only download files that have changed */
|
|
|
|
protected boolean cacheEnabled;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** String to display as a subtask */
|
|
|
|
protected String subtaskMessage = "";
|
|
|
|
|
|
|
|
/** state of applet loader */
|
2011-01-12 15:01:12 -05:00
|
|
|
protected volatile int state = STATE_INIT;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
/** whether lzma is supported */
|
2010-09-28 17:11:35 -04:00
|
|
|
protected boolean lzmaSupported;
|
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
/** whether pack200 is supported */
|
2010-09-28 17:11:35 -04:00
|
|
|
protected boolean pack200Supported;
|
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/** generic error message to display on error */
|
|
|
|
protected String[] genericErrorMessage = { "An error occured while loading the applet.",
|
2009-05-08 16:29:22 -04:00
|
|
|
"Please contact support to resolve this issue.",
|
2007-06-10 16:30:03 -04:00
|
|
|
"<placeholder for error message>"};
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-11 14:10:19 -04:00
|
|
|
/** whether a certificate refused error occured */
|
|
|
|
protected boolean certificateRefused;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-11 14:10:19 -04:00
|
|
|
/** error message to display if user refuses to accept certicate*/
|
|
|
|
protected String[] certificateRefusedMessage = { "Permissions for Applet Refused.",
|
|
|
|
"Please accept the permissions dialog to allow",
|
|
|
|
"the applet to continue the loading process."};
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-04-01 17:01:51 -04:00
|
|
|
/** have natives been loaded by another instance of this applet */
|
2010-09-28 17:11:35 -04:00
|
|
|
protected static boolean natives_loaded;
|
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/*
|
|
|
|
* @see java.applet.Applet#init()
|
|
|
|
*/
|
|
|
|
public void init() {
|
2011-01-22 08:26:07 -05:00
|
|
|
setState(STATE_INIT);
|
2010-10-07 16:33:01 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
// sanity check
|
|
|
|
String[] requiredArgs = {"al_main", "al_logo", "al_progressbar", "al_jars"};
|
2010-09-28 17:11:35 -04:00
|
|
|
for ( String requiredArg : requiredArgs ) {
|
|
|
|
if ( getParameter(requiredArg) == null ) {
|
|
|
|
fatalErrorOccured("missing required applet parameter: " + requiredArg, null);
|
|
|
|
return;
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
// whether to use cache system
|
|
|
|
cacheEnabled = getBooleanParameter("al_cache", true);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
// whether to run in debug mode
|
|
|
|
debugMode = getBooleanParameter("al_debug", false);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-10 17:02:04 -04:00
|
|
|
// whether to prepend host to cache path
|
|
|
|
prependHost = getBooleanParameter("al_prepend_host", true);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
// get colors of applet
|
AppletLoader: Parameters boxbgcolor, boxfgcolor and boxerrorcolor have been added. Previous parameters al_bgcolor, al_fgcolor and al_errorcolor have been removed. Unlike the previous color support now you can specify the color as a string name of any AWT Color ("red", "blue", "yellow", etc), RGB format (0-255, e.g. "255,0,0") or html HEX color (must use leading #, previous didn't need to have the # e.g. "#FF0000"). This is to match the color support of boxbgcolor and boxfgcolor of the java plugin, so now the color is set and appears before the appletloader is even loaded.
2010-07-04 10:35:41 -04:00
|
|
|
bgColor = getColor("boxbgcolor", Color.white);
|
2007-10-24 17:55:39 -04:00
|
|
|
setBackground(bgColor);
|
2010-09-28 17:11:35 -04:00
|
|
|
fgColor = getColor("boxfgcolor", Color.black);
|
2007-06-10 16:30:03 -04:00
|
|
|
|
2010-07-25 09:31:49 -04:00
|
|
|
// load logos, if value is "" then skip
|
2010-07-25 10:22:09 -04:00
|
|
|
if (getParameter("al_logo").length() > 0) {
|
2010-07-25 09:31:49 -04:00
|
|
|
logo = getImage(getParameter("al_logo"));
|
|
|
|
}
|
2010-07-25 10:22:09 -04:00
|
|
|
if (getParameter("al_progressbar").length() > 0) {
|
2010-07-25 09:31:49 -04:00
|
|
|
progressbar = getImage(getParameter("al_progressbar"));
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
// check for lzma support
|
|
|
|
try {
|
|
|
|
Class.forName("LZMA.LzmaInputStream");
|
|
|
|
lzmaSupported = true;
|
|
|
|
} catch (Throwable e) {
|
|
|
|
/* no lzma support */
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
// check pack200 support
|
|
|
|
try {
|
|
|
|
java.util.jar.Pack200.class.getSimpleName();
|
|
|
|
pack200Supported = true;
|
|
|
|
} catch (Throwable e) {
|
|
|
|
/* no pack200 support */
|
2010-09-28 17:11:35 -04:00
|
|
|
}
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
|
|
|
|
2009-06-11 17:07:34 -04:00
|
|
|
/**
|
|
|
|
* Generates a stacktrace in the form of a string
|
|
|
|
* @param exception Exception to make stacktrace of
|
|
|
|
* @return Stacktrace of exception in the form of a string
|
|
|
|
*/
|
2010-09-28 17:11:35 -04:00
|
|
|
private static String generateStacktrace(Exception exception) {
|
2009-06-11 17:07:34 -04:00
|
|
|
Writer result = new StringWriter();
|
|
|
|
PrintWriter printWriter = new PrintWriter(result);
|
|
|
|
exception.printStackTrace(printWriter);
|
|
|
|
return result.toString();
|
|
|
|
}
|
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/*
|
|
|
|
* @see java.applet.Applet#start()
|
|
|
|
*/
|
|
|
|
public void start() {
|
2008-04-22 16:32:32 -04:00
|
|
|
if (lwjglApplet != null) {
|
|
|
|
lwjglApplet.start();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(loaderThread == null && !fatalError) {
|
|
|
|
loaderThread = new Thread(this);
|
|
|
|
loaderThread.setName("AppletLoader.loaderThread");
|
|
|
|
loaderThread.start();
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-22 16:32:32 -04:00
|
|
|
animationThread = new Thread() {
|
|
|
|
public void run() {
|
|
|
|
while(loaderThread != null) {
|
|
|
|
repaint();
|
|
|
|
AppletLoader.this.sleep(100);
|
|
|
|
}
|
|
|
|
animationThread = null;
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
2008-04-22 16:32:32 -04:00
|
|
|
};
|
|
|
|
animationThread.setName("AppletLoader.animationthread");
|
|
|
|
animationThread.start();
|
|
|
|
}
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/*
|
|
|
|
* @see java.applet.Applet#stop()
|
|
|
|
*/
|
|
|
|
public void stop() {
|
|
|
|
if (lwjglApplet != null) {
|
|
|
|
lwjglApplet.stop();
|
|
|
|
}
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/*
|
|
|
|
* @see java.applet.Applet#destroy()
|
|
|
|
*/
|
|
|
|
public void destroy() {
|
|
|
|
if (lwjglApplet != null) {
|
|
|
|
lwjglApplet.destroy();
|
|
|
|
}
|
2010-07-24 16:00:58 -04:00
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-24 16:00:58 -04:00
|
|
|
/**
|
|
|
|
* Clean up resources
|
|
|
|
*/
|
|
|
|
protected void cleanUp() {
|
2007-06-10 16:30:03 -04:00
|
|
|
progressbar = null;
|
|
|
|
logo = null;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-10 07:56:55 -04:00
|
|
|
logoBuffer = null;
|
|
|
|
progressbarBuffer = null;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-24 16:00:58 -04:00
|
|
|
offscreen = null;
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/**
|
2008-05-11 10:41:46 -04:00
|
|
|
* Retrieves the applet that has been loaded. Useful for liveconnect.
|
2007-06-10 16:30:03 -04:00
|
|
|
*/
|
|
|
|
public Applet getApplet() {
|
|
|
|
return lwjglApplet;
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-10-20 17:20:00 -04:00
|
|
|
/**
|
2010-09-28 17:11:35 -04:00
|
|
|
* Transfers the call of AppletResize from the stub to the lwjglApplet.
|
2007-06-10 16:30:03 -04:00
|
|
|
*/
|
|
|
|
public void appletResize(int width, int height) {
|
2007-10-20 17:20:00 -04:00
|
|
|
resize(width, height);
|
2010-09-28 17:11:35 -04:00
|
|
|
}
|
2007-06-10 16:30:03 -04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* @see java.awt.Container#update(java.awt.Graphics)
|
|
|
|
*/
|
|
|
|
public final void update(Graphics g) {
|
|
|
|
paint(g);
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/*
|
|
|
|
* @see java.awt.Container#paint(java.awt.Graphics)
|
|
|
|
*/
|
2008-05-06 17:47:49 -04:00
|
|
|
public void paint(Graphics g) {
|
2007-10-20 17:20:00 -04:00
|
|
|
// don't paint loader if applet loaded
|
|
|
|
if(state == STATE_DONE) {
|
2011-01-12 15:01:12 -05:00
|
|
|
cleanUp(); // clean up resources
|
2007-06-10 16:30:03 -04:00
|
|
|
return;
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
// create offscreen if missing
|
|
|
|
if (offscreen == null) {
|
|
|
|
offscreen = createImage(getWidth(), getHeight());
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-10 07:56:55 -04:00
|
|
|
// create buffers for animated gifs
|
2010-07-25 08:18:17 -04:00
|
|
|
if (logo != null) {
|
|
|
|
logoBuffer = createImage(logo.getWidth(null), logo.getHeight(null));
|
2010-09-28 17:11:35 -04:00
|
|
|
// add image observer, it will notify when next animated gif frame is ready
|
2010-07-25 08:18:17 -04:00
|
|
|
offscreen.getGraphics().drawImage(logo, 0, 0, this);
|
|
|
|
// in case image is not animated fill image buffer once
|
|
|
|
imageUpdate(logo, ImageObserver.FRAMEBITS, 0, 0, 0, 0);
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-25 08:18:17 -04:00
|
|
|
if (progressbar != null) {
|
|
|
|
progressbarBuffer = createImage(progressbar.getWidth(null), progressbar.getHeight(null));
|
2010-09-28 17:11:35 -04:00
|
|
|
// add image observer, it will notify when next animated gif frame is ready
|
2010-07-25 08:18:17 -04:00
|
|
|
offscreen.getGraphics().drawImage(progressbar, 0, 0, this);
|
|
|
|
// in case image is not animated fill image buffer once
|
|
|
|
imageUpdate(progressbar, ImageObserver.FRAMEBITS, 0, 0, 0, 0);
|
|
|
|
}
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// draw everything onto an image before drawing to avoid flicker
|
|
|
|
Graphics og = offscreen.getGraphics();
|
|
|
|
FontMetrics fm = og.getFontMetrics();
|
|
|
|
|
2010-07-08 17:12:20 -04:00
|
|
|
// clear background color
|
2007-06-10 16:30:03 -04:00
|
|
|
og.setColor(bgColor);
|
2010-07-08 17:12:20 -04:00
|
|
|
og.fillRect(0, 0, offscreen.getWidth(null), offscreen.getHeight(null));
|
2007-06-10 16:30:03 -04:00
|
|
|
|
|
|
|
og.setColor(fgColor);
|
2007-06-11 14:10:19 -04:00
|
|
|
String message = getDescriptionForState();
|
2007-06-10 16:30:03 -04:00
|
|
|
|
2007-06-11 14:10:19 -04:00
|
|
|
// if we had a failure of some sort, notify the user
|
2007-06-10 16:30:03 -04:00
|
|
|
if (fatalError) {
|
2007-06-11 14:10:19 -04:00
|
|
|
String[] errorMessage = (certificateRefused) ? certificateRefusedMessage : genericErrorMessage;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-11 14:10:19 -04:00
|
|
|
for(int i=0; i<errorMessage.length; i++) {
|
2009-06-11 17:07:34 -04:00
|
|
|
if(errorMessage[i] != null) {
|
2010-07-08 17:12:20 -04:00
|
|
|
int messageX = (offscreen.getWidth(null) - fm.stringWidth(errorMessage[i])) / 2;
|
|
|
|
int messageY = (offscreen.getHeight(null) - (fm.getHeight() * errorMessage.length)) / 2;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-06-11 17:07:34 -04:00
|
|
|
og.drawString(errorMessage[i], messageX, messageY + i*fm.getHeight());
|
|
|
|
}
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
og.setColor(fgColor);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-10 07:56:55 -04:00
|
|
|
painting = true;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-25 09:31:49 -04:00
|
|
|
// get position at the middle of the offscreen buffer
|
2010-09-28 17:11:35 -04:00
|
|
|
int x = offscreen.getWidth(null)/2;
|
2010-07-25 09:31:49 -04:00
|
|
|
int y = offscreen.getHeight(null)/2;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
// draw logo
|
2010-07-25 09:31:49 -04:00
|
|
|
if (logo != null) {
|
|
|
|
og.drawImage(logoBuffer, x-logo.getWidth(null)/2, y-logo.getHeight(null)/2, this);
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
// draw message
|
2010-07-08 17:12:20 -04:00
|
|
|
int messageX = (offscreen.getWidth(null) - fm.stringWidth(message)) / 2;
|
2010-07-25 08:18:17 -04:00
|
|
|
int messageY = y + 20;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-25 09:31:49 -04:00
|
|
|
if (logo != null) messageY += logo.getHeight(null)/2;
|
|
|
|
else if (progressbar != null) messageY += progressbar.getHeight(null)/2;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
og.drawString(message, messageX, messageY);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
// draw subtaskmessage, if any
|
|
|
|
if(subtaskMessage.length() > 0) {
|
2010-07-08 17:12:20 -04:00
|
|
|
messageX = (offscreen.getWidth(null) - fm.stringWidth(subtaskMessage)) / 2;
|
2007-06-10 16:30:03 -04:00
|
|
|
og.drawString(subtaskMessage, messageX, messageY+20);
|
|
|
|
}
|
|
|
|
|
|
|
|
// draw loading bar, clipping it depending on percentage done
|
2010-07-25 08:18:17 -04:00
|
|
|
if (progressbar != null) {
|
2010-07-25 09:31:49 -04:00
|
|
|
int barSize = (progressbar.getWidth(null) * percentage) / 100;
|
|
|
|
og.clipRect(x-progressbar.getWidth(null)/2, 0, barSize, offscreen.getHeight(null));
|
|
|
|
og.drawImage(progressbarBuffer, x-progressbar.getWidth(null)/2, y-progressbar.getHeight(null)/2, this);
|
2010-07-25 08:18:17 -04:00
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-10 07:56:55 -04:00
|
|
|
painting = false;
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
og.dispose();
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
// finally draw it all centred
|
2010-07-08 17:12:20 -04:00
|
|
|
g.drawImage(offscreen, (getWidth() - offscreen.getWidth(null))/2, (getHeight() - offscreen.getHeight(null))/2, null);
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-10 07:56:55 -04:00
|
|
|
/**
|
2010-09-28 17:11:35 -04:00
|
|
|
* When an animated gif frame is ready to be drawn the ImageObserver
|
2010-07-10 07:56:55 -04:00
|
|
|
* will call this method.
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
|
|
|
* The Image frame is copied into a buffer, which is then drawn.
|
2010-07-10 07:56:55 -04:00
|
|
|
* This is done to prevent image tearing on gif animations.
|
|
|
|
*/
|
|
|
|
public boolean imageUpdate(Image img, int flag, int x, int y, int width, int height) {
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-24 16:00:58 -04:00
|
|
|
// finish with this ImageObserver
|
|
|
|
if (state == STATE_DONE) return false;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-10 07:56:55 -04:00
|
|
|
// if image frame is ready to be drawn and is currently not being painted
|
|
|
|
if (flag == ImageObserver.FRAMEBITS && !painting) {
|
|
|
|
Image buffer;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-10 07:56:55 -04:00
|
|
|
// select which buffer to fill
|
|
|
|
if (img == logo) buffer = logoBuffer;
|
|
|
|
else buffer = progressbarBuffer;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-10 07:56:55 -04:00
|
|
|
Graphics g = buffer.getGraphics();
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-10 07:56:55 -04:00
|
|
|
// clear background on buffer
|
|
|
|
g.setColor(bgColor);
|
|
|
|
g.fillRect(0, 0, buffer.getWidth(null), buffer.getHeight(null));
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-10 07:56:55 -04:00
|
|
|
// buffer background is cleared, so draw logo under progressbar
|
2010-07-25 09:31:49 -04:00
|
|
|
if (img == progressbar && logo != null) {
|
2010-09-28 17:11:35 -04:00
|
|
|
g.drawImage(logoBuffer, progressbar.getWidth(null)/2-logo.getWidth(null)/2,
|
2010-07-25 09:31:49 -04:00
|
|
|
progressbar.getHeight(null)/2-logo.getHeight(null)/2, null);
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-10 07:56:55 -04:00
|
|
|
g.drawImage(img, 0, 0, this);
|
|
|
|
g.dispose();
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-10 07:56:55 -04:00
|
|
|
repaint();
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-10 07:56:55 -04:00
|
|
|
return true;
|
|
|
|
}
|
2007-06-10 16:30:03 -04:00
|
|
|
|
2007-06-11 14:10:19 -04:00
|
|
|
/**
|
|
|
|
* @return string describing the state of the loader
|
|
|
|
*/
|
|
|
|
protected String getDescriptionForState() {
|
|
|
|
switch (state) {
|
|
|
|
case STATE_INIT:
|
|
|
|
return "Initializing loader";
|
|
|
|
case STATE_DETERMINING_PACKAGES:
|
|
|
|
return "Determining packages to load";
|
|
|
|
case STATE_CHECKING_CACHE:
|
2010-07-11 09:54:52 -04:00
|
|
|
return "Calculating download size";
|
2007-06-11 14:10:19 -04:00
|
|
|
case STATE_DOWNLOADING:
|
|
|
|
return "Downloading packages";
|
|
|
|
case STATE_EXTRACTING_PACKAGES:
|
|
|
|
return "Extracting downloaded packages";
|
|
|
|
case STATE_UPDATING_CLASSPATH:
|
|
|
|
return "Updating classpath";
|
|
|
|
case STATE_SWITCHING_APPLET:
|
|
|
|
return "Switching applet";
|
|
|
|
case STATE_INITIALIZE_REAL_APPLET:
|
|
|
|
return "Initializing real applet";
|
|
|
|
case STATE_START_REAL_APPLET:
|
|
|
|
return "Starting real applet";
|
|
|
|
case STATE_DONE:
|
|
|
|
return "Done loading";
|
|
|
|
default:
|
|
|
|
return "unknown state";
|
|
|
|
}
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
/**
|
|
|
|
* Trims the passed file string based on the available capabilities
|
|
|
|
* @param file string of files to be trimmed
|
|
|
|
* @return trimmed string based on capabilities of client
|
|
|
|
*/
|
|
|
|
protected String trimExtensionByCapabilities(String file) {
|
|
|
|
if (!pack200Supported) {
|
|
|
|
file = file.replaceAll(".pack", "");
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
if (!lzmaSupported) {
|
|
|
|
file = file.replaceAll(".lzma", "");
|
2010-09-28 17:11:35 -04:00
|
|
|
}
|
2008-04-18 18:34:11 -04:00
|
|
|
return file;
|
|
|
|
}
|
2007-06-11 14:10:19 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/**
|
|
|
|
* Reads list of jars to download and adds the urls to urlList
|
|
|
|
* also finds out which OS you are on and adds appropriate native
|
|
|
|
* jar to the urlList
|
|
|
|
*/
|
2007-06-11 14:10:19 -04:00
|
|
|
protected void loadJarURLs() throws Exception {
|
2011-01-22 08:26:07 -05:00
|
|
|
setState(STATE_DETERMINING_PACKAGES);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-11 14:10:19 -04:00
|
|
|
// jars to load
|
|
|
|
String jarList = getParameter("al_jars");
|
2011-01-24 17:35:11 -05:00
|
|
|
String nativeJarList = null;
|
|
|
|
|
|
|
|
String osName = System.getProperty("os.name");
|
|
|
|
|
2007-06-11 14:10:19 -04:00
|
|
|
if (osName.startsWith("Win")) {
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-04 07:03:20 -04:00
|
|
|
// check if arch specific natives have been specified
|
|
|
|
if (System.getProperty("os.arch").endsWith("64")) {
|
2011-01-24 17:35:11 -05:00
|
|
|
nativeJarList = getParameter("al_windows64");
|
2010-07-04 07:03:20 -04:00
|
|
|
} else {
|
2011-01-24 17:35:11 -05:00
|
|
|
nativeJarList = getParameter("al_windows32");
|
2010-07-04 07:03:20 -04:00
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2011-01-24 17:35:11 -05:00
|
|
|
if (nativeJarList == null) {
|
|
|
|
nativeJarList = getParameter("al_windows");
|
2010-07-04 07:03:20 -04:00
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-04-01 14:27:51 -04:00
|
|
|
} else if (osName.startsWith("Linux")) {
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-04 07:03:20 -04:00
|
|
|
// check if arch specific natives have been specified
|
|
|
|
if (System.getProperty("os.arch").endsWith("64")) {
|
2011-01-24 17:35:11 -05:00
|
|
|
nativeJarList = getParameter("al_linux64");
|
2010-07-04 07:03:20 -04:00
|
|
|
} else {
|
2011-01-24 17:35:11 -05:00
|
|
|
nativeJarList = getParameter("al_linux32");
|
2010-07-04 07:03:20 -04:00
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2011-01-24 17:35:11 -05:00
|
|
|
if (nativeJarList == null) {
|
|
|
|
nativeJarList = getParameter("al_linux");
|
2010-07-04 07:03:20 -04:00
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2011-01-25 01:43:28 -05:00
|
|
|
} else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) {
|
2011-01-24 17:35:11 -05:00
|
|
|
nativeJarList = getParameter("al_mac");
|
2008-08-12 17:02:06 -04:00
|
|
|
} else if (osName.startsWith("Solaris") || osName.startsWith("SunOS")) {
|
2011-01-24 17:35:11 -05:00
|
|
|
nativeJarList = getParameter("al_solaris");
|
2010-04-01 14:27:51 -04:00
|
|
|
} else if (osName.startsWith("FreeBSD")) {
|
2011-01-24 17:35:11 -05:00
|
|
|
nativeJarList = getParameter("al_freebsd");
|
2007-06-11 14:10:19 -04:00
|
|
|
} else {
|
2009-06-11 17:07:34 -04:00
|
|
|
fatalErrorOccured("OS (" + osName + ") not supported", null);
|
2011-01-24 17:35:11 -05:00
|
|
|
return;
|
2007-06-11 14:10:19 -04:00
|
|
|
}
|
2011-01-24 17:35:11 -05:00
|
|
|
|
|
|
|
if (nativeJarList == null) {
|
2009-06-11 17:07:34 -04:00
|
|
|
fatalErrorOccured("no lwjgl natives files found", null);
|
2011-01-24 17:35:11 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
jarList = trimExtensionByCapabilities(jarList);
|
|
|
|
StringTokenizer jars = new StringTokenizer(jarList, ", ");
|
|
|
|
|
|
|
|
nativeJarList = trimExtensionByCapabilities(nativeJarList);
|
|
|
|
StringTokenizer nativeJars = new StringTokenizer(nativeJarList, ", ");
|
|
|
|
|
|
|
|
int jarCount = jars.countTokens();
|
|
|
|
nativeJarCount = nativeJars.countTokens();
|
|
|
|
|
|
|
|
urlList = new URL[jarCount+nativeJarCount];
|
|
|
|
|
|
|
|
URL path = getCodeBase();
|
|
|
|
|
|
|
|
// set jars urls
|
|
|
|
for (int i = 0; i < jarCount; i++) {
|
|
|
|
urlList[i] = new URL(path, jars.nextToken());
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = jarCount; i < jarCount+nativeJarCount; i++) {
|
|
|
|
urlList[i] = new URL(path, nativeJars.nextToken());
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 4 steps
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2007-06-10 16:30:03 -04:00
|
|
|
* 1) check version of applet and decide whether to download jars
|
|
|
|
* 2) download the jars
|
|
|
|
* 3) extract natives
|
|
|
|
* 4) add to jars to class path
|
|
|
|
* 5) switch applets
|
|
|
|
*/
|
|
|
|
public void run() {
|
2011-01-22 08:26:07 -05:00
|
|
|
setState(STATE_CHECKING_CACHE);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-10-24 17:25:54 -04:00
|
|
|
percentage = 5;
|
2007-06-10 16:30:03 -04:00
|
|
|
|
2008-04-20 15:55:55 -04:00
|
|
|
try {
|
|
|
|
debug_sleep(2000);
|
2007-06-10 16:30:03 -04:00
|
|
|
|
2007-06-11 14:10:19 -04:00
|
|
|
// parse the urls for the jars into the url list
|
|
|
|
loadJarURLs();
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
// get path where applet will be stored
|
2010-09-28 17:11:35 -04:00
|
|
|
String path = AccessController.doPrivileged(new PrivilegedExceptionAction<String>() {
|
|
|
|
public String run() throws Exception {
|
|
|
|
|
2008-04-10 17:02:04 -04:00
|
|
|
// we append the code base to avoid naming collisions with al_title
|
|
|
|
String codebase = "";
|
|
|
|
if(prependHost) {
|
|
|
|
codebase = getCodeBase().getHost();
|
|
|
|
if(codebase == null || codebase.length() == 0) {
|
|
|
|
codebase = "localhost";
|
|
|
|
}
|
|
|
|
codebase += File.separator;
|
|
|
|
}
|
2010-10-07 16:33:01 -04:00
|
|
|
return getCacheDir() + File.separator + codebase + getParameter("al_title") + File.separator;
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
|
|
|
});
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
File dir = new File(path);
|
|
|
|
|
|
|
|
// create directory
|
|
|
|
if (!dir.exists()) {
|
2008-04-10 17:02:04 -04:00
|
|
|
dir.mkdirs();
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
File versionFile = new File(dir, "version");
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
// if specified applet version already available don't download anything
|
|
|
|
boolean versionAvailable = false;
|
2007-06-10 16:30:03 -04:00
|
|
|
|
|
|
|
// version of applet
|
|
|
|
String version = getParameter("al_version");
|
|
|
|
float latestVersion = 0;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
// if applet version specifed, check if you have latest version of applet
|
|
|
|
if (version != null) {
|
|
|
|
|
|
|
|
latestVersion = Float.parseFloat(version);
|
|
|
|
|
|
|
|
// if version file exists
|
2010-07-11 08:13:34 -04:00
|
|
|
if (versionFile.exists()) {
|
2007-06-10 16:30:03 -04:00
|
|
|
// compare to new version
|
2010-08-28 09:47:18 -04:00
|
|
|
if (latestVersion != readVersionFile(versionFile)) {
|
2010-07-11 08:13:34 -04:00
|
|
|
versionAvailable = true;
|
2007-06-10 16:30:03 -04:00
|
|
|
percentage = 90;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-03-10 11:34:38 -04:00
|
|
|
if(debugMode) {
|
|
|
|
System.out.println("Loading Cached Applet Version " + latestVersion);
|
|
|
|
}
|
2008-04-20 15:55:55 -04:00
|
|
|
debug_sleep(2000);
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if jars not available or need updating download them
|
2010-07-11 08:13:34 -04:00
|
|
|
if (!versionAvailable) {
|
|
|
|
// get jars file sizes and check cache
|
|
|
|
getJarInfo(dir); // 5-15%
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
// downloads jars from the server
|
2010-07-11 08:13:34 -04:00
|
|
|
downloadJars(path); // 15-55%
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
// Extract Pack and LZMA files
|
|
|
|
extractJars(path); // 55-65%
|
2007-06-10 16:30:03 -04:00
|
|
|
|
|
|
|
// Extracts Native Files
|
|
|
|
extractNatives(path); // 65-85%
|
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
// save version information once jars downloaded successfully
|
2007-06-10 16:30:03 -04:00
|
|
|
if (version != null) {
|
|
|
|
percentage = 90;
|
2010-07-21 14:53:41 -04:00
|
|
|
writeVersionFile(versionFile, latestVersion);
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
// save file names with last modified info once downloaded successfully
|
|
|
|
writeCacheFile(new File(dir, "cache"), filesLastModified);
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// add the downloaded jars and natives to classpath
|
|
|
|
updateClassPath(path);
|
2011-01-10 16:50:21 -05:00
|
|
|
|
|
|
|
// set lwjgl properties
|
|
|
|
setLWJGLProperties();
|
2007-06-10 16:30:03 -04:00
|
|
|
|
|
|
|
// switch to LWJGL Applet
|
2011-01-22 13:08:21 -05:00
|
|
|
EventQueue.invokeAndWait(new Runnable() {
|
|
|
|
public void run() {
|
|
|
|
try {
|
|
|
|
switchApplet();
|
|
|
|
} catch (Exception e) {
|
|
|
|
fatalErrorOccured("This occurred while '" + getDescriptionForState() + "'", e);
|
|
|
|
}
|
|
|
|
setState(STATE_DONE);
|
|
|
|
repaint();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
} catch (AccessControlException ace) {
|
2009-06-11 17:07:34 -04:00
|
|
|
fatalErrorOccured(ace.getMessage(), ace);
|
2007-06-11 14:10:19 -04:00
|
|
|
certificateRefused = true;
|
2007-06-10 16:30:03 -04:00
|
|
|
} catch (Exception e) {
|
2010-07-25 07:40:58 -04:00
|
|
|
fatalErrorOccured("This occurred while '" + getDescriptionForState() + "'", e);
|
2007-06-10 16:30:03 -04:00
|
|
|
} finally {
|
|
|
|
loaderThread = null;
|
|
|
|
}
|
|
|
|
}
|
2010-10-07 16:33:01 -04:00
|
|
|
|
2011-01-10 16:50:21 -05:00
|
|
|
/**
|
|
|
|
* Parses the java_arguments list and sets lwjgl specific
|
|
|
|
* properties accordingly, before the launch.
|
|
|
|
*/
|
|
|
|
protected void setLWJGLProperties() {
|
2011-01-11 15:54:26 -05:00
|
|
|
String lwjglArguments = getParameter("lwjgl_arguments");
|
|
|
|
|
|
|
|
if(lwjglArguments != null && lwjglArguments.length() > 0) {
|
|
|
|
int start = lwjglArguments.indexOf("-Dorg.lwjgl");
|
2011-01-10 16:50:21 -05:00
|
|
|
while(start != -1) {
|
2011-01-11 15:54:26 -05:00
|
|
|
int end = lwjglArguments.indexOf(" ", start);
|
2011-01-10 16:50:21 -05:00
|
|
|
if(end == -1) {
|
2011-01-11 15:54:26 -05:00
|
|
|
end = lwjglArguments.length();
|
2011-01-10 16:50:21 -05:00
|
|
|
}
|
2011-01-11 15:54:26 -05:00
|
|
|
String[] keyValue = lwjglArguments.substring(start+2, end).split("=");
|
2011-01-10 16:50:21 -05:00
|
|
|
System.setProperty(keyValue[0], keyValue[1]);
|
2011-01-11 15:54:26 -05:00
|
|
|
if(debugMode) {
|
|
|
|
System.out.println("Setting property " + keyValue[0] + " to " + keyValue[1]);
|
|
|
|
}
|
|
|
|
start = lwjglArguments.indexOf("-Dorg.lwjgl", end);
|
2011-01-10 16:50:21 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-07 16:33:01 -04:00
|
|
|
/**
|
|
|
|
* get path to the lwjgl cache directory
|
|
|
|
*
|
|
|
|
* @return path to the lwjgl cache directory
|
|
|
|
*/
|
|
|
|
protected String getCacheDir() {
|
|
|
|
String cacheDir = System.getProperty("deployment.user.cachedir");
|
|
|
|
|
2010-10-08 16:57:23 -04:00
|
|
|
if (cacheDir == null || System.getProperty("os.name").startsWith("Win")) {
|
2010-10-07 16:33:01 -04:00
|
|
|
cacheDir = System.getProperty("java.io.tmpdir");
|
|
|
|
}
|
|
|
|
|
|
|
|
return cacheDir + File.separator + "lwjglcache";
|
|
|
|
}
|
2007-06-10 16:30:03 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* read the current version file
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2007-06-10 16:30:03 -04:00
|
|
|
* @param file the file to read
|
|
|
|
* @return the version value of saved file
|
|
|
|
* @throws Exception if it fails to read value
|
|
|
|
*/
|
|
|
|
protected float readVersionFile(File file) throws Exception {
|
|
|
|
DataInputStream dis = new DataInputStream(new FileInputStream(file));
|
|
|
|
float version = dis.readFloat();
|
|
|
|
dis.close();
|
|
|
|
return version;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* write out version file of applet
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2007-06-10 16:30:03 -04:00
|
|
|
* @param file the file to write out to
|
|
|
|
* @param version the version of the applet as a float
|
|
|
|
* @throws Exception if it fails to write file
|
|
|
|
*/
|
|
|
|
protected void writeVersionFile(File file, float version) throws Exception {
|
|
|
|
DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));
|
|
|
|
dos.writeFloat(version);
|
|
|
|
dos.close();
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
/**
|
|
|
|
* read the current cache file
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2010-07-11 08:13:34 -04:00
|
|
|
* @param file the file to read
|
|
|
|
* @return the hashmap containing the files names and lastModified times
|
|
|
|
* @throws Exception if it fails to read hashmap
|
|
|
|
*/
|
2010-09-28 17:11:35 -04:00
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
protected HashMap<String, Long> readCacheFile(File file) throws Exception {
|
2010-07-11 08:13:34 -04:00
|
|
|
ObjectInputStream dis = new ObjectInputStream(new FileInputStream(file));
|
2010-09-28 17:11:35 -04:00
|
|
|
HashMap<String, Long> hashMap = (HashMap<String, Long>)dis.readObject();
|
2010-07-11 08:13:34 -04:00
|
|
|
dis.close();
|
|
|
|
return hashMap;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* write out cache file of applet
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2010-07-11 08:13:34 -04:00
|
|
|
* @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
|
|
|
|
*/
|
2010-09-28 17:11:35 -04:00
|
|
|
protected void writeCacheFile(File file, HashMap<String, Long> filesLastModified) throws Exception {
|
2010-07-11 08:13:34 -04:00
|
|
|
ObjectOutputStream dos = new ObjectOutputStream(new FileOutputStream(file));
|
|
|
|
dos.writeObject(filesLastModified);
|
|
|
|
dos.close();
|
|
|
|
}
|
2007-06-10 16:30:03 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Edits the ClassPath at runtime to include the jars
|
|
|
|
* that have just been downloaded and then adds the
|
|
|
|
* lwjgl natives folder property.
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2007-06-10 16:30:03 -04:00
|
|
|
* @param path location where applet is stored
|
|
|
|
* @throws Exception if it fails to add classpath
|
|
|
|
*/
|
2011-01-12 15:29:06 -05:00
|
|
|
protected void updateClassPath(final String path) throws Exception {
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2011-01-22 08:26:07 -05:00
|
|
|
setState(STATE_UPDATING_CLASSPATH);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
percentage = 95;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-05-22 05:14:38 -04:00
|
|
|
URL[] urls = new URL[urlList.length];
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-05-22 05:14:38 -04:00
|
|
|
for (int i = 0; i < urlList.length; i++) {
|
|
|
|
urls[i] = new URL("file:" + path + getJarName(urlList[i]));
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-05-28 14:17:04 -04:00
|
|
|
// add downloaded jars to the classpath with required permissions
|
2009-05-22 05:14:38 -04:00
|
|
|
classLoader = new URLClassLoader(urls) {
|
|
|
|
protected PermissionCollection getPermissions (CodeSource codesource) {
|
|
|
|
PermissionCollection perms = null;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-05-22 05:14:38 -04:00
|
|
|
try {
|
2009-05-28 14:17:04 -04:00
|
|
|
// getPermissions from original classloader is important as it checks for signed jars and shows any security dialogs needed
|
2009-05-22 05:14:38 -04:00
|
|
|
Method method = SecureClassLoader.class.getDeclaredMethod("getPermissions", new Class[] { CodeSource.class });
|
|
|
|
method.setAccessible(true);
|
|
|
|
perms = (PermissionCollection)method.invoke(getClass().getClassLoader(), new Object[] {codesource});
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-05-22 05:14:38 -04:00
|
|
|
String host = getCodeBase().getHost();
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-05-22 05:14:38 -04:00
|
|
|
if (host != null && (host.length() > 0)) {
|
2009-05-28 14:17:04 -04:00
|
|
|
// add permission for downloaded jars to access host they were from
|
2009-05-22 05:14:38 -04:00
|
|
|
perms.add(new SocketPermission(host, SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION));
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
else if ( "file".equals(codesource.getLocation().getProtocol()) ) {
|
2009-05-22 05:14:38 -04:00
|
|
|
// if running locally add file permission
|
|
|
|
String path = codesource.getLocation().getFile().replace('/', File.separatorChar);
|
|
|
|
perms.add(new FilePermission(path, SecurityConstants.FILE_READ_ACTION));
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-05-22 05:14:38 -04:00
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-05-22 05:14:38 -04:00
|
|
|
return perms;
|
|
|
|
}
|
2011-01-12 15:18:38 -05:00
|
|
|
|
|
|
|
// allow non lwjgl native to be found from cache directory
|
|
|
|
protected String findLibrary (String libname) {
|
|
|
|
return path + "natives" + File.separator + System.mapLibraryName(libname);
|
|
|
|
}
|
2009-05-22 05:14:38 -04:00
|
|
|
};
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-20 15:55:55 -04:00
|
|
|
debug_sleep(2000);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-04-01 17:01:51 -04:00
|
|
|
// unload natives loaded by a previous instance of this lwjgl applet
|
|
|
|
unloadNatives(path);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
// add natives files path to native class path
|
|
|
|
System.setProperty("org.lwjgl.librarypath", path + "natives");
|
|
|
|
|
|
|
|
// Make sure jinput knows about the new path too
|
|
|
|
System.setProperty("net.java.games.input.librarypath", path + "natives");
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-08-28 09:47:18 -04:00
|
|
|
// set the library path, useful for non lwjgl natives
|
2010-08-28 08:04:55 -04:00
|
|
|
System.setProperty("java.library.path", path + "natives");
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-04-01 17:01:51 -04:00
|
|
|
// mark natives as loaded
|
|
|
|
natives_loaded = true;
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-04-01 17:01:51 -04:00
|
|
|
/**
|
|
|
|
* Unload natives loaded by a different classloader.
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
|
|
|
* Due to limitations of the jvm, native files can only
|
|
|
|
* be loaded once and only be used by the classloader
|
2010-04-01 17:01:51 -04:00
|
|
|
* they were loaded from.
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2010-04-01 17:01:51 -04:00
|
|
|
* Due to the way applets on plugin1 work, one jvm must
|
2010-09-28 17:11:35 -04:00
|
|
|
* be used for all applets. We need to use multiple
|
|
|
|
* classloaders in the same jvm due to LWJGL's static
|
2010-12-15 13:48:56 -05:00
|
|
|
* nature. In order to solve this we simply remove the
|
2010-09-28 17:11:35 -04:00
|
|
|
* natives from a previous classloader allowing a new
|
2010-04-01 17:01:51 -04:00
|
|
|
* classloader to use those natives in the same jvm.
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2010-04-01 17:01:51 -04:00
|
|
|
* This method will only attempt to unload natives from a
|
|
|
|
* previous classloader if it detects that the natives have
|
|
|
|
* been loaded in the same jvm.
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2010-04-01 17:01:51 -04:00
|
|
|
* @param nativePath directory where natives are stored
|
|
|
|
*/
|
|
|
|
private void unloadNatives(String nativePath) {
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-04-01 17:01:51 -04:00
|
|
|
// check whether natives have been loaded into this jvm
|
|
|
|
if (!natives_loaded) {
|
|
|
|
return;
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-04-01 17:01:51 -04:00
|
|
|
try {
|
|
|
|
Field field = ClassLoader.class.getDeclaredField("loadedLibraryNames");
|
|
|
|
field.setAccessible(true);
|
|
|
|
Vector libs = (Vector) field.get(getClass().getClassLoader());
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-04-01 17:01:51 -04:00
|
|
|
String path = new File(nativePath).getCanonicalPath();
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-04-01 17:01:51 -04:00
|
|
|
for (int i = 0; i < libs.size(); i++) {
|
|
|
|
String s = (String) libs.get(i);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-04-01 17:01:51 -04:00
|
|
|
// if a native from the nativePath directory is loaded, unload it
|
|
|
|
if (s.startsWith(path)) {
|
|
|
|
libs.remove(i);
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* replace the current applet with the lwjgl applet
|
|
|
|
* using AppletStub and initialise and start it
|
|
|
|
*/
|
2008-05-06 17:47:49 -04:00
|
|
|
protected void switchApplet() throws Exception {
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2011-01-22 08:26:07 -05:00
|
|
|
setState(STATE_SWITCHING_APPLET);
|
2007-06-10 16:30:03 -04:00
|
|
|
percentage = 100;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-20 15:55:55 -04:00
|
|
|
debug_sleep(2000);
|
2007-06-10 16:30:03 -04:00
|
|
|
|
2009-05-22 05:14:38 -04:00
|
|
|
Class appletClass = classLoader.loadClass(getParameter("al_main"));
|
2007-06-10 16:30:03 -04:00
|
|
|
lwjglApplet = (Applet) appletClass.newInstance();
|
|
|
|
|
|
|
|
lwjglApplet.setStub(this);
|
2007-10-20 17:20:00 -04:00
|
|
|
lwjglApplet.setSize(getWidth(), getHeight());
|
2007-06-10 16:30:03 -04:00
|
|
|
|
2007-10-24 17:55:39 -04:00
|
|
|
setLayout(new BorderLayout());
|
2007-06-10 16:30:03 -04:00
|
|
|
add(lwjglApplet);
|
2008-04-24 16:43:42 -04:00
|
|
|
validate();
|
2007-06-10 16:30:03 -04:00
|
|
|
|
2011-01-22 08:26:07 -05:00
|
|
|
setState(STATE_INITIALIZE_REAL_APPLET);
|
2007-06-10 16:30:03 -04:00
|
|
|
lwjglApplet.init();
|
|
|
|
|
2011-01-22 08:26:07 -05:00
|
|
|
setState(STATE_START_REAL_APPLET);
|
2007-06-10 16:30:03 -04:00
|
|
|
lwjglApplet.start();
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/**
|
2010-07-11 08:13:34 -04:00
|
|
|
* 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.
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2010-07-11 08:13:34 -04:00
|
|
|
* @param dir - location to read cache file from
|
|
|
|
* @throws Exception - if fails to get infomation
|
2007-06-10 16:30:03 -04:00
|
|
|
*/
|
2010-07-11 08:13:34 -04:00
|
|
|
protected void getJarInfo(File dir) throws Exception {
|
2010-09-28 17:11:35 -04:00
|
|
|
|
|
|
|
filesLastModified = new HashMap<String, Long>();
|
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
// store file sizes and mark which files not to download
|
|
|
|
fileSizes = new int[urlList.length];
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
URLConnection urlconnection;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
File cacheFile = new File(dir, "cache");
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
// if cache file exists, load it
|
|
|
|
if (cacheFile.exists()) {
|
|
|
|
filesLastModified = readCacheFile(cacheFile);
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
// calculate total size of jars to download
|
|
|
|
for (int i = 0; i < urlList.length; i++) {
|
|
|
|
urlconnection = urlList[i].openConnection();
|
2009-09-09 07:24:29 -04:00
|
|
|
urlconnection.setDefaultUseCaches(false);
|
2009-11-20 18:26:26 -05:00
|
|
|
if (urlconnection instanceof HttpURLConnection) {
|
|
|
|
((HttpURLConnection) urlconnection).setRequestMethod("HEAD");
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-10-07 20:03:55 -04:00
|
|
|
fileSizes[i] = urlconnection.getContentLength();
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
long lastModified = urlconnection.getLastModified();
|
|
|
|
String fileName = getFileName(urlList[i]);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
|
|
|
|
|
|
|
if (cacheEnabled && lastModified != 0 &&
|
2010-07-11 08:13:34 -04:00
|
|
|
filesLastModified.containsKey(fileName)) {
|
2010-09-28 17:11:35 -04:00
|
|
|
long savedLastModified = filesLastModified.get(fileName);
|
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
// if lastModifed time is the same, don't redownload
|
|
|
|
if (savedLastModified == lastModified) {
|
|
|
|
fileSizes[i] = -2; // mark it to not redownload
|
|
|
|
}
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
if (fileSizes[i] >= 0) {
|
|
|
|
totalSizeDownload += fileSizes[i];
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
// put key and value in the hashmap
|
2010-09-28 17:11:35 -04:00
|
|
|
filesLastModified.put(fileName, lastModified);
|
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
// update progress bar
|
|
|
|
percentage = 5 + (int)(10 * i/(float)urlList.length);
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
2010-07-11 08:13:34 -04:00
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
/**
|
|
|
|
* Will download the jars from the server using the list of urls
|
|
|
|
* in urlList, while at the same time updating progress bar
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2010-07-11 08:13:34 -04:00
|
|
|
* @param path location of the directory to save to
|
|
|
|
* @throws Exception if download fails
|
|
|
|
*/
|
|
|
|
protected void downloadJars(String path) throws Exception {
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2011-01-22 08:26:07 -05:00
|
|
|
setState(STATE_DOWNLOADING);
|
2010-07-11 08:13:34 -04:00
|
|
|
|
|
|
|
URLConnection urlconnection;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
int initialPercentage = percentage = 15;
|
2007-06-10 16:30:03 -04:00
|
|
|
|
|
|
|
// download each jar
|
|
|
|
byte buffer[] = new byte[65536];
|
|
|
|
for (int i = 0; i < urlList.length; i++) {
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-11 08:13:34 -04:00
|
|
|
// skip file if marked as -2 (already downloaded and not changed)
|
|
|
|
if (fileSizes[i] == -2) continue;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-10-07 20:03:55 -04:00
|
|
|
int unsuccessfulAttempts = 0;
|
|
|
|
int maxUnsuccessfulAttempts = 3;
|
|
|
|
boolean downloadFile = true;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-10-07 20:03:55 -04:00
|
|
|
// download the jar a max of 3 times
|
|
|
|
while(downloadFile) {
|
|
|
|
downloadFile = false;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-10-07 20:03:55 -04:00
|
|
|
debug_sleep(2000);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-10-07 20:03:55 -04:00
|
|
|
urlconnection = urlList[i].openConnection();
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-10-07 20:03:55 -04:00
|
|
|
if (urlconnection instanceof HttpURLConnection) {
|
|
|
|
urlconnection.setRequestProperty("Cache-Control", "no-cache");
|
|
|
|
urlconnection.connect();
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-10-07 20:03:55 -04:00
|
|
|
String currentFile = getFileName(urlList[i]);
|
|
|
|
InputStream inputstream = getJarInputStream(currentFile, urlconnection);
|
|
|
|
FileOutputStream fos = new FileOutputStream(path + currentFile);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
|
|
|
|
2009-10-07 20:03:55 -04:00
|
|
|
int bufferSize;
|
|
|
|
long downloadStartTime = System.currentTimeMillis();
|
|
|
|
int downloadedAmount = 0;
|
|
|
|
int fileSize = 0;
|
|
|
|
String downloadSpeedMessage = "";
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-10-07 20:03:55 -04:00
|
|
|
while ((bufferSize = inputstream.read(buffer, 0, buffer.length)) != -1) {
|
|
|
|
debug_sleep(10);
|
|
|
|
fos.write(buffer, 0, bufferSize);
|
|
|
|
currentSizeDownload += bufferSize;
|
|
|
|
fileSize += bufferSize;
|
|
|
|
percentage = initialPercentage + ((currentSizeDownload * 45) / totalSizeDownload);
|
|
|
|
subtaskMessage = "Retrieving: " + currentFile + " " + ((currentSizeDownload * 100) / totalSizeDownload) + "%";
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-10-07 20:03:55 -04:00
|
|
|
downloadedAmount += bufferSize;
|
|
|
|
long timeLapse = System.currentTimeMillis() - downloadStartTime;
|
|
|
|
// update only if a second or more has passed
|
|
|
|
if (timeLapse >= 1000) {
|
|
|
|
// get kb/s, nice that bytes/millis is same as kilobytes/seconds
|
|
|
|
float downloadSpeed = (float) downloadedAmount / timeLapse;
|
|
|
|
// round to two decimal places
|
|
|
|
downloadSpeed = ((int)(downloadSpeed*100))/100f;
|
|
|
|
// set current speed message
|
2010-07-15 16:00:41 -04:00
|
|
|
downloadSpeedMessage = " - " + downloadSpeed + " KB/sec";
|
2009-10-07 20:03:55 -04:00
|
|
|
// reset downloaded amount
|
|
|
|
downloadedAmount = 0;
|
|
|
|
// reset start time
|
|
|
|
downloadStartTime = System.currentTimeMillis();
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-10-07 20:03:55 -04:00
|
|
|
subtaskMessage += downloadSpeedMessage;
|
2008-05-21 20:04:11 -04:00
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-10-07 20:03:55 -04:00
|
|
|
inputstream.close();
|
|
|
|
fos.close();
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-10-07 20:03:55 -04:00
|
|
|
// download complete, verify if it was successful
|
|
|
|
if (urlconnection instanceof HttpURLConnection) {
|
|
|
|
if (fileSize == fileSizes[i]) {
|
|
|
|
// successful download
|
|
|
|
}
|
|
|
|
else if (fileSizes[i] <= 0) {
|
|
|
|
// If contentLength for fileSizes[i] <= 0, we don't know if the download
|
|
|
|
// is complete. We're going to guess the download is complete.
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
unsuccessfulAttempts++;
|
|
|
|
// download failed try again
|
|
|
|
if (unsuccessfulAttempts < maxUnsuccessfulAttempts) {
|
|
|
|
downloadFile = true;
|
|
|
|
currentSizeDownload -= fileSize; // reset progress bar
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// retry attempts exhasted, download failed
|
2009-10-12 07:56:46 -04:00
|
|
|
throw new Exception("failed to download " + currentFile);
|
2009-10-07 20:03:55 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
subtaskMessage = "";
|
|
|
|
}
|
|
|
|
|
2007-10-24 17:25:54 -04:00
|
|
|
/**
|
|
|
|
* Retrieves a jar files input stream. This method exists primarily to fix an Opera hang in getInputStream
|
|
|
|
* @param urlconnection connection to get input stream from
|
|
|
|
* @return InputStream or null if not possible
|
|
|
|
*/
|
2008-04-18 18:34:11 -04:00
|
|
|
protected InputStream getJarInputStream(final String currentFile, final URLConnection urlconnection) throws Exception {
|
2007-10-24 17:25:54 -04:00
|
|
|
final InputStream[] is = new InputStream[1];
|
2010-09-28 17:11:35 -04:00
|
|
|
|
|
|
|
// try to get the input stream 3 times.
|
2007-10-24 17:25:54 -04:00
|
|
|
// Wait at most 5 seconds before interrupting the thread
|
|
|
|
for (int j = 0; j < 3 && is[0] == null; j++) {
|
|
|
|
Thread t = new Thread() {
|
|
|
|
public void run() {
|
|
|
|
try {
|
|
|
|
is[0] = urlconnection.getInputStream();
|
|
|
|
} catch (IOException e) {
|
|
|
|
/* ignored */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
t.setName("JarInputStreamThread");
|
|
|
|
t.start();
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-10-24 17:25:54 -04:00
|
|
|
int iterationCount = 0;
|
2008-04-06 18:15:16 -04:00
|
|
|
while(is[0] == null && iterationCount++ < 5) {
|
2007-10-24 17:25:54 -04:00
|
|
|
try {
|
|
|
|
t.join(1000);
|
|
|
|
} catch (InterruptedException inte) {
|
|
|
|
/* ignored */
|
|
|
|
}
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-06 18:15:16 -04:00
|
|
|
if(is[0] == null) {
|
|
|
|
try {
|
|
|
|
t.interrupt();
|
|
|
|
t.join();
|
|
|
|
} catch (InterruptedException inte) {
|
|
|
|
/* ignored */
|
|
|
|
}
|
|
|
|
}
|
2007-10-24 17:25:54 -04:00
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-10-24 17:25:54 -04:00
|
|
|
if(is[0] == null) {
|
|
|
|
throw new Exception("Unable to get input stream for " + currentFile);
|
|
|
|
}
|
|
|
|
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-10-24 17:25:54 -04:00
|
|
|
return is[0];
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
/**
|
|
|
|
* Extract LZMA File
|
|
|
|
* @param in Input path to pack file
|
|
|
|
* @param out output path to resulting file
|
2010-09-28 17:11:35 -04:00
|
|
|
* @throws Exception if any errors occur
|
2008-04-18 18:34:11 -04:00
|
|
|
*/
|
|
|
|
protected void extractLZMA(String in, String out) throws Exception {
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
File f = new File(in);
|
|
|
|
FileInputStream fileInputHandle = new FileInputStream(f);
|
|
|
|
|
|
|
|
// use reflection to avoid hard dependency
|
2010-09-28 17:11:35 -04:00
|
|
|
Class<?> clazz = Class.forName( "LZMA.LzmaInputStream" );
|
|
|
|
Constructor constructor = clazz.getDeclaredConstructor(InputStream.class);
|
|
|
|
InputStream inputHandle = (InputStream) constructor.newInstance(fileInputHandle);
|
2008-04-18 18:34:11 -04:00
|
|
|
|
|
|
|
OutputStream outputHandle;
|
|
|
|
outputHandle = new FileOutputStream(out);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
byte [] buffer = new byte [1<<14];
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
int ret = inputHandle.read(buffer);
|
|
|
|
while (ret >= 1) {
|
|
|
|
outputHandle.write(buffer,0,ret);
|
|
|
|
ret = inputHandle.read(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
inputHandle.close();
|
|
|
|
outputHandle.close();
|
|
|
|
|
|
|
|
outputHandle = null;
|
|
|
|
inputHandle = null;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
// delete LZMA file, as it is no longer needed
|
|
|
|
f.delete();
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
/**
|
|
|
|
* Extract Pack File
|
|
|
|
* @param in Input path to pack file
|
|
|
|
* @param out output path to resulting file
|
2010-09-28 17:11:35 -04:00
|
|
|
* @throws Exception if any errors occur
|
2008-04-18 18:34:11 -04:00
|
|
|
*/
|
2010-09-28 17:11:35 -04:00
|
|
|
protected void extractPack(String in, String out) throws Exception {
|
2008-04-18 18:34:11 -04:00
|
|
|
File f = new File(in);
|
|
|
|
FileOutputStream fostream = new FileOutputStream(out);
|
|
|
|
JarOutputStream jostream = new JarOutputStream(fostream);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
Pack200.Unpacker unpacker = Pack200.newUnpacker();
|
|
|
|
unpacker.unpack(f, jostream);
|
|
|
|
jostream.close();
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
// delete pack file as its no longer needed
|
|
|
|
f.delete();
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
/**
|
|
|
|
* Extract all jars from any lzma/pack files
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2008-04-18 18:34:11 -04:00
|
|
|
* @param path output path
|
2010-09-28 17:11:35 -04:00
|
|
|
* @throws Exception if any errors occur
|
2008-04-18 18:34:11 -04:00
|
|
|
*/
|
|
|
|
protected void extractJars(String path) throws Exception {
|
2011-01-22 08:26:07 -05:00
|
|
|
setState(STATE_EXTRACTING_PACKAGES);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
float increment = (float) 10.0 / urlList.length;
|
|
|
|
// extract all lzma and pack.lzma files
|
|
|
|
for (int i = 0; i < urlList.length; i++) {
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-11 11:26:33 -04:00
|
|
|
// if file has not changed, skip it
|
|
|
|
if (fileSizes[i] == -2) continue;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-20 15:55:55 -04:00
|
|
|
percentage = 55 + (int) (increment * (i+1));
|
2008-04-18 18:34:11 -04:00
|
|
|
String filename = getFileName(urlList[i]);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-18 18:34:11 -04:00
|
|
|
if (filename.endsWith(".pack.lzma")) {
|
2008-04-20 15:55:55 -04:00
|
|
|
subtaskMessage = "Extracting: " + filename + " to " + filename.replaceAll(".lzma", "");
|
|
|
|
debug_sleep(1000);
|
2008-04-18 18:34:11 -04:00
|
|
|
extractLZMA(path + filename, path + filename.replaceAll(".lzma", ""));
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-20 15:55:55 -04:00
|
|
|
subtaskMessage = "Extracting: " + filename.replaceAll(".lzma", "") + " to " + filename.replaceAll(".pack.lzma", "");
|
|
|
|
debug_sleep(1000);
|
2008-04-18 18:34:11 -04:00
|
|
|
extractPack(path + filename.replaceAll(".lzma", ""), path + filename.replaceAll(".pack.lzma", ""));
|
2010-09-28 17:11:35 -04:00
|
|
|
}
|
2008-04-18 18:34:11 -04:00
|
|
|
else if (filename.endsWith(".pack")) {
|
2008-04-20 15:55:55 -04:00
|
|
|
subtaskMessage = "Extracting: " + filename + " to " + filename.replace(".pack", "");
|
|
|
|
debug_sleep(1000);
|
2008-04-18 18:34:11 -04:00
|
|
|
extractPack(path + filename, path + filename.replace(".pack", ""));
|
|
|
|
}
|
|
|
|
else if (filename.endsWith(".lzma")) {
|
2008-04-20 15:55:55 -04:00
|
|
|
subtaskMessage = "Extracting: " + filename + " to " + filename.replace(".lzma", "");
|
|
|
|
debug_sleep(1000);
|
2008-04-18 18:34:11 -04:00
|
|
|
extractLZMA(path + filename, path + filename.replace(".lzma", ""));
|
|
|
|
}
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
}
|
2007-10-24 17:25:54 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/**
|
|
|
|
* This method will extract all file from the native jar and extract them
|
|
|
|
* to the subdirectory called "natives" in the local path, will also check
|
2010-09-28 17:11:35 -04:00
|
|
|
* to see if the native jar files is signed properly
|
|
|
|
*
|
2007-06-10 16:30:03 -04:00
|
|
|
* @param path base folder containing all downloaded jars
|
|
|
|
* @throws Exception if it fails to extract files
|
|
|
|
*/
|
|
|
|
protected void extractNatives(String path) throws Exception {
|
2011-01-24 17:35:11 -05:00
|
|
|
|
2011-01-22 08:26:07 -05:00
|
|
|
setState(STATE_EXTRACTING_PACKAGES);
|
2011-01-24 20:29:22 -05:00
|
|
|
|
|
|
|
float percentageParts = 20f/nativeJarCount; // parts for each native jar from 20%
|
|
|
|
|
2011-01-24 17:35:11 -05:00
|
|
|
// create native folder
|
|
|
|
File nativeFolder = new File(path + "natives");
|
|
|
|
if (!nativeFolder.exists()) {
|
|
|
|
nativeFolder.mkdir();
|
|
|
|
}
|
|
|
|
|
2010-09-28 17:11:35 -04:00
|
|
|
// get the current certificate to compare against native files
|
2007-06-10 16:30:03 -04:00
|
|
|
Certificate[] certificate = AppletLoader.class.getProtectionDomain().getCodeSource().getCertificates();
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-11-20 18:06:24 -05:00
|
|
|
// workaround for bug where cached applet loader does not have certificates!?
|
|
|
|
if (certificate == null) {
|
|
|
|
URL location = AppletLoader.class.getProtectionDomain().getCodeSource().getLocation();
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-11-20 18:06:24 -05:00
|
|
|
// manually load the certificate
|
|
|
|
JarURLConnection jurl = (JarURLConnection) (new URL("jar:" + location.toString() + "!/org/lwjgl/util/applet/AppletLoader.class").openConnection());
|
|
|
|
jurl.setDefaultUseCaches(true);
|
|
|
|
certificate = jurl.getCertificates();
|
|
|
|
}
|
2011-01-24 17:35:11 -05:00
|
|
|
|
2011-01-24 20:29:22 -05:00
|
|
|
for (int i = urlList.length - nativeJarCount; i < urlList.length; i++) {
|
2011-01-24 17:35:11 -05:00
|
|
|
|
|
|
|
// if a new native jar was not downloaded, no extracting needed
|
|
|
|
if (fileSizes[i] == -2) {
|
2007-06-10 16:30:03 -04:00
|
|
|
continue;
|
|
|
|
}
|
2011-01-24 17:35:11 -05:00
|
|
|
|
|
|
|
// get name of jar file with natives from urlList
|
|
|
|
String nativeJar = getJarName(urlList[i]);
|
|
|
|
|
|
|
|
// open jar file
|
|
|
|
JarFile jarFile = new JarFile(path + nativeJar, true);
|
|
|
|
|
|
|
|
// get list of files in jar
|
|
|
|
Enumeration entities = jarFile.entries();
|
|
|
|
|
|
|
|
totalSizeExtract = 0;
|
2011-01-24 20:29:22 -05:00
|
|
|
int jarNum = i - (urlList.length - nativeJarCount); // used for progressbar
|
|
|
|
|
2011-01-24 17:35:11 -05:00
|
|
|
// calculate the size of the files to extract for progress bar
|
|
|
|
while (entities.hasMoreElements()) {
|
|
|
|
JarEntry entry = (JarEntry) entities.nextElement();
|
|
|
|
|
|
|
|
// skip directories and anything in directories
|
|
|
|
// conveniently ignores the manifest
|
|
|
|
if (entry.isDirectory() || entry.getName().indexOf('/') != -1) {
|
|
|
|
continue;
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
2011-01-24 17:35:11 -05:00
|
|
|
totalSizeExtract += entry.getSize();
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
2011-01-24 17:35:11 -05:00
|
|
|
|
|
|
|
currentSizeExtract = 0;
|
|
|
|
|
|
|
|
// reset point to begining by getting list of file again
|
|
|
|
entities = jarFile.entries();
|
|
|
|
|
|
|
|
// extract all files from the jar
|
|
|
|
while (entities.hasMoreElements()) {
|
|
|
|
JarEntry entry = (JarEntry) entities.nextElement();
|
|
|
|
|
|
|
|
// skip directories and anything in directories
|
|
|
|
// conveniently ignores the manifest
|
|
|
|
if (entry.isDirectory() || entry.getName().indexOf('/') != -1) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if native file already exists if so delete it to make room for new one
|
|
|
|
// useful when using the reload button on the browser
|
|
|
|
File f = new File(path + "natives" + File.separator + entry.getName());
|
|
|
|
if (f.exists()) {
|
|
|
|
if (!f.delete()) {
|
|
|
|
continue; // unable to delete file, it is in use, skip extracting it
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
debug_sleep(1000);
|
|
|
|
|
|
|
|
InputStream in = jarFile.getInputStream(jarFile.getEntry(entry.getName()));
|
|
|
|
OutputStream out = new FileOutputStream(path + "natives" + File.separator + entry.getName());
|
|
|
|
|
|
|
|
int bufferSize;
|
|
|
|
byte buffer[] = new byte[65536];
|
|
|
|
|
|
|
|
while ((bufferSize = in.read(buffer, 0, buffer.length)) != -1) {
|
|
|
|
debug_sleep(10);
|
|
|
|
out.write(buffer, 0, bufferSize);
|
|
|
|
currentSizeExtract += bufferSize;
|
|
|
|
|
|
|
|
// update progress bar
|
2011-01-24 20:29:22 -05:00
|
|
|
percentage = 65 + (int)(percentageParts * (jarNum + currentSizeExtract/(float)totalSizeExtract));
|
2011-01-24 17:35:11 -05:00
|
|
|
subtaskMessage = "Extracting: " + entry.getName() + " " + ((currentSizeExtract * 100) / totalSizeExtract) + "%";
|
|
|
|
}
|
|
|
|
|
|
|
|
// validate if the certificate for native file is correct
|
|
|
|
validateCertificateChain(certificate, entry.getCertificates());
|
|
|
|
|
|
|
|
in.close();
|
|
|
|
out.close();
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
2011-01-24 17:35:11 -05:00
|
|
|
subtaskMessage = "";
|
|
|
|
|
|
|
|
jarFile.close();
|
|
|
|
|
|
|
|
// delete native jar as it is no longer needed
|
|
|
|
File f = new File(path + nativeJar);
|
|
|
|
f.delete();
|
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Validates the certificate chain for a single file
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2007-06-10 16:30:03 -04:00
|
|
|
* @param ownCerts Chain of certificates to check against
|
|
|
|
* @param native_certs Chain of certificates to check
|
|
|
|
*/
|
|
|
|
protected static void validateCertificateChain(Certificate[] ownCerts, Certificate[] native_certs) throws Exception {
|
|
|
|
if (native_certs == null)
|
|
|
|
throw new Exception("Unable to validate certificate chain. Native entry did not have a certificate chain at all");
|
|
|
|
|
|
|
|
if (ownCerts.length != native_certs.length)
|
|
|
|
throw new Exception("Unable to validate certificate chain. Chain differs in length [" + ownCerts.length + " vs " + native_certs.length + "]");
|
|
|
|
|
|
|
|
for (int i = 0; i < ownCerts.length; i++) {
|
|
|
|
if (!ownCerts[i].equals(native_certs[i])) {
|
|
|
|
throw new Exception("Certificate mismatch: " + ownCerts[i] + " != " + native_certs[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/**
|
|
|
|
* Get Image from path provided
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2007-06-10 16:30:03 -04:00
|
|
|
* @param s location of the image
|
|
|
|
* @return the Image file
|
|
|
|
*/
|
|
|
|
protected Image getImage(String s) {
|
|
|
|
try {
|
2010-08-23 14:12:06 -04:00
|
|
|
URL url = Thread.currentThread().getContextClassLoader().getResource("/"+s);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-07-01 14:05:44 -04:00
|
|
|
// if image not found in jar, look outside it
|
2009-06-15 09:08:52 -04:00
|
|
|
if (url == null) {
|
|
|
|
url = new URL(getCodeBase(), s);
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-07-01 14:05:44 -04:00
|
|
|
Image image = super.getImage(url);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2009-07-01 14:05:44 -04:00
|
|
|
// wait for image to load
|
|
|
|
MediaTracker tracker = new MediaTracker(this);
|
|
|
|
tracker.addImage(image, 0);
|
|
|
|
tracker.waitForAll();
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-25 08:18:17 -04:00
|
|
|
// if no errors return image
|
|
|
|
if (!tracker.isErrorAny()) {
|
|
|
|
return image;
|
|
|
|
}
|
2007-06-10 16:30:03 -04:00
|
|
|
} catch (Exception e) {
|
|
|
|
/* */
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2010-07-25 09:31:49 -04:00
|
|
|
// show error as image could not be loaded
|
|
|
|
fatalErrorOccured("Unable to load logo and progressbar images", null);
|
2007-06-10 16:30:03 -04:00
|
|
|
return null;
|
|
|
|
}
|
2008-04-20 12:59:57 -04:00
|
|
|
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2008-04-20 12:59:57 -04:00
|
|
|
/**
|
|
|
|
* Get jar name from URL.
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2008-04-20 12:59:57 -04:00
|
|
|
* @param url Get jar file name from this url
|
|
|
|
* @return file name as string
|
|
|
|
*/
|
|
|
|
protected String getJarName(URL url) {
|
|
|
|
String fileName = url.getFile();
|
|
|
|
|
|
|
|
if (fileName.endsWith(".pack.lzma")) {
|
|
|
|
fileName = fileName.replaceAll(".pack.lzma", "");
|
|
|
|
} else if (fileName.endsWith(".pack")) {
|
|
|
|
fileName = fileName.replaceAll(".pack", "");
|
|
|
|
} else if (fileName.endsWith(".lzma")) {
|
|
|
|
fileName = fileName.replaceAll(".lzma", "");
|
|
|
|
}
|
|
|
|
|
|
|
|
return fileName.substring(fileName.lastIndexOf('/') + 1);
|
2010-09-28 17:11:35 -04:00
|
|
|
}
|
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/**
|
|
|
|
* Get file name portion of URL.
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2007-06-10 16:30:03 -04:00
|
|
|
* @param url Get file name from this url
|
|
|
|
* @return file name as string
|
|
|
|
*/
|
|
|
|
protected String getFileName(URL url) {
|
|
|
|
String fileName = url.getFile();
|
|
|
|
return fileName.substring(fileName.lastIndexOf('/') + 1);
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/**
|
|
|
|
* Retrieves the color
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
|
|
|
* @param param Color to load
|
2007-06-10 16:30:03 -04:00
|
|
|
* @param defaultColor Default color to use if no color to load
|
|
|
|
* @return Color to use
|
|
|
|
*/
|
AppletLoader: Parameters boxbgcolor, boxfgcolor and boxerrorcolor have been added. Previous parameters al_bgcolor, al_fgcolor and al_errorcolor have been removed. Unlike the previous color support now you can specify the color as a string name of any AWT Color ("red", "blue", "yellow", etc), RGB format (0-255, e.g. "255,0,0") or html HEX color (must use leading #, previous didn't need to have the # e.g. "#FF0000"). This is to match the color support of boxbgcolor and boxfgcolor of the java plugin, so now the color is set and appears before the appletloader is even loaded.
2010-07-04 10:35:41 -04:00
|
|
|
protected Color getColor(String param, Color defaultColor) {
|
|
|
|
String color = getParameter(param);
|
2010-09-28 17:11:35 -04:00
|
|
|
|
AppletLoader: Parameters boxbgcolor, boxfgcolor and boxerrorcolor have been added. Previous parameters al_bgcolor, al_fgcolor and al_errorcolor have been removed. Unlike the previous color support now you can specify the color as a string name of any AWT Color ("red", "blue", "yellow", etc), RGB format (0-255, e.g. "255,0,0") or html HEX color (must use leading #, previous didn't need to have the # e.g. "#FF0000"). This is to match the color support of boxbgcolor and boxfgcolor of the java plugin, so now the color is set and appears before the appletloader is even loaded.
2010-07-04 10:35:41 -04:00
|
|
|
if (color == null) return defaultColor;
|
2010-09-28 17:11:35 -04:00
|
|
|
|
AppletLoader: Parameters boxbgcolor, boxfgcolor and boxerrorcolor have been added. Previous parameters al_bgcolor, al_fgcolor and al_errorcolor have been removed. Unlike the previous color support now you can specify the color as a string name of any AWT Color ("red", "blue", "yellow", etc), RGB format (0-255, e.g. "255,0,0") or html HEX color (must use leading #, previous didn't need to have the # e.g. "#FF0000"). This is to match the color support of boxbgcolor and boxfgcolor of the java plugin, so now the color is set and appears before the appletloader is even loaded.
2010-07-04 10:35:41 -04:00
|
|
|
// Check if RGB format
|
|
|
|
if (color.indexOf(",") != -1) {
|
|
|
|
StringTokenizer st = new StringTokenizer(color, ",");
|
2010-09-28 17:11:35 -04:00
|
|
|
|
AppletLoader: Parameters boxbgcolor, boxfgcolor and boxerrorcolor have been added. Previous parameters al_bgcolor, al_fgcolor and al_errorcolor have been removed. Unlike the previous color support now you can specify the color as a string name of any AWT Color ("red", "blue", "yellow", etc), RGB format (0-255, e.g. "255,0,0") or html HEX color (must use leading #, previous didn't need to have the # e.g. "#FF0000"). This is to match the color support of boxbgcolor and boxfgcolor of the java plugin, so now the color is set and appears before the appletloader is even loaded.
2010-07-04 10:35:41 -04:00
|
|
|
// We've got three components for the color
|
|
|
|
try {
|
2010-09-28 17:11:35 -04:00
|
|
|
return new Color(Integer.parseInt(st.nextToken().trim()),
|
|
|
|
Integer.parseInt(st.nextToken().trim()),
|
AppletLoader: Parameters boxbgcolor, boxfgcolor and boxerrorcolor have been added. Previous parameters al_bgcolor, al_fgcolor and al_errorcolor have been removed. Unlike the previous color support now you can specify the color as a string name of any AWT Color ("red", "blue", "yellow", etc), RGB format (0-255, e.g. "255,0,0") or html HEX color (must use leading #, previous didn't need to have the # e.g. "#FF0000"). This is to match the color support of boxbgcolor and boxfgcolor of the java plugin, so now the color is set and appears before the appletloader is even loaded.
2010-07-04 10:35:41 -04:00
|
|
|
Integer.parseInt(st.nextToken().trim()));
|
|
|
|
} catch (Exception e) {
|
|
|
|
// failed to parse
|
|
|
|
return defaultColor;
|
|
|
|
}
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
AppletLoader: Parameters boxbgcolor, boxfgcolor and boxerrorcolor have been added. Previous parameters al_bgcolor, al_fgcolor and al_errorcolor have been removed. Unlike the previous color support now you can specify the color as a string name of any AWT Color ("red", "blue", "yellow", etc), RGB format (0-255, e.g. "255,0,0") or html HEX color (must use leading #, previous didn't need to have the # e.g. "#FF0000"). This is to match the color support of boxbgcolor and boxfgcolor of the java plugin, so now the color is set and appears before the appletloader is even loaded.
2010-07-04 10:35:41 -04:00
|
|
|
// Check & decode if the color is in hexadecimal color format (i.e. #808000)
|
|
|
|
try {
|
|
|
|
return Color.decode(color);
|
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
// ignore exception
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
AppletLoader: Parameters boxbgcolor, boxfgcolor and boxerrorcolor have been added. Previous parameters al_bgcolor, al_fgcolor and al_errorcolor have been removed. Unlike the previous color support now you can specify the color as a string name of any AWT Color ("red", "blue", "yellow", etc), RGB format (0-255, e.g. "255,0,0") or html HEX color (must use leading #, previous didn't need to have the # e.g. "#FF0000"). This is to match the color support of boxbgcolor and boxfgcolor of the java plugin, so now the color is set and appears before the appletloader is even loaded.
2010-07-04 10:35:41 -04:00
|
|
|
// Get the color by name if it exists
|
|
|
|
try {
|
|
|
|
return (Color)Color.class.getField(color).get(null);
|
|
|
|
} catch (Exception e) {
|
|
|
|
return defaultColor;
|
|
|
|
}
|
2007-06-10 16:30:03 -04:00
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/**
|
|
|
|
* Retrieves the boolean value for the applet
|
|
|
|
* @param name Name of parameter
|
|
|
|
* @param defaultValue default value to return if no such parameter
|
|
|
|
* @return value of parameter or defaultValue
|
|
|
|
*/
|
|
|
|
protected boolean getBooleanParameter(String name, boolean defaultValue) {
|
|
|
|
String parameter = getParameter(name);
|
|
|
|
if(parameter != null) {
|
|
|
|
return Boolean.parseBoolean(parameter);
|
|
|
|
}
|
|
|
|
return defaultValue;
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/**
|
|
|
|
* Sets the state of the loaded and prints some debug information
|
2010-09-28 17:11:35 -04:00
|
|
|
*
|
2007-06-10 16:30:03 -04:00
|
|
|
* @param error Error message to print
|
|
|
|
*/
|
2009-06-11 17:07:34 -04:00
|
|
|
protected void fatalErrorOccured(String error, Exception e) {
|
2007-06-10 16:30:03 -04:00
|
|
|
fatalError = true;
|
2010-07-25 07:40:58 -04:00
|
|
|
genericErrorMessage[genericErrorMessage.length-1] = error;
|
|
|
|
System.out.println(error);
|
2009-06-11 17:07:34 -04:00
|
|
|
if(e != null) {
|
2010-07-25 07:40:58 -04:00
|
|
|
System.out.println(e.getMessage());
|
2009-06-11 17:07:34 -04:00
|
|
|
System.out.println(generateStacktrace(e));
|
|
|
|
}
|
2007-06-10 16:30:03 -04:00
|
|
|
repaint();
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2011-01-22 08:26:07 -05:00
|
|
|
/**
|
|
|
|
* set the state of applet loader
|
|
|
|
* @param new state of applet loader
|
|
|
|
* */
|
|
|
|
protected void setState(int state) {
|
|
|
|
this.state = state;
|
|
|
|
if(debugMode) {
|
|
|
|
System.out.println(getDescriptionForState());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-20 15:55:55 -04:00
|
|
|
/**
|
|
|
|
* Utility method for sleeping
|
|
|
|
* Will only really sleep if debug has been enabled
|
|
|
|
* @param ms milliseconds to sleep
|
|
|
|
*/
|
|
|
|
protected void debug_sleep(long ms) {
|
|
|
|
if(debugMode) {
|
|
|
|
sleep(ms);
|
|
|
|
}
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
|
2007-06-10 16:30:03 -04:00
|
|
|
/**
|
|
|
|
* Utility method for sleeping
|
|
|
|
* @param ms milliseconds to sleep
|
|
|
|
*/
|
|
|
|
protected void sleep(long ms) {
|
|
|
|
try {
|
|
|
|
Thread.sleep(ms);
|
|
|
|
} catch (Exception e) {
|
|
|
|
/* ignored */
|
|
|
|
}
|
2010-09-28 17:11:35 -04:00
|
|
|
}
|
|
|
|
|
2009-10-07 20:03:55 -04:00
|
|
|
}
|