/******************************************************************************* * 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.p2; import static org.eclipse.buckminster.jnlp.p2.MaterializationConstants.ERROR_CODE_MISSING_ARGUMENT_EXCEPTION; import static org.eclipse.buckminster.jnlp.p2.MaterializationConstants.ERROR_CODE_REMOTE_IO_EXCEPTION; import static org.eclipse.buckminster.jnlp.p2.MaterializationConstants.ERROR_CODE_RUNTIME_EXCEPTION; import static org.eclipse.buckminster.jnlp.p2.MaterializationConstants.ERROR_HELP_URL; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Date; import java.util.HashMap; import java.util.Map; import org.apache.commons.codec.binary.Base64; import org.eclipse.buckminster.core.CorePlugin; import org.eclipse.buckminster.core.helpers.BMProperties; import org.eclipse.buckminster.jnlp.p2.ui.general.wizard.AdvancedWizardDialog; import org.eclipse.buckminster.jnlp.p2.wizard.install.InstallWizard; import org.eclipse.buckminster.runtime.BuckminsterException; import org.eclipse.buckminster.runtime.BuckminsterPreferences; import org.eclipse.buckminster.runtime.IOUtils; import org.eclipse.buckminster.runtime.Logger; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.equinox.app.IApplication; import org.eclipse.equinox.app.IApplicationContext; import org.eclipse.jface.window.Window; import org.eclipse.jface.window.Window.IExceptionHandler; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ShellAdapter; import org.eclipse.swt.events.ShellEvent; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; /** * This class controls all aspects of the application's execution */ public class Application implements IApplication { public static final Integer OK_EXIT_CODE = new Integer(0); // fake, however, exit code 1 opens ugly window once the application is closed public static final Integer ERROR_EXIT_CODE = new Integer(0); /** * The wizard dialog width */ private static final int WIZARD_MIN_WIDTH = 550; private static final int WIZARD_MAX_WIDTH = 750; /** * The wizard dialog height */ private static final int WIZARD_MIN_HEIGHT = 550; private static final int WIZARD_MAX_HEIGHT = 750; private static final long DEFAULT_POPUP_DELAY = 500; /** * String for synchronization with the bootstrap */ private String m_syncString = null; private String m_errorURL = ERROR_HELP_URL; private String m_supportEmail; public Object start(IApplicationContext context) throws Exception { Object runArgs = context.getArguments().get(IApplicationContext.APPLICATION_ARGS); String errorCode = null; try { String configUrl = null; Long popupAfter = null; if(runArgs instanceof String[]) { String[] args = (String[])runArgs; for(int idx = 0; idx < args.length; ++idx) { String arg = args[idx]; if("-configURL".equals(arg)) { if(++idx < args.length) { configUrl = args[idx]; if(configUrl != null) { configUrl = configUrl.trim(); if(configUrl.length() == 0) configUrl = null; } } } else if("-syncString".equals(arg)) { if(++idx < args.length) { m_syncString = args[idx]; if(m_syncString != null) { m_syncString = m_syncString.trim(); if(m_syncString.length() == 0) m_syncString = null; } } } else if("-popupAfter".equals(arg)) { if(++idx < args.length) { try { popupAfter = Long.valueOf(args[idx]); } catch(NumberFormatException e) { // popupAfter remains null } } } } } // We need to create a display first thing since many mechanisms // depend on its presence. // Display.setAppName("Materializer"); Display display = Display.getDefault(); HelpLinkErrorDialog.setSyncString(m_syncString); if(!Platform.getInstanceLocation().lock()) { errorCode = MaterializationConstants.ERROR_CODE_ALREADY_RUNNING_EXCEPTION; throw BuckminsterException.fromMessage("Materializer is already running"); } BuckminsterPreferences.setLogLevelConsole(Logger.SILENT); BuckminsterPreferences.setLogLevelEclipseLogger(Logger.DEBUG); if(configUrl == null) { errorCode = ERROR_CODE_MISSING_ARGUMENT_EXCEPTION; throw BuckminsterException.fromMessage("Missing required argument -configURL <URL to config properties>"); } Map<String, String> properties = new HashMap<String, String>(); InputStream propStream = null; try { URL propertiesURL = new URL(configUrl); propStream = new BufferedInputStream(propertiesURL.openStream()); Map<String, String> allProperties = new BMProperties(propStream); // Get rid of empty properties for(Map.Entry<String, String> entry : allProperties.entrySet()) { String value = entry.getValue(); if(!(value == null || value.trim().length() == 0)) properties.put(entry.getKey(), value); } } catch(IOException e) { errorCode = ERROR_CODE_REMOTE_IO_EXCEPTION; throw BuckminsterException.fromMessage(e, "Can not read materialization information"); } finally { IOUtils.close(propStream); } m_errorURL = properties.get(MaterializationConstants.PROP_ERROR_URL); if(m_errorURL == null) m_errorURL = MaterializationConstants.ERROR_HELP_URL; m_supportEmail = properties.get(MaterializationConstants.PROP_SUPPORT_EMAIL); String errorMessage = properties.get(MaterializationConstants.PROP_ERROR_MESSAGE); if(errorMessage != null) { errorCode = MaterializationConstants.ERROR_CODE_404_EXCEPTION; throw BuckminsterException.fromMessage(new String(Base64.decodeBase64(errorMessage.getBytes()), "UTF-8")); //$NON-NLS-1$ } try { // Create the wizard dialog and resize it. // final InstallWizard installWizard = new InstallWizard(properties); m_errorURL = installWizard.getErrorURL(); AdvancedWizardDialog dialog = new AdvancedWizardDialog(installWizard, ~SWT.APPLICATION_MODAL); dialog.create(); // General exception handler Window.setExceptionHandler(new IExceptionHandler() { public void handleException(Throwable t) { if(t instanceof ThreadDeath) { // Don't catch ThreadDeath as this is a normal occurrence when // the thread dies throw (ThreadDeath)t; } IStatus status = BuckminsterException.wrap(t.getCause() != null ? t.getCause() : t).getStatus(); CorePlugin.logWarningsAndErrors(status); String localErrorCode; String message; boolean reportable; if(t instanceof JNLPException) { JNLPException e = (JNLPException)t; localErrorCode = e.getErrorCode(); message = e.getMessage(); reportable = e.isReportable(); } else { localErrorCode = ERROR_CODE_RUNTIME_EXCEPTION; message = "An unexpected error occurred.\n\nThis could be because of intermittent network problems."; reportable = true; } HelpLinkErrorDialog.openError(null, installWizard.getWindowImage(), MaterializationConstants.ERROR_WINDOW_TITLE, message, status, localErrorCode, reportable, m_supportEmail, "Materialization Error"); } }); final Shell shell = dialog.getShell(); shell.setSize(Math.min(Math.max(WIZARD_MIN_WIDTH, shell.getSize().x), WIZARD_MAX_WIDTH), Math.min( Math.max(WIZARD_MIN_HEIGHT, shell.getSize().y), WIZARD_MAX_HEIGHT)); // when the shell is not started "ON TOP", it starts blinking shell.addShellListener(new ShellAdapter() { private int m_cnt = 0; @Override public void shellActivated(ShellEvent e) { if(m_cnt == 0) { Display.getDefault().asyncExec(new Runnable() { public void run() { shell.forceActive(); } }); m_cnt++; } } }); try { if(popupAfter != null) { long popupDelay = popupAfter.longValue() - (new Date()).getTime(); if(popupDelay > 0) Thread.sleep(popupDelay); } synchronizeWithBootstrap(); long popupDelay = DEFAULT_POPUP_DELAY; String popupDelayString = properties.get(MaterializationConstants.PROP_POPUP_DELAY); if(popupDelayString != null) { try { popupDelay = new Long(popupDelayString).longValue(); } catch(Throwable e) { popupDelay = DEFAULT_POPUP_DELAY; } } // need to wait a while until applet finishes Thread.sleep(popupDelay); dialog.open(); return OK_EXIT_CODE; } catch(Throwable e) { errorCode = ERROR_CODE_RUNTIME_EXCEPTION; final String finalErrorCode = errorCode; final IStatus status = BuckminsterException.wrap(e).getStatus(); CorePlugin.logWarningsAndErrors(status); Display.getDefault().syncExec(new Runnable() { public void run() { HelpLinkErrorDialog.openError(null, null, MaterializationConstants.ERROR_WINDOW_TITLE, "Materialization wizard failed", status, finalErrorCode, true, m_supportEmail, "Materialization Error"); } }); return ERROR_EXIT_CODE; } } finally { display.dispose(); } } catch(Throwable e) { e.printStackTrace(); if(errorCode == null) { errorCode = ERROR_CODE_RUNTIME_EXCEPTION; } final String finalErrorCode = errorCode; final IStatus status = BuckminsterException.wrap(e).getStatus(); CorePlugin.logWarningsAndErrors(status); Display.getDefault().syncExec(new Runnable() { public void run() { HelpLinkErrorDialog.openError(null, null, MaterializationConstants.ERROR_WINDOW_TITLE, "Materialization cannot be started", status, finalErrorCode, true, m_supportEmail, "Materialization Error"); } }); return ERROR_EXIT_CODE; } } public void stop() { } private void synchronizeWithBootstrap() { if(m_syncString != null) System.out.println(m_syncString); } }