org.eclipse.jubula.client.core.ClientTestImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jubula.client.core.ClientTestImpl.java

Source

/*******************************************************************************
 * 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.client.core;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import javax.swing.event.EventListenerList;

import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jubula.client.core.businessprocess.AbstractXMLReportGenerator;
import org.eclipse.jubula.client.core.businessprocess.CompleteXMLReportGenerator;
import org.eclipse.jubula.client.core.businessprocess.ErrorsOnlyXMLReportGenerator;
import org.eclipse.jubula.client.core.businessprocess.FileXMLReportWriter;
import org.eclipse.jubula.client.core.businessprocess.ITestExecutionEventListener;
import org.eclipse.jubula.client.core.businessprocess.IWritableComponentNameMapper;
import org.eclipse.jubula.client.core.businessprocess.ObjectMappingEventDispatcher;
import org.eclipse.jubula.client.core.businessprocess.TestExecution;
import org.eclipse.jubula.client.core.businessprocess.TestExecution.PauseMode;
import org.eclipse.jubula.client.core.businessprocess.TestExecutionEvent;
import org.eclipse.jubula.client.core.businessprocess.TestExecutionEvent.State;
import org.eclipse.jubula.client.core.businessprocess.TestResultBP;
import org.eclipse.jubula.client.core.businessprocess.TestresultSummaryBP;
import org.eclipse.jubula.client.core.commands.CAPRecordedCommand;
import org.eclipse.jubula.client.core.commands.DisconnectFromAutAgentResponseCommand;
import org.eclipse.jubula.client.core.commands.GetAutConfigMapResponseCommand;
import org.eclipse.jubula.client.core.communication.AUTConnection;
import org.eclipse.jubula.client.core.communication.AutAgentConnection;
import org.eclipse.jubula.client.core.communication.BaseConnection;
import org.eclipse.jubula.client.core.communication.UnknownMessageException;
import org.eclipse.jubula.client.core.communication.BaseConnection.NotConnectedException;
import org.eclipse.jubula.client.core.communication.ConnectionException;
import org.eclipse.jubula.client.core.events.AUTEvent;
import org.eclipse.jubula.client.core.events.AUTServerEvent;
import org.eclipse.jubula.client.core.events.AutAgentEvent;
import org.eclipse.jubula.client.core.events.DataEventDispatcher;
import org.eclipse.jubula.client.core.events.IAUTEventListener;
import org.eclipse.jubula.client.core.events.IAUTServerEventListener;
import org.eclipse.jubula.client.core.events.IServerEventListener;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.DataState;
import org.eclipse.jubula.client.core.i18n.Messages;
import org.eclipse.jubula.client.core.model.IAUTConfigPO;
import org.eclipse.jubula.client.core.model.IAUTMainPO;
import org.eclipse.jubula.client.core.model.INodePO;
import org.eclipse.jubula.client.core.model.IRefTestSuitePO;
import org.eclipse.jubula.client.core.model.ISpecTestCasePO;
import org.eclipse.jubula.client.core.model.ITestJobPO;
import org.eclipse.jubula.client.core.model.ITestResult;
import org.eclipse.jubula.client.core.model.ITestResultSummaryPO;
import org.eclipse.jubula.client.core.model.ITestSuitePO;
import org.eclipse.jubula.client.core.model.MonitoringReportPO;
import org.eclipse.jubula.client.core.model.PoMaker;
import org.eclipse.jubula.client.core.model.TestResult;
import org.eclipse.jubula.client.core.model.TestResultNode;
import org.eclipse.jubula.client.core.persistence.GeneralStorage;
import org.eclipse.jubula.client.core.persistence.TestResultPM;
import org.eclipse.jubula.client.core.persistence.TestResultSummaryPM;
import org.eclipse.jubula.communication.ICommand;
import org.eclipse.jubula.communication.message.BuildMonitoringReportMessage;
import org.eclipse.jubula.communication.message.ChangeAUTModeMessage;
import org.eclipse.jubula.communication.message.DisconnectFromAutAgentMessage;
import org.eclipse.jubula.communication.message.GetAutConfigMapMessage;
import org.eclipse.jubula.communication.message.GetMonitoringDataMessage;
import org.eclipse.jubula.communication.message.Message;
import org.eclipse.jubula.communication.message.StartAUTServerMessage;
import org.eclipse.jubula.communication.message.StopAUTServerMessage;
import org.eclipse.jubula.toolkit.common.businessprocess.ToolkitSupportBP;
import org.eclipse.jubula.toolkit.common.exception.ToolkitPluginException;
import org.eclipse.jubula.toolkit.common.monitoring.MonitoringAttribute;
import org.eclipse.jubula.toolkit.common.monitoring.MonitoringRegistry;
import org.eclipse.jubula.toolkit.common.xml.businessprocess.ComponentBuilder;
import org.eclipse.jubula.tools.constants.AutConfigConstants;
import org.eclipse.jubula.tools.constants.EnvConstants;
import org.eclipse.jubula.tools.constants.InputConstants;
import org.eclipse.jubula.tools.constants.MonitoringConstants;
import org.eclipse.jubula.tools.constants.StringConstants;
import org.eclipse.jubula.tools.constants.ToolkitConstants;
import org.eclipse.jubula.tools.exception.CommunicationException;
import org.eclipse.jubula.tools.exception.JBException;
import org.eclipse.jubula.tools.exception.JBVersionException;
import org.eclipse.jubula.tools.messagehandling.MessageIDs;
import org.eclipse.jubula.tools.objects.IMonitoringValue;
import org.eclipse.jubula.tools.registration.AutIdentifier;
import org.eclipse.jubula.tools.utils.MonitoringUtil;
import org.eclipse.jubula.tools.utils.TimeUtil;
import org.eclipse.osgi.util.NLS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class contains methods for starting and stopping a test. It's also holds
 * the listener for AutAgentEvent, AUTServerEvent and AUTEvent.
 * 
 * @author BREDEX GmbH
 * @created 16.07.2004
 */
public class ClientTestImpl implements IClientTest {
    /**
     * <code>TEST_SUITE_EXECUTION_RELATIVE_WORK_AMOUNT</code>
     */
    public static final int TEST_SUITE_EXECUTION_RELATIVE_WORK_AMOUNT = 1000;

    /** the logger */
    private static Logger log = LoggerFactory.getLogger(ClientTestImpl.class);

    /** file extension for XML */
    private static final String XML_FILE_EXT = ".xml"; //$NON-NLS-1$

    /** used in filenames for reports for successful tests */
    private static final String TEST_SUCCESSFUL = "ok"; //$NON-NLS-1$

    /** used in filenames for reports for failed tests */
    private static final String TEST_FAILED = "failed"; //$NON-NLS-1$
    /**
     * timeout for report job, after this time the job will be canceled
     * 1200000ms = 20min
     */
    private static final int BUILD_REPORT_TIMEOUT = 1200000;

    /** timeout for requesting AutConfigMap from Agent */
    private static final int REQUEST_CONFIG_MAP_TIMEOUT = 10000;

    /** A list of listeners for all events*/
    private static EventListenerList eventListenerList = new EventListenerList();

    /**
     * Time of test suite start
     */
    private Date m_testsuiteStartTime = null;

    /**
     * Time of test job start
     */
    private Date m_testjobStartTime = null;

    /**
     * Time of TestEnd
     */
    private Date m_endTime = null;

    /** log style (for example, Complete or Errors only) */
    private String m_logStyle = null;

    /**
     * log path for results
     */
    private String m_logPath = null;

    /** The test result summary */
    private ITestResultSummaryPO m_summary;

    /**
     * <code>m_relevant</code> the relevant flag
     */
    private boolean m_relevant = true;

    /**
     * <code>m_xmlScrennshot</code> the XML screenshot flag
     */
    private boolean m_xmlScrennshot = true;

    /**
     * <code>m_pauseOnError</code>
     */
    private boolean m_pauseOnError = false;

    /**
     * empty default constructor
     */
    public ClientTestImpl() {
        super();
        ComponentBuilder.getInstance().getCompSystem();
    }

    /**
     * {@inheritDoc}
     */
    public void connectToAutAgent(String serverName, String port) {

        try {
            if (!initServerConnection(serverName, port)) {
                // *ServerEvnetListener are already notfied from 
                // initConnections() 
                fireAutAgentStateChanged(new AutAgentEvent(AutAgentEvent.SERVER_CANNOT_CONNECTED));
                return;
            }
        } catch (JBVersionException e) {
            fireAutAgentStateChanged(new AutAgentEvent(AutAgentEvent.VERSION_ERROR));
        }
    }

    /**
     * 
     * {@inheritDoc}
     */
    public void disconnectFromAutAgent() {
        // Send request to aut starter and wait for response
        ICommand command = new DisconnectFromAutAgentResponseCommand();
        Message message = new DisconnectFromAutAgentMessage();
        try {
            AutAgentConnection.getInstance().request(message, command, 10000);
        } catch (NotConnectedException e) {
            // Exceptions thrown from getInstance(): no connections are
            // established, just log
            log.info(Messages.ClosingTheConnectionsFailed, e);
        } catch (CommunicationException e) {
            // Exceptions thrown from getInstance(): no connections are
            // established, just log
            log.info(Messages.ClosingTheConnectionsFailed, e);
        }
    }

    /**
     * {@inheritDoc}
     */
    public void startAut(IAUTMainPO aut, IAUTConfigPO conf, Locale locale) throws ToolkitPluginException {

        final String autToolkit = aut.getToolkit();
        if (!ComponentBuilder.getInstance().getLevelToolkitIds().contains(autToolkit)
                && ToolkitConstants.LEVEL_TOOLKIT.equals(ToolkitSupportBP.getToolkitLevel(autToolkit))) {

            throw new ToolkitPluginException(Messages.ErrorMessageAUT_TOOLKIT_NOT_AVAILABLE);
        }

        try {
            // start the AUTServer
            Map<String, String> autConfigMap = createAutConfigMap(conf);
            StartAUTServerMessage startAUTServerMessage = new StartAUTServerMessage(EnvConstants.LOCALHOST_FQDN,
                    AUTConnection.getInstance().getCommunicator().getLocalPort(), autConfigMap, autToolkit,
                    aut.isGenerateNames());
            startAUTServerMessage.setLocale(locale);
            AutAgentConnection.getInstance().send(startAUTServerMessage);
            if (log.isDebugEnabled()) {
                log.debug(Messages.StartAUTServerMessageSend);
            }
        } catch (NotConnectedException nce) {
            // The AutAgentConnection was closed. This Exception occurs after 
            // initializing the server, so there must be a shutdown(). The 
            // listeners are already notified from the ConnectionListener of
            // the AutAgentConnection, -> just log.
            log.info(nce.getLocalizedMessage(), nce);
        } catch (ConnectionException ce) {
            // This exception is thrown from AutAgentConnection.getInstance(). See comment above.
            log.info(ce.getLocalizedMessage(), ce);
        } catch (CommunicationException cce) {
            log.error(cce.getLocalizedMessage(), cce);
            // message could not send for any reason, close the connections
            try {
                closeConnections();
            } catch (ConnectionException ce) {
                log.error(Messages.ClosingTheConnectionsFailed, ce);
            }
        }
    }

    /**
     * Creates the Map with the autConfig which will be send to the server.
     * @param autConfig the {@link IAUTConfigPO}
     * @return the Map which will be send to the server.
     */
    private Map<String, String> createAutConfigMap(IAUTConfigPO autConfig) {
        final Set<String> autConfigKeys = autConfig.getAutConfigKeys();
        final Map<String, String> mapToSend = new HashMap<String, String>(autConfigKeys.size());
        for (String key : autConfigKeys) {
            String value = autConfig.getValue(key, null);
            mapToSend.put(key, value);
        }

        // exists only if the monitoring agent has been selected in the AUT configuration
        final String monitoringID = mapToSend.get(AutConfigConstants.MONITORING_AGENT_ID);
        // add non-rendered monitoring attributes
        if (!StringUtils.isEmpty(monitoringID)) {

            IConfigurationElement monitoringExtension = MonitoringRegistry.getElement(monitoringID);

            if (monitoringExtension != null) {
                // read all monitoring attributes for the given monitoring id
                List<MonitoringAttribute> attributeList = MonitoringRegistry.getAttributes(monitoringExtension);

                for (MonitoringAttribute monitoringAttribute : attributeList) {
                    if (!monitoringAttribute.isRender()) {
                        mapToSend.put(monitoringAttribute.getId(), monitoringAttribute.getDefaultValue());
                    }
                }
            }
        }

        try {
            mapToSend.put(AutConfigConstants.AUT_AGENT_PORT,
                    String.valueOf(AutAgentConnection.getInstance().getCommunicator().getPort()));
            mapToSend.put(AutConfigConstants.AUT_AGENT_HOST,
                    AutAgentConnection.getInstance().getCommunicator().getHostName());
            mapToSend.put(AutConfigConstants.AUT_NAME, mapToSend.get(AutConfigConstants.AUT_ID));
        } catch (ConnectionException e) {
            log.error(Messages.UnableToAppendAUTAgent);
        }
        return mapToSend;
    }

    /**
     * closes the connections
     * @throws ConnectionException in case of error.
     */
    private void closeConnections() throws ConnectionException {
        AutAgentConnection.getInstance().close();
        AUTConnection.getInstance().close();
    }

    /**
     * {@inheritDoc}
     */
    public void stopAut(AutIdentifier autId) {
        if (log.isInfoEnabled()) {
            log.info(Messages.StoppingTest);
        }
        try {
            AutAgentConnection.getInstance().getCommunicator().send(new StopAUTServerMessage(autId));
        } catch (ConnectionException ce) {
            // Exceptions thrown from getInstance(): no connections are
            // established, just log
            if (log.isInfoEnabled()) {
                log.info(Messages.ClosingTheConnectionsFailed, ce);
            }
        } catch (CommunicationException e) {
            log.error(Messages.ErrorOccurredWhileTryingToStopAUT, e);
        }
        TestExecution te = TestExecution.getInstance();
        ITestSuitePO startedTestSuite = te.getStartedTestSuite();
        if (startedTestSuite != null && startedTestSuite.isStarted()) {
            startedTestSuite.setStarted(false);
        }
        te.setStartedTestSuite(null);
        if (te.getStartedTestSuite() != null && te.getStartedTestSuite().isStarted()) {
            fireEndTestExecution();
        }
    }

    /**
     * 
     * {@inheritDoc}
     */
    public void startObjectMapping(AutIdentifier autId, int mod, int inputCode, int inputType)
            throws ConnectionException, NotConnectedException, CommunicationException {

        log.info(Messages.StartingObjectMapping);
        // put the AUTServer into the mode OBJECT_MAPPING via sending a
        // ChangeAUTModeMessage(OBJECT_MAPPING).

        if (AUTConnection.getInstance().connectToAut(autId, new NullProgressMonitor())) {

            ChangeAUTModeMessage message = new ChangeAUTModeMessage();
            message.setMode(ChangeAUTModeMessage.OBJECT_MAPPING);
            message.setKeyModifier(mod);
            switch (inputType) {
            case InputConstants.TYPE_MOUSE_CLICK:
                message.setMouseButton(inputCode);
                message.setKey(InputConstants.NO_INPUT);
                break;
            case InputConstants.TYPE_KEY_PRESS:
                // fall through
            default:
                message.setKey(inputCode);
                message.setMouseButton(InputConstants.NO_INPUT);
                break;
            }
            AUTConnection.getInstance().send(message);
        }

    }

    /**
     * 
     * {@inheritDoc}
     */
    public void startRecordTestCase(ISpecTestCasePO spec, IWritableComponentNameMapper compNamesMapper,
            int recordCompMod, int recordCompKey, int recordApplMod, int recordApplKey, int checkModeKeyMod,
            int checkModeKey, int checkCompKeyMod, int checkCompKey, boolean dialogOpen,
            SortedSet<String> singleLineTrigger, SortedSet<String> multiLineTrigger, Locale locale) {
        log.info(Messages.StartingRecordModus);
        // put the AUTServer into the mode RECORD_MODE via sending a
        // ChangeAUTModeMessage(RECORD_MODE).
        try {
            ChangeAUTModeMessage message = new ChangeAUTModeMessage();
            message.setMode(ChangeAUTModeMessage.RECORD_MODE);
            message.setKeyModifier(recordCompMod);
            message.setKey(recordCompKey);
            message.setKey2Modifier(recordApplMod);
            message.setKey2(recordApplKey);
            message.setCheckModeKeyModifier(checkModeKeyMod);
            message.setCheckModeKey(checkModeKey);
            message.setCheckCompKeyModifier(checkCompKeyMod);
            message.setCheckCompKey(checkCompKey);
            message.setRecordDialogOpen(dialogOpen);
            message.setSingleLineTrigger(singleLineTrigger);
            message.setMultiLineTrigger(multiLineTrigger);
            message.setToolkit(GeneralStorage.getInstance().getProject().getToolkit());
            ObjectMappingEventDispatcher.setCategoryToCreateIn(null);

            AUTConnection.getInstance().send(message);
            CAPRecordedCommand.setRecSpecTestCase(spec);
            CAPRecordedCommand.setCompNamesMapper(compNamesMapper);
            CAPRecordedCommand.setRecordLocale(locale);
        } catch (UnknownMessageException ume) {
            fireAUTServerStateChanged(new AUTServerEvent(ume.getErrorId()));
        } catch (NotConnectedException nce) {
            log.error(nce.getLocalizedMessage(), nce);
            // HERE: notify the listeners about unsuccessful mode change
        } catch (CommunicationException ce) {
            log.error(ce.getLocalizedMessage(), ce);
            // HERE: notify the listeners about unsuccessful mode change
        }
    }

    /**
     * {@inheritDoc}
     */
    public void resetToTesting() {
        log.info("setting mode to test"); //$NON-NLS-1$
        // stops the object mapping modew by sending a
        // ChangeAUTModeMessage(TESTING) to the AUTServer and then closing the
        // connection to the AUT.
        CAPRecordedCommand.setRecordListener(null);
        try {
            if (AUTConnection.getInstance().isConnected()) {
                try {
                    ChangeAUTModeMessage message = new ChangeAUTModeMessage();
                    message.setMode(ChangeAUTModeMessage.TESTING);
                    AUTConnection.getInstance().send(message);
                } catch (UnknownMessageException ume) {
                    fireAUTServerStateChanged(new AUTServerEvent(ume.getErrorId()));
                } catch (NotConnectedException nce) {
                    log.error(nce.getLocalizedMessage(), nce);
                    // HERE: notify the listeners about unsuccessful mode
                    // change
                } catch (CommunicationException ce) {
                    log.error(ce.getLocalizedMessage(), ce);
                    // HERE: notify the listeners about unsuccessful mode
                    // change
                }
                AUTConnection.getInstance().close();
            }
        } catch (ConnectionException e) {
            log.error("Error occurred while closing connection to AUT.", e); //$NON-NLS-1$
        }
    }

    /**
     * {@inheritDoc}
     */
    public void startTestSuite(final ITestSuitePO execTestSuite, final Locale locale, final AutIdentifier autId,
            final boolean autoScreenshot, final Map<String, String> externalVars, final String noRunOptMode) {
        final String jobName = NLS.bind(Messages.StartWorkingWithTestSuite, execTestSuite.getName());
        Job runningTestSuite = new Job(jobName) {
            protected IStatus run(IProgressMonitor monitor) {
                monitor.beginTask(jobName, TEST_SUITE_EXECUTION_RELATIVE_WORK_AMOUNT);
                TestExecution.getInstance().setStartedTestSuite(execTestSuite);
                execTestSuite.setStarted(true);
                m_testsuiteStartTime = new Date();
                setTestresultSummary(PoMaker.createTestResultSummaryPO());
                TestExecution.getInstance().executeTestSuite(execTestSuite, locale, autId, autoScreenshot,
                        externalVars, getTestresultSummary(), monitor, noRunOptMode);
                if (monitor.isCanceled()) {
                    return Status.CANCEL_STATUS;
                }
                return Status.OK_STATUS;
            }
        };
        runningTestSuite.addJobChangeListener(new JobChangeAdapter() {
            public void done(IJobChangeEvent event) {
                if (event.getResult().matches(IStatus.CANCEL)) {
                    stopTestExecution();
                }
            }
        });
        runningTestSuite.schedule();
    }

    /** {@inheritDoc} */
    public void startTestJob(ITestJobPO testJob, Locale locale, boolean autoScreenshot, String noRunOptMode) {
        TestExecution.getInstance().setStartedTestJob(testJob);
        m_testjobStartTime = new Date();
        try {
            final AtomicBoolean isTestExecutionFailed = new AtomicBoolean(false);
            final AtomicInteger testExecutionMessageId = new AtomicInteger(0);
            final AtomicInteger testExecutionState = new AtomicInteger(0);
            final AtomicBoolean isTestExecutionFinished = new AtomicBoolean(false);
            ITestExecutionEventListener executionListener = new ITestExecutionEventListener() {
                /** {@inheritDoc} */
                public void stateChanged(TestExecutionEvent event) {
                    testExecutionState.set(event.getState().ordinal());
                    if (event.getState() == State.TEST_EXEC_FAILED) {
                        if (event.getException() instanceof JBException) {
                            JBException e = (JBException) event.getException();
                            testExecutionMessageId.set(e.getErrorId());
                        }
                        isTestExecutionFailed.set(true);
                        testExecutionFinished();
                    }
                }

                /** {@inheritDoc} */
                public void endTestExecution() {
                    testExecutionFinished();
                }

                private void testExecutionFinished() {
                    isTestExecutionFinished.set(true);
                    removeTestExecutionEventListener(this);
                }
            };
            List<INodePO> refTestSuiteList = testJob.getUnmodifiableNodeList();
            for (INodePO node : refTestSuiteList) {
                IRefTestSuitePO refTestSuite = (IRefTestSuitePO) node;
                isTestExecutionFailed.set(false);
                isTestExecutionFinished.set(false);
                addTestExecutionEventListener(executionListener);
                AutIdentifier autId = new AutIdentifier(refTestSuite.getTestSuiteAutID());
                startTestSuite(refTestSuite.getTestSuite(), locale, autId, autoScreenshot, null, noRunOptMode);
                while (!isTestExecutionFinished.get()) {
                    TimeUtil.delay(500);
                }
                if (!continueTestJobExecution(testExecutionState, testExecutionMessageId)) {
                    break;
                }
            }
        } finally {
            TestExecution.getInstance().setStartedTestJob(null);
        }
    }

    /**
     * @param testExecutionState the test execution state 
     * @param testExecutionMessageId the test execution message id
     * @return whether the test job execution should be stopped or not
     */
    private boolean continueTestJobExecution(AtomicInteger testExecutionState,
            AtomicInteger testExecutionMessageId) {
        if (testExecutionMessageId.get() == MessageIDs.E_NO_AUT_CONNECTION_ERROR.intValue()) {
            return false;
        }
        if (testExecutionState.get() == State.TEST_EXEC_STOP.ordinal()) {
            return false;
        }
        return true;
    }

    /**
     * {@inheritDoc}
     */
    public void stopTestExecution() {
        fireTestExecutionChanged(new TestExecutionEvent(State.TEST_EXEC_STOP));
        TestExecution.getInstance().stopExecution();
    }

    /**
     * {@inheritDoc}
     */
    public void pauseTestExecution(PauseMode pm) {
        TestExecution.getInstance().pauseExecution(pm);
    }

    /**
     * {@inheritDoc}
     */
    public void addTestEventListener(IAUTEventListener listener) {
        if (log.isInfoEnabled()) {
            log.info(Messages.AddingIAUTEventListener + StringConstants.SPACE + listener.getClass().getName()
                    + StringConstants.COLON + listener.toString());
        }
        eventListenerList.add(IAUTEventListener.class, listener);
    }

    /**
     * 
     * {@inheritDoc}
     */
    public void removeTestEventListener(IAUTEventListener listener) {
        if (log.isInfoEnabled()) {
            log.info(Messages.RemovingIAUTEventListener + StringConstants.SPACE + listener.getClass().getName()
                    + StringConstants.COLON + listener.toString());
        }
        eventListenerList.remove(IAUTEventListener.class, listener);
    }

    /**
     * 
     * {@inheritDoc}
     */
    public void addAutAgentEventListener(IServerEventListener listener) {
        eventListenerList.add(IServerEventListener.class, listener);
    }

    /**
     * 
     * {@inheritDoc}
     */
    public void removeAutAgentEventListener(IServerEventListener listener) {

        eventListenerList.remove(IServerEventListener.class, listener);
    }

    /**
     * 
     * {@inheritDoc}
     */
    public void addAUTServerEventListener(IAUTServerEventListener listener) {
        eventListenerList.add(IAUTServerEventListener.class, listener);
    }

    /**
     * 
     * {@inheritDoc}
     */
    public void removeAUTServerEventListener(IAUTServerEventListener listener) {
        eventListenerList.remove(IAUTServerEventListener.class, listener);
    }

    /**
     * 
     * {@inheritDoc}
     */
    public void addTestExecutionEventListener(ITestExecutionEventListener listener) {
        eventListenerList.add(ITestExecutionEventListener.class, listener);
    }

    /**
     * 
     * {@inheritDoc}
     */
    public void removeTestExecutionEventListener(ITestExecutionEventListener listener) {
        eventListenerList.remove(ITestExecutionEventListener.class, listener);

    }

    /**
     * 
     * {@inheritDoc}
     */
    public void fireAUTStateChanged(AUTEvent event) {
        if (log.isInfoEnabled()) {
            log.info(Messages.FiringAUTStateChanged + StringConstants.COLON + String.valueOf(event.getState()));
        }
        // Guaranteed to return a non-null array
        Object[] listeners = eventListenerList.getListenerList();

        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length - 2; i >= 0; i -= 2) {
            if (listeners[i] == IAUTEventListener.class) {
                ((IAUTEventListener) listeners[i + 1]).stateChanged(event);
            }
        }
    }

    /**
     * 
     * {@inheritDoc}
     */
    public void fireAutAgentStateChanged(AutAgentEvent event) {
        if (log.isInfoEnabled()) {
            log.info(Messages.FiringAUTStateChanged + StringConstants.COLON + String.valueOf(event.getState()));
        }
        // Guaranteed to return a non-null array
        Object[] listeners = eventListenerList.getListenerList();
        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length - 2; i >= 0; i -= 2) {
            if (listeners[i] == IServerEventListener.class) {
                ((IServerEventListener) listeners[i + 1]).stateChanged(event);
            }
        }
    }

    /**
     * 
     * {@inheritDoc}
     */
    public void fireAUTServerStateChanged(AUTServerEvent event) {
        if (log.isInfoEnabled()) {
            log.info(Messages.FiringAUTStateChanged + StringConstants.COLON + String.valueOf(event.getState()));
        }
        // Guaranteed to return a non-null array
        Object[] listeners = eventListenerList.getListenerList();
        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length - 2; i >= 0; i -= 2) {
            if (listeners[i] == IAUTServerEventListener.class) {
                ((IAUTServerEventListener) listeners[i + 1]).stateChanged(event);
            }
        }
    }

    /**
     * 
     * {@inheritDoc}
     */
    public void fireTestExecutionChanged(TestExecutionEvent event) {
        Object[] listeners = eventListenerList.getListenerList();
        for (int i = listeners.length - 2; i >= 0; i -= 2) {
            if (listeners[i] == ITestExecutionEventListener.class) {
                ((ITestExecutionEventListener) listeners[i + 1]).stateChanged(event);
            }
        }
    }

    /**
     * if the execution of a test ends normally the execution data from
     * the profiling agent can be collected. For that, a GetMonitoringDataMessage
     * is send to the AutAgent to collect the data.
     */
    public void getMonitoringData() {
        GetMonitoringDataMessage message = new GetMonitoringDataMessage(
                TestExecution.getInstance().getConnectedAutId().getExecutableName());
        try {
            AutAgentConnection.getInstance().send(message);
        } catch (NotConnectedException nce) {
            log.error(nce.getLocalizedMessage(), nce);
        } catch (CommunicationException ce) {
            log.error(ce.getLocalizedMessage(), ce);
        }

    }

    /**
     * Many Agents are supporting a mechansim to generate reports 
     * from the execution data, 
     */
    public void buildMonitoringReport() {
        BuildMonitoringReportMessage message = new BuildMonitoringReportMessage(
                TestExecution.getInstance().getConnectedAutId().getExecutableName());

        try {
            AutAgentConnection.getInstance().send(message);
        } catch (NotConnectedException nce) {
            log.error(nce.getLocalizedMessage(), nce);
        } catch (CommunicationException ce) {
            log.error(ce.getLocalizedMessage(), ce);
        }

    }

    /** {@inheritDoc} */
    public Map<String, String> requestAutConfigMapFromAgent(String autId) {
        Map<String, String> autConfigMap = null;
        GetAutConfigMapMessage message = new GetAutConfigMapMessage(autId);
        GetAutConfigMapResponseCommand response = new GetAutConfigMapResponseCommand();
        try {
            AutAgentConnection.getInstance().request(message, response, REQUEST_CONFIG_MAP_TIMEOUT);
            final AtomicBoolean timeoutFlag = new AtomicBoolean(true);
            final Timer timerTimeout = new Timer();
            timerTimeout.schedule(new TimerTask() {
                public void run() {
                    timeoutFlag.set(false);
                    timerTimeout.cancel();
                }
            }, REQUEST_CONFIG_MAP_TIMEOUT);
            while (!response.hasReceivedResponse() && timeoutFlag.get()) {
                TimeUtil.delay(200);
                log.info(Messages.WaitingForAutConfigMapFromAgent);
            }
            autConfigMap = response.getAutConfigMap();
        } catch (NotConnectedException nce) {
            log.error(nce.getLocalizedMessage(), nce);
        } catch (CommunicationException ce) {
            log.error(ce.getLocalizedMessage(), ce);
        }
        return autConfigMap;
    }

    /** 
     * {@inheritDoc}
     */
    public void fireEndTestExecution() {
        m_endTime = new Date();
        TestResult result = TestResultBP.getInstance().getResultTestModel();
        if (result != null) {
            createReportJob(result);
        }

        Object[] listeners = eventListenerList.getListenerList();
        for (int i = listeners.length - 2; i >= 0; i -= 2) {
            if (listeners[i] == ITestExecutionEventListener.class) {
                ((ITestExecutionEventListener) listeners[i + 1]).endTestExecution();
            }
        }
    }

    /**
     * creating the job that is building and writing test data to DB. 
     * @param result The test results  
     */
    private void createReportJob(final TestResult result) {
        final AtomicBoolean ab = new AtomicBoolean(false);
        final Job job = new Job(Messages.ClientCollectingInformation) {
            private String m_jobFamily = this.getName();

            public boolean belongsTo(Object family) {
                return m_jobFamily.equals(family);
            }

            protected IStatus run(IProgressMonitor monitor) {
                try {
                    monitor.beginTask(Messages.ClientWritingReportToDB, IProgressMonitor.UNKNOWN);
                    ITestResultSummaryPO summary = writeTestresultToDB(result);
                    if (m_logPath != null) {
                        monitor.beginTask(Messages.ClientWritingReport, IProgressMonitor.UNKNOWN);
                        writeReportToFileSystem(result);
                    }
                    if (isRunningWithMonitoring()) {
                        monitor.setTaskName(Messages.ClientCalculating);
                        getMonitoringData();
                        while (result.getMonitoringValues() == null || result.getMonitoringValues().isEmpty()) {
                            TimeUtil.delay(500);
                            if (result.getMonitoringValues() != null) {
                                break;
                            }
                            if (monitor.isCanceled()) {
                                return Status.CANCEL_STATUS;
                            }
                        }
                        monitor.setTaskName(Messages.ClientBuildingReport);
                        buildMonitoringReport();
                        while (result.getReportData() == null) {
                            TimeUtil.delay(500);
                            if (result.getReportData() == (MonitoringConstants.EMPTY_REPORT)) {
                                break;
                            }
                            if (monitor.isCanceled()) {
                                return Status.CANCEL_STATUS;
                            }
                        }
                        writeMonitoringResults(result);
                    }
                    DataEventDispatcher.getInstance().fireTestresultSummaryChanged(summary, DataState.Added);
                    monitor.done();
                    return Status.OK_STATUS;
                } catch (Throwable t) {
                    // this is due that everything that happens in the job
                    // will otherwise not be logged (like memory Exception)
                    log.error(Messages.ClientWritingReportError, t);
                    return Status.CANCEL_STATUS;
                }
            }
        };
        job.addJobChangeListener(new JobChangeAdapter() {
            public void done(IJobChangeEvent event) {
                ab.set(true);
            }
        });
        final Timer timerTimeout = new Timer();
        timerTimeout.schedule(new TimerTask() {
            public void run() {
                job.cancel();
                timerTimeout.cancel();
            }
        }, BUILD_REPORT_TIMEOUT);
        job.setPriority(Job.LONG);
        job.schedule();
        while (!ab.get()) {
            TimeUtil.delay(200);
        }
    }

    /**
     * writes monitoring results
     * @param result The monitoring results
     */
    public void writeMonitoringResults(TestResult result) {

        ITestResultSummaryPO summary = getTestresultSummary();
        summary.setMonitoringValues(result.getMonitoringValues());

        IMonitoringValue significantValue = findSignificantValue(result.getMonitoringValues());
        if (significantValue == null) {
            summary.setMonitoringValue(null);
        } else {
            summary.setMonitoringValue(significantValue.getValue());
            summary.setMonitoringValueType(significantValue.getType());
        }
        summary.setInternalMonitoringId(result.getMonitoringId());
        if (result.getReportData() == MonitoringConstants.EMPTY_REPORT) {
            summary.setReportWritten(false);
        } else {
            summary.setMonitoringReport(new MonitoringReportPO(result.getReportData()));
            summary.setReportWritten(true);
        }
        TestResultSummaryPM.mergeTestResultSummaryInDB(summary);
        //set the monitoring report in result to null, 
        //so it can be garbage collected
        result.setReportData(null);
    }

    /**
     * find the significant monitoring value
     * @param map The map containing monitoring values
     * @return The MonitoringValue or null if no significant value was set
     */
    public IMonitoringValue findSignificantValue(Map<String, IMonitoringValue> map) {

        for (IMonitoringValue value : map.values()) {
            if (value.isSignificant()) {
                return value;
            }
        }

        return null;
    }

    /**
     * checks if last connected AUT was running with monitoring agent.
     * 
     * @return true if last connected AUT was running with monitoring else false
     */
    private boolean isRunningWithMonitoring() {
        AutIdentifier autID = TestExecution.getInstance().getConnectedAutId();
        if (autID != null) {
            Map<String, String> m = requestAutConfigMapFromAgent(autID.getExecutableName());
            if (m != null) {
                if (MonitoringUtil.shouldAndCanRunWithMonitoring(m)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * @param result
     *            the result to write
     * @return the id of the persisted test result summary
     */
    public ITestResultSummaryPO writeTestresultToDB(TestResult result) {
        ITestResultSummaryPO summary = getTestresultSummary();
        TestresultSummaryBP instance = TestresultSummaryBP.getInstance();
        instance.fillTestResultSummary(result, summary);

        TestResultSummaryPM.storeTestResultSummaryInDB(summary);
        Long summaryId = summary.getId();
        TestResultPM.storeTestResult(instance.createTestResultDetailsSession(result, summaryId));
        return summary;
    }

    /**
     * @param result
     *            the result to write
     */
    public void writeReportToFileSystem(TestResult result) {
        if (result != null && m_logPath != null) {
            AbstractXMLReportGenerator generator = null;
            // Use the appropriate report generator
            // Default is currently Complete
            if (Messages.TestResultViewPreferencePageStyleErrorsOnly.equalsIgnoreCase(m_logStyle)) {

                generator = new ErrorsOnlyXMLReportGenerator(result);
            } else {
                generator = new CompleteXMLReportGenerator(result);
            }
            writeReport(generator);
        }
    }

    /**
     * Writes a report to disk using the given ReportGenerator.
     * 
     * @param generator
     *            generates the XML that will be written to disk.
     */
    private void writeReport(AbstractXMLReportGenerator generator) {
        Document document = generator.generateXmlReport();
        String fileName = createFilename(generator.getTestResult());
        try {
            new FileXMLReportWriter(fileName).write(document);
        } catch (IOException e) {
            log.error(Messages.ClientWritingReportError, e);
        }
    }

    /**
     * @param result The Test Result.
     * @return a suitable filename for the given test result model.
     */
    private String createFilename(ITestResult result) {
        StringBuilder sb = new StringBuilder(m_logPath);
        sb.append(StringConstants.SLASH);
        sb.append(Messages.ExecutionLog);
        sb.append(StringConstants.MINUS);
        sb.append(result.getProjectName());
        sb.append(StringConstants.MINUS);
        TestResultNode testSuiteNode = result.getRootResultNode();
        sb.append(testSuiteNode.getName());
        sb.append(StringConstants.MINUS);

        // Add result of test
        if (testSuiteNode.getStatus() == TestResultNode.SUCCESS) {
            sb.append(TEST_SUCCESSFUL);
        } else {
            sb.append(TEST_FAILED);
        }

        if (new File(sb.toString() + XML_FILE_EXT).exists()) {
            int postfix = 1;
            sb.append(StringConstants.MINUS);
            while (new File(sb.toString() + postfix + XML_FILE_EXT).exists()) {
                postfix++;
            }
            sb.append(postfix);
        }

        return sb.toString();
    }

    /**
     * Initializes the AutAgentConnection and the AUTConnection, in case of an
     * error, the listeners are notified with appropriate ServerEvent.
     * @param serverName The name of the server.
     * @param port The port number.
     * @throws JBVersionException in case of a version error between Client
     * and AutStarter
     * @return false if an error occurs, true otherwise
     */
    private boolean initServerConnection(String serverName, String port) throws JBVersionException {

        try {
            AutAgentConnection.createInstance(serverName, port);
            AutAgentConnection.getInstance().run();
            if (log.isDebugEnabled()) {
                log.debug(Messages.ConnectedToTheServer);
            }
        } catch (ConnectionException ce) {
            log.error(ce.getLocalizedMessage(), ce);
            return false;
        } catch (BaseConnection.AlreadyConnectedException ae) {
            // The connection is already established.
            if (log.isDebugEnabled()) {
                log.debug(ae.getLocalizedMessage(), ae);
            }
            return false;
        }
        return true;
    }

    /**
     * 
     * {@inheritDoc}
     */
    public Date getEndTime() {
        return m_endTime;
    }

    /**
     * 
     * {@inheritDoc}
     */
    public Date getTestsuiteStartTime() {
        return m_testsuiteStartTime;
    }

    /**
     * 
     * {@inheritDoc}
     */
    public Date getTestjobStartTime() {
        return m_testjobStartTime;
    }

    /**
     * 
     * {@inheritDoc}
     */
    public void setLogPath(String logPath) {
        m_logPath = logPath;
    }

    /**
     * 
     * {@inheritDoc}
     */
    public void setLogStyle(String logStyle) {
        m_logStyle = logStyle;
    }

    /**
     * @return the Test Result Summary for the current test execution, or for
     *         the previous test execution if no test is currently running.
     */
    private ITestResultSummaryPO getTestresultSummary() {
        return m_summary;
    }

    /**
     * @param summary The Test Result Summary to set.
     */
    private void setTestresultSummary(ITestResultSummaryPO summary) {
        m_summary = summary;
    }

    /**
     * {@inheritDoc}
     */
    public void setRelevantFlag(boolean relevant) {
        m_relevant = relevant;
    }

    /**
     * {@inheritDoc}
     */
    public boolean isRelevant() {
        return m_relevant;
    }

    /**
     * {@inheritDoc}
     */
    public boolean isPauseTestExecutionOnError() {
        return m_pauseOnError;
    }

    /**
     * {@inheritDoc}
     */
    public void pauseTestExecutionOnError(boolean pauseOnError) {
        m_pauseOnError = pauseOnError;
    }

    /**
     * {@inheritDoc}
     */
    public void setScreenshotXMLFlag(boolean screenshotXml) {
        m_xmlScrennshot = screenshotXml;
    }

    /**
     * {@inheritDoc}
     */
    public boolean isScreenshotForXML() {
        return m_xmlScrennshot;
    }

}