Revision: 4618 http://sourceforge.net/p/vexi/code/4618 Author: mkpg2 Date: 2013-12-19 23:55:02 +0000 (Thu, 19 Dec 2013) Log Message: ----------- Launcher. Display console/log in the event of an error.
Modified Paths: -------------- trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/Launcher.java trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/LauncherApplet.java trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/LauncherMain.java trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/Splash.java trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/util/StreamReader.java Added Paths: ----------- trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/Log.java Removed Paths: ------------- trunk/org.vexi-launcher/Launcher.java trunk/org.vexi-launcher/LauncherApplet.java Deleted: trunk/org.vexi-launcher/Launcher.java =================================================================== --- trunk/org.vexi-launcher/Launcher.java 2013-12-19 22:33:44 UTC (rev 4617) +++ trunk/org.vexi-launcher/Launcher.java 2013-12-19 23:55:02 UTC (rev 4618) @@ -1,463 +0,0 @@ -package org.vexi.launcher; - -import java.applet.Applet; -import java.awt.Color; -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.Vector; - -import org.vexi.DotVexi; - -/** - * @author m...@webenableit.co.uk - * @contributor char...@webenableit.co.uk - * - * <p>The launcher is responsible for downloading the Vexi Core - * and the principle application components (.vexi files) - * and launching it as a separate process so that it can - * exist and survive outside of the restrictive environment - * that is imposed upon applets.</p> - * - */ -abstract public class Launcher { - - // REMARK although a signed applet doesn't have any known securities - // we restrict it to running from domains that we control because in - // the event that it is compromised we can update the copy on these - // domains. In this way the fetching of the applet acts as the security - // check. - abstract public Color getTextColor(); - abstract public Color getBorderColor(); - abstract public Color getBarColor(); - abstract public URL getSplashImageResource(); - abstract public String[] getPermittedDomains(); - abstract public Map getCerts(); - abstract public String getVersion(); - - //////////////// - // INIT - final LauncherApplet applet; - DotVexi dotvexi; - String fetchCount = "?"; - int fetchIndex = 1; - public Launcher(LauncherApplet applet) { - this.applet = applet; - } - - static protected void logflush() { - System.err.flush(); - } - - static protected void log(String s) { - System.err.println(s); - } - - - static private String getEnv(String name) { - try { - return System.getenv(name); - } catch(Throwable t) { - // REMARK - they deprecated this in 1.4, only to bring it back in 1.5. - // By deprecated we mean it throws an error. So here we fall back to - // getting it from the commandline. - try { - String os = System.getProperty("os.name").toLowerCase(); - Process p; - String cmd; - if (os.indexOf("windows 9") != -1 || os.indexOf("windows me") != -1) { - cmd = "command.com /c set"; - } else if (os.indexOf("windows") > -1) { - cmd = "cmd.exe /c set"; - } else { - cmd = "env"; - } - p = Runtime.getRuntime().exec(cmd); - BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())); - String s; - while ((s = br.readLine()) != null) { - if (s.startsWith(name + "=")) { - return s.substring(name.length() + 1); - } - } - } catch (Throwable t2) { - log("Encountered an exception during fallback discovery of: '"+name+"'"); - t2.printStackTrace(); - } - return null; - } - } - - /** generates the basic command string to start java */ - static private String findInJavaHome(String os_name, String javaHome) { - if (javaHome != null && !javaHome.equals("")) { - String r = javaHome + File.separatorChar + "bin" + File.separatorChar + "java"; - if (os_name.indexOf("windows") != -1) { - r += ".exe"; - } - if (new File(r).exists()) { - return r; - } - } - return null; - } - - /** searches for the JVM binary in the usual places - * @throws Problem */ - static private String findJvmBinary() throws Exception { - log("-- Locating the Java Binary --"); - String jvmBinary = null; - String os_name = System.getProperty("os.name", "").toLowerCase(); - - log("Trying Environment Variable 'VEXI_JRE'"); - jvmBinary = findInJavaHome(os_name,getEnv("VEXI_JRE")); - if (jvmBinary != null) { - return jvmBinary; - } - - log("Trying Environment Variable 'JAVA_HOME'"); - jvmBinary = findInJavaHome(os_name,getEnv("JAVA_HOME")); - if (jvmBinary != null) { - return jvmBinary; - } - - log("Trying System Property 'java.home'"); - jvmBinary = findInJavaHome(os_name,System.getProperty("java.home")); - if (jvmBinary != null) { - return jvmBinary; - } - - // check PATH - log("Checking to see if java is on the PATH Environment Variable"); - String path = getEnv("PATH"); - if (path == null) { - path = getEnv("Path"); - } - if (path!=null) { - StringTokenizer st = new StringTokenizer(path, File.pathSeparatorChar + ""); - while (st.hasMoreTokens()) { - String s = st.nextToken(); - if (new File(s + File.separatorChar + "java").exists() || new File(s + File.separatorChar + "java.exe").exists() ) { - jvmBinary = s + File.separatorChar + "java"; - if (os_name.indexOf("windows") != -1) { - jvmBinary += ".exe"; - } - return jvmBinary; - } - } - } - - throw new Problem("Couldn't find a suitable JVM binary! See console log for details"); - } - - long lastDate = -1; - protected InputStream getInputStream(String url) throws IOException{ - final URLConnection uc = connect(url); - InputStream is = uc.getInputStream(); - int contentLength = uc.getContentLength(); - lastDate = uc.getLastModified(); - return progressInputStream(is, url, contentLength); - } - - public void initDotVexi() { - dotvexi = new DotVexi(getCerts()) { - - protected void log(String s) { Launcher.log(s); } - - protected InputStream getInputStream(Object fountain, Object principal) throws IOException { - String url = (String)fountain; - return Launcher.this.getInputStream(url); - } - protected long getRemoteDate(Object fountain, Object principal) { - return lastDate; - } - }; - } - - public void initSplash(){ - Splash.init(getVersion(),getSplashImageResource(), getTextColor(), getBorderColor(), getBarColor()); - } - - - private InputStream progressInputStream(InputStream is, final String displayname, final int contentLength ) { - final String left = "Downloading: "+displayname; - final String right = fetchIndex+"/"+fetchCount; - - return new FilterInputStream(new BufferedInputStream(is)) { - int total = 0; - int percent = 0; - private void display() { - double loaded = ((double)total) / ((double)contentLength); - int newpercent = ((int)Math.ceil(loaded * 100)); - if (newpercent!=percent) { - percent = newpercent; - - //log(percent + "%"); - Splash.update(left, right, (double)percent); - } - } - - public int read() throws IOException { - int ret = super.read(); - if (ret != -1) { - total++; - } - display(); - return ret; - } - public int read(byte[] buf, int off, int len) throws IOException { - int ret = super.read(buf, off, len); - if (ret != -1) { - total += ret; - } - display(); - return ret; - } - }; - } - - /** check if a url falls within the permitted domains - * @param url a string of an absolute url, must start with 'http://' or 'file://' - * @return true iff url is permitted */ - protected boolean checkUrl(String url) { - if (url.startsWith("file")) { - return true; - } - if (url.startsWith("http")) { - // remove the protocol - url = url.substring(url.indexOf("//")+2); - while (true) { - String[] permittedDomains = getPermittedDomains(); - for (int i=0; i<permittedDomains.length; i++) { - if (url.startsWith(permittedDomains[i])) { - return true; - } - } - // if we are a subdomain remove leading part and recheck - if (url.indexOf('.')==-1) { - break; - } - url = url.substring(url.indexOf('.')+1); - } - } - return false; - } - - static private String join(String[] ss) { - String r = ""; - for (int i=0; i<ss.length; i++) { - if (i>0) { - r += ","; - } - r += ss[i]; - } - return r; - } - - /** fetches a file from the distribution site, writing it to the appropriate place */ - public File fetch(String url) throws IOException { - File localfile = dotvexi.getLocalFile(url); - dotvexi.fetch(url, null, url, localfile); - fetchIndex++; - return localfile; - } - - /** attempts to create a local file for logging vexi output to */ - protected File createLog(String logfile) throws IOException { - File dir = dotvexi.findSubDir("logs"); - dir.mkdirs(); - File f=null; - String fname = logfile; - for (int i=0; i<100; i++) { - f = new File(dir,fname); - if ((f.exists() && !f.delete())) { - fname = logfile+i; - continue; // file occupied! - } - if (!f.createNewFile()) { - break; - } - return f; - } - throw new RuntimeException("Could not create log file: " + f.getCanonicalPath()); - } - - - - static public class Problem extends Exception { - public Problem(String message) { super(message); } - } - - - - public void go( - String core, - String mem, - List<String> fetchVexis) { - //log("Codebase is "+url); - fetchCount = ""+(fetchVexis.size()+1); - - - String coreurl = core; - if (!coreurl.endsWith(".signed")) { - permitUnsignedCore(coreurl); - } - File corefile = fetch(coreurl); - - List command = new ArrayList(); - command.add(findJvmBinary()); - if (mem!=null) { - command.add("-Xmx" + mem); - } - command.add("-jar"); - command.add(corefile.getPath()); - - String logfile = getParameter("logfile"); - if (logfile!=null) { - createLog(logfile); - command.add("-l"); - command.add("logs/"+logfile); - } - command.add("-biscuitid"); - command.add(DotVexi.urlUniqueName(codebase)); - - - for (int i = 0; i<10000;i++) { - if (getParameter("option" + i) == null) { - break; - } - command.add(getParameter("option" + i)); - } - - - for (int i = 0; i<fetchVexis.size();i++) { - File f = fetch((String)fetchVexis.get(i)); - command.add(f.getPath()); - } - - - // REMARK - discovering os/architecture not relevant until - // native builds are working again - /* - String os_name = System.getProperty("os.name", "").toLowerCase(); - log("os.name == " + os_name); - Vector command = new Vector(); - String arch = null; - if (os_name.indexOf("linux") != -1) { - arch = new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec("/bin/uname -m").getInputStream())).readLine(); - log("arch is " + arch); - }*/ - - spawn(command); - } - - /** spawns the Vexi core - * @param command contains the full command - including java */ - private void spawn(List<String> command) throws IOException { - File dir = dotvexi.getBaseDir(); - String[] command_vec = command.toArray(new String[command.size()]); - log("in directory : " + dir.getCanonicalPath()); - log("executing : "); - for (int i=0; i<command_vec.length; i++) { - log(" \"" + command_vec[i] + "\""); - } - - final Process p = Runtime.getRuntime().exec(command_vec,null,dir); - - new Thread(new Runnable() { - public void run() { - // catch output - StreamReader errorstream = new StreamReader(p.getErrorStream(), "ERROR", true); - StreamReader outputstream = new StreamReader(p.getInputStream(), "OUTPUT", false); - // kick off output streams - errorstream.start(); - outputstream.start(); - try { - updateStatus("Vexi loaded"); - int exitValue = p.waitFor(); - if (exitValue != 0) { - updateError("Vexi exited abnormally with error code '"+exitValue+"', see log output"); - } else { - updateStatus("Vexi has finished running"); - } - } catch (Throwable t) { - log("Error exiting... " + p.exitValue()); - t.printStackTrace(); - } - log("Exiting..."); - logflush(); - } - }).start(); - } - - - /** - * @author char...@webenableit.co.uk - * - * A very simple stream reader, copied from: - * http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html - */ - static class StreamReader extends Thread { - InputStream is; - String type; - - StreamReader(InputStream is, String type, boolean listenDisplay) { - this.is = is; - this.type = type; - this.listenDisplay = listenDisplay; - } - private boolean listenDisplay; - - public void run() { - try { - InputStreamReader isr = new InputStreamReader(is); - BufferedReader br = new BufferedReader(isr); - String line=null; - while ((line = br.readLine()) != null) { - if (listenDisplay && line.contains("**display launched**")) { - Splash.close(); - } - log(type + ">" + line); - } - } catch (IOException ioe) { - ioe.printStackTrace(); - } - } - } - - - //////////////////// - //// Utility - static private URLConnection connect(String url) throws IOException { - try { - URL u = new URL(url); - final URLConnection uc = u.openConnection(); - uc.setUseCaches(false); // don't use the possibly short Java cache - uc.connect(); - return uc; - } catch (NullPointerException npe) { - // WORKAROUND - sun libraries throw a NPE rather than - // a more informative exception. - throw new IOException("Invalid url: "+url); - } - } - - ////////////// - // Permission - void permitAlternativeURL(String url) throws Problem { - throw new Problem("Applet can not be run from unknown domain " + url + "\nPermitted domains: " + join(getPermittedDomains())); - } - void permitUnsignedCore(String file) throws Problem { - throw new Problem("Applet will not run unsigned core file: "+ file); - } -} Deleted: trunk/org.vexi-launcher/LauncherApplet.java =================================================================== --- trunk/org.vexi-launcher/LauncherApplet.java 2013-12-19 22:33:44 UTC (rev 4617) +++ trunk/org.vexi-launcher/LauncherApplet.java 2013-12-19 23:55:02 UTC (rev 4618) @@ -1,153 +0,0 @@ -package org.vexi.launcher; - -import java.applet.Applet; -import java.awt.Color; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Image; -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Vector; - -import org.vexi.DotVexi; -import org.vexi.launcher.Launcher.Problem; - -/** - * @author m...@webenableit.co.uk - * @contributor char...@webenableit.co.uk - * - * <p>The launcher is responsible for downloading the Vexi Core - * and the principle application components (.vexi files) - * and launching it as a separate process so that it can - * exist and survive outside of the restrictive environment - * that is imposed upon applets.</p> - * - */ -abstract public class LauncherApplet extends Applet { - abstract protected Launcher createLauncher(); - - /////////////////////// - // APPLET - /////////////////////// - - private Launcher launcher; - - /** applet entry point - this is where it all begins */ - public final void init() { - launcher = createLauncher(); - launcher.initSplash(); - launcher.initDotVexi(); - - // the rest is initialized outside of the restrictive applet sandbox - // as we need to download several files and start up a new process - // REMARK: this requires the applet to be signed, an unsigned applet - // will most likely fail very soon after this next thread is started - new Thread() { - public void run() { - java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() { - public Object run() { - launcher.go(); - return null; - } - }); - } - }.start(); - - } - - void log(String s){ Launcher.log(s);} - - public void go() { - try{ - log("Launcher Build : "+launcher.getVersion()); - - // Check codebase is permitted - String codebase = getCodeBase()+""; - updateStatus(""+codebase); - if (!checkUrl(codebase)) { - permitAlternativeURL(codebase); - } - - String core = getParameter("core"); - if (core==null) { - throw new Problem("Core property not set"); - } - - List<String> fetchVexis = new ArrayList(10); - for (int i = 0; i<10000;i++) { - String fetch = getParameter("vexi" + i); - if (fetch == null) { - break; - } - fetchVexis.add(fetch); - } - - go(core, fetchVexis); - - } catch (Problem e) { - updateError(e.getMessage()); - log(e.getMessage()); - } catch (Throwable e) { - updateError("Error; please check the Java console"); - e.printStackTrace(); - } finally { - Splash.close(); - } - } - - - - final Font font = new Font("Sans-serif", Font.BOLD, 12); - final private Object statusLock = new Object(); - private String statusText; - private Color statusColor; - private Image backbuffer = null; - - protected void updateStatus(String statusText) { - updateStatus(statusText, Color.black); - } - protected void updateError(String statusText) { - Launcher.log("Error: "+statusText); - updateStatus(statusText, Color.red); - } - - void updateStatus(String statusText, Color statusColor) { - synchronized (statusLock) { - this.statusText = statusText; - this.statusColor = statusColor; - } - repaint(); - } - - - public final void paint(Graphics g) { update(g); } - public final void update(Graphics g2) { - if (backbuffer == null || backbuffer.getWidth(null) != getSize().width || backbuffer.getHeight(null) != getSize().height) { - backbuffer = createImage(getSize().width, getSize().height); - } - if (backbuffer == null) { - return; - } - Graphics2D g = (Graphics2D)backbuffer.getGraphics(); - - Color color; - String text; - synchronized(statusLock) { - text = statusText; - color = statusColor; - } - - g.setColor(Color.white); - g.fillRect(0, 0, getSize().width, getSize().height); - - int centerOffset = (getSize().width-(int)font.getStringBounds(text, g.getFontRenderContext()).getWidth())/2; - g.setColor(color); - g.setFont(font); - g.drawString(text, centerOffset, 15); - - g2.setClip(0, 0, getSize().width, getSize().height); - g2.drawImage(backbuffer, 0, 0, null); - } -} Modified: trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/Launcher.java =================================================================== --- trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/Launcher.java 2013-12-19 22:33:44 UTC (rev 4617) +++ trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/Launcher.java 2013-12-19 23:55:02 UTC (rev 4618) @@ -32,13 +32,11 @@ */ abstract public class Launcher { public interface Context { - public void flush(); - public void log(String msg); - public void warn(String msg); - public void error(String msg); public void updateStatus(String msg); + public void updateError(String msg); public String getParameter(String s); public void check() throws Problem; + public void exited(); } // REMARK although a signed applet doesn't have any known securities @@ -56,25 +54,27 @@ //////////////// // INIT + final public Log log; final protected Context context; DotVexi dotvexi; String fetchCount = "?"; int fetchIndex = 1; - public Launcher(Context feedback) { - this.context = feedback; + public Launcher(Context context) { + this.log = new Log(context); + this.context = context; } protected void log(String s) { - context.log(s); + log.log(s); } public Map getCerts() { try { return loadCerts(); } catch (Throwable e) { - context.error("Error: applet unable to load root certificates"); + log.error("Error: applet unable to load root certificates"); throw new Error(e); } } @@ -180,6 +180,7 @@ public InputStream getInputStream(String url) throws IOException{ final URLConnection uc = connect(url); InputStream is = uc.getInputStream(); + int contentLength = uc.getContentLength(); lastDate = uc.getLastModified(); return progressInputStream(is, url, contentLength); @@ -188,7 +189,7 @@ public void initDotVexi() { dotvexi = new DotVexi(getCerts()) { - protected void log(String s) { context.log(s); } + protected void log(String s) { log.log(s); } protected InputStream getInputStream(Object fountain, Object principal) throws IOException { String url = (String)fountain; @@ -202,7 +203,7 @@ public void initSplash(){ - Splash.init(context, getVersion(),getSplashImageResource(), getTextColor(), getBorderColor(), getBarColor()); + Splash.init(log, getVersion(),getSplashImageResource(), getTextColor(), getBorderColor(), getBarColor()); } @@ -310,7 +311,7 @@ throw new RuntimeException("Could not create log file: " + f.getCanonicalPath()); } - public void go() { + public void go() throws Exception { try { log("Launcher Build : "+getVersion()); @@ -387,12 +388,6 @@ }*/ spawn(command); - } catch (Problem e) { - context.error(e.getMessage()); - log(e.getMessage()); - } catch (Throwable e) { - context.error("Error; please check the Java console"); - e.printStackTrace(); } finally { Splash.close(); } @@ -416,25 +411,26 @@ new Thread(new Runnable() { public void run() { // catch output - StreamReader errorstream = new StreamReader(context, p.getErrorStream(), "ERROR", true); - StreamReader outputstream = new StreamReader(context, p.getInputStream(), "OUTPUT", false); + StreamReader errorstream = new StreamReader(log, p.getErrorStream(), "ERROR", true); + StreamReader outputstream = new StreamReader(log, p.getInputStream(), "OUTPUT", false); // kick off output streams errorstream.start(); outputstream.start(); try { - context.updateStatus("Vexi loaded"); + log.status("Vexi loaded"); int exitValue = p.waitFor(); if (exitValue != 0) { - context.error("Vexi exited abnormally with error code '"+exitValue+"', see log output"); + log.error("Vexi exited abnormally with error code '"+exitValue+"', see log output"); } else { - context.updateStatus("Vexi has finished running"); + log.status("Vexi has finished running"); + log.log("Exiting..."); + context.exited(); } } catch (Throwable t) { - context.error("Error exiting... " + p.exitValue()); - t.printStackTrace(); + log.error("Error exiting... " + p.exitValue()); + log.error(t); + log.flush(); } - context.log("Exiting..."); - context.flush(); } }).start(); } @@ -444,7 +440,7 @@ //////////////////// //// Utility - static private URLConnection connect(String url) throws IOException { + public URLConnection connect(String url) throws IOException { try { URL u = new URL(url); final URLConnection uc = u.openConnection(); @@ -455,7 +451,7 @@ // WORKAROUND - sun libraries throw a NPE rather than // a more informative exception. throw new IOException("Invalid url: "+url); - } + } } ////////////// Modified: trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/LauncherApplet.java =================================================================== --- trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/LauncherApplet.java 2013-12-19 22:33:44 UTC (rev 4617) +++ trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/LauncherApplet.java 2013-12-19 23:55:02 UTC (rev 4618) @@ -13,36 +13,53 @@ abstract public class LauncherApplet extends Applet implements Context{ Launcher launcher; + Log log; abstract protected Launcher createLauncher(); /** applet entry point - this is where it all begins */ public final void init() { - launcher = createLauncher(); - launcher.initSplash(); - launcher.initDotVexi(); - - // the rest is initialized outside of the restrictive applet sandbox - // as we need to download several files and start up a new process - // REMARK: this requires the applet to be signed, an unsigned applet - // will most likely fail very soon after this next thread is started - new Thread() { - public void run() { - java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() { - public Object run() { - launcher.go(); - return null; - } - }); - } - }.start(); + + launcher = createLauncher(); + launcher.initSplash(); + launcher.initDotVexi(); + log = launcher.log; + // the rest is initialized outside of the restrictive applet sandbox + // as we need to download several files and start up a new process + // REMARK: this requires the applet to be signed, an unsigned applet + // will most likely fail very soon after this next thread is started + new Thread() { + public void run() { + java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() { + public Object run() { + go(); + return null; + } + }); + } + }.start(); + } + + public void exited(){} + + public void go(){ + try{ + launcher.go(); + } catch (Problem e) { + log.error(e.getMessage()); + } catch (Throwable e) { + log.error("Unhandled exception"); + log.error(e); + } + } + public void check() throws Problem { String codebase = getCodeBase()+""; - updateStatus(""+codebase); + log.status(""+codebase); //log("Codebase is "+url); if (!launcher.checkUrl(codebase)) { @@ -72,20 +89,7 @@ * @param text * message or error to display in the applet */ - - public void log(String msg) { - System.err.println(msg); - } - public void flush() { - System.err.flush(); - } - - public void warn(String msg) { log("[WARNING]: "+msg); } - - public void error(String statusText) { - log("[ERROR]: "+statusText); - updateStatus(statusText, Color.red); - } + public void updateError(String statusText) { updateStatus(statusText, Color.red); } public void updateStatus(String statusText) { updateStatus(statusText, Color.black); } private void updateStatus(String statusText, Color statusColor) { synchronized (statusLock) { Modified: trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/LauncherMain.java =================================================================== --- trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/LauncherMain.java 2013-12-19 22:33:44 UTC (rev 4617) +++ trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/LauncherMain.java 2013-12-19 23:55:02 UTC (rev 4618) @@ -2,6 +2,9 @@ import java.io.File; import java.io.InputStreamReader; +import java.net.ConnectException; +import java.net.HttpURLConnection; +import java.net.URLConnection; import java.util.LinkedHashMap; import java.util.Map; @@ -16,20 +19,29 @@ */ abstract public class LauncherMain implements Context{ + + + + final Launcher launcher; + final Log log; + private Map<String,String> params; - private String application; + private String applicationUrl; private String hash; - - abstract public Launcher getLauncher(); + public LauncherMain() { + this.launcher = createLauncher(); + this.log = launcher.log; + } + abstract public Launcher createLauncher(); void init(String[] args){ for(String s: args){ String[] k_v = s.split("="); String k = k_v[0]; String v = k_v[1]; - if("application".equals(k)){ - this.application = v; + if("application_url".equals(k)){ + this.applicationUrl = v; }else if("hash".equals(k)){ this.hash = v; } @@ -37,49 +49,71 @@ } public void run(String[] args) throws Exception{ - getLauncher().initSplash(); - - File confFile = new File("conf"); - if(confFile.isFile()){ - String[] conf = IOUtil.fileToString(confFile).split("/n"); - init(conf); - }else{ - warn("conf file does not exist"); + try{ + launcher.initSplash(); + + File confFile = new File("conf"); + if(confFile.isFile()){ + String[] conf = IOUtil.fileToString(confFile).split("/n"); + init(conf); + }else{ + log.warn("conf file does not exist"); + } + + init(args); + if(applicationUrl==null){ + log.error("'application' not specified (in conf or args)"); + System.exit(1); + } + + checkVersion(); + fetchArgs(); + launcher.initDotVexi(); + launcher.go(); + } catch (Problem e) { + log.error(e.getMessage()); + } catch (Throwable e) { + log.error("Unexpected problem"); + log.error(e); } - init(args); - if(application==null){ - error("'application' not specified (in conf or args)"); - System.exit(1); - } - - checkVersion(); - fetchArgs(); - getLauncher().initDotVexi(); - getLauncher().go(); - } - String readString(String path) throws Exception{ - return IOUtil.readerToString(new InputStreamReader(getLauncher().getInputStream(path), "UTF8")); + String readString(String url) throws Exception{ + try{ + final URLConnection uc = launcher.connect(url); + if(uc instanceof HttpURLConnection){ + HttpURLConnection huc = (HttpURLConnection)uc; + if(HttpURLConnection.HTTP_OK!=huc.getResponseCode()){ + throw new Problem("Could not read "+url+"\nHttp Code '"+huc.getResponseCode()+"'"); + } + String contentType = huc.getContentType(); + if(!contentType.contains("text/plain")){ + throw new Problem("Could not read "+url+"\nInvalid content type '"+contentType+"'"); + } + } + return IOUtil.readerToString(new InputStreamReader(uc.getInputStream(), "UTF8")); + }catch (ConnectException e) { + throw new Problem("Unable to connect: "+e.getMessage()); + } } void checkVersion() throws Exception{ - String hashes = readString(application+"/launcherversions"); + String hashes = readString(applicationUrl+"/launcherversions"); if(hash==null){ - warn("no version check"); + log.warn("no version check"); }else{ for(String hash: hashes.split("\n")){ if(this.hash.equals(hash)){ return; } } - log("** Launcher incompatible, please download new version **"); - log("our hash: "+hash); - log("allowed: "); + log.error("** Launcher incompatible, please download new version **"); + log.log("our hash: "+hash); + log.log("allowed: "); for(String hash: hashes.split("\n")){ - log(" "+hash); + log.log(" "+hash); } System.exit(0); } @@ -87,7 +121,7 @@ void fetchArgs() throws Exception{ params = new LinkedHashMap(); - String args = readString(application+"/launcherargs"); + String args = readString(applicationUrl+"/launcher/args"); String[] argArr = args.split("\n"); for(String s: argArr){ if("".equals(s.trim())) continue; @@ -96,18 +130,17 @@ if(k_v.length==2){ params.put(k_v[0], k_v[1]); }else{ - warn("invalid arg: "+s); + log.warn("invalid arg: "+s); } } } - public void flush() { System.err.flush(); } - public void log(String msg) { System.err.println(msg); } - public void warn(String msg) { log("[WARNING]: "+msg); } - public void error(String msg) { log("[ERROR]: "+msg); } - public void updateStatus(String msg) { log(msg); } + public void updateError(String msg) {} + public void updateStatus(String msg) { } public String getParameter(String key) { return params.get(key); } - public void check() throws Problem {} + public void check() throws Problem {} + + public void exited(){ System.exit(0); } } Added: trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/Log.java =================================================================== --- trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/Log.java (rev 0) +++ trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/Log.java 2013-12-19 23:55:02 UTC (rev 4618) @@ -0,0 +1,89 @@ +package org.vexi.launcher; + +import java.awt.BorderLayout; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; + +import org.vexi.launcher.Launcher.Context; + + +public class Log { + final Context context; + private List<String> log = new ArrayList(); + private JTextArea text; + + Log(Context context){ + this.context = context; + } + + public void flush(){ + System.err.flush(); + } + + public void status(String msg){ + log(msg); + if(context!=null) context.updateStatus(msg); + } + + public void log(String msg){ + if(text!=null){ + text.append(msg); + text.append("\n"); + }else{ + if(log.size()>1000){ + log.remove(0); + } + log.add(msg); + } + System.err.println(msg); + } + public void warn(String msg){ log("[WARNING] "+msg); } + public void error(String msg){ + log("[ERROR] "+msg); + if(context!=null) context.updateError(msg); + if(text==null){ + text = new JTextArea(); + text.setLineWrap(true); + text.setWrapStyleWord(true); + for(String s: log){ + text.append(s); + text.append("\n"); + } + text.setBounds(5, 35, 385, 330); + JScrollPane scroll = new JScrollPane(text); + JPanel panel = new JPanel(null); + panel.setLayout(new BorderLayout()); + panel.add(scroll, BorderLayout.CENTER); + + JFrame frame = new JFrame(); + frame.setSize(400,400); + + frame.setLocation(0,0); + frame.setTitle("Launcher Log"); + frame.add(panel); + frame.setVisible(true); + + frame.addWindowListener( new WindowAdapter() { + public void windowClosing(WindowEvent we) { + context.exited(); + } + } ); + } + } + public void error(Throwable e) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + pw.flush(); + log(sw.toString()); + } +} \ No newline at end of file Property changes on: trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/Log.java ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Modified: trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/Splash.java =================================================================== --- trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/Splash.java 2013-12-19 22:33:44 UTC (rev 4617) +++ trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/Splash.java 2013-12-19 23:55:02 UTC (rev 4618) @@ -15,8 +15,6 @@ import java.io.IOException; import java.net.URL; -import org.vexi.launcher.Launcher.Context; - /** * * @author Mike Goodwin @@ -31,24 +29,24 @@ static private SplashWindow initFallback() { return new Fallback(); } - static private SplashWindow initFast(Context context) { + static private SplashWindow initFast(Log log) { SplashScreen splash = SplashScreen.getSplashScreen(); if (splash==null) { - context.warn("could not find fast splash screen, using old style"); + log.warn("could not find fast splash screen, using old style"); return initFallback(); } else { return new Fast(splash); } } - static public SplashWindow init(Context context, String version, URL splashImage, Color textcolor, Color bordercolor, Color barcolor) { + static public SplashWindow init(Log log, String version, URL splashImage, Color textcolor, Color bordercolor, Color barcolor) { Splash.version = version; Splash.textcolor = textcolor; Splash.bordercolor = bordercolor; Splash.barcolor = barcolor; try { Splash.class.getClassLoader().loadClass("java.awt.SplashScreen"); - instance = initFast(context); + instance = initFast(log); } catch (ClassNotFoundException e) { instance = initFallback(); } Modified: trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/util/StreamReader.java =================================================================== --- trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/util/StreamReader.java 2013-12-19 22:33:44 UTC (rev 4617) +++ trunk/org.vexi-launcher/src/main/java/org/vexi/launcher/util/StreamReader.java 2013-12-19 23:55:02 UTC (rev 4618) @@ -5,7 +5,7 @@ import java.io.InputStream; import java.io.InputStreamReader; -import org.vexi.launcher.Launcher.Context; +import org.vexi.launcher.Log; import org.vexi.launcher.Splash; /** @@ -15,12 +15,12 @@ * http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html */ public class StreamReader extends Thread { - final Context feedback; + final Log log; final InputStream is; final String type; - public StreamReader(Context feedback, InputStream is, String type, boolean listenDisplay) { - this.feedback = feedback; + public StreamReader(Log log, InputStream is, String type, boolean listenDisplay) { + this.log = log; this.is = is; this.type = type; this.listenDisplay = listenDisplay; @@ -36,10 +36,10 @@ if (listenDisplay && line.contains("**display launched**")) { Splash.close(); } - feedback.log(type + ">" + line); + log.log(type + ">" + line); } } catch (IOException ioe) { - ioe.printStackTrace(); + log.error(ioe); } } } \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------------ Rapidly troubleshoot problems before they affect your business. Most IT organizations don't have a clear picture of how application performance affects their revenue. With AppDynamics, you get 100% visibility into your Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro! http://pubads.g.doubleclick.net/gampad/clk?id=84349831&iu=/4140/ostg.clktrk _______________________________________________ Vexi-svn mailing list Vexi-svn@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/vexi-svn