/******************************************************************************* * 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 java.lang.ref.WeakReference; import java.lang.reflect.InvocationTargetException; import org.apache.commons.lang.Validate; import org.eclipse.jubula.communication.internal.ICommand; import org.eclipse.jubula.communication.internal.message.CAPTestMessage; import org.eclipse.jubula.communication.internal.message.CAPTestResponseMessage; import org.eclipse.jubula.communication.internal.message.ChangeAUTModeMessage; import org.eclipse.jubula.communication.internal.message.Message; import org.eclipse.jubula.communication.internal.message.MessageCap; import org.eclipse.jubula.communication.internal.message.MessageParam; import org.eclipse.jubula.rc.common.AUTServer; import org.eclipse.jubula.rc.common.AUTServerConfiguration; import org.eclipse.jubula.rc.common.exception.ComponentNotFoundException; import org.eclipse.jubula.rc.common.exception.EventSupportException; import org.eclipse.jubula.rc.common.exception.ExecutionEvent; import org.eclipse.jubula.rc.common.exception.MethodParamException; import org.eclipse.jubula.rc.common.exception.StepExecutionException; import org.eclipse.jubula.rc.common.exception.StepVerifyFailedException; import org.eclipse.jubula.rc.common.exception.UnsupportedComponentException; import org.eclipse.jubula.rc.common.tester.AbstractUITester; import org.eclipse.jubula.rc.common.tester.WidgetTester; import org.eclipse.jubula.rc.common.tester.adapter.interfaces.IComponent; import org.eclipse.jubula.rc.common.util.Verifier; import org.eclipse.jubula.tools.internal.constants.TimingConstantsServer; import org.eclipse.jubula.tools.internal.i18n.CompSystemI18n; import org.eclipse.jubula.tools.internal.messagehandling.MessageIDs; import org.eclipse.jubula.tools.internal.objects.IComponentIdentifier; import org.eclipse.jubula.tools.internal.objects.event.EventFactory; import org.eclipse.jubula.tools.internal.objects.event.TestErrorEvent; import org.eclipse.jubula.tools.internal.utils.TimeUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class gets an message with ICommand action parameter triples. It invokes * the implementation class and executes the method. Then it creates a * <code>CAPTestResponseMessage</code> and sends it back to the client. The * <code>CAPTestResponseMessage</code> contains an error event only if the * test step fails, due to a problem prior to or during the execution of the * implementation class action method. * @author BREDEX GmbH * @created 02.01.2007 */ public class CapTestCommand implements ICommand { /** The logger */ private static final Logger LOG = LoggerFactory.getLogger( CapTestCommand.class); /** The logger */ private static final Logger CAPLOG = LoggerFactory.getLogger("CAP"); //$NON-NLS-1$ /** The message. */ private CAPTestMessage m_capTestMessage; /** * {@inheritDoc} */ public Message getMessage() { return m_capTestMessage; } /** * {@inheritDoc} */ public void setMessage(Message message) { m_capTestMessage = (CAPTestMessage)message; } /** * Is called if the graphics component cannot be found. Logs the error and * sets the action error event into the message. * @param response The response message * @param e The exception. */ private void handleComponentNotFound(CAPTestResponseMessage response, Throwable e) { if (LOG.isWarnEnabled()) { LOG.warn(e.getLocalizedMessage(), e); } response.setTestErrorEvent(EventFactory .createComponentNotFoundErrorEvent()); } /** * Is called if one or more CAP parameters are invalid. Logs the error and * sets the action error event into the message. * @param e The error message. */ private void handleInvalidInput(String e) { throw new StepExecutionException(e, EventFactory .createImplClassErrorEvent()); } /** * Gets the implementation class. * @param response The response message. * @return the implementation class or null if an error occurs. */ protected Object getImplClass(CAPTestResponseMessage response) { Object implClass = null; final MessageCap messageCap = m_capTestMessage.getMessageCap(); IComponentIdentifier ci = messageCap.getCi(); if (LOG.isInfoEnabled()) { LOG.info("component class name: " //$NON-NLS-1$ + (ci == null ? "(none)" : ci.getComponentClassName())); //$NON-NLS-1$ } try { if (!messageCap.hasDefaultMapping()) { Validate.notNull(ci); } int timeout = 0; // FIXME : Extra handling for waitForComponent and verifyExists boolean isWaitForComponent = WidgetTester.RC_METHOD_NAME_WAIT_FOR_COMPONENT .equals(messageCap.getMethod()); boolean isCheckExistenceComponent = WidgetTester.RC_METHOD_NAME_CHECK_EXISTENCE .equals(messageCap.getMethod()); if (isWaitForComponent) { timeout = getTimeoutParameter(messageCap, 0, TimingConstantsServer.DEFAULT_FIND_COMPONENT_TIMEOUT); } final AUTServerConfiguration rcConfig = AUTServerConfiguration .getInstance(); if (!messageCap.hasDefaultMapping()) { if (isCheckExistenceComponent) { implClass = handleCheckComponentExistenceAction(messageCap, ci, rcConfig); } else { Object component = AUTServer.getInstance().findComponent(ci, timeout); implClass = rcConfig.prepareImplementationClass(component, component.getClass()); if (implClass instanceof AbstractUITester) { saveErrorComponent(((AbstractUITester) implClass) .getComponent()); } } } else { implClass = rcConfig.getImplementationClass(ci .getComponentClassName()); } if (isWaitForComponent) { delayWaitingForComponent(messageCap); } } catch (IllegalArgumentException e) { handleComponentNotFound(response, e); } catch (ComponentNotFoundException e) { if (WidgetTester.RC_METHOD_NAME_CHECK_EXISTENCE .equals(messageCap.getMethod())) { MessageParam isVisibleParam = messageCap.getMessageParams().get(0); handleComponentDoesNotExist(response, Boolean.valueOf(isVisibleParam.getValue()) .booleanValue()); } else { handleComponentNotFound(response, e); } } catch (UnsupportedComponentException buce) { LOG.error(buce.getLocalizedMessage(), buce); response.setTestErrorEvent(EventFactory.createConfigErrorEvent()); } catch (Throwable e) { if (LOG.isErrorEnabled()) { LOG.error(e.getLocalizedMessage(), e); } response.setTestErrorEvent( EventFactory.createImplClassErrorEvent()); } return implClass; } /** * @param componentAdapter the adapter for the component at which the error occured */ private void saveErrorComponent(IComponent componentAdapter) { if (componentAdapter != null) { WeakReference<IComponent> errorCompRef = new WeakReference<IComponent>( componentAdapter); AUTServer.getInstance(). setErrorComponent(errorCompRef); } } /** * Delay action on waiting for component * @param messageCap the CAP message data. */ private void delayWaitingForComponent(final MessageCap messageCap) { MessageParam delayParam = messageCap. getMessageParams().get(1); try { int delay = Integer.parseInt(delayParam.getValue()); TimeUtil.delay(delay); } catch (IllegalArgumentException iae) { handleInvalidInput("Invalid input: " //$NON-NLS-1$ + CompSystemI18n.getString("CompSystem.DelayAfterVisibility") //$NON-NLS-1$ + " must be a non-negative integer."); //$NON-NLS-1$ } } /** * Handle the component exist action. * * @param messageCap * the CAP message data * @param ci * the component identifier * @param rcConfig * AUT server configuration * @return the implementation class or null if an error occurs. * @throws UnsupportedComponentException * when an implementation class is requested, which was not configured * @throws ComponentNotFoundException * when the component not found */ private Object handleCheckComponentExistenceAction( final MessageCap messageCap, IComponentIdentifier ci, final AUTServerConfiguration rcConfig) throws UnsupportedComponentException, ComponentNotFoundException { Object implClass; // Get the expected existence MessageParam isVisibleParam = messageCap.getMessageParams().get(0); boolean shouldBeVisible = Boolean.valueOf(isVisibleParam.getValue()); // Get the timeout parameter int timeout = getTimeoutParameter(messageCap, 1, 0); Object component = null; try { // To check whether the component is disappeared, the timeout is not // used, // because have to know the fact immediately component = AUTServer.getInstance().findComponent(ci, shouldBeVisible ? timeout : 0); if (!shouldBeVisible && component != null) { // This is the case, when the component is still not // disappeared, but it's expected // and to start a poll is necessary if (AUTServer.getInstance().isComponentDisappeared(ci, timeout)) { // This is the case, when the component successfully gone throw new ComponentNotFoundException( "Component disappeared", //$NON-NLS-1$ MessageIDs.E_COMPONENT_NOT_FOUND); } } } catch (ComponentNotFoundException e) { // The searched component is not found, throw exception // manage in common way throw e; } implClass = rcConfig.prepareImplementationClass(component, component.getClass()); return implClass; } /** * * @param messageCap * the CAP message data * @param indexOfParameter * index of the timeout parameter in the message data * @param defaultValue * which will be set, if the message data does not contain * timeout parameter * @return timeout parameter */ private int getTimeoutParameter(final MessageCap messageCap, int indexOfParameter, int defaultValue) { MessageParam timeoutParam = messageCap.getMessageParams() .get(indexOfParameter); int timeout = defaultValue; try { timeout = Integer.parseInt(timeoutParam.getValue()); } catch (NumberFormatException e) { LOG.warn("Error while parsing timeout parameter. " //$NON-NLS-1$ + "Using default value.", e); //$NON-NLS-1$ } return timeout; } /** * Handles the scenario where a component does not exist, but may also * not be expected to exist. * Is called if the graphics component cannot be found and the current * request is attempting to verify the existence/non-existence of that * component. * Sets the status of the response to Verification Error if the component is * expected to exist. Otherwise continues normal operation. * @param response The response message * @param shouldExist <code>True</code> if the component is expected to * exist. Otherwise, <code>false</code>. */ private void handleComponentDoesNotExist(CAPTestResponseMessage response, boolean shouldExist) { try { Verifier.equals(shouldExist, false); } catch (StepVerifyFailedException svfe) { response.setTestErrorEvent(EventFactory.createVerifyFailed( String.valueOf(shouldExist), String.valueOf(false))); } } /** * calls the method of the implementation class per reflection * {@inheritDoc} */ public Message execute() { AUTServer autServer = AUTServer.getInstance(); autServer.setErrorComponent(null); final int oldMode = autServer.getMode(); TestErrorEvent event = null; CAPTestResponseMessage response = new CAPTestResponseMessage(); autServer.setMode(ChangeAUTModeMessage.TESTING); try { MessageCap messageCap = m_capTestMessage.getMessageCap(); response.setMessageCap(messageCap); // get the implementation class Object implClass = getImplClass(response); if (implClass == null) { return response; } MethodInvoker invoker = new MethodInvoker(messageCap); Object returnValue = invoker.invoke(implClass); if (returnValue != null) { response.setReturnValue(String.valueOf(returnValue)); } if ("true".equals(System.getenv("LogExecutedCaps")) //$NON-NLS-1$ //$NON-NLS-2$ && messageCap != null && messageCap.getCi() != null && messageCap.getCi().getComponentClassName() != null && messageCap.getAction() != null && messageCap.getAction().getName() != null) { CAPLOG.debug(messageCap.getCi().getComponentClassName() + " - " //$NON-NLS-1$ + CompSystemI18n.getString( messageCap.getAction().getName())); } } catch (NoSuchMethodException nsme) { LOG.error("implementation class method not found", nsme); //$NON-NLS-1$ event = EventFactory.createUnsupportedActionError(); } catch (IllegalAccessException iae) { LOG.error("Failed accessing implementation class method", iae); //$NON-NLS-1$ event = EventFactory.createConfigErrorEvent(); } catch (InvocationTargetException ite) { if (ite.getTargetException() instanceof EventSupportException) { EventSupportException e = (EventSupportException) ite.getTargetException(); event = e.getEvent(); if (LOG.isDebugEnabled()) { LOG.debug(e.getLocalizedMessage(), e); } } else if (ite.getTargetException() instanceof ExecutionEvent) { ExecutionEvent e = (ExecutionEvent)ite.getTargetException(); response.setState(e.getEvent()); if (LOG.isDebugEnabled()) { LOG.debug(e.getLocalizedMessage(), e); } } else { event = EventFactory.createConfigErrorEvent(); if (LOG.isErrorEnabled()) { LOG.error("InvocationTargetException: ", ite); //$NON-NLS-1$ LOG.error("TargetException: ", ite.getTargetException()); //$NON-NLS-1$ } } } catch (IllegalArgumentException e) { LOG.error(e.getLocalizedMessage(), e); } catch (MethodParamException ex) { LOG.error(ex.getLocalizedMessage(), ex); } finally { autServer.setMode(oldMode); } if (event != null) { response.setTestErrorEvent(event); } return response; } /** * {@inheritDoc} */ public void timeout() { LOG.error(this.getClass().getName() + "timeout() called"); //$NON-NLS-1$ } }