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