| /******************************************************************************* |
| * Copyright (c) 2004, 2011 BREDEX GmbH. |
| * 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: |
| * BREDEX GmbH - initial API and implementation and/or initial documentation |
| *******************************************************************************/ |
| package org.eclipse.jubula.app.autrun; |
| |
| import java.net.ConnectException; |
| import java.net.InetSocketAddress; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.BrokenBarrierException; |
| import java.util.concurrent.CyclicBarrier; |
| |
| import org.apache.commons.cli.BasicParser; |
| import org.apache.commons.cli.CommandLine; |
| import org.apache.commons.cli.HelpFormatter; |
| import org.apache.commons.cli.Option; |
| import org.apache.commons.cli.OptionBuilder; |
| import org.apache.commons.cli.OptionGroup; |
| import org.apache.commons.cli.Options; |
| import org.apache.commons.cli.ParseException; |
| import org.apache.commons.cli.Parser; |
| import org.apache.commons.lang.StringUtils; |
| import org.eclipse.core.runtime.adaptor.EclipseStarter; |
| import org.eclipse.equinox.app.IApplication; |
| import org.eclipse.equinox.app.IApplicationContext; |
| import org.eclipse.jubula.app.autrun.i18n.Messages; |
| import org.eclipse.jubula.tools.internal.constants.AutConfigConstants; |
| import org.eclipse.jubula.tools.internal.constants.EnvConstants; |
| import org.eclipse.jubula.tools.internal.constants.StringConstants; |
| import org.eclipse.jubula.tools.internal.registration.AutIdentifier; |
| import org.eclipse.jubula.tools.internal.utils.IsAliveThread; |
| import org.eclipse.jubula.tools.internal.utils.TimeUtil; |
| import org.eclipse.jubula.version.Vn; |
| import org.eclipse.osgi.util.NLS; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| |
| /** |
| * Starts an AUT and registers the AUT with an AUT Agent. In order to terminate |
| * at the right time (not too early, not too late) this application assumes |
| * that the following JVM parameters (or equivalent) are used:<ul> |
| * <li>osgi.noShutdown=true</li> |
| * <li>eclipse.jobs.daemon=true</li> |
| * </ul> |
| * These parameters are required because the original application was designed |
| * to run outside of an OSGi context, i.e. the application should end only |
| * when no non-daemon threads are active. |
| * |
| * @author BREDEX GmbH |
| * @created Dec 9, 2009 |
| */ |
| public class AutRunApplication implements IApplication { |
| |
| /** the logger */ |
| private static final Logger LOG = |
| LoggerFactory.getLogger(AutRunApplication.class); |
| |
| /** |
| * <code>LAUNCHER_NAME</code> |
| */ |
| private static final String LAUNCHER_NAME = "autrun"; //$NON-NLS-1$ |
| |
| /** <code>TOOLKIT_RCP</code> */ |
| private static final String TK_RCP = "rcp"; //$NON-NLS-1$ |
| |
| /** <code>TK_SWT</code> */ |
| private static final String TK_SWT = "swt"; //$NON-NLS-1$ |
| |
| /** <code>TK_SWING</code> */ |
| private static final String TK_SWING = "swing"; //$NON-NLS-1$ |
| |
| /** <code>TK_JAVAFX</code> */ |
| private static final String TK_JAVAFX = "javafx"; //$NON-NLS-1$ |
| |
| /** <code>DEFAULT_NAME_TECHNICAL_COMPONENTS</code> */ |
| private static final boolean DEFAULT_NAME_TECHNICAL_COMPONENTS = true; |
| |
| // - Command line options - Start // |
| /** port number for the Aut Agent with which to register */ |
| private static final String OPT_AUT_AGENT_PORT = "p"; //$NON-NLS-1$ |
| |
| /** port number for the Aut Agent with which to register */ |
| private static final String OPT_AUT_AGENT_PORT_LONG = "autagentport"; //$NON-NLS-1$ |
| |
| /** hostname for the Aut Agent with which to register */ |
| private static final String OPT_AUT_AGENT_HOST = "a"; //$NON-NLS-1$ |
| |
| /** hostname for the Aut Agent with which to register */ |
| private static final String OPT_AUT_AGENT_HOST_LONG = "autagenthost"; //$NON-NLS-1$ |
| |
| /** help option */ |
| private static final String OPT_HELP = "h"; //$NON-NLS-1$ |
| |
| /** hostname for the Aut Agent with which to register */ |
| private static final String OPT_HELP_LONG = "help"; //$NON-NLS-1$ |
| |
| /** name of the AUT to register */ |
| private static final String OPT_AUT_ID = "i"; //$NON-NLS-1$ |
| |
| /** name of the AUT to register */ |
| private static final String OPT_AUT_ID_LONG = "autid"; //$NON-NLS-1$ |
| |
| /** flag for name generation for certain technical components */ |
| private static final String OPT_NAME_TECHNICAL_COMPONENTS = "g"; //$NON-NLS-1$ |
| |
| /** flag for name generation for certain technical components */ |
| private static final String OPT_NAME_TECHNICAL_COMPONENTS_LONG = "generatenames"; //$NON-NLS-1$ |
| |
| /** keyboard layout */ |
| private static final String OPT_KEYBOARD_LAYOUT = "k"; //$NON-NLS-1$ |
| |
| /** keyboard layout */ |
| private static final String OPT_KEYBOARD_LAYOUT_LONG = "kblayout"; //$NON-NLS-1$ |
| |
| /** AUT working directory */ |
| private static final String OPT_WORKING_DIR = "w"; //$NON-NLS-1$ |
| |
| /** AUT working directory */ |
| private static final String OPT_WORKING_DIR_LONG = "workingdir"; //$NON-NLS-1$ |
| |
| /** executable file used to start the AUT */ |
| private static final String OPT_EXECUTABLE = "e"; //$NON-NLS-1$ |
| |
| /** executable file used to start the AUT */ |
| private static final String OPT_EXECUTABLE_LONG = "exec"; //$NON-NLS-1$ |
| |
| /** AUT agent host name */ |
| private static final String HOSTNAME = "hostname"; //$NON-NLS-1$ |
| |
| /** AUT agent port */ |
| private static final String PORT = "port"; //$NON-NLS-1$ |
| |
| /** AUT id */ |
| private static final String ID = "id"; //$NON-NLS-1$ |
| |
| /** technical components */ |
| private static final String TRUE_FALSE = "true / false"; //$NON-NLS-1$ |
| |
| /** AUT keyboard layout */ |
| private static final String LOCALE = "locale"; //$NON-NLS-1$ |
| |
| /** AUT working directory */ |
| private static final String DIRECTORY = "directory"; //$NON-NLS-1$ |
| |
| /** AUT options */ |
| private static final String COMMAND = "command"; //$NON-NLS-1$ |
| |
| /** swing class prefix */ |
| private static final String SWING_AUT_TOOLKIT_CLASS_PREFIX = "Swing"; //$NON-NLS-1$ |
| |
| /** SWT class prefix */ |
| private static final String SWT_AUT_TOOLKIT_CLASS_PREFIX = "Swt"; //$NON-NLS-1$ |
| |
| /** RCP class prefix */ |
| private static final String RCP_AUT_TOOLKIT_CLASS_PREFIX = "Rcp"; //$NON-NLS-1$ |
| |
| /** JavaFX class prefix */ |
| private static final String JAVAFX_AUT_TOOLKIT_CLASS_PREFIX = "JavaFX"; //$NON-NLS-1$ |
| // - Command line options - End // |
| |
| /** |
| * prints help options |
| * @param pe a parse Exception - may also be null |
| */ |
| private static void printHelp(ParseException pe) { |
| System.out.println(Vn.getDefault().getVersion()); |
| HelpFormatter formatter = new HelpFormatter(); |
| formatter.setOptionComparator(new OptionComparator()); |
| if (pe != null) { |
| formatter.printHelp( |
| LAUNCHER_NAME, |
| StringConstants.EMPTY, |
| createCmdLineOptions(), |
| "\n" + pe.getLocalizedMessage(), //$NON-NLS-1$ |
| true); |
| } else { |
| formatter.printHelp(LAUNCHER_NAME, |
| createCmdLineOptions(), true); |
| } |
| } |
| |
| /** |
| * Creates and returns settings for starting an AUT based on the given |
| * command line. |
| * |
| * @param cmdLine Provides the settings for the AUT configuration. |
| * @return new settings for starting an AUT. |
| */ |
| private static Map<String, String> createAutConfig(CommandLine cmdLine) { |
| Map<String, String> autConfig = new HashMap<String, String>(); |
| if (cmdLine.hasOption(OPT_WORKING_DIR)) { |
| autConfig.put(AutConfigConstants.WORKING_DIR, cmdLine |
| .getOptionValue(OPT_WORKING_DIR)); |
| } else { |
| autConfig.put(AutConfigConstants.WORKING_DIR, System |
| .getProperty("user.dir")); //$NON-NLS-1$ |
| } |
| |
| if (cmdLine.hasOption(OPT_NAME_TECHNICAL_COMPONENTS)) { |
| autConfig.put(AutConfigConstants.NAME_TECHNICAL_COMPONENTS, String |
| .valueOf(cmdLine.getOptionValue( |
| OPT_NAME_TECHNICAL_COMPONENTS))); |
| } else { |
| autConfig.put(AutConfigConstants.NAME_TECHNICAL_COMPONENTS, |
| String.valueOf(DEFAULT_NAME_TECHNICAL_COMPONENTS)); |
| } |
| autConfig.put(AutConfigConstants.EXECUTABLE, cmdLine |
| .getOptionValue(OPT_EXECUTABLE)); |
| |
| if (cmdLine.hasOption(OPT_KEYBOARD_LAYOUT)) { |
| autConfig.put(AutConfigConstants.KEYBOARD_LAYOUT, |
| cmdLine.getOptionValue(OPT_KEYBOARD_LAYOUT)); |
| } |
| |
| String[] autArguments = cmdLine.getOptionValues(OPT_EXECUTABLE); |
| if (autArguments.length > 1) { |
| autConfig.put(AutConfigConstants.AUT_RUN_AUT_ARGUMENTS, StringUtils |
| .join(autArguments, |
| AutConfigConstants.AUT_RUN_AUT_ARGUMENTS_SEPARATOR_CHAR, 1, |
| autArguments.length)); |
| } |
| |
| return autConfig; |
| } |
| |
| /** |
| * @return the command line options available when invoking the main method. |
| */ |
| private static Options createCmdLineOptions() { |
| Options options = new Options(); |
| Option autAgentHostOption = new Option(OPT_AUT_AGENT_HOST, true, |
| NLS.bind(Messages.infoAutAgentHost, EnvConstants.LOCALHOST_ALIAS)); |
| autAgentHostOption.setLongOpt(OPT_AUT_AGENT_HOST_LONG); |
| autAgentHostOption.setArgName(HOSTNAME); |
| options.addOption(autAgentHostOption); |
| |
| Option autAgentPortOption = new Option(OPT_AUT_AGENT_PORT, true, |
| NLS.bind(Messages.infoAutAgentPort, |
| EnvConstants.AUT_AGENT_DEFAULT_PORT)); |
| autAgentPortOption.setLongOpt(OPT_AUT_AGENT_PORT_LONG); |
| autAgentPortOption.setArgName(PORT); |
| options.addOption(autAgentPortOption); |
| |
| OptionGroup autToolkitOptionGroup = new OptionGroup(); |
| autToolkitOptionGroup.addOption(new Option(TK_SWING, |
| Messages.infoSwingToolkit)); |
| autToolkitOptionGroup.addOption(new Option(TK_SWT, |
| Messages.infoSwtToolkit)); |
| autToolkitOptionGroup.addOption(new Option(TK_RCP, |
| Messages.infoRcpToolkit)); |
| autToolkitOptionGroup.addOption(new Option(TK_JAVAFX, |
| Messages.infoJavaFXToolkit)); |
| autToolkitOptionGroup.setRequired(true); |
| options.addOptionGroup(autToolkitOptionGroup); |
| |
| Option autIdOption = new Option(OPT_AUT_ID, true, Messages.infoAutId); |
| autIdOption.setLongOpt(OPT_AUT_ID_LONG); |
| autIdOption.setArgName(ID); |
| autIdOption.setRequired(true); |
| options.addOption(autIdOption); |
| |
| Option nameTechnicalComponentsOption = new Option( |
| OPT_NAME_TECHNICAL_COMPONENTS, true, |
| Messages.infoGenerateTechnicalComponentNames); |
| nameTechnicalComponentsOption |
| .setLongOpt(OPT_NAME_TECHNICAL_COMPONENTS_LONG); |
| nameTechnicalComponentsOption.setArgName(TRUE_FALSE); |
| options.addOption(nameTechnicalComponentsOption); |
| |
| Option keyboardLayoutOption = new Option(OPT_KEYBOARD_LAYOUT, true, |
| Messages.infoKbLayout); |
| keyboardLayoutOption.setLongOpt(OPT_KEYBOARD_LAYOUT_LONG); |
| keyboardLayoutOption.setArgName(LOCALE); |
| options.addOption(keyboardLayoutOption); |
| |
| Option workingDirOption = new Option(OPT_WORKING_DIR, true, |
| Messages.infoAutWorkingDirectory); |
| workingDirOption.setLongOpt(OPT_WORKING_DIR_LONG); |
| workingDirOption.setArgName(DIRECTORY); |
| options.addOption(workingDirOption); |
| |
| Option helpOption = new Option(OPT_HELP, false, Messages.infoHelp); |
| helpOption.setLongOpt(OPT_HELP_LONG); |
| options.addOption(helpOption); |
| |
| OptionBuilder.hasArgs(); |
| Option autExecutableFileOption = OptionBuilder.create(OPT_EXECUTABLE); |
| autExecutableFileOption.setDescription(Messages.infoExecutableFile); |
| autExecutableFileOption.setLongOpt(OPT_EXECUTABLE_LONG); |
| autExecutableFileOption.setRequired(true); |
| autExecutableFileOption.setArgName(COMMAND); |
| options.addOption(autExecutableFileOption); |
| |
| return options; |
| } |
| |
| /** |
| * @author BREDEX GmbH |
| */ |
| private static final class WatchDog extends Thread { |
| /** |
| * the barrier to await |
| */ |
| private CyclicBarrier m_b; |
| |
| /** |
| * Constructor |
| * |
| * @param name |
| * the name |
| * @param b the barrier to use |
| */ |
| private WatchDog(String name, CyclicBarrier b) { |
| super(name); |
| m_b = b; |
| } |
| |
| /** {@inheritDoc} */ |
| public void run() { |
| try { |
| boolean shouldShutdown; |
| do { |
| TimeUtil.delay(2500); |
| shouldShutdown = true; |
| Set<Thread> allThreads = Thread.getAllStackTraces() |
| .keySet(); |
| for (Thread t : allThreads) { |
| if (t instanceof IsAliveThread) { |
| shouldShutdown = false; |
| break; |
| } |
| } |
| } while (!shouldShutdown); |
| } finally { |
| try { |
| m_b.await(); |
| } catch (InterruptedException e) { |
| LOG.error(e.getLocalizedMessage(), e); |
| } catch (BrokenBarrierException e) { |
| LOG.error(e.getLocalizedMessage(), e); |
| } |
| } |
| |
| try { |
| EclipseStarter.shutdown(); |
| } catch (Exception e) { |
| LOG.error(e.getLocalizedMessage(), e); |
| } |
| } |
| } |
| |
| /** |
| * This class implements the <code>Comparator</code> interface for comparing |
| * Options. |
| */ |
| private static class OptionComparator implements Comparator { |
| /** {@inheritDoc} */ |
| public int compare(Object o1, Object o2) { |
| Option opt1 = (Option)o1; |
| Option opt2 = (Option)o2; |
| // always list -exec as last option |
| if (opt1.getOpt().equals(OPT_EXECUTABLE)) { |
| return 1; |
| } |
| if (opt2.getOpt().equals(OPT_EXECUTABLE)) { |
| return -1; |
| } |
| return 0; |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Object start(final IApplicationContext context) throws Exception { |
| String[] args = (String[])context.getArguments().get( |
| IApplicationContext.APPLICATION_ARGS); |
| if (args == null) { |
| args = new String[0]; |
| } |
| Options options = createCmdLineOptions(); |
| Parser parser = new BasicParser(); |
| CommandLine cmdLine = null; |
| try { |
| cmdLine = parser.parse(options, args, false); |
| if (!cmdLine.hasOption(OPT_HELP)) { |
| |
| String toolkit = StringConstants.EMPTY; |
| if (cmdLine.hasOption(TK_SWING)) { |
| toolkit = SWING_AUT_TOOLKIT_CLASS_PREFIX; |
| } else if (cmdLine.hasOption(TK_SWT)) { |
| toolkit = SWT_AUT_TOOLKIT_CLASS_PREFIX; |
| } else if (cmdLine.hasOption(TK_RCP)) { |
| toolkit = RCP_AUT_TOOLKIT_CLASS_PREFIX; |
| } else if (cmdLine.hasOption(TK_JAVAFX)) { |
| toolkit = JAVAFX_AUT_TOOLKIT_CLASS_PREFIX; |
| } |
| |
| int autAgentPort = EnvConstants.AUT_AGENT_DEFAULT_PORT; |
| if (cmdLine.hasOption(OPT_AUT_AGENT_PORT)) { |
| try { |
| autAgentPort = Integer.parseInt(cmdLine |
| .getOptionValue(OPT_AUT_AGENT_PORT)); |
| } catch (NumberFormatException nfe) { |
| // use default |
| } |
| } |
| String autAgentHost = EnvConstants.LOCALHOST_ALIAS; |
| if (cmdLine.hasOption(OPT_AUT_AGENT_HOST)) { |
| autAgentHost = cmdLine.getOptionValue(OPT_AUT_AGENT_HOST); |
| } |
| |
| InetSocketAddress agentAddr = |
| new InetSocketAddress(autAgentHost, autAgentPort); |
| AutIdentifier autId = new AutIdentifier(cmdLine |
| .getOptionValue(OPT_AUT_ID)); |
| |
| Map<String, String> autConfiguration = createAutConfig(cmdLine); |
| |
| AutRunner runner = new AutRunner( |
| toolkit, autId, agentAddr, autConfiguration); |
| try { |
| runner.run(); |
| } catch (ConnectException ce) { |
| LOG.info(Messages.infoConnectionToAutAgentFailed, ce); |
| System.err.println(Messages.infoNonAutAgentConnectionInfo); |
| } |
| } else { |
| printHelp(null); |
| } |
| } catch (ParseException pe) { |
| printHelp(pe); |
| } finally { |
| CyclicBarrier b = new CyclicBarrier(2); |
| Thread watchDog = new WatchDog("http://eclip.se/457600#c8", b); //$NON-NLS-1$ |
| watchDog.setDaemon(true); |
| watchDog.start(); |
| // http://eclip.se/461810: prevent application to quit too early, otherwise framework bundle lookups do not work |
| b.await(); |
| } |
| |
| return IApplication.EXIT_OK; |
| } |
| |
| /** |
| * |
| * {@inheritDoc} |
| */ |
| public void stop() { |
| // no-op |
| } |
| } |