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