/******************************************************************************* * Copyright (c) 2004, 2010 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.rc.common.commands; import org.eclipse.jubula.communication.internal.Communicator; import org.eclipse.jubula.communication.internal.ICommand; import org.eclipse.jubula.communication.internal.connection.Connection; import org.eclipse.jubula.communication.internal.listener.IErrorHandler; import org.eclipse.jubula.communication.internal.message.CAPTestResponseMessage; import org.eclipse.jubula.communication.internal.message.Message; import org.eclipse.jubula.communication.internal.message.MessageCap; import org.eclipse.jubula.communication.internal.message.MessageHeader; import org.eclipse.jubula.communication.internal.message.PrepareForShutdownMessage; import org.eclipse.jubula.rc.common.AUTServer; import org.eclipse.jubula.tools.internal.constants.AUTServerExitConstants; import org.eclipse.jubula.tools.internal.constants.TimeoutConstants; import org.eclipse.jubula.tools.internal.exception.CommunicationException; import org.eclipse.jubula.tools.internal.objects.ComponentIdentifier; import org.eclipse.jubula.tools.internal.utils.EnvironmentUtils; import org.eclipse.jubula.tools.internal.utils.TimeUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Prepares the AUT and AUT Server for shutdown (i.e. deregisters communication * error listeners). * * @author BREDEX GmbH * @created Mar 23, 2010 */ public class PrepareForShutdownCommand implements ICommand { /** * Name of the variable to override the AUTs termination delay */ public static final String AUT_KEEP_ALIVE_DELAY_VAR = "TEST_AUT_KEEP_ALIVE_DELAY"; //$NON-NLS-1$ /** * the shutdown hook thread */ private static Thread shutdownHookThread = null; /** * @author BREDEX GmbH * Shutdown hook runnable to allow a proper AUT termination */ private static class AUTProperTerminationShutdownHook implements Runnable { /** * to represent an additional delay to use when keeping the AUT alive */ private int m_addDelay; /** * Constructor * * @param addDelay * the additional delay */ public AUTProperTerminationShutdownHook(int addDelay) { setAddDelay(addDelay); } /** {@inheritDoc} */ public void run() { AUTServer autRC = AUTServer.getInstance(); // FIXME improve AUT toolkit handling if (!autRC.isRcpAccessible()) { // send fake message back - say last CAP execution went OK // this is necessary as e.g. in Swing the AUT event thread blocks // and thereby our event confirming until the AUT terminates sendFakeCAPTestReponseMessage(autRC); } Communicator agentCommunicator = autRC.getServerCommunicator(); if (agentCommunicator != null) { agentCommunicator.clearListeners(); } // keep the AUT alive to perform proper AUT termination synchronization long timeToWait = TimeoutConstants.AUT_KEEP_ALIVE_DELAY_DEFAULT; try { String value = EnvironmentUtils .getProcessOrSystemProperty(AUT_KEEP_ALIVE_DELAY_VAR); timeToWait = Long.valueOf(value).longValue(); } catch (NumberFormatException e) { // ignore invalid formatted values and use default instead } TimeUtil.delay(timeToWait + getAddDelay()); } /** * @param autRC * the AUT-Server instance to use */ private void sendFakeCAPTestReponseMessage(AUTServer autRC) { Communicator iteCom = autRC.getCommunicator(); CAPTestResponseMessage fakeMessage = new CAPTestResponseMessage(); MessageCap fakeMessageCap = new MessageCap(); fakeMessageCap.setCi(new ComponentIdentifier()); fakeMessage.setMessageCap(fakeMessageCap); try { iteCom.send(fakeMessage); } catch (CommunicationException e) { // This might also occur if hook has been registered but // AUT terminates without a connection to the ITE e.g. // normal AUT shutdown LOG.error(e.getLocalizedMessage(), e); } } /** * @return the addDelay */ public int getAddDelay() { return m_addDelay; } /** * @param addDelay the addDelay to set */ public void setAddDelay(int addDelay) { m_addDelay = addDelay; } } /** the logger */ private static final Logger LOG = LoggerFactory.getLogger(PrepareForShutdownCommand.class); /** the message */ private PrepareForShutdownMessage m_message; /** * {@inheritDoc} */ public Message execute() { PrepareForShutdownMessage message = m_message; boolean isForce = message.isForce(); if (isForce) { Communicator agentCommunicator = AUTServer.getInstance().getServerCommunicator(); if (agentCommunicator != null) { agentCommunicator.clearListeners(); } Connection autAgentConnection = agentCommunicator.getConnection(); if (shutdownHookThread != null) { Runtime.getRuntime().removeShutdownHook(shutdownHookThread); } if (autAgentConnection != null) { // Add a listener to exit the AUT normally when the connection is // closed autAgentConnection.addErrorHandler(new IErrorHandler() { public void shutDown() { terminate(); } public void sendFailed(MessageHeader header, String msg) { terminate(); } private void terminate() { try { AUTServer.getInstance().shutdown(); } finally { System.exit(AUTServerExitConstants.EXIT_OK); } } }); } } else { if (shutdownHookThread == null) { int addDelay = message.getAdditionalDelay(); shutdownHookThread = new Thread( new AUTProperTerminationShutdownHook(addDelay)); Runtime.getRuntime().addShutdownHook(shutdownHookThread); } } return null; } /** * {@inheritDoc} */ public Message getMessage() { return m_message; } /** * {@inheritDoc} */ public void setMessage(Message message) { m_message = (PrepareForShutdownMessage)message; } /** * {@inheritDoc} */ public void timeout() { LOG.error(this.getClass().getName() + "timeout() called"); //$NON-NLS-1$ } }