/******************************************************************************* * Copyright (c) 2012 Google, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Google, Inc. - initial API and implementation *******************************************************************************/ package com.windowtester.runner; import java.io.PrintWriter; import java.io.StringWriter; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IPlatformRunnable; import org.eclipse.core.runtime.IProduct; import org.eclipse.core.runtime.Platform; import org.osgi.framework.Bundle; import com.windowtester.runner.util.Logger; /** * Wrappers an application that resides in another plugin that is not directly * accessible from this plugin. * */ public class WrapperedTestRunner implements IPlatformRunnable { private final String bundleId; private final String appClassName; private IPlatformRunnable app; public WrapperedTestRunner(String bundleId, String appClassName) { this.bundleId = bundleId; this.appClassName = appClassName; } /** * Determine if the wrappered application can be successfully resolved, accessed and * started. * * @param args an array of {@link String} arguments * @return <code>true</code> if the application can be started, else * <code>false</code> */ public boolean canStart(Object args) { initApp(args); return app != null; } /** * Called to start the application * * @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext) */ public Object run(Object args) throws Exception { initApp(args); if (app == null) return new Integer(1); return app.run(args); } /** * Attempt to access the bundle and instantiate the application. * * @param args an array of {@link String} arguments */ private void initApp(Object rawArgs) { if (app != null) return; // Access the bundle Bundle bundle = Platform.getBundle(bundleId); if (bundle == null) { Logger.log("Bundle " + bundleId + " cannot be found."); return; } int state = bundle.getState(); Logger.log("Bundle " + bundleId + " is " + getBundleStateName(state)); if (state != Bundle.RESOLVED && state != Bundle.STARTING && state != Bundle.ACTIVE) { Logger.log("Bundle " + bundleId + " cannot be accessed."); return; } // Load the application class Class appClass; try { appClass = bundle.loadClass(appClassName); } catch (ClassNotFoundException e) { Logger.log("Cannot find class " + appClassName + " in bundle " + bundleId); return; } catch (IllegalStateException e) { Logger.log("Cannot access class " + appClassName + " in bundle " + bundleId); return; } // Instantiate the application instance try { app = (IPlatformRunnable) appClass.newInstance(); } catch (InstantiationException e) { Logger.log("Cannot instantiate " + appClassName + " in bundle " + bundleId); return; } catch (IllegalAccessException e) { Logger.log("Cannot access instance of " + appClassName + " in bundle " + bundleId); return; } catch (ClassCastException e) { Logger.log("Cannot cast instance of " + appClassName + " in bundle " + bundleId + " to IPlatformRunnable"); return; } // If this is the Eclipse UITestApplication, make additional checks // because UITestApplication can fail with poor error messages if (!appClassName.equals("org.eclipse.pde.internal.junit.runtime.UITestApplication")) return; if (!(rawArgs instanceof String[])) { Logger.logStackTrace("Illegal argument - must be array of String"); return; } Object application; try { application = getApplication((String[]) rawArgs); } catch (CoreException e) { application = "Failed to determine application-under-test"; Logger.log((String) application, e); } if (!(application instanceof IPlatformRunnable)) { StringWriter stringWriter = new StringWriter(); PrintWriter writer = new PrintWriter(stringWriter); if (application instanceof String) writer.println((String) application); else if (application != null) writer.println("Application " + application.getClass() + " does not implement " + IPlatformRunnable.class); else writer.println("Failed to locate application-under-test"); writer.println("Specify the identifier for the application-under-test using one of the following:"); writer.println("1) -testApplication command line argument"); writer.println("2) via a branding plug-in"); Logger.log(stringWriter.toString()); app = null; } } /** * Answer the name for the specified bundle state * * @param state the bundle state * @return the bundle state name (not <code>null</code>) */ private String getBundleStateName(int state) { switch (state) { case Bundle.UNINSTALLED : return "uninstalled"; case Bundle.INSTALLED : return "installed"; case Bundle.RESOLVED : return "resolved"; case Bundle.STARTING : return "starting"; case Bundle.ACTIVE : return "active"; case Bundle.STOPPING : return "stopping"; default : return "unknown state: " + state; } } //////////////////////////////////////////////////////////////////////////// // // Support specific to UITestApplication // //////////////////////////////////////////////////////////////////////////// /** * Return the application to run, or an error message (String) if not even the default * application is found. */ private Object getApplication(String[] args) throws CoreException { // Find the name of the application as specified by the PDE JUnit launcher. // If no application is specified, the 3.0 default workbench application // is returned. String applicationToRun = getApplicationToRun(args); IExtension extension = Platform.getExtensionRegistry().getExtension(Platform.PI_RUNTIME, Platform.PT_APPLICATIONS, applicationToRun); if (extension == null) return "Failed to locate extension " + Platform.PI_RUNTIME + "." + Platform.PT_APPLICATIONS // extension point + " with id=" + applicationToRun; // application identifier // If the extension does not have the correct grammar, return an error message. // Otherwise, return the application object. IConfigurationElement[] elements = extension.getConfigurationElements(); if (elements.length > 0) { IConfigurationElement[] runs = elements[0].getChildren("run"); //$NON-NLS-1$ if (runs.length > 0) { return runs[0].createExecutableExtension("class"); } } return "Found extension " + Platform.PI_RUNTIME + "." + Platform.PT_APPLICATIONS // extension point + " with id=" + applicationToRun + " but extension does not have the correct <run class=\"...\" grammer"; } /** * COPIED from Eclipse 3.3 UITestApplication * <p> * The -testApplication argument specifies the application to be run. If the PDE JUnit * launcher did not set this argument, then return the name of the default * application. In 3.0, the default is the "org.eclipse.ui.ide.worbench" application. */ private String getApplicationToRun(String[] args) { IProduct product = Platform.getProduct(); if (product != null) return product.getApplication(); for (int i = 0; i < args.length; i++) { if (args[i].equals("-testApplication") && i < args.length - 1) //$NON-NLS-1$ return args[i + 1]; } return "org.eclipse.ui.ide.workbench"; } }