/*
* Copyright 2011 Christian Thiemann <christian@spato.net>
* Developed at Northwestern University <http://rocs.northwestern.edu>
*
* This file is part of the SPaTo Visual Explorer (SPaTo).
*
* SPaTo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SPaTo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SPaTo. If not, see <http://www.gnu.org/licenses/>.
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.URL;
import java.net.URLClassLoader;
public class SPaTo_Prelude implements Runnable {
public static final String VERSION = "20110823T180000";
private static final boolean isMac = System.getProperty("os.name").startsWith("Mac");
private static final boolean isWin = System.getProperty("os.name").startsWith("Windows");
private static final boolean isLin = !isMac && !isWin; // quartum non datur
private static final File jarFolder =
new File(System.getProperty("spato.app-dir"), isMac ? "Contents/Resources/Java" : "lib");
private static final File updateCacheFolder =
isLin ? new File(System.getProperty("user.home"), ".spato/update")
: new File(System.getProperty("spato.app-dir"), isMac ? "Contents/Resources/update" : "update");
public static String args[] = new String[0]; // command line arguments
private static void printOut(String msg) { System.out.println("+++ SPaTo Prelude: " + msg); }
private static void printErr(String msg) { System.err.println("!!! SPaTo Prelude: " + msg); }
private static void copy(File src, File dst) throws IOException {
FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(dst);
byte buf[] = new byte[8*1024]; int len = 0;
while ((len = fis.read(buf)) > 0)
fos.write(buf, 0, len);
fos.close(); fis.close();
}
/*
* Bootstrapping mechanism (set up log file and check for updated SPaTo_Prelude.class)
*/
private static OutputStream initLog() {
OutputStream os = null;
if (System.getProperty("spato.logfile") != null) {
try {
os = new FileOutputStream(System.getProperty("spato.logfile"));
PrintStream ps = new PrintStream(os, true);
System.setOut(ps); System.setErr(ps);
} catch (IOException e) {
printErr("failed to redirect output to " + System.getProperty("spato.logfile"));
}
}
return os;
}
private static void bootstrap() {
printOut("version " + VERSION + " [bootstrap]");
File update = new File(updateCacheFolder, "common" + File.separator + "SPaTo_Prelude.class");
if (update.exists() && new File(updateCacheFolder, "INDEX").exists()) {
printOut("loading updated SPaTo_Prelude");
Runnable prelude = null;
// load updated class
try {
URL urls[] = new URL[] { new File(updateCacheFolder, "common").toURI().toURL() };
ClassLoader cl = new URLClassLoader(urls, null);
prelude = (Runnable)cl.loadClass("SPaTo_Prelude").newInstance();
} catch (Exception e) {
printErr("could not instantiate updated SPaTo_Prelude");
printErr(e.getClass().getName() + ": " + e.getMessage());
javax.swing.JOptionPane.showMessageDialog(null,
"<html>Updating SPaTo Visual Explorer has failed horribly.<br><br>" +
"Please delete the application and manually download<br>" +
"the lastest version from http://www.spato.net/",
"SPaTo Updater", javax.swing.JOptionPane.ERROR_MESSAGE);
return;
}
// try to hand down command line arguments
try {
prelude.getClass().getField("args").set(prelude, args);
} catch (Exception e) {
printErr("could not pass command line arguments to updated SPaTo_Prelude");
}
// run updated class
prelude.run();
} else {
// run an instance of this class
new SPaTo_Prelude().run();
}
}
public static void main(String args[]) {
SPaTo_Prelude.args = args;
OutputStream out = initLog();
bootstrap();
try { out.close(); } catch (Exception e) {}
}
/*
* Main prelude stuff (can be overridden by an updated SPaTo_Prelude.class)
*/
private static final String preludeJars[] = { "SPaTo_Prelude.jar", "core.jar" };
private ClassLoader createClassLoader() throws Exception {
boolean hasUpdate = new File(updateCacheFolder, "INDEX").exists();
// create temporary directory if needed
File tmpDir = null;
if (hasUpdate) {
tmpDir = File.createTempFile("spato", "");
if (!tmpDir.delete()) throw new IOException("could not delete " + tmpDir);
if (!tmpDir.mkdir()) throw new IOException("could not create directory " + tmpDir);
tmpDir.deleteOnExit();
}
// collect jar files (copy updates into tmpdir)
URL urls[] = new URL[preludeJars.length];
for (int i = 0; i < preludeJars.length; i++) {
File oldJar = new File(jarFolder, preludeJars[i]);
File newJar = new File(updateCacheFolder, "common" + File.separator + preludeJars[i]);
File tmpJar = new File(tmpDir, preludeJars[i]);
if (hasUpdate && newJar.exists()) {
copy(newJar, tmpJar);
tmpJar.deleteOnExit();
printOut("using updated " + preludeJars[i]);
urls[i] = tmpJar.toURI().toURL();
} else
urls[i] = oldJar.toURI().toURL();
}
// finished
return new URLClassLoader(urls);
}
private void run(ClassLoader cl, String className) throws Exception {
Runnable task = (Runnable)cl.loadClass("net.spato.sve.prelude." + className).newInstance();
try { task.getClass().getField("args").set(task, args); } catch (Exception e) {}
task.run();
}
public void run() {
printOut("version " + VERSION + " [run]");
try {
ClassLoader cl = createClassLoader();
run(cl, "UpdateInstaller");
run(cl, "ApplicationLauncher");
} catch (Exception e) {
printErr("something went wrong");
e.printStackTrace();
}
}
}