com.eviware.soapui.impl.wsdl.monitor.SoapMonitor.java Source code

Java tutorial

Introduction

Here is the source code for com.eviware.soapui.impl.wsdl.monitor.SoapMonitor.java

Source

/*
 *  soapUI, copyright (C) 2004-2012 smartbear.com 
 *
 *  soapUI is free software; you can redistribute it and/or modify it under the 
 *  terms of version 2.1 of the GNU Lesser General Public License as published by 
 *  the Free Software Foundation.
 *
 *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
 *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 *  See the GNU Lesser General Public License for more details at gnu.org.
 */

package com.eviware.soapui.impl.wsdl.monitor;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;

import org.apache.commons.collections.list.TreeList;
import org.apache.http.HttpRequest;
import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.decorator.Filter;
import org.jdesktop.swingx.decorator.FilterPipeline;
import org.jdesktop.swingx.decorator.PatternFilter;

import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.support.AbstractInterface;
import com.eviware.soapui.impl.wsdl.WsdlInterface;
import com.eviware.soapui.impl.wsdl.WsdlProject;
import com.eviware.soapui.impl.wsdl.WsdlRequest;
import com.eviware.soapui.impl.wsdl.WsdlTestSuite;
import com.eviware.soapui.impl.wsdl.actions.monitor.SoapMonitorAction;
import com.eviware.soapui.impl.wsdl.actions.monitor.SoapMonitorAction.LaunchForm;
import com.eviware.soapui.impl.wsdl.mock.WsdlMockOperation;
import com.eviware.soapui.impl.wsdl.mock.WsdlMockResponse;
import com.eviware.soapui.impl.wsdl.mock.WsdlMockService;
import com.eviware.soapui.impl.wsdl.support.HelpUrls;
import com.eviware.soapui.impl.wsdl.support.MessageExchangeModelItem;
import com.eviware.soapui.impl.wsdl.support.MessageExchangeRequestMessageEditor;
import com.eviware.soapui.impl.wsdl.support.MessageExchangeResponseMessageEditor;
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
import com.eviware.soapui.impl.wsdl.teststeps.HttpTestRequest;
import com.eviware.soapui.impl.wsdl.teststeps.HttpTestRequestStep;
import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequest;
import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep;
import com.eviware.soapui.impl.wsdl.teststeps.registry.HttpRequestStepFactory;
import com.eviware.soapui.impl.wsdl.teststeps.registry.WsdlTestRequestStepFactory;
import com.eviware.soapui.model.iface.Attachment;
import com.eviware.soapui.model.iface.Interface;
import com.eviware.soapui.model.settings.Settings;
import com.eviware.soapui.model.support.ModelSupport;
import com.eviware.soapui.model.testsuite.TestSuite;
import com.eviware.soapui.settings.ProxySettings;
import com.eviware.soapui.support.DateUtil;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.components.BrowserComponent;
import com.eviware.soapui.support.components.JComponentInspector;
import com.eviware.soapui.support.components.JInspectorPanel;
import com.eviware.soapui.support.components.JInspectorPanelFactory;
import com.eviware.soapui.support.components.JXToolBar;
import com.eviware.soapui.support.types.StringList;
import com.eviware.soapui.support.types.StringToStringsMap;
import com.eviware.x.form.XFormDialog;
import com.eviware.x.form.XFormField;
import com.eviware.x.form.XFormFieldListener;
import com.eviware.x.form.support.ADialogBuilder;
import com.eviware.x.form.support.AField;
import com.eviware.x.form.support.AField.AFieldType;
import com.eviware.x.form.support.AForm;
import com.jgoodies.forms.builder.ButtonBarBuilder;

/**
 * A SOAP Monitor..
 */

@SuppressWarnings("serial")
public class SoapMonitor extends JPanel {
    private static final String ALL_FILTER_OPTION = "- all -";
    private JProgressBar progressBar;
    private JButton stopButton = null;

    private JXTable logTable = null;
    private MonitorLogTableModel tableModel = null;

    private String httpProxyHost = null;
    private int httpProxyPort = 80;

    private JButton startButton;
    private final WsdlProject project;
    private MessageExchangeRequestMessageEditor requestViewer;
    private MessageExchangeResponseMessageEditor responseViewer;
    private SoapUIListenerSupport<MonitorListener> listeners = new SoapUIListenerSupport<MonitorListener>(
            MonitorListener.class);
    private MessageExchangeModelItem requestModelItem;
    private JButton optionsButton;
    private int listenPort;
    private String targetEndpoint;
    private JButton clearButton;
    private int maxRows;
    private JButton addToTestCaseButton;
    // private JButton addToRestTestCaseButton;
    private JButton createRequestButton;
    private JButton addToMockServiceButton;
    private Stack<WsdlMonitorMessageExchange> messageExchangeStack = new Stack<WsdlMonitorMessageExchange>();
    private StackProcessor stackProcessor = new StackProcessor();
    private PatternFilter operationFilter;
    private PatternFilter interfaceFilter;
    private PatternFilter targetHostFilter;
    private JLabel infoLabel;
    private PatternFilter requestHostFilter;
    private JComboBox requestHostFilterCombo;
    private JComboBox targetHostFilterCombo;
    private JComboBox interfaceFilterCombo;
    private JComboBox operationFilterCombo;
    private DefaultComboBoxModel operationFilterModel;
    private DefaultComboBoxModel requestFilterModel;
    private DefaultComboBoxModel targetHostFilterModel;
    private JLabel rowCountLabel = new JLabel();
    private Map<AbstractInterface<?>, String> addedEndpoints;
    private JXToolBar toolbar;
    private String incomingRequestWss;
    private String incomingResponseWss;
    private boolean setAsProxy;
    private XFormDialog optionsDialog;
    private SoapMonitorEngine monitorEngine;
    private String oldProxyHost;
    private String oldProxyPort;
    private boolean oldProxyEnabled;
    private String sslEndpoint;
    private JInspectorPanel inspectorPanel;

    public SoapMonitor(WsdlProject project, int listenPort, String incomingRequestWss, String incomingResponseWss,
            JXToolBar mainToolbar, boolean setAsProxy, String sslEndpoint) {
        super(new BorderLayout());
        this.project = project;
        this.listenPort = listenPort;
        this.incomingRequestWss = incomingRequestWss;
        this.incomingResponseWss = incomingResponseWss;
        this.setAsProxy = setAsProxy;
        this.maxRows = 100;
        this.sslEndpoint = sslEndpoint;

        // set the slow link to the passed down link

        this.setLayout(new BorderLayout());

        add(buildToolbars(mainToolbar), BorderLayout.NORTH);
        add(buildContent(), BorderLayout.CENTER);

        start();
    }

    public SoapMonitor(WsdlProject project, int sourcePort, String incomingRequestWss, String incomingResponseWss,
            JXToolBar toolbar, boolean setAsProxy) {
        this(project, sourcePort, incomingRequestWss, incomingResponseWss, toolbar, setAsProxy, null);
    }

    private JComponent buildContent() {
        inspectorPanel = JInspectorPanelFactory.build(buildLog());

        JComponentInspector<JComponent> viewInspector = new JComponentInspector<JComponent>(buildViewer(),
                "Message Content", "Shows message content", true);
        inspectorPanel.addInspector(viewInspector);

        return inspectorPanel.getComponent();
    }

    private JComponent buildLog() {
        tableModel = new MonitorLogTableModel();
        logTable = new JXTable(1, 2);
        logTable.setColumnControlVisible(true);
        logTable.setModel(tableModel);
        logTable.setHorizontalScrollEnabled(true);
        logTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);

        operationFilter = new PatternFilter(".*", 0, 4);
        operationFilter.setAcceptNull(true);
        interfaceFilter = new PatternFilter(".*", 0, 3);
        interfaceFilter.setAcceptNull(true);
        targetHostFilter = new PatternFilter(".*", 0, 2);
        targetHostFilter.setAcceptNull(true);
        requestHostFilter = new PatternFilter(".*", 0, 1);
        requestHostFilter.setAcceptNull(true);

        Filter[] filters = new Filter[] { requestHostFilter, targetHostFilter, interfaceFilter, operationFilter };

        FilterPipeline pipeline = new FilterPipeline(filters);
        logTable.setFilters(pipeline);

        ListSelectionModel sel = logTable.getSelectionModel();
        sel.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent event) {
                int row = logTable.getSelectedRow();
                if (row == -1) {
                    // requestXmlDocument.setXml( null );
                    // responseXmlDocument.setXml( null );
                    requestModelItem.setMessageExchange(null);
                } else {
                    WsdlMonitorMessageExchange exchange = tableModel.getMessageExchangeAt(row);
                    requestModelItem.setMessageExchange(exchange);
                    // responseModelItem.setMessageExchange( exchange );
                    // requestXmlDocument.setXml( exchange.getRequestContent() );
                    // responseXmlDocument.setXml( exchange.getResponseContent() );
                }

                addToMockServiceButton.setEnabled(row != -1);
                addToTestCaseButton.setEnabled(row != -1);
                // addToRestTestCaseButton.setEnabled( row != -1 );
                createRequestButton.setEnabled(row != -1);
            }
        });

        JPanel tablePane = new JPanel();
        tablePane.setLayout(new BorderLayout());

        toolbar.addGlue();

        tablePane.add(buildFilterBar(), BorderLayout.NORTH);
        tablePane.add(new JScrollPane(logTable), BorderLayout.CENTER);

        return tablePane;
    }

    private JPanel buildFilterBar() {
        requestFilterModel = new DefaultComboBoxModel(new String[] { ALL_FILTER_OPTION });
        targetHostFilterModel = new DefaultComboBoxModel(new String[] { ALL_FILTER_OPTION });
        Dimension comboBoxSize = new Dimension(90, 18);
        requestHostFilterCombo = UISupport.setFixedSize(new JComboBox(requestFilterModel), comboBoxSize);

        // toolbar.addFixed( new JLabel( "<html><b>Filter:</b></html>"));
        // toolbar.addUnrelatedGap();

        ButtonBarBuilder toolbar = new ButtonBarBuilder();

        toolbar.addFixed(new JLabel("Request Host"));
        toolbar.addRelatedGap();
        toolbar.addFixed(requestHostFilterCombo);
        toolbar.addUnrelatedGap();

        requestHostFilterCombo.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                int ix = requestHostFilterCombo.getSelectedIndex();
                if (ix == -1)
                    return;

                requestHostFilter.setAcceptNull(ix == 0);

                if (ix == 0)
                    requestHostFilter.setPattern(".*", 0);
                else
                    requestHostFilter.setPattern(requestHostFilterCombo.getSelectedItem().toString(), 0);

                updateRowCountLabel();
            }
        });

        toolbar.addFixed(new JLabel("Target Host"));
        toolbar.addRelatedGap();
        targetHostFilterCombo = UISupport.setFixedSize(new JComboBox(targetHostFilterModel), comboBoxSize);
        toolbar.addFixed(targetHostFilterCombo);
        toolbar.addUnrelatedGap();

        targetHostFilterCombo.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                int ix = targetHostFilterCombo.getSelectedIndex();
                if (ix == -1)
                    return;

                targetHostFilter.setAcceptNull(ix == 0);

                if (ix == 0)
                    targetHostFilter.setPattern(".*", 0);
                else
                    targetHostFilter.setPattern(targetHostFilterCombo.getSelectedItem().toString(), 0);

                updateRowCountLabel();
            }
        });

        String[] interfaceNames = ModelSupport.getNames(new String[] { ALL_FILTER_OPTION },
                ModelSupport.getChildren(getProject(), WsdlInterface.class));

        toolbar.addFixed(new JLabel("Interface"));
        toolbar.addRelatedGap();
        interfaceFilterCombo = UISupport.setFixedSize(new JComboBox(interfaceNames), comboBoxSize);
        toolbar.addFixed(interfaceFilterCombo);
        toolbar.addUnrelatedGap();

        operationFilterModel = new DefaultComboBoxModel(new String[] { ALL_FILTER_OPTION });
        interfaceFilterCombo.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                String item = (String) interfaceFilterCombo.getSelectedItem();
                operationFilterModel.removeAllElements();

                if (item == null || getProject().getInterfaceByName(item) == null) {
                    operationFilterModel.addElement(ALL_FILTER_OPTION);
                    interfaceFilter.setPattern(".*", 0);
                } else if (getProject().getInterfaceByName(item) != null) {
                    WsdlInterface iface = (WsdlInterface) getProject().getInterfaceByName(item);
                    String[] operationNames = ModelSupport.getNames(new String[] { ALL_FILTER_OPTION },
                            iface.getOperationList());
                    for (String s : operationNames)
                        operationFilterModel.addElement(s);

                    interfaceFilter.setPattern(iface.getName(), 0);
                }
            }
        });

        toolbar.addFixed(new JLabel("Operation"));
        toolbar.addRelatedGap();
        operationFilterCombo = UISupport.setFixedSize(new JComboBox(operationFilterModel), comboBoxSize);
        toolbar.addFixed(operationFilterCombo);

        operationFilterCombo.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                int ix = operationFilterCombo.getSelectedIndex();
                if (ix == -1) {
                    operationFilter.setPattern(".*", 0);
                    updateRowCountLabel();
                    return;
                }

                operationFilter.setAcceptNull(ix == 0);

                if (ix == 0)
                    operationFilter.setPattern(".*", 0);
                else
                    operationFilter.setPattern(operationFilterCombo.getSelectedItem().toString(), 0);

                updateRowCountLabel();
            }
        });

        toolbar.setBorder(BorderFactory.createEmptyBorder(3, 2, 3, 0));
        return toolbar.getPanel();
    }

    protected void updateRowCountLabel() {
        rowCountLabel.setText(logTable.getRowCount() + "/" + tableModel.getRowCount() + " entries");
    }

    private JComponent buildViewer() {
        requestModelItem = new MessageExchangeModelItem("monitor message exchange", null) {

            @Override
            public boolean hasRawData() {
                return true;
            }
        };

        requestViewer = new MessageExchangeRequestMessageEditor(requestModelItem);
        responseViewer = new MessageExchangeResponseMessageEditor(requestModelItem);

        return UISupport.createHorizontalSplit(requestViewer, responseViewer);
    }

    private JComponent buildToolbars(JXToolBar mainToolbar) {
        toolbar = UISupport.createSmallToolbar();
        mainToolbar.addFixed(
                startButton = UISupport.createToolbarButton(UISupport.createImageIcon("/run_testcase.gif")));
        mainToolbar.addFixed(
                stopButton = UISupport.createToolbarButton(UISupport.createImageIcon("/stop_testcase.gif")));
        mainToolbar.addFixed(optionsButton = UISupport.createToolbarButton(new SoapMonitorOptionsAction()));

        toolbar.addFixed(
                createRequestButton = UISupport.createToolbarButton(UISupport.createImageIcon("/request.gif")));
        toolbar.addFixed(
                addToTestCaseButton = UISupport.createToolbarButton(UISupport.createImageIcon("/testCase.gif")));
        // toolbar.addFixed( addToRestTestCaseButton =
        // UISupport.createToolbarButton( UISupport
        // .createImageIcon( "/testCase.gif" ) ) );
        toolbar.addFixed(addToMockServiceButton = UISupport
                .createToolbarButton(UISupport.createImageIcon("/mockService.gif")));
        toolbar.addFixed(
                clearButton = UISupport.createToolbarButton(UISupport.createImageIcon("/clear_loadtest.gif")));

        startButton.setToolTipText("Starts the HTTP Monitor as configured");
        stopButton.setToolTipText("Stops the HTTP Monitor");
        optionsButton.setToolTipText("Sets Monitor Options");
        clearButton.setToolTipText("Clear all/selected messages from the log");
        createRequestButton.setToolTipText("Creates requests from selected messages");
        addToTestCaseButton.setToolTipText("Adds selected requests to a TestCase");
        // addToRestTestCaseButton.setToolTipText(
        // "Adds selected REST requests to a TestCase" );
        addToMockServiceButton.setToolTipText("Adds selected reponses to a MockService");

        createRequestButton.setEnabled(false);
        addToMockServiceButton.setEnabled(false);
        addToTestCaseButton.setEnabled(false);
        // addToRestTestCaseButton.setEnabled( false );

        startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                start();
            }
        });

        stopButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                stop();
            }
        });

        clearButton.addActionListener(new ClearAction());
        createRequestButton.addActionListener(new CreateRequestsAction());
        addToTestCaseButton.addActionListener(new AddToTestCaseAction());
        // addToRestTestCaseButton.addActionListener( new
        // AddToRESTTestCaseAction() );
        addToMockServiceButton.addActionListener(new AddToMockServiceAction());

        mainToolbar.addGlue();

        infoLabel = new JLabel();
        infoLabel.setPreferredSize(new Dimension(150, 20));
        infoLabel.setOpaque(false);
        mainToolbar.addFixed(infoLabel);

        progressBar = new JProgressBar();

        JPanel progressBarPanel = UISupport.createProgressBarPanel(progressBar, 2, false);
        progressBarPanel.setPreferredSize(new Dimension(60, 20));

        mainToolbar.addFixed(progressBarPanel);
        return toolbar;
    }

    /**
     * Method start
     */
    public void start() {
        int localPort = getLocalPort();
        // monitorEngine = new TcpMonMonitorEngine();

        monitorEngine = new SoapMonitorEngineImpl();
        ((SoapMonitorEngineImpl) monitorEngine).setSslEndpoint(sslEndpoint);
        monitorEngine.start(this, localPort);

        if (monitorEngine.isRunning()) {
            stopButton.setEnabled(true);
            startButton.setEnabled(false);
            optionsButton.setEnabled(false);
            infoLabel.setText((monitorEngine.isProxy() ? "HTTP Proxy " : "SSL Tunnel ") + "on port " + localPort);
            progressBar.setIndeterminate(true);

            if (setAsProxy) {
                oldProxyHost = SoapUI.getSettings().getString(ProxySettings.HOST, "");
                oldProxyPort = SoapUI.getSettings().getString(ProxySettings.PORT, "");
                oldProxyEnabled = SoapUI.getSettings().getBoolean(ProxySettings.ENABLE_PROXY);

                SoapUI.getSettings().setString(ProxySettings.HOST, "127.0.0.1");
                SoapUI.getSettings().setString(ProxySettings.PORT, String.valueOf(localPort));
                SoapUI.getSettings().setBoolean(ProxySettings.ENABLE_PROXY, true);
                SoapUI.setProxyEnabled(true);
                JToggleButton applyProxyButton = (JToggleButton) SoapUI.getApplyProxyButton();
                if (applyProxyButton != null)
                    applyProxyButton.setIcon(UISupport.createImageIcon(SoapUI.PROXY_ENABLED_ICON));
            }

            SoapUI.log.info("Started HTTP Monitor on local port " + localPort);
        } else {
            stopButton.setEnabled(false);
            startButton.setEnabled(true);
            optionsButton.setEnabled(true);
            infoLabel.setText("Stopped");
            progressBar.setIndeterminate(false);

            SoapUI.log.info("Could not start HTTP Monitor on local port " + localPort);
        }
    }

    /**
     * Method close
     */
    public void close() {
        stop();
    }

    /**
     * Method stop
     */
    public void stop() {
        monitorEngine.stop();
        if (addedEndpoints != null) {
            for (Interface iface : addedEndpoints.keySet())
                iface.removeEndpoint(addedEndpoints.get(iface));

            addedEndpoints.clear();
        }

        stopButton.setEnabled(false);
        startButton.setEnabled(true);
        optionsButton.setEnabled(true);
        progressBar.setIndeterminate(false);
        infoLabel.setText("Stopped");

        if (setAsProxy) {
            SoapUI.getSettings().setString(ProxySettings.HOST, oldProxyHost);
            SoapUI.getSettings().setString(ProxySettings.PORT, oldProxyPort);
            SoapUI.getSettings().setBoolean(ProxySettings.ENABLE_PROXY, oldProxyEnabled);
            SoapUI.setProxyEnabled(oldProxyEnabled);
            JToggleButton applyProxyButton = (JToggleButton) SoapUI.getApplyProxyButton();
            if (applyProxyButton != null) {
                if (oldProxyEnabled) {
                    applyProxyButton.setIcon(UISupport.createImageIcon(SoapUI.PROXY_ENABLED_ICON));
                } else {
                    applyProxyButton.setIcon(UISupport.createImageIcon(SoapUI.PROXY_DISABLED_ICON));
                }
            }
        }
    }

    @AForm(description = "Set options for adding selected requests to a MockService", name = "Add To MockService")
    private final class AddToMockServiceAction implements ActionListener {
        private static final String CREATE_NEW_OPTION = "<Create New>";
        private XFormDialog dialog;

        @AField(name = "Target MockService", description = "The target TestSuite", type = AFieldType.ENUMERATION)
        public final static String MOCKSERVICE = "Target MockService";

        @AField(name = "Open Editor", description = "Open the created MockService", type = AFieldType.BOOLEAN)
        public final static String OPENEDITOR = "Open Editor";

        public void actionPerformed(ActionEvent e) {
            int[] rows = logTable.getSelectedRows();
            if (rows.length == 0)
                return;

            if (dialog == null) {
                dialog = ADialogBuilder.buildDialog(this.getClass());
            }

            String[] testSuiteNames = ModelSupport.getNames(new String[] { CREATE_NEW_OPTION },
                    getProject().getMockServiceList());
            dialog.setOptions(MOCKSERVICE, testSuiteNames);

            if (dialog.show()) {
                int withoutOperation = 0;
                for (int row : rows) {
                    WsdlMonitorMessageExchange me = tableModel.getMessageExchangeAt(row);
                    if (me.getOperation() == null)
                        withoutOperation++;
                }
                if (withoutOperation == rows.length) {
                    UISupport.showInfoMessage("No SOAP requests selected!");
                    return;
                }
                String targetMockServiceName = dialog.getValue(MOCKSERVICE);

                WsdlMockService mockService = getProject().getMockServiceByName(targetMockServiceName);
                if (mockService == null) {
                    targetMockServiceName = ModelSupport.promptForUniqueName("MockService", getProject(), "");
                    if (targetMockServiceName == null)
                        return;

                    mockService = getProject().addNewMockService(targetMockServiceName);
                    mockService.setIncomingWss(incomingResponseWss);
                }

                int cnt = 0;
                for (int row : rows) {
                    WsdlMonitorMessageExchange me = tableModel.getMessageExchangeAt(row);
                    if (me.getOperation() == null)
                        continue;

                    WsdlMockOperation mockOperation = mockService.getMockOperation(me.getOperation());
                    if (mockOperation == null)
                        mockOperation = mockService.addNewMockOperation(me.getOperation());

                    WsdlMockResponse mockResponse = mockOperation.addNewMockResponse("Monitor Response " + (++cnt),
                            false);
                    mockResponse.setResponseContent(me.getResponseContent());

                    Attachment[] requestAttachments = me.getResponseAttachments();
                    if (requestAttachments != null) {
                        for (Attachment attachment : requestAttachments) {
                            mockResponse.addAttachment(attachment);
                        }
                    }
                }

                if (cnt == 0) {
                    UISupport.showInfoMessage("No response messages found");
                } else {
                    UISupport.showInfoMessage("Added " + cnt + " MockResponses to MockService");

                    if (dialog.getBooleanValue(OPENEDITOR))
                        UISupport.selectAndShow(mockService);
                }
            }
        }
    }

    @AForm(description = "Set options for adding selected requests to a TestCase", name = "Add To TestCase")
    private final class AddToTestCaseAction implements ActionListener {
        private static final String CREATE_NEW_OPTION = "<Create New>";
        private XFormDialog dialog;

        @AField(name = "Target TestSuite", description = "The target TestSuite", type = AFieldType.ENUMERATION)
        public final static String TESTSUITE = "Target TestSuite";

        @AField(name = "Target TestCase", description = "The target TestCase for the requests", type = AFieldType.ENUMERATION)
        public final static String TESTCASE = "Target TestCase";

        @AField(name = "Open Editor", description = "Open the created TestCase", type = AFieldType.BOOLEAN)
        public final static String OPENEDITOR = "Open Editor";

        TestSuite testSuite;

        public void actionPerformed(ActionEvent e) {
            int[] rows = logTable.getSelectedRows();
            if (rows.length == 0)
                return;

            if (dialog == null) {
                dialog = ADialogBuilder.buildDialog(this.getClass());
                dialog.getFormField(TESTSUITE).addFormFieldListener(new XFormFieldListener() {
                    public void valueChanged(XFormField sourceField, String newValue, String oldValue) {
                        if (newValue.equals(CREATE_NEW_OPTION)) {
                            dialog.setOptions(TESTCASE, new String[] { CREATE_NEW_OPTION });
                        } else {
                            testSuite = getProject().getTestSuiteByName(newValue);
                            dialog.setOptions(TESTCASE,
                                    testSuite == null ? new String[] { CREATE_NEW_OPTION }
                                            : ModelSupport.getNames(testSuite.getTestCaseList(),
                                                    new String[] { CREATE_NEW_OPTION }));
                        }
                    }
                });
            }

            String[] testSuiteNames = ModelSupport.getNames(new String[] { CREATE_NEW_OPTION },
                    getProject().getTestSuiteList());
            dialog.setOptions(TESTSUITE, testSuiteNames);
            testSuite = getProject().getTestSuiteByName(dialog.getValue(TESTSUITE));
            dialog.setOptions(TESTCASE, testSuite == null ? new String[] { CREATE_NEW_OPTION }
                    : ModelSupport.getNames(testSuite.getTestCaseList(), new String[] { CREATE_NEW_OPTION }));

            if (dialog.show()) {
                String targetTestSuiteName = dialog.getValue(TESTSUITE);
                String targetTestCaseName = dialog.getValue(TESTCASE);

                WsdlTestSuite testSuite = getProject().getTestSuiteByName(targetTestSuiteName);
                if (testSuite == null) {
                    targetTestSuiteName = ModelSupport.promptForUniqueName("TestSuite", getProject(), "");
                    if (targetTestSuiteName == null)
                        return;

                    testSuite = getProject().addNewTestSuite(targetTestSuiteName);
                }

                WsdlTestCase testCase = testSuite.getTestCaseByName(targetTestCaseName);
                if (testCase == null) {
                    targetTestCaseName = ModelSupport.promptForUniqueName("TestCase", testSuite, "");
                    if (targetTestCaseName == null)
                        return;

                    testCase = testSuite.addNewTestCase(targetTestCaseName);
                }

                for (int row : rows) {
                    WsdlMonitorMessageExchange me = tableModel.getMessageExchangeAt(row);
                    if (me.getOperation() != null) {
                        WsdlTestRequestStep test = (WsdlTestRequestStep) testCase
                                .insertTestStep(WsdlTestRequestStepFactory.createConfig(me.getOperation(),
                                        "Monitor Request " + (row + 1)), -1);

                        WsdlTestRequest request = test.getTestRequest();
                        request.setRequestContent(me.getRequestContent());
                        request.setEndpoint(me.getTargetUrl().toString());
                        request.setIncomingWss(incomingRequestWss);

                        Attachment[] requestAttachments = me.getRequestAttachments();
                        if (requestAttachments != null) {
                            for (Attachment attachment : requestAttachments) {
                                request.importAttachment(attachment);
                            }
                        }
                    } else {

                        // if( me.getResponseContentType().contains( "/x-amf" ) )
                        // {
                        // AMFRequestStepFactory httpRequestStepFactory = new
                        // AMFRequestStepFactory();
                        // AMFRequestTestStep test = ( AMFRequestTestStep
                        // )testCase.insertTestStep( httpRequestStepFactory
                        // .createConfig( me, "Monitor Request " + ( row + 1 ) ), -1
                        // );
                        //
                        // AMFRequest request = test.getAMFRequest();
                        // // request.setRequestContent( me.getRequestContent() );
                        // request.setEndpoint( me.getTargetUrl().toString() );
                        // request.setHttpHeaders( me.getRequestHeaders() );
                        //
                        // }
                        // else
                        // {
                        HttpRequestStepFactory httpRequestStepFactory = new HttpRequestStepFactory();
                        HttpTestRequestStep test = (HttpTestRequestStep) testCase.insertTestStep(
                                httpRequestStepFactory.createConfig(me, "Monitor Request " + (row + 1)), -1);

                        test.getTestRequest().setRequestHeaders(excludeHeaders(me.getRequestHeaders()));

                        HttpTestRequest request = (HttpTestRequest) test.getHttpRequest();

                        request.setEndpoint(me.getTargetUrl().toString());
                        // request.setIncomingWss( incomingRequestWss );
                        String existingMediaType = me.getResponseHeaders().get("Content-Type", "");
                        if (!StringUtils.isNullOrEmpty(existingMediaType)) {
                            request.setMediaType(existingMediaType);
                        }
                        if ("application/octet-stream".equals(existingMediaType)
                                || "application/x-amf".equals(existingMediaType)) {
                            request.attachBinaryData(me.getRequestContent().getBytes(), existingMediaType);
                        } else {
                            request.setRequestContent(me.getRequestContent());
                            test.getTestRequest().setRequestContent(me.getRequestContent());
                        }
                        Attachment[] requestAttachments = me.getRequestAttachments();
                        if (requestAttachments != null) {
                            for (Attachment attachment : requestAttachments) {
                                request.importAttachment(attachment);
                            }
                        }
                        // }

                    }
                }

                if (dialog.getBooleanValue(OPENEDITOR))
                    UISupport.selectAndShow(testCase);
            }
        }
    }

    // @AForm( description =
    // "Set options for adding selected REST requests to a TestCase", name =
    // "Add Rest Test Step(s) To TestCase" )
    // // private final class AddToRESTTestCaseAction implements ActionListener
    // {
    // private static final String CREATE_NEW_OPTION = "<Create New>";
    // private XFormDialog dialog;
    //
    // @AField( name = "Target TestSuite", description = "The target TestSuite",
    // type = AFieldType.ENUMERATION )
    // public final static String TESTSUITE = "Target TestSuite";
    //
    // @AField( name = "Target TestCase", description =
    // "The target TestCase for the requests", type = AFieldType.ENUMERATION )
    // public final static String TESTCASE = "Target TestCase";
    //
    // @AField( name = "Open Editor", description = "Open the created TestCase",
    // type = AFieldType.BOOLEAN )
    // public final static String OPENEDITOR = "Open Editor";
    //
    // TestSuite testSuite;
    //
    // public void actionPerformed( ActionEvent e )
    // {
    // int[] rows = logTable.getSelectedRows();
    // if( rows.length == 0 )
    // return;
    //
    // if( dialog == null )
    // {
    // dialog = ADialogBuilder.buildDialog( this.getClass() );
    // dialog.getFormField( TESTSUITE ).addFormFieldListener( new
    // XFormFieldListener()
    // {
    // public void valueChanged( XFormField sourceField, String newValue, String
    // oldValue )
    // {
    // if( newValue.equals( CREATE_NEW_OPTION ) )
    // {
    // dialog.setOptions( TESTCASE, new String[] { CREATE_NEW_OPTION } );
    // }
    // else
    // {
    // testSuite = getProject().getTestSuiteByName( newValue );
    // dialog.setOptions( TESTCASE, testSuite == null ? new String[] {
    // CREATE_NEW_OPTION } : ModelSupport
    // .getNames( testSuite.getTestCaseList(), new String[] { CREATE_NEW_OPTION }
    // ) );
    // }
    // }
    // } );
    // }
    //
    // String[] testSuiteNames = ModelSupport.getNames( new String[] {
    // CREATE_NEW_OPTION }, getProject()
    // .getTestSuiteList() );
    // dialog.setOptions( TESTSUITE, testSuiteNames );
    // testSuite = getProject().getTestSuiteByName( dialog.getValue( TESTSUITE )
    // );
    // dialog.setOptions( TESTCASE, testSuite == null ? new String[] {
    // CREATE_NEW_OPTION } : ModelSupport.getNames(
    // testSuite.getTestCaseList(), new String[] { CREATE_NEW_OPTION } ) );
    //
    // if( dialog.show() )
    // {
    // String targetTestSuiteName = dialog.getValue( TESTSUITE );
    // String targetTestCaseName = dialog.getValue( TESTCASE );
    //
    // WsdlTestSuite testSuite = getProject().getTestSuiteByName(
    // targetTestSuiteName );
    // if( testSuite == null )
    // {
    // targetTestSuiteName = ModelSupport.promptForUniqueName( "TestSuite",
    // getProject(), "" );
    // if( targetTestSuiteName == null )
    // return;
    //
    // testSuite = getProject().addNewTestSuite( targetTestSuiteName );
    // }
    //
    // WsdlTestCase testCase = testSuite.getTestCaseByName( targetTestCaseName );
    // if( testCase == null )
    // {
    // targetTestCaseName = ModelSupport.promptForUniqueName( "TestCase",
    // testSuite, "" );
    // if( targetTestCaseName == null )
    // return;
    //
    // testCase = testSuite.addNewTestCase( targetTestCaseName );
    // }
    //
    // for( int row : rows )
    // {
    // WsdlMonitorMessageExchange me = tableModel.getMessageExchangeAt( row );
    //
    // RestService restService = ( RestService )project.addNewInterface(
    // "Monitor Interface " + ( row + 1 ),
    // RestServiceFactory.REST_TYPE );
    // restService.addEndpoint( me.getTargetUrl().getProtocol()
    // +"://"+me.getTargetUrl().getHost() );
    // restService.setBasePath( me.getTargetUrl().getPath() );
    // ( ( NewRestResourceActionBase )SoapUI.getActionRegistry().getAction(
    // NewRestResourceAction.SOAPUI_ACTION_ID ) ).performAutomatic( restService,
    // me.getTargetUrl() );
    //
    // RestRequestStepFactory restRequestStepFactory = new
    // RestRequestStepFactory();
    // RestTestRequestStep test = ( RestTestRequestStep )testCase.insertTestStep(
    // restRequestStepFactory
    // .createNewTestStep( testCase, "Monitor Request " + ( row + 1 ) ), -1 );
    // test.getTestRequest().setRequestContent( me.getRequestContent() );
    // test.getTestRequest().setRequestHeaders( me.getRequestHeaders() );
    //
    // RestTestRequest request = ( RestTestRequest )test.getHttpRequest();
    // request.setRequestContent( me.getRequestContent() );
    // request.setEndpoint( me.getTargetUrl().toString() );
    //
    // Attachment[] requestAttachments = me.getRequestAttachments();
    // if( requestAttachments != null )
    // {
    // for( Attachment attachment : requestAttachments )
    // {
    // request.importAttachment( attachment );
    // }
    // }
    // }
    //
    // if( dialog.getBooleanValue( OPENEDITOR ) )
    // UISupport.selectAndShow( testCase );
    // }
    // }
    // }

    private final class CreateRequestsAction implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            int[] rows = logTable.getSelectedRows();
            if (rows.length == 0)
                return;

            if (UISupport.confirm("Create " + rows.length + " requests", "Create Request")) {
                int withoutOperation = 0;
                for (int row : rows) {
                    WsdlMonitorMessageExchange me = tableModel.getMessageExchangeAt(row);
                    if (me.getOperation() == null) {
                        withoutOperation++;
                        continue;
                    }

                    WsdlRequest request = me.getOperation().addNewRequest("Monitor Request " + (row + 1));

                    request.setRequestContent(me.getRequestContent());
                    request.setEndpoint(me.getTargetUrl().toString());

                    Attachment[] requestAttachments = me.getRequestAttachments();
                    if (requestAttachments != null) {
                        for (Attachment attachment : requestAttachments) {
                            request.importAttachment(attachment);
                        }
                    }
                }
                if (withoutOperation > 0) {
                    UISupport.showInfoMessage("For " + withoutOperation + "request(s) there are no operations",
                            "Create Request");
                }
            }
        }
    }

    private final class ClearAction implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            if (logTable.getRowCount() == 0)
                return;

            int[] rows = logTable.getSelectedRows();

            if (rows.length == 0) {
                if (UISupport.confirm("Clear monitor log?", "Clear Log"))
                    tableModel.clear();
            } else if (UISupport.confirm("Clear " + rows.length + " rows from monitor log?", "Clear Log")) {
                tableModel.clearRows(rows);
            }
        }
    }

    @SuppressWarnings("unchecked")
    public class MonitorLogTableModel extends AbstractTableModel {
        private List<WsdlMonitorMessageExchange> exchanges = new TreeList();

        public MonitorLogTableModel() {
        }

        public synchronized void clear() {
            int sz = exchanges.size();
            while (exchanges.size() > 0) {
                WsdlMonitorMessageExchange removed = exchanges.remove(0);
                removed.discard();
            }

            fireTableRowsDeleted(0, sz);

            while (requestFilterModel.getSize() > 1)
                requestFilterModel.removeElementAt(1);

            while (targetHostFilterModel.getSize() > 1)
                targetHostFilterModel.removeElementAt(1);

            updateRowCountLabel();
        }

        public synchronized void clearRows(int[] indices) {
            for (int c = indices.length; c > 0; c--) {
                int index = indices[c - 1];
                WsdlMonitorMessageExchange removed = exchanges.remove(logTable.convertRowIndexToModel(index));
                removed.discard();
                fireTableRowsDeleted(index, index);
                updateRowCountLabel();
            }
        }

        public int getColumnCount() {
            return 12;
        }

        public WsdlMonitorMessageExchange getMessageExchangeAt(int tableRow) {
            return exchanges.get(logTable.convertRowIndexToModel(tableRow));
        }

        @Override
        public String getColumnName(int column) {
            switch (column) {
            case 0:
                return "Count.";
            case 1:
                return "Time";
            case 2:
                return "Request Host";
            case 3:
                return "Target Host";
            case 4:
                return "Interface";
            case 5:
                return "Operation";
            case 6:
                return "Time Taken";
            case 7:
                return "Req Sz";
            case 8:
                return "Resp Sz";
            case 9:
                return "Method";
            case 10:
                return "Path";
            case 11:
                return "Content-Type";
            }

            return null;
        }

        public int getRowCount() {
            return exchanges.size();
        }

        public Object getValueAt(int rowIndex, int columnIndex) {
            if (rowIndex < 0 || rowIndex >= exchanges.size())
                return null;

            WsdlMonitorMessageExchange exchange = exchanges.get(rowIndex);
            if (exchange == null)
                return null;

            switch (columnIndex) {
            case 0:
                return rowIndex;
            case 1:
                return DateUtil.formatFull(new Date(exchange.getTimestamp()));
            case 2:
                return exchange.getRequestHost();
            case 3:
                return exchange.getTargetUrl().getHost();
            case 4:
                return exchange.getOperation() == null ? "- unknown -"
                        : exchange.getOperation().getInterface().getName();
            case 5:
                return exchange.getOperation() == null ? "- unknown -" : exchange.getOperation().getName();
            case 6:
                return String.valueOf(exchange.getTimeTaken());
            case 7:
                return String.valueOf(exchange.getRequestContentLength());
            case 8:
                return String.valueOf(exchange.getResponseContentLength());
            case 9:
                return String.valueOf(exchange.getRequestMethod());
            case 10:
                return exchange.getTargetUrl().getPath();
            case 11:
                return String.valueOf(exchange.getResponseContentType());
            }

            return null;
        }

        public synchronized void addMessageExchange(WsdlMonitorMessageExchange exchange) {
            exchanges.add(exchange);
            int size = exchanges.size();
            fireTableRowsInserted(size - 1, size);

            fitSizeToMaxRows();

            String requestHost = exchange.getRequestHost();
            if (requestFilterModel.getIndexOf(requestHost) == -1) {
                requestFilterModel.addElement(requestHost);
            }

            String host = exchange.getTargetUrl().getHost();
            if (targetHostFilterModel.getIndexOf(host) == -1) {
                targetHostFilterModel.addElement(host);
            }

            updateRowCountLabel();
        }

        public void fitSizeToMaxRows() {
            int removeCnt = 0;

            while (exchanges.size() > maxRows) {
                WsdlMonitorMessageExchange removed = exchanges.remove(0);
                removed.discard();
                removeCnt++;
            }

            if (removeCnt > 0) {
                fireTableDataChanged();
                updateRowCountLabel();
            }
        }
    }

    protected String getHttpProxyHost() {
        return httpProxyHost;
    }

    /**
     * excludes proxy headers as well as headers set for excluding in Global
     * Preferences/WebRecordingSettings.EXCLUDED_HEADERS
     * 
     * @param requestHeaders
     * @return
     */
    private StringToStringsMap excludeHeaders(StringToStringsMap requestHeaders) {
        StringToStringsMap stsmap = new StringToStringsMap();
        for (String key : requestHeaders.getKeys()) {
            if (!(key.contains("Proxy") || key.contains("Content")) && !BrowserComponent.isHeaderExcluded(key)) {
                stsmap.add(key, requestHeaders.get(key, ""));
            }
        }
        return stsmap;
    }

    protected void setHttpProxyHost(String proxyHost) {
        httpProxyHost = proxyHost;
    }

    protected int getHttpProxyPort() {
        return httpProxyPort;
    }

    protected void setHttpProxyPort(int proxyPort) {
        httpProxyPort = proxyPort;
    }

    // protected SlowLinkSimulator getSlowLink()
    // {
    // return slowLink;
    // }

    public String getTargetHost() {
        String host = targetEndpoint;

        try {
            URL url = new URL(host);
            return url.getHost();
        } catch (MalformedURLException e) {
            return host;
        }
    }

    public String getTargetEndpoint() {
        return targetEndpoint;
    }

    public int getTargetPort() {
        try {
            URL url = new URL(targetEndpoint);
            return url.getPort() == -1 ? 80 : url.getPort();
        } catch (MalformedURLException e) {
            return 80;
        }
    }

    public int getLocalPort() {
        return listenPort;
    }

    public synchronized void addMessageExchange(WsdlMonitorMessageExchange messageExchange) {
        messageExchangeStack.push(messageExchange);

        if (!stackProcessor.isRunning())
            new Thread(stackProcessor, "SoapMonitor StackProcessor for project [" + getProject().getName() + "]")
                    .start();
    }

    private class StackProcessor implements Runnable {
        private boolean canceled;
        private boolean running;

        public void run() {
            running = true;
            SoapUI.log.info("Started stackprocessor for soapmonitor in project [" + getProject().getName() + "]");
            while (!canceled && messageExchangeStack.size() > 0) {
                WsdlMonitorMessageExchange messageExchange = messageExchangeStack.pop();
                if (messageExchange != null) {
                    processMessage(messageExchange);
                }

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            running = false;
        }

        private synchronized void processMessage(WsdlMonitorMessageExchange messageExchange) {
            messageExchange.prepare(project.getWssContainer().getIncomingWssByName(incomingRequestWss),
                    project.getWssContainer().getIncomingWssByName(incomingResponseWss));

            tableModel.addMessageExchange(messageExchange);

            fireOnMessageExchange(messageExchange);
        }

        @SuppressWarnings("unused")
        public void cancel() {
            canceled = true;
        }

        @SuppressWarnings("unused")
        protected boolean isCanceled() {
            return canceled;
        }

        protected boolean isRunning() {
            return running;
        }
    }

    public MonitorLogTableModel getLogModel() {
        return tableModel;
    }

    public void addSoapMonitorListener(MonitorListener listener) {
        listeners.add(listener);
    }

    public void removeSoapMonitorListener(MonitorListener listener) {
        listeners.remove(listener);
    }

    public WsdlProject getProject() {
        return project;
    }

    public class SoapMonitorOptionsAction extends AbstractAction {

        public SoapMonitorOptionsAction() {
            putValue(SMALL_ICON, UISupport.createImageIcon("/options.gif"));
        }

        public void actionPerformed(ActionEvent e) {
            if (optionsDialog == null) {
                optionsDialog = ADialogBuilder.buildDialog(OptionsForm.class);
            }

            StringList endpoints = new StringList();
            endpoints.add(null);

            for (WsdlInterface iface : ModelSupport.getChildren(getProject(), WsdlInterface.class)) {
                endpoints.addAll(iface.getEndpoints());
            }

            optionsDialog.setIntValue(OptionsForm.PORT, listenPort);
            optionsDialog.setIntValue(OptionsForm.MAXROWS, maxRows);

            optionsDialog.setOptions(OptionsForm.REQUEST_WSS,
                    StringUtils.merge(project.getWssContainer().getIncomingWssNames(), "<none>"));
            optionsDialog.setOptions(OptionsForm.RESPONSE_WSS,
                    StringUtils.merge(project.getWssContainer().getIncomingWssNames(), "<none>"));

            optionsDialog.setValue(OptionsForm.REQUEST_WSS, incomingRequestWss);
            optionsDialog.setValue(OptionsForm.RESPONSE_WSS, incomingResponseWss);
            optionsDialog.setValue(LaunchForm.SET_CONTENT_TYPES, project.getSettings()
                    .getString(LaunchForm.SET_CONTENT_TYPES, SoapMonitorAction.defaultContentTypes()));

            if (optionsDialog.show()) {
                Settings settings = getProject().getSettings();

                settings.setLong(OptionsForm.PORT,
                        listenPort = optionsDialog.getIntValue(OptionsForm.PORT, listenPort));
                settings.setLong(OptionsForm.MAXROWS,
                        maxRows = optionsDialog.getIntValue(OptionsForm.MAXROWS, maxRows));
                settings.setString(LaunchForm.SET_CONTENT_TYPES,
                        optionsDialog.getValue(LaunchForm.SET_CONTENT_TYPES));

                incomingRequestWss = optionsDialog.getValue(OptionsForm.REQUEST_WSS);
                incomingResponseWss = optionsDialog.getValue(OptionsForm.RESPONSE_WSS);

                tableModel.fitSizeToMaxRows();
            }
        }

        @AForm(name = "HTTP Monitor Options", description = "Set options for HTTP Monitor", helpUrl = HelpUrls.SOAPMONITOR_HELP_URL, icon = UISupport.OPTIONS_ICON_PATH)
        private class OptionsForm {
            @AField(description = "The local port to listen on", name = "Port", type = AFieldType.INT)
            public final static String PORT = "Port";

            @AField(description = "The maximum number of exchanges to log", name = "Max Log", type = AFieldType.INT)
            public final static String MAXROWS = "Max Log";

            @AField(description = "The Incoming WSS configuration to use for processing requests", name = "Incoming Request WSS", type = AFieldType.ENUMERATION)
            public final static String REQUEST_WSS = "Incoming Request WSS";

            @AField(description = "The Outgoing WSS configuration to use for processing responses", name = "Incoming Response WSS", type = AFieldType.ENUMERATION)
            public final static String RESPONSE_WSS = "Incoming Response WSS";

            @AField(description = "Content types to monitor", name = "Content types to monitor", type = AFieldType.STRINGAREA)
            public final static String SET_CONTENT_TYPES = "Content types to monitor";
        }
    }

    public void release() {
        requestViewer.release();
        responseViewer.release();

        if (optionsDialog != null) {
            optionsDialog.release();
            optionsDialog = null;
        }

        inspectorPanel.release();
    }

    public boolean isRunning() {
        return monitorEngine.isRunning();
    }

    public void fireOnMessageExchange(WsdlMonitorMessageExchange messageExchange) {
        for (MonitorListener listener : listeners.get()) {
            try {
                listener.onMessageExchange(messageExchange);
            } catch (Throwable t) {
                SoapUI.logError(t);
            }
        }
    }

    public void fireOnRequest(ServletRequest request, ServletResponse response) {
        for (MonitorListener listener : listeners.get()) {
            try {
                listener.onRequest(this, request, response);
            } catch (Throwable t) {
                SoapUI.logError(t);
            }
        }
    }

    public void fireBeforeProxy(ServletRequest request, ServletResponse response, HttpRequest httpRequest) {
        for (MonitorListener listener : listeners.get()) {
            try {
                listener.beforeProxy(this, request, response, httpRequest);
            } catch (Throwable t) {
                SoapUI.logError(t);
            }
        }
    }

    public void fireAfterProxy(ServletRequest request, ServletResponse response, HttpRequest httpRequest,
            WsdlMonitorMessageExchange capturedData) {
        for (MonitorListener listener : listeners.get()) {
            try {
                listener.afterProxy(this, request, response, httpRequest, capturedData);
            } catch (Throwable t) {
                SoapUI.logError(t);
            }
        }
    }

    public static class SoapUIListenerSupport<T extends Object> {
        private Set<T> listeners = new HashSet<T>();
        @SuppressWarnings("unused")
        private final Class<T> listenerClass;

        public SoapUIListenerSupport(Class<T> listenerClass) {
            this.listenerClass = listenerClass;
            listeners.addAll(SoapUI.getListenerRegistry().getListeners(listenerClass));
        }

        public void add(T listener) {
            listeners.add(listener);
        }

        public void remove(T listener) {
            listeners.remove(listener);
        }

        public Collection<T> get() {
            return listeners;
        }
    }

    public MessageExchangeModelItem getRequestModelItem() {
        return requestModelItem;
    }
}