1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.impl.wsdl.monitor;
14
15 import com.eviware.soapui.SoapUI;
16 import com.eviware.soapui.impl.support.AbstractInterface;
17 import com.eviware.soapui.impl.wsdl.WsdlInterface;
18 import com.eviware.soapui.impl.wsdl.WsdlProject;
19 import com.eviware.soapui.impl.wsdl.WsdlRequest;
20 import com.eviware.soapui.impl.wsdl.WsdlTestSuite;
21 import com.eviware.soapui.impl.wsdl.mock.WsdlMockOperation;
22 import com.eviware.soapui.impl.wsdl.mock.WsdlMockResponse;
23 import com.eviware.soapui.impl.wsdl.mock.WsdlMockService;
24 import com.eviware.soapui.impl.wsdl.support.HelpUrls;
25 import com.eviware.soapui.impl.wsdl.support.MessageExchangeModelItem;
26 import com.eviware.soapui.impl.wsdl.support.MessageExchangeRequestMessageEditor;
27 import com.eviware.soapui.impl.wsdl.support.MessageExchangeResponseMessageEditor;
28 import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
29 import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequest;
30 import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep;
31 import com.eviware.soapui.impl.wsdl.teststeps.registry.WsdlTestRequestStepFactory;
32 import com.eviware.soapui.model.iface.Attachment;
33 import com.eviware.soapui.model.iface.Interface;
34 import com.eviware.soapui.model.settings.Settings;
35 import com.eviware.soapui.model.support.ModelSupport;
36 import com.eviware.soapui.model.testsuite.TestSuite;
37 import com.eviware.soapui.settings.ProxySettings;
38 import com.eviware.soapui.support.StringUtils;
39 import com.eviware.soapui.support.UISupport;
40 import com.eviware.soapui.support.components.JComponentInspector;
41 import com.eviware.soapui.support.components.JInspectorPanel;
42 import com.eviware.soapui.support.components.JInspectorPanelFactory;
43 import com.eviware.soapui.support.components.JXToolBar;
44 import com.eviware.soapui.support.types.StringList;
45 import com.eviware.x.form.XFormDialog;
46 import com.eviware.x.form.XFormField;
47 import com.eviware.x.form.XFormFieldListener;
48 import com.eviware.x.form.support.ADialogBuilder;
49 import com.eviware.x.form.support.AField;
50 import com.eviware.x.form.support.AField.AFieldType;
51 import com.eviware.x.form.support.AForm;
52 import com.jgoodies.forms.builder.ButtonBarBuilder;
53 import org.jdesktop.swingx.JXTable;
54 import org.jdesktop.swingx.decorator.Filter;
55 import org.jdesktop.swingx.decorator.FilterPipeline;
56 import org.jdesktop.swingx.decorator.PatternFilter;
57
58 import javax.swing.*;
59 import javax.swing.event.ListSelectionEvent;
60 import javax.swing.event.ListSelectionListener;
61 import javax.swing.table.AbstractTableModel;
62 import java.awt.*;
63 import java.awt.event.ActionEvent;
64 import java.awt.event.ActionListener;
65 import java.awt.event.ItemEvent;
66 import java.awt.event.ItemListener;
67 import java.net.MalformedURLException;
68 import java.net.URL;
69 import java.text.DateFormat;
70 import java.text.SimpleDateFormat;
71 import java.util.*;
72 import java.util.List;
73
74 /***
75 * A SOAP Monitor..
76 */
77
78 public class SoapMonitor extends JPanel
79 {
80 private static final String ALL_FILTER_OPTION = "- all -";
81 private JProgressBar progressBar;
82 private JButton stopButton = null;
83
84 private JXTable logTable = null;
85 private MonitorLogTableModel tableModel = null;
86
87 private String httpProxyHost = null;
88 private int httpProxyPort = 80;
89
90 private JButton startButton;
91 private final WsdlProject project;
92 private MessageExchangeRequestMessageEditor requestViewer;
93 private MessageExchangeResponseMessageEditor responseViewer;
94 private Set<SoapMonitorListener> listeners = new HashSet<SoapMonitorListener>();
95 private MessageExchangeModelItem requestModelItem;
96 private JButton optionsButton;
97 private int listenPort;
98 private String targetEndpoint;
99 private JButton clearButton;
100 private int maxRows;
101 private JButton addToTestCaseButton;
102 private JButton createRequestButton;
103 private JButton addToMockServiceButton;
104 private Stack<WsdlMonitorMessageExchange> messageExchangeStack = new Stack<WsdlMonitorMessageExchange>();
105 private StackProcessor stackProcessor = new StackProcessor();
106 private PatternFilter operationFilter;
107 private PatternFilter interfaceFilter;
108 private PatternFilter targetHostFilter;
109 private JLabel infoLabel;
110 private PatternFilter requestHostFilter;
111 private JComboBox requestHostFilterCombo;
112 private JComboBox targetHostFilterCombo;
113 private JComboBox interfaceFilterCombo;
114 private JComboBox operationFilterCombo;
115 private DefaultComboBoxModel operationFilterModel;
116 private DefaultComboBoxModel requestFilterModel;
117 private DefaultComboBoxModel targetHostFilterModel;
118 private JLabel rowCountLabel = new JLabel();
119 private Map<AbstractInterface<?>, String> addedEndpoints;
120 private JXToolBar toolbar;
121 private String incomingRequestWss;
122 private String incomingResponseWss;
123 private boolean setAsProxy;
124 private XFormDialog optionsDialog;
125 private SoapMonitorEngine monitorEngine;
126 private String oldProxyHost;
127 private String oldProxyPort;
128
129 public SoapMonitor(
130 WsdlProject project, int listenPort,
131 String incomingRequestWss, String incomingResponseWss, JXToolBar mainToolbar, boolean setAsProxy
132 )
133 {
134 super( new BorderLayout() );
135 this.project = project;
136 this.listenPort = listenPort;
137 this.incomingRequestWss = incomingRequestWss;
138 this.incomingResponseWss = incomingResponseWss;
139 this.setAsProxy = setAsProxy;
140 this.maxRows = 100;
141
142
143
144 this.setLayout( new BorderLayout() );
145
146 add( buildToolbars( mainToolbar ), BorderLayout.NORTH );
147 add( buildContent(), BorderLayout.CENTER );
148
149 start();
150 }
151
152 private JComponent buildContent()
153 {
154 JInspectorPanel inspectorPanel = JInspectorPanelFactory.build( buildLog() );
155
156 JComponentInspector<JComponent> viewInspector = new JComponentInspector<JComponent>( buildViewer(), "Message Content",
157 "Shows message content", true );
158 inspectorPanel.addInspector( viewInspector );
159
160 return inspectorPanel.getComponent();
161 }
162
163 private JComponent buildLog()
164 {
165 tableModel = new MonitorLogTableModel();
166 logTable = new JXTable( 1, 2 );
167 logTable.setColumnControlVisible( true );
168 logTable.setModel( tableModel );
169 logTable.setHorizontalScrollEnabled( true );
170 logTable.setSelectionMode( ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
171
172 operationFilter = new PatternFilter( ".*", 0, 4 );
173 operationFilter.setAcceptNull( true );
174 interfaceFilter = new PatternFilter( ".*", 0, 3 );
175 interfaceFilter.setAcceptNull( true );
176 targetHostFilter = new PatternFilter( ".*", 0, 2 );
177 targetHostFilter.setAcceptNull( true );
178 requestHostFilter = new PatternFilter( ".*", 0, 1 );
179 requestHostFilter.setAcceptNull( true );
180
181 Filter[] filters = new Filter[]{requestHostFilter, targetHostFilter, interfaceFilter, operationFilter};
182
183 FilterPipeline pipeline = new FilterPipeline( filters );
184 logTable.setFilters( pipeline );
185
186 ListSelectionModel sel = logTable.getSelectionModel();
187 sel.addListSelectionListener( new ListSelectionListener()
188 {
189 public void valueChanged( ListSelectionEvent event )
190 {
191 int row = logTable.getSelectedRow();
192 if( row == -1 )
193 {
194
195
196 requestModelItem.setMessageExchange( null );
197 }
198 else
199 {
200 WsdlMonitorMessageExchange exchange = tableModel.getMessageExchangeAt( row );
201 requestModelItem.setMessageExchange( exchange );
202
203
204
205 }
206
207 addToMockServiceButton.setEnabled( row != -1 );
208 addToTestCaseButton.setEnabled( row != -1 );
209 createRequestButton.setEnabled( row != -1 );
210 }
211 } );
212
213 JPanel tablePane = new JPanel();
214 tablePane.setLayout( new BorderLayout() );
215
216 toolbar.addGlue();
217
218 tablePane.add( buildFilterBar(), BorderLayout.NORTH );
219 tablePane.add( new JScrollPane( logTable ), BorderLayout.CENTER );
220
221 return tablePane;
222 }
223
224 private JPanel buildFilterBar()
225 {
226 requestFilterModel = new DefaultComboBoxModel( new String[]{ALL_FILTER_OPTION} );
227 targetHostFilterModel = new DefaultComboBoxModel( new String[]{ALL_FILTER_OPTION} );
228 Dimension comboBoxSize = new Dimension( 90, 18 );
229 requestHostFilterCombo = UISupport.setFixedSize( new JComboBox( requestFilterModel ), comboBoxSize );
230
231
232
233
234 ButtonBarBuilder toolbar = new ButtonBarBuilder();
235
236 toolbar.addFixed( new JLabel( "Request Host" ) );
237 toolbar.addRelatedGap();
238 toolbar.addFixed( requestHostFilterCombo );
239 toolbar.addUnrelatedGap();
240
241 requestHostFilterCombo.addItemListener( new ItemListener()
242 {
243 public void itemStateChanged( ItemEvent e )
244 {
245 int ix = requestHostFilterCombo.getSelectedIndex();
246 if( ix == -1 )
247 return;
248
249 requestHostFilter.setAcceptNull( ix == 0 );
250
251 if( ix == 0 )
252 requestHostFilter.setPattern( ".*", 0 );
253 else
254 requestHostFilter.setPattern( requestHostFilterCombo.getSelectedItem().toString(), 0 );
255
256 updateRowCountLabel();
257 }
258 } );
259
260 toolbar.addFixed( new JLabel( "Target Host" ) );
261 toolbar.addRelatedGap();
262 targetHostFilterCombo = UISupport.setFixedSize( new JComboBox( targetHostFilterModel ), comboBoxSize );
263 toolbar.addFixed( targetHostFilterCombo );
264 toolbar.addUnrelatedGap();
265
266 targetHostFilterCombo.addItemListener( new ItemListener()
267 {
268 public void itemStateChanged( ItemEvent e )
269 {
270 int ix = targetHostFilterCombo.getSelectedIndex();
271 if( ix == -1 )
272 return;
273
274 targetHostFilter.setAcceptNull( ix == 0 );
275
276 if( ix == 0 )
277 targetHostFilter.setPattern( ".*", 0 );
278 else
279 targetHostFilter.setPattern( targetHostFilterCombo.getSelectedItem().toString(), 0 );
280
281 updateRowCountLabel();
282 }
283 } );
284
285 String[] interfaceNames = ModelSupport
286 .getNames( new String[]{ALL_FILTER_OPTION}, getProject().getInterfaceList() );
287
288 toolbar.addFixed( new JLabel( "Interface" ) );
289 toolbar.addRelatedGap();
290 interfaceFilterCombo = UISupport.setFixedSize( new JComboBox( interfaceNames ), comboBoxSize );
291 toolbar.addFixed( interfaceFilterCombo );
292 toolbar.addUnrelatedGap();
293
294 operationFilterModel = new DefaultComboBoxModel( new String[]{ALL_FILTER_OPTION} );
295 interfaceFilterCombo.addItemListener( new ItemListener()
296 {
297 public void itemStateChanged( ItemEvent e )
298 {
299 String item = (String) interfaceFilterCombo.getSelectedItem();
300 operationFilterModel.removeAllElements();
301
302 if( item == null || getProject().getInterfaceByName( item ) == null )
303 {
304 operationFilterModel.addElement( ALL_FILTER_OPTION );
305 interfaceFilter.setPattern( ".*", 0 );
306 }
307 else if( getProject().getInterfaceByName( item ) != null )
308 {
309 WsdlInterface iface = (WsdlInterface) getProject().getInterfaceByName( item );
310 String[] operationNames = ModelSupport.getNames( new String[]{ALL_FILTER_OPTION}, iface
311 .getOperationList() );
312 for( String s : operationNames )
313 operationFilterModel.addElement( s );
314
315 interfaceFilter.setPattern( iface.getName(), 0 );
316 }
317 }
318 } );
319
320 toolbar.addFixed( new JLabel( "Operation" ) );
321 toolbar.addRelatedGap();
322 operationFilterCombo = UISupport.setFixedSize( new JComboBox( operationFilterModel ), comboBoxSize );
323 toolbar.addFixed( operationFilterCombo );
324
325 operationFilterCombo.addItemListener( new ItemListener()
326 {
327 public void itemStateChanged( ItemEvent e )
328 {
329 int ix = operationFilterCombo.getSelectedIndex();
330 if( ix == -1 )
331 {
332 operationFilter.setPattern( ".*", 0 );
333 updateRowCountLabel();
334 return;
335 }
336
337 operationFilter.setAcceptNull( ix == 0 );
338
339 if( ix == 0 )
340 operationFilter.setPattern( ".*", 0 );
341 else
342 operationFilter.setPattern( operationFilterCombo.getSelectedItem().toString(), 0 );
343
344 updateRowCountLabel();
345 }
346 } );
347
348 toolbar.setBorder( BorderFactory.createEmptyBorder( 3, 2, 3, 0 ) );
349 return toolbar.getPanel();
350 }
351
352 protected void updateRowCountLabel()
353 {
354 rowCountLabel.setText( logTable.getRowCount() + "/" + tableModel.getRowCount() + " entries" );
355 }
356
357 private JComponent buildViewer()
358 {
359 requestModelItem = new MessageExchangeModelItem( "monitor message exchange", null )
360 {
361
362 @Override
363 public boolean hasRawData()
364 {
365 return true;
366 }
367 };
368
369 requestViewer = new MessageExchangeRequestMessageEditor( requestModelItem );
370 responseViewer = new MessageExchangeResponseMessageEditor( requestModelItem );
371
372 return UISupport.createHorizontalSplit( requestViewer, responseViewer );
373 }
374
375 private JComponent buildToolbars( JXToolBar mainToolbar )
376 {
377 toolbar = UISupport.createSmallToolbar();
378 mainToolbar.addFixed( startButton = UISupport.createToolbarButton( UISupport.createImageIcon( "/run_testcase.gif" ) ) );
379 mainToolbar.addFixed( stopButton = UISupport.createToolbarButton( UISupport.createImageIcon( "/stop_testcase.gif" ) ) );
380 mainToolbar.addFixed( optionsButton = UISupport.createToolbarButton( new SoapMonitorOptionsAction() ) );
381
382 toolbar.addFixed( createRequestButton = UISupport.createToolbarButton( UISupport.createImageIcon( "/request.gif" ) ) );
383 toolbar.addFixed( addToTestCaseButton = UISupport.createToolbarButton( UISupport.createImageIcon( "/testCase.gif" ) ) );
384 toolbar.addFixed( addToMockServiceButton = UISupport.createToolbarButton( UISupport.createImageIcon( "/mockService.gif" ) ) );
385 toolbar.addFixed( clearButton = UISupport.createToolbarButton( UISupport.createImageIcon( "/clear_loadtest.gif" ) ) );
386
387 startButton.setToolTipText( "Starts the SOAP Monitor as configured" );
388 stopButton.setToolTipText( "Stops the SOAP Monitor" );
389 optionsButton.setToolTipText( "Sets Monitor Options" );
390 clearButton.setToolTipText( "Clear all/selected messages from the log" );
391 createRequestButton.setToolTipText( "Creates requests from selected messages" );
392 addToTestCaseButton.setToolTipText( "Adds selected requests to a TestCase" );
393 addToMockServiceButton.setToolTipText( "Adds selected reponses to a MockService" );
394
395 createRequestButton.setEnabled( false );
396 addToMockServiceButton.setEnabled( false );
397 addToTestCaseButton.setEnabled( false );
398
399 startButton.addActionListener( new ActionListener()
400 {
401 public void actionPerformed( ActionEvent e )
402 {
403 start();
404 }
405 } );
406
407 stopButton.addActionListener( new ActionListener()
408 {
409 public void actionPerformed( ActionEvent e )
410 {
411 stop();
412 }
413 } );
414
415 clearButton.addActionListener( new ClearAction() );
416 createRequestButton.addActionListener( new CreateRequestsAction() );
417 addToTestCaseButton.addActionListener( new AddToTestCaseAction() );
418 addToMockServiceButton.addActionListener( new AddToMockServiceAction() );
419
420 mainToolbar.addGlue();
421
422 infoLabel = new JLabel();
423 infoLabel.setPreferredSize( new Dimension( 100, 20 ) );
424 infoLabel.setOpaque( false );
425 mainToolbar.addFixed( infoLabel );
426
427 progressBar = new JProgressBar();
428
429 JPanel progressBarPanel = UISupport.createProgressBarPanel( progressBar, 2, false );
430 progressBarPanel.setPreferredSize( new Dimension( 60, 20 ) );
431
432 mainToolbar.addFixed( progressBarPanel );
433 return toolbar;
434 }
435
436 /***
437 * Method start
438 */
439 public void start()
440 {
441 int localPort = getLocalPort();
442
443
444 monitorEngine = new SoapMonitorEngineImpl();
445 monitorEngine.start( this, localPort );
446
447 if( monitorEngine.isRunning() )
448 {
449 stopButton.setEnabled( true );
450 startButton.setEnabled( false );
451 optionsButton.setEnabled( false );
452 infoLabel.setText( "Proxy " + "on port " + localPort );
453 progressBar.setIndeterminate( true );
454
455 if( setAsProxy )
456 {
457 oldProxyHost = SoapUI.getSettings().getString( ProxySettings.HOST, "" );
458 oldProxyPort = SoapUI.getSettings().getString( ProxySettings.PORT, "" );
459
460 SoapUI.getSettings().setString( ProxySettings.HOST, "127.0.0.1");
461 SoapUI.getSettings().setString( ProxySettings.PORT, String.valueOf(localPort) );
462 }
463
464 SoapUI.log.info( "Started SOAP Monitor on local port " + localPort );
465 }
466 else
467 {
468 stopButton.setEnabled( false );
469 startButton.setEnabled( true );
470 optionsButton.setEnabled( true );
471 infoLabel.setText( "Stoped" );
472 progressBar.setIndeterminate( false );
473
474 SoapUI.log.info( "Could not start SOAP Monitor on local port " + localPort );
475 }
476 }
477
478 /***
479 * Method close
480 */
481 public void close()
482 {
483 stop();
484 }
485
486 /***
487 * Method stop
488 */
489 public void stop()
490 {
491 monitorEngine.stop();
492 if( addedEndpoints != null )
493 {
494 for( Interface iface : addedEndpoints.keySet() )
495 iface.removeEndpoint( addedEndpoints.get( iface ) );
496
497 addedEndpoints.clear();
498 }
499
500 stopButton.setEnabled( false );
501 startButton.setEnabled( true );
502 optionsButton.setEnabled( true );
503 progressBar.setIndeterminate( false );
504 infoLabel.setText( "Stopped" );
505
506 if( setAsProxy )
507 {
508 SoapUI.getSettings().setString( ProxySettings.HOST, oldProxyHost);
509 SoapUI.getSettings().setString( ProxySettings.PORT, oldProxyPort );
510 }
511 }
512
513 @AForm( description = "Set options for adding selected requests to a MockService", name = "Add To MockService" )
514 private final class AddToMockServiceAction implements ActionListener
515 {
516 private static final String CREATE_NEW_OPTION = "<Create New>";
517 private XFormDialog dialog;
518
519 @AField( name = "Target MockService", description = "The target TestSuite", type = AFieldType.ENUMERATION )
520 public final static String MOCKSERVICE = "Target MockService";
521
522 @AField( name = "Open Editor", description = "Open the created MockService", type = AFieldType.BOOLEAN )
523 public final static String OPENEDITOR = "Open Editor";
524
525 public void actionPerformed( ActionEvent e )
526 {
527 int[] rows = logTable.getSelectedRows();
528 if( rows.length == 0 )
529 return;
530
531 if( dialog == null )
532 {
533 dialog = ADialogBuilder.buildDialog( this.getClass() );
534 }
535
536 String[] testSuiteNames = ModelSupport.getNames( new String[]{CREATE_NEW_OPTION}, getProject()
537 .getMockServiceList() );
538 dialog.setOptions( MOCKSERVICE, testSuiteNames );
539
540 if( dialog.show() )
541 {
542 String targetMockServiceName = dialog.getValue( MOCKSERVICE );
543
544 WsdlMockService mockService = getProject().getMockServiceByName( targetMockServiceName );
545 if( mockService == null )
546 {
547 targetMockServiceName = ModelSupport.promptForUniqueName( "MockService", getProject(), "" );
548 if( targetMockServiceName == null )
549 return;
550
551 mockService = getProject().addNewMockService( targetMockServiceName );
552 mockService.setIncomingWss( incomingResponseWss );
553 }
554
555 int cnt = 0;
556 for( int row : rows )
557 {
558 WsdlMonitorMessageExchange me = tableModel.getMessageExchangeAt( row );
559 if( me.getOperation() == null )
560 continue;
561
562 WsdlMockOperation mockOperation = mockService.getMockOperation( me.getOperation() );
563 if( mockOperation == null )
564 mockOperation = mockService.addNewMockOperation( me.getOperation() );
565
566 WsdlMockResponse mockResponse = mockOperation.addNewMockResponse( "Monitor Response " + ( ++cnt ), false );
567 mockResponse.setResponseContent( me.getResponseContent() );
568
569 Attachment[] requestAttachments = me.getResponseAttachments();
570 if( requestAttachments != null )
571 {
572 for( Attachment attachment : requestAttachments )
573 {
574 mockResponse.addAttachment( attachment );
575 }
576 }
577 }
578
579 if( cnt == 0 )
580 {
581 UISupport.showInfoMessage( "No response messages found" );
582 }
583 else
584 {
585 UISupport.showInfoMessage( "Added " + cnt + " MockResponses to MockService" );
586
587 if( dialog.getBooleanValue( OPENEDITOR ) )
588 UISupport.selectAndShow( mockService );
589 }
590 }
591 }
592 }
593
594 @AForm( description = "Set options for adding selected requests to a TestCase", name = "Add To TestCase" )
595 private final class AddToTestCaseAction implements ActionListener
596 {
597 private static final String CREATE_NEW_OPTION = "<Create New>";
598 private XFormDialog dialog;
599
600 @AField( name = "Target TestCase", description = "The target TestCase for the requests", type = AFieldType.ENUMERATION )
601 public final static String TESTCASE = "Target TestCase";
602
603 @AField( name = "Target TestSuite", description = "The target TestSuite", type = AFieldType.ENUMERATION )
604 public final static String TESTSUITE = "Target TestSuite";
605
606 @AField( name = "Open Editor", description = "Open the created TestCase", type = AFieldType.BOOLEAN )
607 public final static String OPENEDITOR = "Open Editor";
608
609 public void actionPerformed( ActionEvent e )
610 {
611 int[] rows = logTable.getSelectedRows();
612 if( rows.length == 0 )
613 return;
614
615 if( dialog == null )
616 {
617 dialog = ADialogBuilder.buildDialog( this.getClass() );
618 dialog.getFormField( TESTSUITE ).addFormFieldListener( new XFormFieldListener()
619 {
620 public void valueChanged( XFormField sourceField, String newValue, String oldValue )
621 {
622 if( newValue.equals( CREATE_NEW_OPTION ) )
623 {
624 dialog.setOptions( TESTCASE, new String[]{CREATE_NEW_OPTION} );
625 }
626 else
627 {
628 TestSuite testSuite = getProject().getTestSuiteByName( newValue );
629 dialog.setOptions( TESTCASE, testSuite == null ? new String[]{CREATE_NEW_OPTION} : ModelSupport
630 .getNames( testSuite.getTestCaseList(), new String[]{CREATE_NEW_OPTION} ) );
631 }
632 }
633 } );
634 }
635
636 String[] testSuiteNames = ModelSupport.getNames( new String[]{CREATE_NEW_OPTION}, getProject()
637 .getTestSuiteList() );
638 dialog.setOptions( TESTSUITE, testSuiteNames );
639 dialog.setOptions( TESTCASE, new String[]{CREATE_NEW_OPTION} );
640
641 if( dialog.show() )
642 {
643 String targetTestSuiteName = dialog.getValue( TESTSUITE );
644 String targetTestCaseName = dialog.getValue( TESTCASE );
645
646 WsdlTestSuite testSuite = getProject().getTestSuiteByName( targetTestSuiteName );
647 if( testSuite == null )
648 {
649 targetTestSuiteName = ModelSupport.promptForUniqueName( "TestSuite", getProject(), "" );
650 if( targetTestSuiteName == null )
651 return;
652
653 testSuite = getProject().addNewTestSuite( targetTestSuiteName );
654 }
655
656 WsdlTestCase testCase = testSuite.getTestCaseByName( targetTestCaseName );
657 if( testCase == null )
658 {
659 targetTestCaseName = ModelSupport.promptForUniqueName( "TestCase", testSuite, "" );
660 if( targetTestCaseName == null )
661 return;
662
663 testCase = testSuite.addNewTestCase( targetTestCaseName );
664 }
665
666 for( int row : rows )
667 {
668 WsdlMonitorMessageExchange me = tableModel.getMessageExchangeAt( row );
669 if( me.getOperation() == null )
670 continue;
671
672 WsdlTestRequestStep test = (WsdlTestRequestStep) testCase.insertTestStep( WsdlTestRequestStepFactory
673 .createConfig( me.getOperation(), "Monitor Request " + ( row + 1 ) ), -1 );
674
675 WsdlTestRequest request = test.getTestRequest();
676 request.setRequestContent( me.getRequestContent() );
677 request.setEndpoint( me.getTargetUrl().toString() );
678 request.setIncomingWss( incomingRequestWss );
679
680 Attachment[] requestAttachments = me.getRequestAttachments();
681 if( requestAttachments != null )
682 {
683 for( Attachment attachment : requestAttachments )
684 {
685 request.importAttachment( attachment );
686 }
687 }
688 }
689
690 if( dialog.getBooleanValue( OPENEDITOR ) )
691 UISupport.selectAndShow( testCase );
692 }
693 }
694 }
695
696 private final class CreateRequestsAction implements ActionListener
697 {
698 public void actionPerformed( ActionEvent e )
699 {
700 int[] rows = logTable.getSelectedRows();
701 if( rows.length == 0 )
702 return;
703
704 if( UISupport.confirm( "Create " + rows.length + " requests", "Create Request" ) )
705 {
706 for( int row : rows )
707 {
708 WsdlMonitorMessageExchange me = tableModel.getMessageExchangeAt( row );
709 if( me.getOperation() == null )
710 continue;
711
712 WsdlRequest request = me.getOperation().addNewRequest( "Monitor Request " + ( row + 1 ) );
713
714 request.setRequestContent( me.getRequestContent() );
715 request.setEndpoint( me.getTargetUrl().toString() );
716
717 Attachment[] requestAttachments = me.getRequestAttachments();
718 if( requestAttachments != null )
719 {
720 for( Attachment attachment : requestAttachments )
721 {
722 request.importAttachment( attachment );
723 }
724 }
725 }
726 }
727 }
728 }
729
730 private final class ClearAction implements ActionListener
731 {
732 public void actionPerformed( ActionEvent e )
733 {
734 if( logTable.getRowCount() == 0 )
735 return;
736
737 int[] rows = logTable.getSelectedRows();
738
739 if( rows.length == 0 )
740 {
741 if( UISupport.confirm( "Clear monitor log?", "Clear Log" ) )
742 tableModel.clear();
743 }
744 else if( UISupport.confirm( "Clear " + rows.length + " rows from monitor log?", "Clear Log" ) )
745 {
746 tableModel.clearRows( rows );
747 }
748 }
749 }
750
751 public class MonitorLogTableModel extends AbstractTableModel
752 {
753 private List<WsdlMonitorMessageExchange> exchanges = new LinkedList<WsdlMonitorMessageExchange>();
754 private DateFormat sdf;
755
756 public MonitorLogTableModel()
757 {
758 sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
759 }
760
761 public synchronized void clear()
762 {
763 int sz = exchanges.size();
764 while( exchanges.size() > 0 )
765 {
766 WsdlMonitorMessageExchange removed = exchanges.remove( 0 );
767 removed.discard();
768 }
769
770 fireTableRowsDeleted( 0, sz );
771
772 while( requestFilterModel.getSize() > 1 )
773 requestFilterModel.removeElementAt( 1 );
774
775 while( targetHostFilterModel.getSize() > 1 )
776 targetHostFilterModel.removeElementAt( 1 );
777
778 updateRowCountLabel();
779 }
780
781 public synchronized void clearRows( int[] indices )
782 {
783 for( int c = indices.length; c > 0; c-- )
784 {
785 int index = indices[c - 1];
786 WsdlMonitorMessageExchange removed = exchanges.remove( logTable.convertRowIndexToModel( index ) );
787 removed.discard();
788 fireTableRowsDeleted( index, index );
789 updateRowCountLabel();
790 }
791 }
792
793 public int getColumnCount()
794 {
795 return 8;
796 }
797
798 public WsdlMonitorMessageExchange getMessageExchangeAt( int tableRow )
799 {
800 return exchanges.get( logTable.convertRowIndexToModel( tableRow ) );
801 }
802
803 @Override
804 public String getColumnName( int column )
805 {
806 switch( column )
807 {
808 case 0:
809 return "Time";
810 case 1:
811 return "Request Host";
812 case 2:
813 return "Target Host";
814 case 3:
815 return "Interface";
816 case 4:
817 return "Operation";
818 case 5:
819 return "Time Taken";
820 case 6:
821 return "Req Sz";
822 case 7:
823 return "Resp Sz";
824 }
825
826 return null;
827 }
828
829 public int getRowCount()
830 {
831 return exchanges.size();
832 }
833
834 public Object getValueAt( int rowIndex, int columnIndex )
835 {
836 if( rowIndex < 0 || rowIndex >= exchanges.size() )
837 return null;
838
839 WsdlMonitorMessageExchange exchange = exchanges.get( rowIndex );
840 if( exchange == null )
841 return null;
842
843 switch( columnIndex )
844 {
845 case 0:
846 return sdf.format( new Date( exchange.getTimestamp() ) );
847 case 1:
848 return exchange.getRequestHost();
849 case 2:
850 return exchange.getTargetUrl().getHost();
851 case 3:
852 return exchange.getOperation() == null ? "- unknown -" : exchange.getOperation().getInterface().getName();
853 case 4:
854 return exchange.getOperation() == null ? "- unknown -" : exchange.getOperation().getName();
855 case 5:
856 return String.valueOf( exchange.getTimeTaken() );
857 case 6:
858 return String.valueOf( exchange.getRequestContentLength() );
859 case 7:
860 return String.valueOf( exchange.getResponseContentLength() );
861 }
862
863 return null;
864 }
865
866 public synchronized void addMessageExchange( WsdlMonitorMessageExchange exchange )
867 {
868 exchanges.add( exchange );
869 int size = exchanges.size();
870 fireTableRowsInserted( size - 1, size );
871
872 fitSizeToMaxRows();
873
874 String requestHost = exchange.getRequestHost();
875 if( requestFilterModel.getIndexOf( requestHost ) == -1 )
876 {
877 requestFilterModel.addElement( requestHost );
878 }
879
880 String host = exchange.getTargetUrl().getHost();
881 if( targetHostFilterModel.getIndexOf( host ) == -1 )
882 {
883 targetHostFilterModel.addElement( host );
884 }
885
886 updateRowCountLabel();
887 }
888
889 public void fitSizeToMaxRows()
890 {
891 int removeCnt = 0;
892
893 while( exchanges.size() > maxRows )
894 {
895 WsdlMonitorMessageExchange removed = exchanges.remove( 0 );
896 removed.discard();
897 removeCnt++;
898 }
899
900 if( removeCnt > 0 )
901 {
902 fireTableDataChanged();
903 updateRowCountLabel();
904 }
905 }
906 }
907
908 protected String getHttpProxyHost()
909 {
910 return httpProxyHost;
911 }
912
913 protected void setHttpProxyHost( String proxyHost )
914 {
915 httpProxyHost = proxyHost;
916 }
917
918 protected int getHttpProxyPort()
919 {
920 return httpProxyPort;
921 }
922
923 protected void setHttpProxyPort( int proxyPort )
924 {
925 httpProxyPort = proxyPort;
926 }
927
928
929
930
931
932
933 public String getTargetHost()
934 {
935 String host = targetEndpoint;
936
937 try
938 {
939 URL url = new URL( host );
940 return url.getHost();
941 }
942 catch( MalformedURLException e )
943 {
944 return host;
945 }
946 }
947
948 public String getTargetEndpoint()
949 {
950 return targetEndpoint;
951 }
952
953 public int getTargetPort()
954 {
955 try
956 {
957 URL url = new URL( targetEndpoint );
958 return url.getPort() == -1 ? 80 : url.getPort();
959 }
960 catch( MalformedURLException e )
961 {
962 return 80;
963 }
964 }
965
966 public int getLocalPort()
967 {
968 return listenPort;
969 }
970
971 public synchronized void addMessageExchange( WsdlMonitorMessageExchange messageExchange )
972 {
973 messageExchangeStack.push( messageExchange );
974
975 if( !stackProcessor.isRunning() )
976 new Thread( stackProcessor, "SoapMonitor StackProcessor for project [" + getProject().getName() + "]" )
977 .start();
978 }
979
980 private class StackProcessor implements Runnable
981 {
982 private boolean canceled;
983 private boolean running;
984
985 public void run()
986 {
987 running = true;
988 SoapUI.log.info( "Started stackprocessor for soapmonitor in project [" + getProject().getName() + "]" );
989 while( !canceled && messageExchangeStack.size() > 0 )
990 {
991 WsdlMonitorMessageExchange messageExchange = messageExchangeStack.pop();
992 if( messageExchange != null )
993 {
994 processMessage( messageExchange );
995 }
996
997 try
998 {
999 Thread.sleep( 100 );
1000 }
1001 catch( InterruptedException e )
1002 {
1003 e.printStackTrace();
1004 }
1005 }
1006 running = false;
1007 }
1008
1009 private synchronized void processMessage( WsdlMonitorMessageExchange messageExchange )
1010 {
1011 messageExchange.prepare(
1012 project.getWssContainer().getIncomingWssByName( incomingRequestWss ),
1013 project.getWssContainer().getIncomingWssByName( incomingResponseWss ) );
1014
1015 tableModel.addMessageExchange( messageExchange );
1016 if( logTable.getSelectedRow() == logTable.getRowCount() - 2 )
1017 {
1018 logTable.setRowSelectionInterval( logTable.getRowCount() - 1, logTable.getRowCount() - 1 );
1019 }
1020
1021 fireOnMessageExchange( messageExchange );
1022 }
1023
1024 public void cancel()
1025 {
1026 canceled = true;
1027 }
1028
1029 protected boolean isCanceled()
1030 {
1031 return canceled;
1032 }
1033
1034 protected boolean isRunning()
1035 {
1036 return running;
1037 }
1038 }
1039
1040 public MonitorLogTableModel getLogModel()
1041 {
1042 return tableModel;
1043 }
1044
1045 public void addSoapMonitorListener( SoapMonitorListener listener )
1046 {
1047 listeners.add( listener );
1048 }
1049
1050 public void fireOnMessageExchange( WsdlMonitorMessageExchange messageExchange )
1051 {
1052 for( SoapMonitorListener listener : listeners.toArray( new SoapMonitorListener[listeners.size()] ) )
1053 {
1054 listener.onMessageExchange( messageExchange );
1055 }
1056 }
1057
1058 public void removeSoapMonitorListener( SoapMonitorListener listener )
1059 {
1060 listeners.remove( listener );
1061 }
1062
1063 public WsdlProject getProject()
1064 {
1065 return project;
1066 }
1067
1068 public class SoapMonitorOptionsAction extends AbstractAction
1069 {
1070
1071 public SoapMonitorOptionsAction()
1072 {
1073 putValue( SMALL_ICON, UISupport.createImageIcon( "/options.gif" ) );
1074 }
1075
1076 public void actionPerformed( ActionEvent e )
1077 {
1078 if( optionsDialog == null )
1079 {
1080 optionsDialog = ADialogBuilder.buildDialog( OptionsForm.class );
1081 }
1082
1083 StringList endpoints = new StringList();
1084 endpoints.add( null );
1085
1086 for( Interface iface : getProject().getInterfaceList() )
1087 {
1088 endpoints.addAll( iface.getEndpoints() );
1089 }
1090
1091 optionsDialog.setIntValue( OptionsForm.PORT, listenPort );
1092 optionsDialog.setIntValue( OptionsForm.MAXROWS, maxRows );
1093
1094 optionsDialog.setOptions( OptionsForm.REQUEST_WSS,
1095 StringUtils.merge( project.getWssContainer().getIncomingWssNames(), "<none>" ) );
1096 optionsDialog.setOptions( OptionsForm.RESPONSE_WSS,
1097 StringUtils.merge( project.getWssContainer().getIncomingWssNames(), "<none>" ) );
1098
1099 optionsDialog.setValue( OptionsForm.REQUEST_WSS, incomingRequestWss );
1100 optionsDialog.setValue( OptionsForm.RESPONSE_WSS, incomingResponseWss );
1101
1102 if( optionsDialog.show() )
1103 {
1104 Settings settings = getProject().getSettings();
1105
1106 settings.setLong( OptionsForm.PORT, listenPort = optionsDialog.getIntValue( OptionsForm.PORT, listenPort ) );
1107 settings.setLong( OptionsForm.MAXROWS, maxRows = optionsDialog.getIntValue( OptionsForm.MAXROWS, maxRows ) );
1108
1109 incomingRequestWss = optionsDialog.getValue( OptionsForm.REQUEST_WSS );
1110 incomingResponseWss = optionsDialog.getValue( OptionsForm.RESPONSE_WSS );
1111
1112 tableModel.fitSizeToMaxRows();
1113 }
1114 }
1115
1116 @AForm( name = "SOAP Monitor Options", description = "Set options for SOAP Monitor", helpUrl = HelpUrls.SOAPMONITOR_HELP_URL, icon = UISupport.OPTIONS_ICON_PATH )
1117 private class OptionsForm
1118 {
1119 @AField( description = "The local port to listen on", name = "Port", type = AFieldType.INT )
1120 public final static String PORT = "Port";
1121
1122 @AField( description = "The maximum number of exchanges to log", name = "Max Log", type = AFieldType.INT )
1123 public final static String MAXROWS = "Max Log";
1124
1125 @AField( description = "The Incoming WSS configuration to use for processing requests", name = "Incoming Request WSS", type = AFieldType.ENUMERATION )
1126 public final static String REQUEST_WSS = "Incoming Request WSS";
1127
1128 @AField( description = "The Outgoing WSS configuration to use for processing responses", name = "Incoming Response WSS", type = AFieldType.ENUMERATION )
1129 public final static String RESPONSE_WSS = "Incoming Response WSS";
1130 }
1131 }
1132
1133 public void release()
1134 {
1135 requestViewer.release();
1136 responseViewer.release();
1137
1138 if( optionsDialog != null )
1139 {
1140 optionsDialog.release();
1141 optionsDialog = null;
1142 }
1143 }
1144
1145 public boolean isRunning()
1146 {
1147 return monitorEngine.isRunning();
1148 }
1149 }