/***************************************************************************** * Copyright (c) 2006-2007, Cloudsmith Inc. * The code, documentation and other materials contained herein have been * licensed under the Eclipse Public License - v 1.0 by the copyright holder * listed above, as the Initial Contributor under such license. The text of * such license is available at www.eclipse.org. *****************************************************************************/ package org.eclipse.buckminster.jnlp.bootstrap; import static org.eclipse.buckminster.jnlp.bootstrap.BootstrapConstants.ERROR_CODE_CORRUPTED_FILE_EXCEPTION; import static org.eclipse.buckminster.jnlp.bootstrap.BootstrapConstants.ERROR_CODE_DIRECTORY_EXCEPTION; import static org.eclipse.buckminster.jnlp.bootstrap.BootstrapConstants.ERROR_CODE_FILE_IO_EXCEPTION; import static org.eclipse.buckminster.jnlp.bootstrap.BootstrapConstants.ERROR_CODE_JAVA_HOME_NOT_SET_EXCEPTION; import static org.eclipse.buckminster.jnlp.bootstrap.BootstrapConstants.ERROR_CODE_JAVA_RUNTIME_EXCEPTION; import static org.eclipse.buckminster.jnlp.bootstrap.BootstrapConstants.ERROR_CODE_LAUNCHER_NOT_FOUND_EXCEPTION; import static org.eclipse.buckminster.jnlp.bootstrap.BootstrapConstants.ERROR_CODE_LAUNCHER_NOT_STARTED_EXCEPTION; import static org.eclipse.buckminster.jnlp.bootstrap.BootstrapConstants.ERROR_CODE_MALFORMED_PROPERTY_EXCEPTION; import static org.eclipse.buckminster.jnlp.bootstrap.BootstrapConstants.ERROR_CODE_MATERIALIZER_EXECUTION_EXCEPTION; import static org.eclipse.buckminster.jnlp.bootstrap.BootstrapConstants.ERROR_CODE_MISSING_ARGUMENT_EXCEPTION; import static org.eclipse.buckminster.jnlp.bootstrap.BootstrapConstants.ERROR_CODE_PROPERTY_IO_EXCEPTION; import static org.eclipse.buckminster.jnlp.bootstrap.BootstrapConstants.ERROR_CODE_REMOTE_IO_EXCEPTION; import static org.eclipse.buckminster.jnlp.bootstrap.BootstrapConstants.ERROR_CODE_RESOURCE_EXCEPTION; import static org.eclipse.buckminster.jnlp.bootstrap.BootstrapConstants.ERROR_CODE_RUNTIME_EXCEPTION; import static org.eclipse.buckminster.jnlp.bootstrap.BootstrapConstants.ERROR_CODE_SITE_ROOT_EXCEPTION; import static org.eclipse.buckminster.jnlp.bootstrap.BootstrapConstants.ERROR_HELP_URL; import java.awt.Image; import java.awt.Toolkit; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; import java.net.InetSocketAddress; import java.net.MalformedURLException; import java.net.Proxy; import java.net.ProxySelector; import java.net.SocketAddress; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Properties; import java.util.regex.Pattern; import org.eclipse.buckminster.jnlp.cache.SimpleJNLPCache; import org.eclipse.buckminster.jnlp.cache.SimpleJNLPCacheAdapter; import org.eclipse.buckminster.jnlp.cache.SimpleJNLPCacheSecurityManager; import org.eclipse.buckminster.jnlp.cache.Utils; import org.w3c.dom.DOMException; /** * This class is supposed to be called as a JNLP application. It pops up a splash and the in will access a resource. The * idea is that the resource should be declared for lazy downloading and thus not triggered until someone tries to * access it. Since that access happens after the splash has popped up, everything should be done in the right order. * * @author Thomas Hallgren */ public class Main { // The package of the product.zip must correspond with the package declaration // in the product.jnlp file. // private static final String PRODUCT_INSTALLER_CLASS = "org.eclipse.buckminster.jnlp.product.ProductInstaller"; //$NON-NLS-1$ // private static final String PRODUCT = "product"; public static final String PROP_SPLASH_IMAGE_BOOT = "splashImageBoot"; //$NON-NLS-1$ public static final String PROP_SPLASH_IMAGE = "splashImage"; //$NON-NLS-1$ public static final String PROP_WINDOW_ICON = "windowIcon"; //$NON-NLS-1$ public static final String PROP_SERVICE_AVAILABLE = "serviceAvailable"; //$NON-NLS-1$ public static final String PROP_SERVICE_MESSAGE = "serviceMessage"; //$NON-NLS-1$ public static final String PROP_MAX_CAPTURED_LINES = "maxErrorLines"; //$NON-NLS-1$ public static final int DEFAULT_MAX_CAPTURED_LINES = 1000; public static final String PROP_ERROR_URL = "errorURL"; //$NON-NLS-1$ public static final String PROP_STARTUP_TIME = "startupTime"; //$NON-NLS-1$ public static final int DEFAULT_STARTUP_TIME = 4000; public static final String PROP_STARTUP_TIMEOUT = "startupTimeout"; //$NON-NLS-1$ public static final String PROP_BASE_PATH_URL = "basePathURL"; //$NON-NLS-1$ public static final String REPORT_ERROR_VIEW = "feedback.seam"; //$NON-NLS-1$ public static final String REPORT_ERROR_PREFIX = "Materializator-"; //$NON-NLS-1$ public static final int DEFAULT_STARTUP_TIMEOUT = 60000; private static String s_basePathUrl = null; private File m_applicationData; private File m_installLocation; private String m_errorURL = ERROR_HELP_URL; private boolean m_jnlpProductStarted = false; private Process m_process = null; private TailLineBuffer m_tailOut = null; private TailLineBuffer m_tailErr = null; private Image m_splashImageBoot = null; private static final Pattern s_launcherPattern = Pattern.compile("^org\\.eclipse\\.equinox\\.launcher_(.+)\\.jar$"); //$NON-NLS-1$ public static void close(Closeable closeable) { if(closeable != null) { try { closeable.close(); } catch(IOException e) { } } } public static boolean isAix() { return isOs("aix"); //$NON-NLS-1$ } public static boolean isMaxOSx() { return isOs("mac os x"); //$NON-NLS-1$ } public static boolean isOs(String osName) { String os = System.getProperty("os.name"); //$NON-NLS-1$ return os != null && os.length() >= osName.length() && osName.equalsIgnoreCase(os.substring(0, osName.length())); } public static boolean isWindows() { return isOs("windows"); //$NON-NLS-1$ } public static void launch(final String[] args, boolean fromApplet) { final Main main = new Main(); try { ThreadGroup trustedGroup = new ThreadGroup("buckminster.bootstrap.threadgroup"); //$NON-NLS-1$ class BootstrapThread extends Thread { Throwable m_t = null; public BootstrapThread(ThreadGroup group, String name) { super(group, name); } public Throwable getError() { return m_t; } @Override public void run() { try { main.run(args); } catch(Throwable t) { m_t = t; } } } BootstrapThread bootstrap = null; SimpleJNLPCacheSecurityManager cacheSecurityManager = SimpleJNLPCacheSecurityManager.getInstance(); try { cacheSecurityManager.addTrustedThreadGroup(trustedGroup); bootstrap = new BootstrapThread(trustedGroup, "buckminster.bootstrap.thread"); //$NON-NLS-1$ bootstrap.start(); bootstrap.join(); } finally { cacheSecurityManager.removeTrustedThreadGroup(trustedGroup); } if(bootstrap.getError() != null) throw bootstrap.getError(); if(!fromApplet) Runtime.getRuntime().exit(0); } catch(OperationCanceledException e) { System.err.println(Messages.getString("warning_operation_was_canceled_by_user")); //$NON-NLS-1$ if(!fromApplet) Runtime.getRuntime().exit(-1); } catch(Throwable t) { String errorCode; if(t instanceof JNLPException) { JNLPException e = (JNLPException)t; String problem = e.getMessage(); errorCode = e.getErrorCode(); if(e.getCause() != null) { problem += "\n\n" + Messages.getString("stack_trace_colon") + "\n" + getStackTrace(e.getCause()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } new ErrorDialog(main.getWindowIconImage(), Messages.getString("materializer_can_not_be_started"), problem, e.getSolution(), //$NON-NLS-1$ main.getErrorURL() == null ? null : main.getErrorURL() + "?errorCode=" + errorCode).open(); //$NON-NLS-1$ } else { String problem = t.getMessage(); errorCode = ERROR_CODE_RUNTIME_EXCEPTION; if(problem == null) { problem = Messages.getString("unknown_runtime_exception"); //$NON-NLS-1$ } problem += "\n\n" + Messages.getString("stack_trace_colon") + "\n" + getStackTrace(t); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ new ErrorDialog(main.getWindowIconImage(), Messages.getString("materializer_can_not_be_started"), problem, //$NON-NLS-1$ Messages.getString("check_your_java_installation_and_try_again"), main.getErrorURL() == null //$NON-NLS-1$ ? null : main.getErrorURL() + "?errorCode=" + errorCode).open(); //$NON-NLS-1$ } try { File errorFile = new File(main.getInstallLocation(), "error.log"); //$NON-NLS-1$ PrintStream ps = new PrintStream(new FileOutputStream(errorFile)); t.printStackTrace(ps); ps.close(); } catch(Throwable ignore) { } try { reportToServer(errorCode); } catch(IOException e) { // no report } if(!fromApplet) Runtime.getRuntime().exit(-1); } } /** * Standard entry point for launching the application from command line or with java web start * * @param args */ public static void main(String[] args) { launch(args, false); } private static String getStackTrace(Throwable e) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); pw.close(); return sw.toString(); } private static void reportToServer(String errorCode) throws IOException { if(s_basePathUrl == null) return; String javaVersion = URLEncoder.encode(System.getProperty("java.version"), "UTF-8"); //$NON-NLS-1$ //$NON-NLS-2$ String javaVendor = URLEncoder.encode(System.getProperty("java.vendor"), "UTF-8"); //$NON-NLS-1$ //$NON-NLS-2$ String string = s_basePathUrl + REPORT_ERROR_VIEW + "?errorCode=" + REPORT_ERROR_PREFIX + errorCode + //$NON-NLS-1$ "&javaVersion=" + javaVersion + "&javaVendor=" + javaVendor; //$NON-NLS-1$ //$NON-NLS-2$ URL feedbackURL = new URL(string); // ping feedback view to report it to apache log InputStream is = feedbackURL.openStream(); byte[] copyBuf = new byte[8192]; while(is.read(copyBuf) > 0) ; is.close(); } private Image m_splashImage = null; private Image m_windowIconImage = null; public File findEclipseLauncher(String applicationFolder) throws JNLPException { // Eclipse 3.3 no longer have a startup.jar in the root. Instead, they have a // org.eclipse.equinox.launcher_xxxx.jar file under plugins. Let's find // it. // File siteRoot = new File(getInstallLocation(), applicationFolder); if(!siteRoot.isDirectory()) { throw new JNLPException( Messages.getString("unable_to_locate_the_site_root_of_0", getInstallLocation()), //$NON-NLS-1$ Messages.getString("check_disk_space_system_permissions_and_try_again"), ERROR_CODE_SITE_ROOT_EXCEPTION); //$NON-NLS-1$ } File pluginsDir = new File(siteRoot, "plugins"); //$NON-NLS-1$ String[] names = pluginsDir.list(); if(names == null) { throw new JNLPException( Messages.getString("_0_is_not_a_directory", pluginsDir), Messages.getString("report_the_error_and_try_later"), //$NON-NLS-1$ //$NON-NLS-2$ ERROR_CODE_DIRECTORY_EXCEPTION); } String found = null; String foundVer = null; int idx = names.length; while(--idx >= 0) { String name = names[idx]; java.util.regex.Matcher matcher = s_launcherPattern.matcher(name); if(matcher.matches()) { String version = matcher.group(1); if(foundVer == null || foundVer.compareTo(version) > 0) { found = name; foundVer = version; } } } File launcher; if(found == null) { // Are we building against an older platform perhaps? // launcher = new File(siteRoot, "startup.jar"); //$NON-NLS-1$ if(!launcher.exists()) { throw new JNLPException( Messages.getString("can_not_find_file_colon") + pluginsDir //$NON-NLS-1$ + "org.eclipse.equinox.launcher_<version>.jar", //$NON-NLS-1$ Messages.getString("clear_your_java_cache_browser_cache_and_try_again"), ERROR_CODE_LAUNCHER_NOT_FOUND_EXCEPTION); //$NON-NLS-1$ } } else launcher = new File(pluginsDir, found); return launcher; } public synchronized File getApplicationDataLocation() throws JNLPException { if(m_applicationData == null) { if(isWindows()) { String appDataEnv = System.getenv("APPDATA"); //$NON-NLS-1$ if(appDataEnv != null) m_applicationData = new File(appDataEnv); else { String userHome = System.getProperty("user.home"); //$NON-NLS-1$ if(userHome != null) m_applicationData = new File(userHome, "Application Data"); //$NON-NLS-1$ } } else { String userHome = System.getProperty("user.home"); //$NON-NLS-1$ if(userHome != null) m_applicationData = new File(userHome); } } return m_applicationData; } public File getCacheLocation() throws JNLPException { return new File(getInstallLocation(), "cache"); //$NON-NLS-1$ } public synchronized File getInstallLocation() throws JNLPException { if(m_installLocation == null) { if(getApplicationDataLocation() != null) { if(isWindows()) m_installLocation = new File(getApplicationDataLocation(), "buckminster"); //$NON-NLS-1$ else m_installLocation = new File(getApplicationDataLocation(), ".buckminster"); //$NON-NLS-1$ } else { try { m_installLocation = File.createTempFile("bucky", ".site"); //$NON-NLS-1$ //$NON-NLS-2$ } catch(IOException e) { throw new JNLPException( Messages.getString("can_not_create_a_temp_file"), //$NON-NLS-1$ Messages.getString("check_disk_space_system_permissions_and_try_again"), ERROR_CODE_FILE_IO_EXCEPTION, e); //$NON-NLS-1$ } } m_installLocation.mkdirs(); } return m_installLocation; } public String getWorkspaceDir() throws JNLPException { // have the workspace location the same as the product installation return getInstallLocation().getAbsolutePath(); } public void startProduct(String applicationFolder, String[] args, long popupAfter) throws JNLPException { File launcherFile = findEclipseLauncher(applicationFolder); String javaHome = System.getProperty("java.home"); //$NON-NLS-1$ if(javaHome == null) { throw new JNLPException( Messages.getString("system_property_0_is_not_set", "java.home"), //$NON-NLS-1$ //$NON-NLS-2$ Messages .getString("set_the_system_property_which_should_point_to_java_home_directory_and_try_again"), //$NON-NLS-1$ ERROR_CODE_JAVA_HOME_NOT_SET_EXCEPTION); } File javaBin = new File(javaHome, "bin"); //$NON-NLS-1$ File javaExe = new File(javaBin, isWindows() ? "javaw.exe" //$NON-NLS-1$ : "java"); //$NON-NLS-1$ if(!javaExe.exists()) { throw new JNLPException( Messages.getString("unable_to_locate_java_runtime"), Messages.getString("check_java_installation_and_try_again"), //$NON-NLS-1$ //$NON-NLS-2$ ERROR_CODE_JAVA_RUNTIME_EXCEPTION); } ArrayList<String> allArgs = new ArrayList<String>(); allArgs.add(javaExe.toString()); allArgs.addAll(parseExtraArgs(args)); allArgs.add("-Xmx512m"); //$NON-NLS-1$ allArgs.add("-jar"); //$NON-NLS-1$ allArgs.add(launcherFile.toString()); String wsDir = getWorkspaceDir(); if(wsDir != null) { allArgs.add("-data"); //$NON-NLS-1$ allArgs.add(wsDir); } // application is set in config.ini // allArgs.add("-application"); //$NON-NLS-1$ // allArgs.add("org.eclipse.buckminster.jnlp.application"); //$NON-NLS-1$ for(String arg : args) allArgs.add(arg); try { allArgs.addAll(getProxySettings()); } catch(URISyntaxException e) { throw new JNLPException( Messages.getString("unable_to_detect_proxy_settings"), Messages.getString("report_the_problem"), //$NON-NLS-1$ //$NON-NLS-2$ ERROR_CODE_JAVA_RUNTIME_EXCEPTION); } final String syncString = "sync info: application launched"; //$NON-NLS-1$ allArgs.add("-syncString"); //$NON-NLS-1$ allArgs.add(syncString); allArgs.add("-consoleLog"); //$NON-NLS-1$ allArgs.add("-popupAfter"); //$NON-NLS-1$ allArgs.add("" + popupAfter); //$NON-NLS-1$ allArgs.add("-ws"); //$NON-NLS-1$ if(isWindows()) allArgs.add("win32"); //$NON-NLS-1$ else if(isAix()) allArgs.add("motif"); //$NON-NLS-1$ else if(isMaxOSx()) { allArgs.add("carbon"); //$NON-NLS-1$ allArgs.add("-XstartOnFirstThread"); //$NON-NLS-1$ } else allArgs.add("gtk"); //$NON-NLS-1$ Runtime runtime = Runtime.getRuntime(); m_tailOut = new TailLineBuffer(Integer.getInteger(PROP_MAX_CAPTURED_LINES, DEFAULT_MAX_CAPTURED_LINES) .intValue()); m_tailErr = new TailLineBuffer(Integer.getInteger(PROP_MAX_CAPTURED_LINES, DEFAULT_MAX_CAPTURED_LINES) .intValue()); try { m_process = runtime.exec(allArgs.toArray(new String[allArgs.size()])); InputStream is = m_process.getInputStream(); InputStream eis = m_process.getErrorStream(); final BufferedReader rd = new BufferedReader(new InputStreamReader(is)); final BufferedReader erd = new BufferedReader(new InputStreamReader(eis)); new Thread() { @Override public void run() { String line; try { while((line = rd.readLine()) != null) { if(syncString.equals(line)) m_jnlpProductStarted = true; m_tailOut.writeLine(line); } } catch(IOException e) { System.err .println(Messages .getString("error_reading_from_JNLP_application_standard_output_colon") + e.getMessage()); //$NON-NLS-1$ } finally { close(rd); } } }.start(); new Thread() { @Override public void run() { String line; try { while((line = erd.readLine()) != null) m_tailErr.writeLine(line); } catch(IOException e) { System.err .println(Messages.getString("error_reading_from_JNLP_application_standard_error_colon") + e.getMessage()); //$NON-NLS-1$ } finally { close(erd); } } }.start(); } catch(IOException e) { throw new JNLPException( Messages.getString("can_not_run_materializer_wizard"), Messages.getString("check_your_system_permissions_and_try_again"), //$NON-NLS-1$ //$NON-NLS-2$ ERROR_CODE_MATERIALIZER_EXECUTION_EXCEPTION, e); } } void run(String[] args) throws JNLPException, DOMException, OperationCanceledException { try { Properties props = parseArguments(args); s_basePathUrl = props.getProperty(PROP_BASE_PATH_URL); String tmp = props.getProperty(PROP_ERROR_URL); if(tmp != null) { m_errorURL = tmp; } tmp = props.getProperty(PROP_SERVICE_AVAILABLE); boolean serviceAvailable = true; if(tmp != null && "false".equalsIgnoreCase(tmp)) //$NON-NLS-1$ { serviceAvailable = false; } String serviceMessage = props.getProperty(PROP_SERVICE_MESSAGE); if(!serviceAvailable || (serviceMessage != null && serviceMessage.length() > 0)) { new ServiceDialog(getWindowIconImage(), serviceMessage, serviceAvailable).open(); if(!serviceAvailable) { return; } } int startupTime = Integer.getInteger(PROP_STARTUP_TIME, DEFAULT_STARTUP_TIME).intValue(); byte[] splashImageBootData = loadData(props.getProperty(PROP_SPLASH_IMAGE_BOOT)); byte[] splashImageData = loadData(props.getProperty(PROP_SPLASH_IMAGE)); byte[] windowIconData = loadData(props.getProperty(PROP_WINDOW_ICON)); m_splashImageBoot = splashImageBootData != null ? Toolkit.getDefaultToolkit().createImage(splashImageBootData) : null; m_splashImage = splashImageData != null ? Toolkit.getDefaultToolkit().createImage(splashImageData) : null; m_windowIconImage = windowIconData != null ? Toolkit.getDefaultToolkit().createImage(windowIconData) : null; final ProgressFacade monitor = SplashWindow.getDownloadServiceListener(); SimpleJNLPCache cache = new SimpleJNLPCache(getCacheLocation()); if(splashImageBootData != null || splashImageData != null) { cache.addListener(new SimpleJNLPCacheAdapter() { @Override public void updateStarted(URL jnlp) { SplashWindow.splash(m_splashImageBoot, m_splashImage, m_windowIconImage); } }); } /* * // Uncomment to get two testloops of progress - do not use in production // test loop - uncomment to test * splash progress without actually // running under Java Web Start - i.e. keep this comment in the code. * DownloadServiceListener xdsl = SplashWindow.getDownloadServiceListener(); for(int i = 0; i < 101; i++) { * xdsl.progress(null,"", 0L, 0L, i); Thread.sleep(50); } for(int i = 0; i < 51; i++) { * xdsl.progress(null,"", 0L, 0L, i); Thread.sleep(50); } // For debugging purposes - obtain data from the * splash and put them in user's clipboard // SplashWindow.disposeSplash(); * System.err.print(SplashWindow.getDebugString()); */ /* * try { // Assume we don't have an installed product // DownloadService ds = * (DownloadService)ServiceManager.lookup("javax.jnlp.DownloadService"); // DownloadServiceListener dsl = * ds.getDefaultProgressWindow(); if(!ds.isPartCached(PRODUCT)) { if(!SplashWindow.splashIsUp() && * (splashImageBootData != null || splashImageData != null)) SplashWindow.splash(m_splashImageBoot, * m_splashImage, m_windowIconImage); // SplashWindow.disposeSplash(); ds.loadPart(PRODUCT, monitor); // * SplashWindow.splash(splashData); productUpdated = true; } } catch(Exception e) { throw new * JNLPException("Can not download materialization wizard", "Check disk space, system permissions, internet * connection and try again", ERROR_CODE_DOWNLOAD_EXCEPTION, e); } */ String jnlpString = getJnlpRef(args); URL url; try { url = new URL(jnlpString); } catch(MalformedURLException e) { throw new JNLPException(Messages.getString( "unable_to_create_a_URL_from_0_colon_1", jnlpString, e.getMessage()), //$NON-NLS-1$ Messages.getString("report_to_vendor"), ERROR_CODE_PROPERTY_IO_EXCEPTION, e); //$NON-NLS-1$ } boolean productUpdated = cache.registerJNLP(url, monitor); IProductInstaller installer; try { // Class<?> installerClass = Class.forName(PRODUCT_INSTALLER_CLASS); Class<?> installerClass = cache.getClassLoader().loadClass(PRODUCT_INSTALLER_CLASS); installer = (IProductInstaller)installerClass.newInstance(); } catch(Exception e) { throw new JNLPException(Messages.getString("can_not_find_materialization_wizard_resource"), //$NON-NLS-1$ Messages.getString("report_the_error_and_try_later"), ERROR_CODE_RESOURCE_EXCEPTION, e); //$NON-NLS-1$ } if(productUpdated || !installer.isInstalled(getInstallLocation())) { if(!SplashWindow.splashIsUp()) { SplashWindow.splash(m_splashImageBoot, m_splashImage, m_windowIconImage); } try { installer.installProduct(this, monitor); } catch(OperationCanceledException e) { for(String installFolder : installer.getInstallFolders()) { Utils.deleteRecursive(new File(getInstallLocation(), installFolder)); } throw e; } catch(CorruptedFileException e) { cache.removeLatest(); throw new JNLPException( Messages.getString("the_downloaded_materialization_wizard_a_contains_corrupted_file"), //$NON-NLS-1$ Messages.getString("trigger_the_materialization_again"), ERROR_CODE_CORRUPTED_FILE_EXCEPTION); //$NON-NLS-1$ } } // NOTE: keep this to enable debugging - uncomment in splash window too. Stores the debug data // in the clipboard. // ClipboardService clipservice = (ClipboardService)ServiceManager.lookup("javax.jnlp.ClipboardService"); // StringSelection ss = new StringSelection(SplashWindow.getDebugString()); // clipservice.setContents(ss); startProduct(installer.getApplicationFolder(), args, (new Date()).getTime() + startupTime); try { // Two seconds to start, with progressbar. The time is an // estimate of course. // if(splashImageData != null) { // Switch splash screen // if(!SplashWindow.splashIsUp()) SplashWindow.splash(null, m_splashImage, m_windowIconImage); else SplashWindow.setSplashImage(SplashWindow.SPLASH_IMAGE_ID); } startupTime /= 100; monitor.setTask(Messages.getString("starting"), startupTime); //$NON-NLS-1$ while(--startupTime >= 0 && !m_jnlpProductStarted) { monitor.checkCanceled(); Thread.sleep(100); monitor.taskIncrementalProgress(1); } monitor.taskDone(); int processExitValue = 0; boolean processTerminated = false; // Add some grace startup time with progress bar frozen at 100% // Check often if the process is still alive; if not, break the loop if(m_process != null) { int startupTimeOut = Integer.getInteger(PROP_STARTUP_TIMEOUT, DEFAULT_STARTUP_TIMEOUT).intValue() / 100; while(--startupTimeOut >= 0 && !m_jnlpProductStarted) try { monitor.checkCanceled(); processExitValue = m_process.exitValue(); processTerminated = true; break; } catch(IllegalThreadStateException e) { // The process is still alive, let's wait Thread.sleep(100); } } if(!m_jnlpProductStarted) { if(processTerminated) { String capturedErrors = m_tailErr.getLinesAsString(); String capturedOutput = m_tailOut.getLinesAsString(); throw new JNLPException( Messages.getString("unable_to_launch_materializer_colon") + "\nExit code: " + processExitValue //$NON-NLS-1$ //$NON-NLS-2$ + (capturedErrors != null ? "\n" + Messages.getString("captured_errors_colon") + "\n" + capturedErrors //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ : "") + (capturedOutput != null //$NON-NLS-1$ ? "\n" + Messages.getString("captured_output_colon") + "\n" + capturedOutput //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ : ""), Messages.getString("read_error_description_above"), //$NON-NLS-1$ //$NON-NLS-2$ ERROR_CODE_LAUNCHER_NOT_STARTED_EXCEPTION); } m_process.destroy(); throw new JNLPException(Messages.getString("unable_to_launch_materializer_within_timeout"), //$NON-NLS-1$ Messages.getString("check_your_machine_might_be_too_slow_or_too_busy"), //$NON-NLS-1$ ERROR_CODE_LAUNCHER_NOT_STARTED_EXCEPTION); } } catch(InterruptedException e) { } } catch(OperationCanceledException e) { if(m_process != null) { m_process.destroy(); } throw e; } finally { SplashWindow.disposeSplash(); } } private String getErrorURL() { return m_errorURL; } private String getJnlpRef(String[] args) throws JNLPException { for(int idx = 0; idx < args.length; ++idx) { if("-productJNLP".equals(args[idx])) //$NON-NLS-1$ { if(++idx < args.length) { String arg = args[idx]; if(arg != null && arg.trim().length() > 0) { return arg; } } break; } } throw new JNLPException(Messages .getString("missing_required_argument_productJNLP_URL_to_product_JNLP_descriptor"), //$NON-NLS-1$ Messages.getString("report_the_error_and_try_later"), ERROR_CODE_MISSING_ARGUMENT_EXCEPTION); //$NON-NLS-1$ } /** * This method prepares argument with proxy information which will be passed to the application. Notice that there * arguments don't set system properties, they are supposed to be parsed in the application to set up the proxy * rules internally. * * The algorithm of getting proxy information is not ideal since the proxy selector might use non-trivial rules. * However, we don't know which proxy selector implementation will handle our requests and there is no way of * retrieving all the proxy rules. * * Let's keep it simple - we try to use dummy addresses for the most common protocols. This will guarantee that we * inherit most probable browser proxy settings. * * If the rules are not guessed optimally, there should be an option in the launched application to override * automatic proxy discovery with user's own rules, with the possibility to persist the settings in the application * installation directory. * * @return * @throws URISyntaxException */ private List<String> getProxySettings() throws URISyntaxException { List<String> args = new ArrayList<String>(); ProxySelector proxySelector = ProxySelector.getDefault(); for(URI uri : new URI[] { new URI("http://dummy.host.com"), new URI("https://dummy.host.com"), //$NON-NLS-1$ //$NON-NLS-2$ new URI("ftp://dummy.host.com") }) //$NON-NLS-1$ { List<Proxy> proxies = proxySelector.select(uri); String protocol = uri.getScheme(); for(Proxy proxy : proxies) { if(Proxy.NO_PROXY.equals(proxy)) break; SocketAddress address = proxy.address(); if(address instanceof InetSocketAddress) { InetSocketAddress iaddr = (InetSocketAddress)address; args.add("-" + protocol + ".proxyHost"); //$NON-NLS-1$ //$NON-NLS-2$ args.add(iaddr.getHostName()); args.add("-" + protocol + ".proxyPort"); //$NON-NLS-1$ //$NON-NLS-2$ args.add("" + iaddr.getPort()); //$NON-NLS-1$ args.add("-" + protocol + ".nonProxyHosts"); //$NON-NLS-1$ //$NON-NLS-2$ args.add("localhost|127.0.0.1"); //$NON-NLS-1$ break; } } } return args; } private Image getWindowIconImage() { return m_windowIconImage; } private byte[] loadData(String url) throws JNLPException { byte[] data = null; if(url != null) { InputStream is = null; try { is = new URL(url).openStream(); ByteArrayOutputStream os = new ByteArrayOutputStream(); byte[] buf = new byte[0x1000]; int count; while((count = is.read(buf)) > 0) os.write(buf, 0, count); data = os.toByteArray(); } catch(IOException e) { throw new JNLPException( Messages.getString("unable_to_read_a_splash_screen_or_window_icon_image"), //$NON-NLS-1$ Messages.getString("check_your_internet_connection_and_try_again"), ERROR_CODE_REMOTE_IO_EXCEPTION, e); //$NON-NLS-1$ } finally { close(is); } } return data; } private Properties parseArguments(String[] args) throws JNLPException { int urlIdx = -1; for(int idx = 0; idx < args.length; ++idx) { if("-configURL".equals(args[idx])) //$NON-NLS-1$ { if(++idx < args.length) { String arg = args[idx]; if(arg != null && arg.trim().length() > 0) { urlIdx = idx; break; } } break; } } if(urlIdx == -1) { throw new JNLPException(Messages.getString("missing_required_argument_configURL_URL_to_config_properties"), //$NON-NLS-1$ Messages.getString("report_the_error_and_try_later"), ERROR_CODE_MISSING_ARGUMENT_EXCEPTION); //$NON-NLS-1$ } InputStream propStream = null; OutputStream localStream = null; try { URL propertiesURL = null; try { propertiesURL = new URL(args[urlIdx].trim()); } catch(MalformedURLException e) { throw new JNLPException( Messages.getString("can_not_read_URL_to_config_properties"), Messages.getString("report_the_error_and_try_later"), //$NON-NLS-1$ //$NON-NLS-2$ ERROR_CODE_MALFORMED_PROPERTY_EXCEPTION, e); } if(!"file".equals(propertiesURL)) //$NON-NLS-1$ { // Copy to local file. The installer that we bootstrap will need // this too and we don't want an extra http GET just to get it. // int count; byte[] bytes = new byte[8192]; ByteArrayOutputStream bld = new ByteArrayOutputStream(); try { propStream = propertiesURL.openStream(); while((count = propStream.read(bytes, 0, bytes.length)) > 0) bld.write(bytes, 0, count); propStream.close(); } catch(IOException e) { throw new JNLPException( Messages.getString("unable_to_get_information_about_the_materialization"), //$NON-NLS-1$ Messages.getString("check_your_internet_connection_and_try_again"), ERROR_CODE_PROPERTY_IO_EXCEPTION, e); //$NON-NLS-1$ } bytes = bld.toByteArray(); propStream = new ByteArrayInputStream(bytes); // Create the local file // File localTemp = new File(getInstallLocation(), "temp"); //$NON-NLS-1$ if(!(localTemp.exists() || localTemp.mkdirs())) throw new JNLPException( Messages.getString("unable_to_create_directory") + localTemp, //$NON-NLS-1$ Messages.getString("check_your_system_permissions_and_try_again"), ERROR_CODE_FILE_IO_EXCEPTION); //$NON-NLS-1$ File localProps; try { localProps = File.createTempFile("config", "properties", localTemp); //$NON-NLS-1$ //$NON-NLS-2$ } catch(IOException e) { throw new JNLPException( Messages.getString("can_not_create_a_temp_file"), //$NON-NLS-1$ Messages.getString("check_disk_space_system_permissions_and_try_again"), ERROR_CODE_FILE_IO_EXCEPTION, e); //$NON-NLS-1$ } try { localStream = new FileOutputStream(localProps); localStream.write(bytes); } catch(IOException e) { throw new JNLPException( Messages.getString("can_not_write_to_a_temp_file"), //$NON-NLS-1$ Messages.getString("check_your_system_permissions_and_try_again"), ERROR_CODE_FILE_IO_EXCEPTION, e); //$NON-NLS-1$ } // Replace the configURL option value in the argument array with a pointer // to the local file. We convert to URI first since the toURL() on File // is broken (it doesn't convert spaces correctly). // try { args[urlIdx] = localProps.toURI().toURL().toExternalForm(); } catch(MalformedURLException e) { throw new JNLPException( Messages.getString("can_not_read_from_a_temp_file"), //$NON-NLS-1$ Messages.getString("check_your_system_permissions_and_try_again"), ERROR_CODE_FILE_IO_EXCEPTION, e); //$NON-NLS-1$ } } else try { propStream = new BufferedInputStream(propertiesURL.openStream()); } catch(IOException e) { throw new JNLPException( Messages.getString("unable_to_get_information_about_the_materialization"), //$NON-NLS-1$ Messages.getString("check_your_internet_connection_and_try_again"), ERROR_CODE_PROPERTY_IO_EXCEPTION, e); //$NON-NLS-1$ } Properties props = new Properties(); try { props.load(propStream); } catch(IOException e) { throw new JNLPException(Messages.getString("unable_to_read_materialization_information"), //$NON-NLS-1$ Messages.getString("check_your_system_permissions_internet_connection_and_try_again"), //$NON-NLS-1$ ERROR_CODE_PROPERTY_IO_EXCEPTION, e); } return props; } finally { close(propStream); close(localStream); } } /** * Converts a single -extra string parameter into a list of parameters. Parameters are delimited by space. Example: * -extra "-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y" * * @param args * @return */ private List<String> parseExtraArgs(String[] args) { for(int i = 0; i < args.length; i++) { if("-extra".equals(args[i])) //$NON-NLS-1$ { String extraArgsString = args[++i]; if(extraArgsString != null && !"null".equals(extraArgsString)) //$NON-NLS-1$ { String[] extraArgs = extraArgsString.split(" "); //$NON-NLS-1$ return Arrays.asList(extraArgs); } break; } } return Collections.emptyList(); } }