View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2010 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.impl.wsdl.monitor;
14  
15  import java.awt.BorderLayout;
16  import java.awt.Dimension;
17  import java.awt.event.ActionEvent;
18  import java.awt.event.ActionListener;
19  import java.awt.event.ItemEvent;
20  import java.awt.event.ItemListener;
21  import java.net.MalformedURLException;
22  import java.net.URL;
23  import java.text.DateFormat;
24  import java.text.SimpleDateFormat;
25  import java.util.Collection;
26  import java.util.Date;
27  import java.util.HashSet;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Set;
31  import java.util.Stack;
32  
33  import javax.servlet.ServletRequest;
34  import javax.servlet.ServletResponse;
35  import javax.swing.AbstractAction;
36  import javax.swing.BorderFactory;
37  import javax.swing.DefaultComboBoxModel;
38  import javax.swing.JButton;
39  import javax.swing.JComboBox;
40  import javax.swing.JComponent;
41  import javax.swing.JLabel;
42  import javax.swing.JPanel;
43  import javax.swing.JProgressBar;
44  import javax.swing.JScrollPane;
45  import javax.swing.JToggleButton;
46  import javax.swing.ListSelectionModel;
47  import javax.swing.event.ListSelectionEvent;
48  import javax.swing.event.ListSelectionListener;
49  import javax.swing.table.AbstractTableModel;
50  
51  import org.apache.commons.collections.list.TreeList;
52  import org.apache.commons.httpclient.HostConfiguration;
53  import org.apache.commons.httpclient.HttpMethod;
54  import org.jdesktop.swingx.JXTable;
55  import org.jdesktop.swingx.decorator.Filter;
56  import org.jdesktop.swingx.decorator.FilterPipeline;
57  import org.jdesktop.swingx.decorator.PatternFilter;
58  
59  import com.eviware.soapui.SoapUI;
60  import com.eviware.soapui.impl.support.AbstractInterface;
61  import com.eviware.soapui.impl.wsdl.WsdlInterface;
62  import com.eviware.soapui.impl.wsdl.WsdlProject;
63  import com.eviware.soapui.impl.wsdl.WsdlRequest;
64  import com.eviware.soapui.impl.wsdl.WsdlTestSuite;
65  import com.eviware.soapui.impl.wsdl.actions.monitor.SoapMonitorAction;
66  import com.eviware.soapui.impl.wsdl.actions.monitor.SoapMonitorAction.LaunchForm;
67  import com.eviware.soapui.impl.wsdl.mock.WsdlMockOperation;
68  import com.eviware.soapui.impl.wsdl.mock.WsdlMockResponse;
69  import com.eviware.soapui.impl.wsdl.mock.WsdlMockService;
70  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
71  import com.eviware.soapui.impl.wsdl.support.MessageExchangeModelItem;
72  import com.eviware.soapui.impl.wsdl.support.MessageExchangeRequestMessageEditor;
73  import com.eviware.soapui.impl.wsdl.support.MessageExchangeResponseMessageEditor;
74  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
75  import com.eviware.soapui.impl.wsdl.teststeps.HttpTestRequest;
76  import com.eviware.soapui.impl.wsdl.teststeps.HttpTestRequestStep;
77  import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequest;
78  import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep;
79  import com.eviware.soapui.impl.wsdl.teststeps.registry.HttpRequestStepFactory;
80  import com.eviware.soapui.impl.wsdl.teststeps.registry.WsdlTestRequestStepFactory;
81  import com.eviware.soapui.model.iface.Attachment;
82  import com.eviware.soapui.model.iface.Interface;
83  import com.eviware.soapui.model.settings.Settings;
84  import com.eviware.soapui.model.support.ModelSupport;
85  import com.eviware.soapui.model.testsuite.TestSuite;
86  import com.eviware.soapui.settings.ProxySettings;
87  import com.eviware.soapui.settings.WebRecordingSettings;
88  import com.eviware.soapui.support.StringUtils;
89  import com.eviware.soapui.support.UISupport;
90  import com.eviware.soapui.support.components.BrowserComponent;
91  import com.eviware.soapui.support.components.JComponentInspector;
92  import com.eviware.soapui.support.components.JInspectorPanel;
93  import com.eviware.soapui.support.components.JInspectorPanelFactory;
94  import com.eviware.soapui.support.components.JXToolBar;
95  import com.eviware.soapui.support.types.StringList;
96  import com.eviware.soapui.support.types.StringToStringsMap;
97  import com.eviware.x.form.XFormDialog;
98  import com.eviware.x.form.XFormField;
99  import com.eviware.x.form.XFormFieldListener;
100 import com.eviware.x.form.support.ADialogBuilder;
101 import com.eviware.x.form.support.AField;
102 import com.eviware.x.form.support.AForm;
103 import com.eviware.x.form.support.AField.AFieldType;
104 import com.jgoodies.forms.builder.ButtonBarBuilder;
105 
106 /***
107  * A SOAP Monitor..
108  */
109 
110 @SuppressWarnings( "serial" )
111 public class SoapMonitor extends JPanel
112 {
113 	private static final String ALL_FILTER_OPTION = "- all -";
114 	private JProgressBar progressBar;
115 	private JButton stopButton = null;
116 
117 	private JXTable logTable = null;
118 	private MonitorLogTableModel tableModel = null;
119 
120 	private String httpProxyHost = null;
121 	private int httpProxyPort = 80;
122 
123 	private JButton startButton;
124 	private final WsdlProject project;
125 	private MessageExchangeRequestMessageEditor requestViewer;
126 	private MessageExchangeResponseMessageEditor responseViewer;
127 	private SoapUIListenerSupport<MonitorListener> listeners = new SoapUIListenerSupport<MonitorListener>(
128 			MonitorListener.class );
129 	private MessageExchangeModelItem requestModelItem;
130 	private JButton optionsButton;
131 	private int listenPort;
132 	private String targetEndpoint;
133 	private JButton clearButton;
134 	private int maxRows;
135 	private JButton addToTestCaseButton;
136 	// private JButton addToRestTestCaseButton;
137 	private JButton createRequestButton;
138 	private JButton addToMockServiceButton;
139 	private Stack<WsdlMonitorMessageExchange> messageExchangeStack = new Stack<WsdlMonitorMessageExchange>();
140 	private StackProcessor stackProcessor = new StackProcessor();
141 	private PatternFilter operationFilter;
142 	private PatternFilter interfaceFilter;
143 	private PatternFilter targetHostFilter;
144 	private JLabel infoLabel;
145 	private PatternFilter requestHostFilter;
146 	private JComboBox requestHostFilterCombo;
147 	private JComboBox targetHostFilterCombo;
148 	private JComboBox interfaceFilterCombo;
149 	private JComboBox operationFilterCombo;
150 	private DefaultComboBoxModel operationFilterModel;
151 	private DefaultComboBoxModel requestFilterModel;
152 	private DefaultComboBoxModel targetHostFilterModel;
153 	private JLabel rowCountLabel = new JLabel();
154 	private Map<AbstractInterface<?>, String> addedEndpoints;
155 	private JXToolBar toolbar;
156 	private String incomingRequestWss;
157 	private String incomingResponseWss;
158 	private boolean setAsProxy;
159 	private XFormDialog optionsDialog;
160 	private SoapMonitorEngine monitorEngine;
161 	private String oldProxyHost;
162 	private String oldProxyPort;
163 	private boolean oldProxyEnabled;
164 	private String sslEndpoint;
165 	private JInspectorPanel inspectorPanel;
166 
167 	public SoapMonitor( WsdlProject project, int listenPort, String incomingRequestWss, String incomingResponseWss,
168 			JXToolBar mainToolbar, boolean setAsProxy, String sslEndpoint )
169 	{
170 		super( new BorderLayout() );
171 		this.project = project;
172 		this.listenPort = listenPort;
173 		this.incomingRequestWss = incomingRequestWss;
174 		this.incomingResponseWss = incomingResponseWss;
175 		this.setAsProxy = setAsProxy;
176 		this.maxRows = 100;
177 		this.sslEndpoint = sslEndpoint;
178 
179 		// set the slow link to the passed down link
180 
181 		this.setLayout( new BorderLayout() );
182 
183 		add( buildToolbars( mainToolbar ), BorderLayout.NORTH );
184 		add( buildContent(), BorderLayout.CENTER );
185 
186 		start();
187 	}
188 
189 	public SoapMonitor( WsdlProject project, int sourcePort, String incomingRequestWss, String incomingResponseWss,
190 			JXToolBar toolbar, boolean setAsProxy )
191 	{
192 		this( project, sourcePort, incomingRequestWss, incomingResponseWss, toolbar, setAsProxy, null );
193 	}
194 
195 	private JComponent buildContent()
196 	{
197 		inspectorPanel = JInspectorPanelFactory.build( buildLog() );
198 
199 		JComponentInspector<JComponent> viewInspector = new JComponentInspector<JComponent>( buildViewer(),
200 				"Message Content", "Shows message content", true );
201 		inspectorPanel.addInspector( viewInspector );
202 
203 		return inspectorPanel.getComponent();
204 	}
205 
206 	private JComponent buildLog()
207 	{
208 		tableModel = new MonitorLogTableModel();
209 		logTable = new JXTable( 1, 2 );
210 		logTable.setColumnControlVisible( true );
211 		logTable.setModel( tableModel );
212 		logTable.setHorizontalScrollEnabled( true );
213 		logTable.setSelectionMode( ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
214 
215 		operationFilter = new PatternFilter( ".*", 0, 4 );
216 		operationFilter.setAcceptNull( true );
217 		interfaceFilter = new PatternFilter( ".*", 0, 3 );
218 		interfaceFilter.setAcceptNull( true );
219 		targetHostFilter = new PatternFilter( ".*", 0, 2 );
220 		targetHostFilter.setAcceptNull( true );
221 		requestHostFilter = new PatternFilter( ".*", 0, 1 );
222 		requestHostFilter.setAcceptNull( true );
223 
224 		Filter[] filters = new Filter[] { requestHostFilter, targetHostFilter, interfaceFilter, operationFilter };
225 
226 		FilterPipeline pipeline = new FilterPipeline( filters );
227 		logTable.setFilters( pipeline );
228 
229 		ListSelectionModel sel = logTable.getSelectionModel();
230 		sel.addListSelectionListener( new ListSelectionListener()
231 		{
232 			public void valueChanged( ListSelectionEvent event )
233 			{
234 				int row = logTable.getSelectedRow();
235 				if( row == -1 )
236 				{
237 					// requestXmlDocument.setXml( null );
238 					// responseXmlDocument.setXml( null );
239 					requestModelItem.setMessageExchange( null );
240 				}
241 				else
242 				{
243 					WsdlMonitorMessageExchange exchange = tableModel.getMessageExchangeAt( row );
244 					requestModelItem.setMessageExchange( exchange );
245 					// responseModelItem.setMessageExchange( exchange );
246 					// requestXmlDocument.setXml( exchange.getRequestContent() );
247 					// responseXmlDocument.setXml( exchange.getResponseContent() );
248 				}
249 
250 				addToMockServiceButton.setEnabled( row != -1 );
251 				addToTestCaseButton.setEnabled( row != -1 );
252 				// addToRestTestCaseButton.setEnabled( row != -1 );
253 				createRequestButton.setEnabled( row != -1 );
254 			}
255 		} );
256 
257 		JPanel tablePane = new JPanel();
258 		tablePane.setLayout( new BorderLayout() );
259 
260 		toolbar.addGlue();
261 
262 		tablePane.add( buildFilterBar(), BorderLayout.NORTH );
263 		tablePane.add( new JScrollPane( logTable ), BorderLayout.CENTER );
264 
265 		return tablePane;
266 	}
267 
268 	private JPanel buildFilterBar()
269 	{
270 		requestFilterModel = new DefaultComboBoxModel( new String[] { ALL_FILTER_OPTION } );
271 		targetHostFilterModel = new DefaultComboBoxModel( new String[] { ALL_FILTER_OPTION } );
272 		Dimension comboBoxSize = new Dimension( 90, 18 );
273 		requestHostFilterCombo = UISupport.setFixedSize( new JComboBox( requestFilterModel ), comboBoxSize );
274 
275 		// toolbar.addFixed( new JLabel( "<html><b>Filter:</b></html>"));
276 		// toolbar.addUnrelatedGap();
277 
278 		ButtonBarBuilder toolbar = new ButtonBarBuilder();
279 
280 		toolbar.addFixed( new JLabel( "Request Host" ) );
281 		toolbar.addRelatedGap();
282 		toolbar.addFixed( requestHostFilterCombo );
283 		toolbar.addUnrelatedGap();
284 
285 		requestHostFilterCombo.addItemListener( new ItemListener()
286 		{
287 			public void itemStateChanged( ItemEvent e )
288 			{
289 				int ix = requestHostFilterCombo.getSelectedIndex();
290 				if( ix == -1 )
291 					return;
292 
293 				requestHostFilter.setAcceptNull( ix == 0 );
294 
295 				if( ix == 0 )
296 					requestHostFilter.setPattern( ".*", 0 );
297 				else
298 					requestHostFilter.setPattern( requestHostFilterCombo.getSelectedItem().toString(), 0 );
299 
300 				updateRowCountLabel();
301 			}
302 		} );
303 
304 		toolbar.addFixed( new JLabel( "Target Host" ) );
305 		toolbar.addRelatedGap();
306 		targetHostFilterCombo = UISupport.setFixedSize( new JComboBox( targetHostFilterModel ), comboBoxSize );
307 		toolbar.addFixed( targetHostFilterCombo );
308 		toolbar.addUnrelatedGap();
309 
310 		targetHostFilterCombo.addItemListener( new ItemListener()
311 		{
312 			public void itemStateChanged( ItemEvent e )
313 			{
314 				int ix = targetHostFilterCombo.getSelectedIndex();
315 				if( ix == -1 )
316 					return;
317 
318 				targetHostFilter.setAcceptNull( ix == 0 );
319 
320 				if( ix == 0 )
321 					targetHostFilter.setPattern( ".*", 0 );
322 				else
323 					targetHostFilter.setPattern( targetHostFilterCombo.getSelectedItem().toString(), 0 );
324 
325 				updateRowCountLabel();
326 			}
327 		} );
328 
329 		String[] interfaceNames = ModelSupport.getNames( new String[] { ALL_FILTER_OPTION }, ModelSupport.getChildren(
330 				getProject(), WsdlInterface.class ) );
331 
332 		toolbar.addFixed( new JLabel( "Interface" ) );
333 		toolbar.addRelatedGap();
334 		interfaceFilterCombo = UISupport.setFixedSize( new JComboBox( interfaceNames ), comboBoxSize );
335 		toolbar.addFixed( interfaceFilterCombo );
336 		toolbar.addUnrelatedGap();
337 
338 		operationFilterModel = new DefaultComboBoxModel( new String[] { ALL_FILTER_OPTION } );
339 		interfaceFilterCombo.addItemListener( new ItemListener()
340 		{
341 			public void itemStateChanged( ItemEvent e )
342 			{
343 				String item = ( String )interfaceFilterCombo.getSelectedItem();
344 				operationFilterModel.removeAllElements();
345 
346 				if( item == null || getProject().getInterfaceByName( item ) == null )
347 				{
348 					operationFilterModel.addElement( ALL_FILTER_OPTION );
349 					interfaceFilter.setPattern( ".*", 0 );
350 				}
351 				else if( getProject().getInterfaceByName( item ) != null )
352 				{
353 					WsdlInterface iface = ( WsdlInterface )getProject().getInterfaceByName( item );
354 					String[] operationNames = ModelSupport.getNames( new String[] { ALL_FILTER_OPTION }, iface
355 							.getOperationList() );
356 					for( String s : operationNames )
357 						operationFilterModel.addElement( s );
358 
359 					interfaceFilter.setPattern( iface.getName(), 0 );
360 				}
361 			}
362 		} );
363 
364 		toolbar.addFixed( new JLabel( "Operation" ) );
365 		toolbar.addRelatedGap();
366 		operationFilterCombo = UISupport.setFixedSize( new JComboBox( operationFilterModel ), comboBoxSize );
367 		toolbar.addFixed( operationFilterCombo );
368 
369 		operationFilterCombo.addItemListener( new ItemListener()
370 		{
371 			public void itemStateChanged( ItemEvent e )
372 			{
373 				int ix = operationFilterCombo.getSelectedIndex();
374 				if( ix == -1 )
375 				{
376 					operationFilter.setPattern( ".*", 0 );
377 					updateRowCountLabel();
378 					return;
379 				}
380 
381 				operationFilter.setAcceptNull( ix == 0 );
382 
383 				if( ix == 0 )
384 					operationFilter.setPattern( ".*", 0 );
385 				else
386 					operationFilter.setPattern( operationFilterCombo.getSelectedItem().toString(), 0 );
387 
388 				updateRowCountLabel();
389 			}
390 		} );
391 
392 		toolbar.setBorder( BorderFactory.createEmptyBorder( 3, 2, 3, 0 ) );
393 		return toolbar.getPanel();
394 	}
395 
396 	protected void updateRowCountLabel()
397 	{
398 		rowCountLabel.setText( logTable.getRowCount() + "/" + tableModel.getRowCount() + " entries" );
399 	}
400 
401 	private JComponent buildViewer()
402 	{
403 		requestModelItem = new MessageExchangeModelItem( "monitor message exchange", null )
404 		{
405 
406 			@Override
407 			public boolean hasRawData()
408 			{
409 				return true;
410 			}
411 		};
412 
413 		requestViewer = new MessageExchangeRequestMessageEditor( requestModelItem );
414 		responseViewer = new MessageExchangeResponseMessageEditor( requestModelItem );
415 
416 		return UISupport.createHorizontalSplit( requestViewer, responseViewer );
417 	}
418 
419 	private JComponent buildToolbars( JXToolBar mainToolbar )
420 	{
421 		toolbar = UISupport.createSmallToolbar();
422 		mainToolbar.addFixed( startButton = UISupport.createToolbarButton( UISupport
423 				.createImageIcon( "/run_testcase.gif" ) ) );
424 		mainToolbar.addFixed( stopButton = UISupport.createToolbarButton( UISupport
425 				.createImageIcon( "/stop_testcase.gif" ) ) );
426 		mainToolbar.addFixed( optionsButton = UISupport.createToolbarButton( new SoapMonitorOptionsAction() ) );
427 
428 		toolbar.addFixed( createRequestButton = UISupport
429 				.createToolbarButton( UISupport.createImageIcon( "/request.gif" ) ) );
430 		toolbar.addFixed( addToTestCaseButton = UISupport.createToolbarButton( UISupport
431 				.createImageIcon( "/testCase.gif" ) ) );
432 		// toolbar.addFixed( addToRestTestCaseButton =
433 		// UISupport.createToolbarButton( UISupport
434 		// .createImageIcon( "/testCase.gif" ) ) );
435 		toolbar.addFixed( addToMockServiceButton = UISupport.createToolbarButton( UISupport
436 				.createImageIcon( "/mockService.gif" ) ) );
437 		toolbar.addFixed( clearButton = UISupport
438 				.createToolbarButton( UISupport.createImageIcon( "/clear_loadtest.gif" ) ) );
439 
440 		startButton.setToolTipText( "Starts the HTTP Monitor as configured" );
441 		stopButton.setToolTipText( "Stops the HTTP Monitor" );
442 		optionsButton.setToolTipText( "Sets Monitor Options" );
443 		clearButton.setToolTipText( "Clear all/selected messages from the log" );
444 		createRequestButton.setToolTipText( "Creates requests from selected messages" );
445 		addToTestCaseButton.setToolTipText( "Adds selected requests to a TestCase" );
446 		// addToRestTestCaseButton.setToolTipText(
447 		// "Adds selected REST requests to a TestCase" );
448 		addToMockServiceButton.setToolTipText( "Adds selected reponses to a MockService" );
449 
450 		createRequestButton.setEnabled( false );
451 		addToMockServiceButton.setEnabled( false );
452 		addToTestCaseButton.setEnabled( false );
453 		// addToRestTestCaseButton.setEnabled( false );
454 
455 		startButton.addActionListener( new ActionListener()
456 		{
457 			public void actionPerformed( ActionEvent e )
458 			{
459 				start();
460 			}
461 		} );
462 
463 		stopButton.addActionListener( new ActionListener()
464 		{
465 			public void actionPerformed( ActionEvent e )
466 			{
467 				stop();
468 			}
469 		} );
470 
471 		clearButton.addActionListener( new ClearAction() );
472 		createRequestButton.addActionListener( new CreateRequestsAction() );
473 		addToTestCaseButton.addActionListener( new AddToTestCaseAction() );
474 		// addToRestTestCaseButton.addActionListener( new
475 		// AddToRESTTestCaseAction() );
476 		addToMockServiceButton.addActionListener( new AddToMockServiceAction() );
477 
478 		mainToolbar.addGlue();
479 
480 		infoLabel = new JLabel();
481 		infoLabel.setPreferredSize( new Dimension( 150, 20 ) );
482 		infoLabel.setOpaque( false );
483 		mainToolbar.addFixed( infoLabel );
484 
485 		progressBar = new JProgressBar();
486 
487 		JPanel progressBarPanel = UISupport.createProgressBarPanel( progressBar, 2, false );
488 		progressBarPanel.setPreferredSize( new Dimension( 60, 20 ) );
489 
490 		mainToolbar.addFixed( progressBarPanel );
491 		return toolbar;
492 	}
493 
494 	/***
495 	 * Method start
496 	 */
497 	public void start()
498 	{
499 		int localPort = getLocalPort();
500 		// monitorEngine = new TcpMonMonitorEngine();
501 
502 		monitorEngine = new SoapMonitorEngineImpl();
503 		( ( SoapMonitorEngineImpl )monitorEngine ).setSslEndpoint( sslEndpoint );
504 		monitorEngine.start( this, localPort );
505 
506 		if( monitorEngine.isRunning() )
507 		{
508 			stopButton.setEnabled( true );
509 			startButton.setEnabled( false );
510 			optionsButton.setEnabled( false );
511 			infoLabel.setText( ( monitorEngine.isProxy() ? "HTTP Proxy " : "SSL Tunnel " ) + "on port " + localPort );
512 			progressBar.setIndeterminate( true );
513 
514 			if( setAsProxy )
515 			{
516 				oldProxyHost = SoapUI.getSettings().getString( ProxySettings.HOST, "" );
517 				oldProxyPort = SoapUI.getSettings().getString( ProxySettings.PORT, "" );
518 				oldProxyEnabled = SoapUI.getSettings().getBoolean( ProxySettings.ENABLE_PROXY );
519 
520 				SoapUI.getSettings().setString( ProxySettings.HOST, "127.0.0.1" );
521 				SoapUI.getSettings().setString( ProxySettings.PORT, String.valueOf( localPort ) );
522 				SoapUI.getSettings().setBoolean( ProxySettings.ENABLE_PROXY, true );
523 				SoapUI.setProxyEnabled( true );
524 				JToggleButton applyProxyButton = ( JToggleButton )SoapUI.getApplyProxyButton();
525 				if( applyProxyButton != null )
526 					applyProxyButton.setIcon( UISupport.createImageIcon( SoapUI.PROXY_ENABLED_ICON ) );
527 			}
528 
529 			SoapUI.log.info( "Started HTTP Monitor on local port " + localPort );
530 		}
531 		else
532 		{
533 			stopButton.setEnabled( false );
534 			startButton.setEnabled( true );
535 			optionsButton.setEnabled( true );
536 			infoLabel.setText( "Stopped" );
537 			progressBar.setIndeterminate( false );
538 
539 			SoapUI.log.info( "Could not start HTTP Monitor on local port " + localPort );
540 		}
541 	}
542 
543 	/***
544 	 * Method close
545 	 */
546 	public void close()
547 	{
548 		stop();
549 	}
550 
551 	/***
552 	 * Method stop
553 	 */
554 	public void stop()
555 	{
556 		monitorEngine.stop();
557 		if( addedEndpoints != null )
558 		{
559 			for( Interface iface : addedEndpoints.keySet() )
560 				iface.removeEndpoint( addedEndpoints.get( iface ) );
561 
562 			addedEndpoints.clear();
563 		}
564 
565 		stopButton.setEnabled( false );
566 		startButton.setEnabled( true );
567 		optionsButton.setEnabled( true );
568 		progressBar.setIndeterminate( false );
569 		infoLabel.setText( "Stopped" );
570 
571 		if( setAsProxy )
572 		{
573 			SoapUI.getSettings().setString( ProxySettings.HOST, oldProxyHost );
574 			SoapUI.getSettings().setString( ProxySettings.PORT, oldProxyPort );
575 			SoapUI.getSettings().setBoolean( ProxySettings.ENABLE_PROXY, oldProxyEnabled );
576 			SoapUI.setProxyEnabled( oldProxyEnabled );
577 			JToggleButton applyProxyButton = ( JToggleButton )SoapUI.getApplyProxyButton();
578 			if( applyProxyButton != null )
579 			{
580 				if( oldProxyEnabled )
581 				{
582 					applyProxyButton.setIcon( UISupport.createImageIcon( SoapUI.PROXY_ENABLED_ICON ) );
583 				}
584 				else
585 				{
586 					applyProxyButton.setIcon( UISupport.createImageIcon( SoapUI.PROXY_DISABLED_ICON ) );
587 				}
588 			}
589 		}
590 	}
591 
592 	@AForm( description = "Set options for adding selected requests to a MockService", name = "Add To MockService" )
593 	private final class AddToMockServiceAction implements ActionListener
594 	{
595 		private static final String CREATE_NEW_OPTION = "<Create New>";
596 		private XFormDialog dialog;
597 
598 		@AField( name = "Target MockService", description = "The target TestSuite", type = AFieldType.ENUMERATION )
599 		public final static String MOCKSERVICE = "Target MockService";
600 
601 		@AField( name = "Open Editor", description = "Open the created MockService", type = AFieldType.BOOLEAN )
602 		public final static String OPENEDITOR = "Open Editor";
603 
604 		public void actionPerformed( ActionEvent e )
605 		{
606 			int[] rows = logTable.getSelectedRows();
607 			if( rows.length == 0 )
608 				return;
609 
610 			if( dialog == null )
611 			{
612 				dialog = ADialogBuilder.buildDialog( this.getClass() );
613 			}
614 
615 			String[] testSuiteNames = ModelSupport.getNames( new String[] { CREATE_NEW_OPTION }, getProject()
616 					.getMockServiceList() );
617 			dialog.setOptions( MOCKSERVICE, testSuiteNames );
618 
619 			if( dialog.show() )
620 			{
621 				int withoutOperation = 0;
622 				for( int row : rows )
623 				{
624 					WsdlMonitorMessageExchange me = tableModel.getMessageExchangeAt( row );
625 					if( me.getOperation() == null )
626 						withoutOperation++ ;
627 				}
628 				if( withoutOperation == rows.length )
629 				{
630 					UISupport.showInfoMessage( "No SOAP requests selected!" );
631 					return;
632 				}
633 				String targetMockServiceName = dialog.getValue( MOCKSERVICE );
634 
635 				WsdlMockService mockService = getProject().getMockServiceByName( targetMockServiceName );
636 				if( mockService == null )
637 				{
638 					targetMockServiceName = ModelSupport.promptForUniqueName( "MockService", getProject(), "" );
639 					if( targetMockServiceName == null )
640 						return;
641 
642 					mockService = getProject().addNewMockService( targetMockServiceName );
643 					mockService.setIncomingWss( incomingResponseWss );
644 				}
645 
646 				int cnt = 0;
647 				for( int row : rows )
648 				{
649 					WsdlMonitorMessageExchange me = tableModel.getMessageExchangeAt( row );
650 					if( me.getOperation() == null )
651 						continue;
652 
653 					WsdlMockOperation mockOperation = mockService.getMockOperation( me.getOperation() );
654 					if( mockOperation == null )
655 						mockOperation = mockService.addNewMockOperation( me.getOperation() );
656 
657 					WsdlMockResponse mockResponse = mockOperation
658 							.addNewMockResponse( "Monitor Response " + ( ++cnt ), false );
659 					mockResponse.setResponseContent( me.getResponseContent() );
660 
661 					Attachment[] requestAttachments = me.getResponseAttachments();
662 					if( requestAttachments != null )
663 					{
664 						for( Attachment attachment : requestAttachments )
665 						{
666 							mockResponse.addAttachment( attachment );
667 						}
668 					}
669 				}
670 
671 				if( cnt == 0 )
672 				{
673 					UISupport.showInfoMessage( "No response messages found" );
674 				}
675 				else
676 				{
677 					UISupport.showInfoMessage( "Added " + cnt + " MockResponses to MockService" );
678 
679 					if( dialog.getBooleanValue( OPENEDITOR ) )
680 						UISupport.selectAndShow( mockService );
681 				}
682 			}
683 		}
684 	}
685 
686 	@AForm( description = "Set options for adding selected requests to a TestCase", name = "Add To TestCase" )
687 	private final class AddToTestCaseAction implements ActionListener
688 	{
689 		private static final String CREATE_NEW_OPTION = "<Create New>";
690 		private XFormDialog dialog;
691 
692 		@AField( name = "Target TestSuite", description = "The target TestSuite", type = AFieldType.ENUMERATION )
693 		public final static String TESTSUITE = "Target TestSuite";
694 
695 		@AField( name = "Target TestCase", description = "The target TestCase for the requests", type = AFieldType.ENUMERATION )
696 		public final static String TESTCASE = "Target TestCase";
697 
698 		@AField( name = "Open Editor", description = "Open the created TestCase", type = AFieldType.BOOLEAN )
699 		public final static String OPENEDITOR = "Open Editor";
700 
701 		TestSuite testSuite;
702 
703 		public void actionPerformed( ActionEvent e )
704 		{
705 			int[] rows = logTable.getSelectedRows();
706 			if( rows.length == 0 )
707 				return;
708 
709 			if( dialog == null )
710 			{
711 				dialog = ADialogBuilder.buildDialog( this.getClass() );
712 				dialog.getFormField( TESTSUITE ).addFormFieldListener( new XFormFieldListener()
713 				{
714 					public void valueChanged( XFormField sourceField, String newValue, String oldValue )
715 					{
716 						if( newValue.equals( CREATE_NEW_OPTION ) )
717 						{
718 							dialog.setOptions( TESTCASE, new String[] { CREATE_NEW_OPTION } );
719 						}
720 						else
721 						{
722 							testSuite = getProject().getTestSuiteByName( newValue );
723 							dialog.setOptions( TESTCASE, testSuite == null ? new String[] { CREATE_NEW_OPTION } : ModelSupport
724 									.getNames( testSuite.getTestCaseList(), new String[] { CREATE_NEW_OPTION } ) );
725 						}
726 					}
727 				} );
728 			}
729 
730 			String[] testSuiteNames = ModelSupport.getNames( new String[] { CREATE_NEW_OPTION }, getProject()
731 					.getTestSuiteList() );
732 			dialog.setOptions( TESTSUITE, testSuiteNames );
733 			testSuite = getProject().getTestSuiteByName( dialog.getValue( TESTSUITE ) );
734 			dialog.setOptions( TESTCASE, testSuite == null ? new String[] { CREATE_NEW_OPTION } : ModelSupport.getNames(
735 					testSuite.getTestCaseList(), new String[] { CREATE_NEW_OPTION } ) );
736 
737 			if( dialog.show() )
738 			{
739 				String targetTestSuiteName = dialog.getValue( TESTSUITE );
740 				String targetTestCaseName = dialog.getValue( TESTCASE );
741 
742 				WsdlTestSuite testSuite = getProject().getTestSuiteByName( targetTestSuiteName );
743 				if( testSuite == null )
744 				{
745 					targetTestSuiteName = ModelSupport.promptForUniqueName( "TestSuite", getProject(), "" );
746 					if( targetTestSuiteName == null )
747 						return;
748 
749 					testSuite = getProject().addNewTestSuite( targetTestSuiteName );
750 				}
751 
752 				WsdlTestCase testCase = testSuite.getTestCaseByName( targetTestCaseName );
753 				if( testCase == null )
754 				{
755 					targetTestCaseName = ModelSupport.promptForUniqueName( "TestCase", testSuite, "" );
756 					if( targetTestCaseName == null )
757 						return;
758 
759 					testCase = testSuite.addNewTestCase( targetTestCaseName );
760 				}
761 
762 				for( int row : rows )
763 				{
764 					WsdlMonitorMessageExchange me = tableModel.getMessageExchangeAt( row );
765 					if( me.getOperation() != null )
766 					{
767 						WsdlTestRequestStep test = ( WsdlTestRequestStep )testCase.insertTestStep( WsdlTestRequestStepFactory
768 								.createConfig( me.getOperation(), "Monitor Request " + ( row + 1 ) ), -1 );
769 
770 						WsdlTestRequest request = test.getTestRequest();
771 						request.setRequestContent( me.getRequestContent() );
772 						request.setEndpoint( me.getTargetUrl().toString() );
773 						request.setIncomingWss( incomingRequestWss );
774 
775 						Attachment[] requestAttachments = me.getRequestAttachments();
776 						if( requestAttachments != null )
777 						{
778 							for( Attachment attachment : requestAttachments )
779 							{
780 								request.importAttachment( attachment );
781 							}
782 						}
783 					}
784 					else
785 					{
786 
787 						// if( me.getResponseContentType().contains( "/x-amf" ) )
788 						// {
789 						// AMFRequestStepFactory httpRequestStepFactory = new
790 						// AMFRequestStepFactory();
791 						// AMFRequestTestStep test = ( AMFRequestTestStep
792 						// )testCase.insertTestStep( httpRequestStepFactory
793 						// .createConfig( me, "Monitor Request " + ( row + 1 ) ), -1
794 						// );
795 						//
796 						// AMFRequest request = test.getAMFRequest();
797 						// // request.setRequestContent( me.getRequestContent() );
798 						// request.setEndpoint( me.getTargetUrl().toString() );
799 						// request.setHttpHeaders( me.getRequestHeaders() );
800 						//
801 						// }
802 						// else
803 						// {
804 						HttpRequestStepFactory httpRequestStepFactory = new HttpRequestStepFactory();
805 						HttpTestRequestStep test = ( HttpTestRequestStep )testCase.insertTestStep( httpRequestStepFactory
806 								.createConfig( me, "Monitor Request " + ( row + 1 ) ), -1 );
807 
808 						test.getTestRequest().setRequestHeaders( excludeHeaders( me.getRequestHeaders() ) );
809 
810 						HttpTestRequest request = ( HttpTestRequest )test.getHttpRequest();
811 
812 						request.setEndpoint( me.getTargetUrl().toString() );
813 						// request.setIncomingWss( incomingRequestWss );
814 						String existingMediaType = me.getResponseHeaders().get( "Content-Type", "" );
815 						if( !StringUtils.isNullOrEmpty( existingMediaType ) )
816 						{
817 							request.setMediaType( existingMediaType );
818 						}
819 						if( "application/octet-stream".equals( existingMediaType )
820 								|| "application/x-amf".equals( existingMediaType ) )
821 						{
822 							request.attachBinaryData( me.getRequestContent().getBytes(), existingMediaType );
823 						}
824 						else
825 						{
826 							request.setRequestContent( me.getRequestContent() );
827 							test.getTestRequest().setRequestContent( me.getRequestContent() );
828 						}
829 						Attachment[] requestAttachments = me.getRequestAttachments();
830 						if( requestAttachments != null )
831 						{
832 							for( Attachment attachment : requestAttachments )
833 							{
834 								request.importAttachment( attachment );
835 							}
836 						}
837 						// }
838 
839 					}
840 				}
841 
842 				if( dialog.getBooleanValue( OPENEDITOR ) )
843 					UISupport.selectAndShow( testCase );
844 			}
845 		}
846 	}
847 
848 	// @AForm( description =
849 	// "Set options for adding selected REST requests to a TestCase", name =
850 	// "Add Rest Test Step(s) To TestCase" )
851 	// // private final class AddToRESTTestCaseAction implements ActionListener
852 	// {
853 	// private static final String CREATE_NEW_OPTION = "<Create New>";
854 	// private XFormDialog dialog;
855 	//
856 	// @AField( name = "Target TestSuite", description = "The target TestSuite",
857 	// type = AFieldType.ENUMERATION )
858 	// public final static String TESTSUITE = "Target TestSuite";
859 	//
860 	// @AField( name = "Target TestCase", description =
861 	// "The target TestCase for the requests", type = AFieldType.ENUMERATION )
862 	// public final static String TESTCASE = "Target TestCase";
863 	//
864 	// @AField( name = "Open Editor", description = "Open the created TestCase",
865 	// type = AFieldType.BOOLEAN )
866 	// public final static String OPENEDITOR = "Open Editor";
867 	//
868 	// TestSuite testSuite;
869 	//
870 	// public void actionPerformed( ActionEvent e )
871 	// {
872 	// int[] rows = logTable.getSelectedRows();
873 	// if( rows.length == 0 )
874 	// return;
875 	//
876 	// if( dialog == null )
877 	// {
878 	// dialog = ADialogBuilder.buildDialog( this.getClass() );
879 	// dialog.getFormField( TESTSUITE ).addFormFieldListener( new
880 	// XFormFieldListener()
881 	// {
882 	// public void valueChanged( XFormField sourceField, String newValue, String
883 	// oldValue )
884 	// {
885 	// if( newValue.equals( CREATE_NEW_OPTION ) )
886 	// {
887 	// dialog.setOptions( TESTCASE, new String[] { CREATE_NEW_OPTION } );
888 	// }
889 	// else
890 	// {
891 	// testSuite = getProject().getTestSuiteByName( newValue );
892 	// dialog.setOptions( TESTCASE, testSuite == null ? new String[] {
893 	// CREATE_NEW_OPTION } : ModelSupport
894 	// .getNames( testSuite.getTestCaseList(), new String[] { CREATE_NEW_OPTION }
895 	// ) );
896 	// }
897 	// }
898 	// } );
899 	// }
900 	//
901 	// String[] testSuiteNames = ModelSupport.getNames( new String[] {
902 	// CREATE_NEW_OPTION }, getProject()
903 	// .getTestSuiteList() );
904 	// dialog.setOptions( TESTSUITE, testSuiteNames );
905 	// testSuite = getProject().getTestSuiteByName( dialog.getValue( TESTSUITE )
906 	// );
907 	// dialog.setOptions( TESTCASE, testSuite == null ? new String[] {
908 	// CREATE_NEW_OPTION } : ModelSupport.getNames(
909 	// testSuite.getTestCaseList(), new String[] { CREATE_NEW_OPTION } ) );
910 	//
911 	// if( dialog.show() )
912 	// {
913 	// String targetTestSuiteName = dialog.getValue( TESTSUITE );
914 	// String targetTestCaseName = dialog.getValue( TESTCASE );
915 	//
916 	// WsdlTestSuite testSuite = getProject().getTestSuiteByName(
917 	// targetTestSuiteName );
918 	// if( testSuite == null )
919 	// {
920 	// targetTestSuiteName = ModelSupport.promptForUniqueName( "TestSuite",
921 	// getProject(), "" );
922 	// if( targetTestSuiteName == null )
923 	// return;
924 	//
925 	// testSuite = getProject().addNewTestSuite( targetTestSuiteName );
926 	// }
927 	//
928 	// WsdlTestCase testCase = testSuite.getTestCaseByName( targetTestCaseName );
929 	// if( testCase == null )
930 	// {
931 	// targetTestCaseName = ModelSupport.promptForUniqueName( "TestCase",
932 	// testSuite, "" );
933 	// if( targetTestCaseName == null )
934 	// return;
935 	//
936 	// testCase = testSuite.addNewTestCase( targetTestCaseName );
937 	// }
938 	//
939 	// for( int row : rows )
940 	// {
941 	// WsdlMonitorMessageExchange me = tableModel.getMessageExchangeAt( row );
942 	//
943 	// RestService restService = ( RestService )project.addNewInterface(
944 	// "Monitor Interface " + ( row + 1 ),
945 	// RestServiceFactory.REST_TYPE );
946 	// restService.addEndpoint( me.getTargetUrl().getProtocol()
947 	// +"://"+me.getTargetUrl().getHost() );
948 	// restService.setBasePath( me.getTargetUrl().getPath() );
949 	// ( ( NewRestResourceActionBase )SoapUI.getActionRegistry().getAction(
950 	// NewRestResourceAction.SOAPUI_ACTION_ID ) ).performAutomatic( restService,
951 	// me.getTargetUrl() );
952 	//
953 	// RestRequestStepFactory restRequestStepFactory = new
954 	// RestRequestStepFactory();
955 	// RestTestRequestStep test = ( RestTestRequestStep )testCase.insertTestStep(
956 	// restRequestStepFactory
957 	// .createNewTestStep( testCase, "Monitor Request " + ( row + 1 ) ), -1 );
958 	// test.getTestRequest().setRequestContent( me.getRequestContent() );
959 	// test.getTestRequest().setRequestHeaders( me.getRequestHeaders() );
960 	//
961 	// RestTestRequest request = ( RestTestRequest )test.getHttpRequest();
962 	// request.setRequestContent( me.getRequestContent() );
963 	// request.setEndpoint( me.getTargetUrl().toString() );
964 	//
965 	// Attachment[] requestAttachments = me.getRequestAttachments();
966 	// if( requestAttachments != null )
967 	// {
968 	// for( Attachment attachment : requestAttachments )
969 	// {
970 	// request.importAttachment( attachment );
971 	// }
972 	// }
973 	// }
974 	//
975 	// if( dialog.getBooleanValue( OPENEDITOR ) )
976 	// UISupport.selectAndShow( testCase );
977 	// }
978 	// }
979 	// }
980 
981 	private final class CreateRequestsAction implements ActionListener
982 	{
983 		public void actionPerformed( ActionEvent e )
984 		{
985 			int[] rows = logTable.getSelectedRows();
986 			if( rows.length == 0 )
987 				return;
988 
989 			if( UISupport.confirm( "Create " + rows.length + " requests", "Create Request" ) )
990 			{
991 				int withoutOperation = 0;
992 				for( int row : rows )
993 				{
994 					WsdlMonitorMessageExchange me = tableModel.getMessageExchangeAt( row );
995 					if( me.getOperation() == null )
996 					{
997 						withoutOperation++ ;
998 						continue;
999 					}
1000 
1001 					WsdlRequest request = me.getOperation().addNewRequest( "Monitor Request " + ( row + 1 ) );
1002 
1003 					request.setRequestContent( me.getRequestContent() );
1004 					request.setEndpoint( me.getTargetUrl().toString() );
1005 
1006 					Attachment[] requestAttachments = me.getRequestAttachments();
1007 					if( requestAttachments != null )
1008 					{
1009 						for( Attachment attachment : requestAttachments )
1010 						{
1011 							request.importAttachment( attachment );
1012 						}
1013 					}
1014 				}
1015 				if( withoutOperation > 0 )
1016 				{
1017 					UISupport.showInfoMessage( "For " + withoutOperation + "request(s) there are no operations",
1018 							"Create Request" );
1019 				}
1020 			}
1021 		}
1022 	}
1023 
1024 	private final class ClearAction implements ActionListener
1025 	{
1026 		public void actionPerformed( ActionEvent e )
1027 		{
1028 			if( logTable.getRowCount() == 0 )
1029 				return;
1030 
1031 			int[] rows = logTable.getSelectedRows();
1032 
1033 			if( rows.length == 0 )
1034 			{
1035 				if( UISupport.confirm( "Clear monitor log?", "Clear Log" ) )
1036 					tableModel.clear();
1037 			}
1038 			else if( UISupport.confirm( "Clear " + rows.length + " rows from monitor log?", "Clear Log" ) )
1039 			{
1040 				tableModel.clearRows( rows );
1041 			}
1042 		}
1043 	}
1044 
1045 	@SuppressWarnings( "unchecked" )
1046 	public class MonitorLogTableModel extends AbstractTableModel
1047 	{
1048 		private List<WsdlMonitorMessageExchange> exchanges = new TreeList();
1049 		private DateFormat sdf;
1050 
1051 		public MonitorLogTableModel()
1052 		{
1053 			sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
1054 		}
1055 
1056 		public synchronized void clear()
1057 		{
1058 			int sz = exchanges.size();
1059 			while( exchanges.size() > 0 )
1060 			{
1061 				WsdlMonitorMessageExchange removed = exchanges.remove( 0 );
1062 				removed.discard();
1063 			}
1064 
1065 			fireTableRowsDeleted( 0, sz );
1066 
1067 			while( requestFilterModel.getSize() > 1 )
1068 				requestFilterModel.removeElementAt( 1 );
1069 
1070 			while( targetHostFilterModel.getSize() > 1 )
1071 				targetHostFilterModel.removeElementAt( 1 );
1072 
1073 			updateRowCountLabel();
1074 		}
1075 
1076 		public synchronized void clearRows( int[] indices )
1077 		{
1078 			for( int c = indices.length; c > 0; c-- )
1079 			{
1080 				int index = indices[c - 1];
1081 				WsdlMonitorMessageExchange removed = exchanges.remove( logTable.convertRowIndexToModel( index ) );
1082 				removed.discard();
1083 				fireTableRowsDeleted( index, index );
1084 				updateRowCountLabel();
1085 			}
1086 		}
1087 
1088 		public int getColumnCount()
1089 		{
1090 			return 12;
1091 		}
1092 
1093 		public WsdlMonitorMessageExchange getMessageExchangeAt( int tableRow )
1094 		{
1095 			return exchanges.get( logTable.convertRowIndexToModel( tableRow ) );
1096 		}
1097 
1098 		@Override
1099 		public String getColumnName( int column )
1100 		{
1101 			switch( column )
1102 			{
1103 			case 0 :
1104 				return "Count.";
1105 			case 1 :
1106 				return "Time";
1107 			case 2 :
1108 				return "Request Host";
1109 			case 3 :
1110 				return "Target Host";
1111 			case 4 :
1112 				return "Interface";
1113 			case 5 :
1114 				return "Operation";
1115 			case 6 :
1116 				return "Time Taken";
1117 			case 7 :
1118 				return "Req Sz";
1119 			case 8 :
1120 				return "Resp Sz";
1121 			case 9 :
1122 				return "Method";
1123 			case 10 :
1124 				return "Path";
1125 			case 11 :
1126 				return "Content-Type";
1127 			}
1128 
1129 			return null;
1130 		}
1131 
1132 		public int getRowCount()
1133 		{
1134 			return exchanges.size();
1135 		}
1136 
1137 		public Object getValueAt( int rowIndex, int columnIndex )
1138 		{
1139 			if( rowIndex < 0 || rowIndex >= exchanges.size() )
1140 				return null;
1141 
1142 			WsdlMonitorMessageExchange exchange = exchanges.get( rowIndex );
1143 			if( exchange == null )
1144 				return null;
1145 
1146 			switch( columnIndex )
1147 			{
1148 			case 0 :
1149 				return rowIndex;
1150 			case 1 :
1151 				return sdf.format( new Date( exchange.getTimestamp() ) );
1152 			case 2 :
1153 				return exchange.getRequestHost();
1154 			case 3 :
1155 				return exchange.getTargetUrl().getHost();
1156 			case 4 :
1157 				return exchange.getOperation() == null ? "- unknown -" : exchange.getOperation().getInterface().getName();
1158 			case 5 :
1159 				return exchange.getOperation() == null ? "- unknown -" : exchange.getOperation().getName();
1160 			case 6 :
1161 				return String.valueOf( exchange.getTimeTaken() );
1162 			case 7 :
1163 				return String.valueOf( exchange.getRequestContentLength() );
1164 			case 8 :
1165 				return String.valueOf( exchange.getResponseContentLength() );
1166 			case 9 :
1167 				return String.valueOf( exchange.getRequestMethod() );
1168 			case 10 :
1169 				return exchange.getTargetUrl().getPath();
1170 			case 11 :
1171 				return String.valueOf( exchange.getResponseContentType() );
1172 			}
1173 
1174 			return null;
1175 		}
1176 
1177 		public synchronized void addMessageExchange( WsdlMonitorMessageExchange exchange )
1178 		{
1179 			exchanges.add( exchange );
1180 			int size = exchanges.size();
1181 			fireTableRowsInserted( size - 1, size );
1182 
1183 			fitSizeToMaxRows();
1184 
1185 			String requestHost = exchange.getRequestHost();
1186 			if( requestFilterModel.getIndexOf( requestHost ) == -1 )
1187 			{
1188 				requestFilterModel.addElement( requestHost );
1189 			}
1190 
1191 			String host = exchange.getTargetUrl().getHost();
1192 			if( targetHostFilterModel.getIndexOf( host ) == -1 )
1193 			{
1194 				targetHostFilterModel.addElement( host );
1195 			}
1196 
1197 			updateRowCountLabel();
1198 		}
1199 
1200 		public void fitSizeToMaxRows()
1201 		{
1202 			int removeCnt = 0;
1203 
1204 			while( exchanges.size() > maxRows )
1205 			{
1206 				WsdlMonitorMessageExchange removed = exchanges.remove( 0 );
1207 				removed.discard();
1208 				removeCnt++ ;
1209 			}
1210 
1211 			if( removeCnt > 0 )
1212 			{
1213 				fireTableDataChanged();
1214 				updateRowCountLabel();
1215 			}
1216 		}
1217 	}
1218 
1219 	protected String getHttpProxyHost()
1220 	{
1221 		return httpProxyHost;
1222 	}
1223 
1224 	/***
1225 	 * excludes proxy headers as well as headers set for excluding in Global
1226 	 * Preferences/WebRecordingSettings.EXCLUDED_HEADERS
1227 	 * 
1228 	 * @param requestHeaders
1229 	 * @return
1230 	 */
1231 	private StringToStringsMap excludeHeaders( StringToStringsMap requestHeaders )
1232 	{
1233 		StringToStringsMap stsmap = new StringToStringsMap();
1234 		for( String key : requestHeaders.getKeys() )
1235 		{
1236 			if( !( key.contains( "Proxy" ) || key.contains( "Content" ) ) && !BrowserComponent.isHeaderExcluded( key ) )
1237 			{
1238 				stsmap.add( key, requestHeaders.get( key, "" ) );
1239 			}
1240 		}
1241 		return stsmap;
1242 	}
1243 
1244 	protected void setHttpProxyHost( String proxyHost )
1245 	{
1246 		httpProxyHost = proxyHost;
1247 	}
1248 
1249 	protected int getHttpProxyPort()
1250 	{
1251 		return httpProxyPort;
1252 	}
1253 
1254 	protected void setHttpProxyPort( int proxyPort )
1255 	{
1256 		httpProxyPort = proxyPort;
1257 	}
1258 
1259 	// protected SlowLinkSimulator getSlowLink()
1260 	// {
1261 	// return slowLink;
1262 	// }
1263 
1264 	public String getTargetHost()
1265 	{
1266 		String host = targetEndpoint;
1267 
1268 		try
1269 		{
1270 			URL url = new URL( host );
1271 			return url.getHost();
1272 		}
1273 		catch( MalformedURLException e )
1274 		{
1275 			return host;
1276 		}
1277 	}
1278 
1279 	public String getTargetEndpoint()
1280 	{
1281 		return targetEndpoint;
1282 	}
1283 
1284 	public int getTargetPort()
1285 	{
1286 		try
1287 		{
1288 			URL url = new URL( targetEndpoint );
1289 			return url.getPort() == -1 ? 80 : url.getPort();
1290 		}
1291 		catch( MalformedURLException e )
1292 		{
1293 			return 80;
1294 		}
1295 	}
1296 
1297 	public int getLocalPort()
1298 	{
1299 		return listenPort;
1300 	}
1301 
1302 	public synchronized void addMessageExchange( WsdlMonitorMessageExchange messageExchange )
1303 	{
1304 		messageExchangeStack.push( messageExchange );
1305 
1306 		if( !stackProcessor.isRunning() )
1307 			new Thread( stackProcessor, "SoapMonitor StackProcessor for project [" + getProject().getName() + "]" )
1308 					.start();
1309 	}
1310 
1311 	private class StackProcessor implements Runnable
1312 	{
1313 		private boolean canceled;
1314 		private boolean running;
1315 
1316 		public void run()
1317 		{
1318 			running = true;
1319 			SoapUI.log.info( "Started stackprocessor for soapmonitor in project [" + getProject().getName() + "]" );
1320 			while( !canceled && messageExchangeStack.size() > 0 )
1321 			{
1322 				WsdlMonitorMessageExchange messageExchange = messageExchangeStack.pop();
1323 				if( messageExchange != null )
1324 				{
1325 					processMessage( messageExchange );
1326 				}
1327 
1328 				try
1329 				{
1330 					Thread.sleep( 100 );
1331 				}
1332 				catch( InterruptedException e )
1333 				{
1334 					e.printStackTrace();
1335 				}
1336 			}
1337 			running = false;
1338 		}
1339 
1340 		private synchronized void processMessage( WsdlMonitorMessageExchange messageExchange )
1341 		{
1342 			messageExchange.prepare( project.getWssContainer().getIncomingWssByName( incomingRequestWss ), project
1343 					.getWssContainer().getIncomingWssByName( incomingResponseWss ) );
1344 
1345 			tableModel.addMessageExchange( messageExchange );
1346 
1347 			fireOnMessageExchange( messageExchange );
1348 		}
1349 
1350 		@SuppressWarnings( "unused" )
1351 		public void cancel()
1352 		{
1353 			canceled = true;
1354 		}
1355 
1356 		@SuppressWarnings( "unused" )
1357 		protected boolean isCanceled()
1358 		{
1359 			return canceled;
1360 		}
1361 
1362 		protected boolean isRunning()
1363 		{
1364 			return running;
1365 		}
1366 	}
1367 
1368 	public MonitorLogTableModel getLogModel()
1369 	{
1370 		return tableModel;
1371 	}
1372 
1373 	public void addSoapMonitorListener( MonitorListener listener )
1374 	{
1375 		listeners.add( listener );
1376 	}
1377 
1378 	public void removeSoapMonitorListener( MonitorListener listener )
1379 	{
1380 		listeners.remove( listener );
1381 	}
1382 
1383 	public WsdlProject getProject()
1384 	{
1385 		return project;
1386 	}
1387 
1388 	public class SoapMonitorOptionsAction extends AbstractAction
1389 	{
1390 
1391 		public SoapMonitorOptionsAction()
1392 		{
1393 			putValue( SMALL_ICON, UISupport.createImageIcon( "/options.gif" ) );
1394 		}
1395 
1396 		public void actionPerformed( ActionEvent e )
1397 		{
1398 			if( optionsDialog == null )
1399 			{
1400 				optionsDialog = ADialogBuilder.buildDialog( OptionsForm.class );
1401 			}
1402 
1403 			StringList endpoints = new StringList();
1404 			endpoints.add( null );
1405 
1406 			for( WsdlInterface iface : ModelSupport.getChildren( getProject(), WsdlInterface.class ) )
1407 			{
1408 				endpoints.addAll( iface.getEndpoints() );
1409 			}
1410 
1411 			optionsDialog.setIntValue( OptionsForm.PORT, listenPort );
1412 			optionsDialog.setIntValue( OptionsForm.MAXROWS, maxRows );
1413 
1414 			optionsDialog.setOptions( OptionsForm.REQUEST_WSS, StringUtils.merge( project.getWssContainer()
1415 					.getIncomingWssNames(), "<none>" ) );
1416 			optionsDialog.setOptions( OptionsForm.RESPONSE_WSS, StringUtils.merge( project.getWssContainer()
1417 					.getIncomingWssNames(), "<none>" ) );
1418 
1419 			optionsDialog.setValue( OptionsForm.REQUEST_WSS, incomingRequestWss );
1420 			optionsDialog.setValue( OptionsForm.RESPONSE_WSS, incomingResponseWss );
1421 			optionsDialog.setValue( LaunchForm.SET_CONTENT_TYPES, project.getSettings().getString(
1422 					LaunchForm.SET_CONTENT_TYPES, SoapMonitorAction.defaultContentTypes() ) );
1423 
1424 			if( optionsDialog.show() )
1425 			{
1426 				Settings settings = getProject().getSettings();
1427 
1428 				settings.setLong( OptionsForm.PORT, listenPort = optionsDialog.getIntValue( OptionsForm.PORT, listenPort ) );
1429 				settings.setLong( OptionsForm.MAXROWS, maxRows = optionsDialog.getIntValue( OptionsForm.MAXROWS, maxRows ) );
1430 				settings.setString( LaunchForm.SET_CONTENT_TYPES, optionsDialog.getValue( LaunchForm.SET_CONTENT_TYPES ) );
1431 
1432 				incomingRequestWss = optionsDialog.getValue( OptionsForm.REQUEST_WSS );
1433 				incomingResponseWss = optionsDialog.getValue( OptionsForm.RESPONSE_WSS );
1434 
1435 				tableModel.fitSizeToMaxRows();
1436 			}
1437 		}
1438 
1439 		@AForm( name = "HTTP Monitor Options", description = "Set options for HTTP Monitor", helpUrl = HelpUrls.SOAPMONITOR_HELP_URL, icon = UISupport.OPTIONS_ICON_PATH )
1440 		private class OptionsForm
1441 		{
1442 			@AField( description = "The local port to listen on", name = "Port", type = AFieldType.INT )
1443 			public final static String PORT = "Port";
1444 
1445 			@AField( description = "The maximum number of exchanges to log", name = "Max Log", type = AFieldType.INT )
1446 			public final static String MAXROWS = "Max Log";
1447 
1448 			@AField( description = "The Incoming WSS configuration to use for processing requests", name = "Incoming Request WSS", type = AFieldType.ENUMERATION )
1449 			public final static String REQUEST_WSS = "Incoming Request WSS";
1450 
1451 			@AField( description = "The Outgoing WSS configuration to use for processing responses", name = "Incoming Response WSS", type = AFieldType.ENUMERATION )
1452 			public final static String RESPONSE_WSS = "Incoming Response WSS";
1453 
1454 			@AField( description = "Content types to monitor", name = "Content types to monitor", type = AFieldType.STRINGAREA )
1455 			public final static String SET_CONTENT_TYPES = "Content types to monitor";
1456 		}
1457 	}
1458 
1459 	public void release()
1460 	{
1461 		requestViewer.release();
1462 		responseViewer.release();
1463 
1464 		if( optionsDialog != null )
1465 		{
1466 			optionsDialog.release();
1467 			optionsDialog = null;
1468 		}
1469 
1470 		inspectorPanel.release();
1471 	}
1472 
1473 	public boolean isRunning()
1474 	{
1475 		return monitorEngine.isRunning();
1476 	}
1477 
1478 	public void fireOnMessageExchange( WsdlMonitorMessageExchange messageExchange )
1479 	{
1480 		for( MonitorListener listener : listeners.get() )
1481 		{
1482 			try
1483 			{
1484 				listener.onMessageExchange( messageExchange );
1485 			}
1486 			catch( Throwable t )
1487 			{
1488 				SoapUI.logError( t );
1489 			}
1490 		}
1491 	}
1492 
1493 	public void fireOnRequest( ServletRequest request, ServletResponse response )
1494 	{
1495 		for( MonitorListener listener : listeners.get() )
1496 		{
1497 			try
1498 			{
1499 				listener.onRequest( this, request, response );
1500 			}
1501 			catch( Throwable t )
1502 			{
1503 				SoapUI.logError( t );
1504 			}
1505 		}
1506 	}
1507 
1508 	public void fireBeforeProxy( ServletRequest request, ServletResponse response, HttpMethod method,
1509 			HostConfiguration hostConfiguration )
1510 	{
1511 		for( MonitorListener listener : listeners.get() )
1512 		{
1513 			try
1514 			{
1515 				listener.beforeProxy( this, request, response, method, hostConfiguration );
1516 			}
1517 			catch( Throwable t )
1518 			{
1519 				SoapUI.logError( t );
1520 			}
1521 		}
1522 	}
1523 
1524 	public void fireAfterProxy( ServletRequest request, ServletResponse response, HttpMethod method,
1525 			WsdlMonitorMessageExchange capturedData )
1526 	{
1527 		for( MonitorListener listener : listeners.get() )
1528 		{
1529 			try
1530 			{
1531 				listener.afterProxy( this, request, response, method, capturedData );
1532 			}
1533 			catch( Throwable t )
1534 			{
1535 				SoapUI.logError( t );
1536 			}
1537 		}
1538 	}
1539 
1540 	public static class SoapUIListenerSupport<T extends Object>
1541 	{
1542 		private Set<T> listeners = new HashSet<T>();
1543 		@SuppressWarnings( "unused" )
1544 		private final Class<T> listenerClass;
1545 
1546 		public SoapUIListenerSupport( Class<T> listenerClass )
1547 		{
1548 			this.listenerClass = listenerClass;
1549 			listeners.addAll( SoapUI.getListenerRegistry().getListeners( listenerClass ) );
1550 		}
1551 
1552 		public void add( T listener )
1553 		{
1554 			listeners.add( listener );
1555 		}
1556 
1557 		public void remove( T listener )
1558 		{
1559 			listeners.remove( listener );
1560 		}
1561 
1562 		public Collection<T> get()
1563 		{
1564 			return listeners;
1565 		}
1566 	}
1567 
1568 	public MessageExchangeModelItem getRequestModelItem()
1569 	{
1570 		return requestModelItem;
1571 	}
1572 }