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( Exception 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 }
610
611 int cnt = 0;
612 for( int row : rows )
613 {
614 WsdlMonitorMessageExchange me = tableModel.getMessageExchangeAt( row );
615
616 WsdlMockOperation mockOperation = mockService.getMockOperation( me.getOperation() );
617 if( mockOperation == null )
618 mockOperation = mockService.addNewMockOperation( me.getOperation() );
619
620 WsdlMockResponse mockResponse = mockOperation.addNewMockResponse( "Monitor Response " + ( ++cnt ), false );
621 mockResponse.setResponseContent( me.getResponseContent() );
622
623 Attachment[] requestAttachments = me.getResponseAttachments();
624 if( requestAttachments != null )
625 {
626 for( Attachment attachment : requestAttachments )
627 {
628 mockResponse.addAttachment( attachment );
629 }
630 }
631 }
632
633 if( cnt == 0 )
634 {
635 UISupport.showInfoMessage( "No response messages found" );
636 }
637 else
638 {
639 UISupport.showInfoMessage( "Added " + cnt + " MockResponses to MockService" );
640
641 if( dialog.getBooleanValue( OPENEDITOR ))
642 UISupport.selectAndShow( mockService );
643 }
644 }
645 }
646 }
647
648 @AForm( description = "Set options for adding selected requests to a TestCase", name = "Add To TestCase" )
649 private final class AddToTestCaseAction implements ActionListener
650 {
651 private static final String CREATE_NEW_OPTION = "<Create New>";
652 private XFormDialog dialog;
653
654 @AField( name = "Target TestCase", description = "The target TestCase for the requests", type = AFieldType.ENUMERATION )
655 public final static String TESTCASE = "Target TestCase";
656
657 @AField( name = "Target TestSuite", description = "The target TestSuite", type = AFieldType.ENUMERATION )
658 public final static String TESTSUITE = "Target TestSuite";
659
660 @AField( name = "Open Editor", description = "Open the created TestCase", type = AFieldType.BOOLEAN )
661 public final static String OPENEDITOR = "Open Editor";
662
663 public void actionPerformed( ActionEvent e )
664 {
665 int[] rows = logTable.getSelectedRows();
666 if( rows.length == 0 )
667 return;
668
669 if( dialog == null )
670 {
671 dialog = ADialogBuilder.buildDialog( this.getClass() );
672 dialog.getFormField( TESTSUITE ).addFormFieldListener( new XFormFieldListener()
673 {
674 public void valueChanged( XFormField sourceField, String newValue, String oldValue )
675 {
676 if( newValue.equals( CREATE_NEW_OPTION ) )
677 {
678 dialog.setOptions( TESTCASE, new String[] { CREATE_NEW_OPTION } );
679 }
680 else
681 {
682 TestSuite testSuite = getProject().getTestSuiteByName( newValue );
683 dialog.setOptions( TESTCASE, testSuite == null ? new String[] { CREATE_NEW_OPTION } : ModelSupport
684 .getNames( testSuite.getTestCaseList(), new String[] { CREATE_NEW_OPTION } ) );
685 }
686 }
687 } );
688 }
689
690 String[] testSuiteNames = ModelSupport.getNames( new String[] { CREATE_NEW_OPTION }, getProject()
691 .getTestSuiteList() );
692 dialog.setOptions( TESTSUITE, testSuiteNames );
693 dialog.setOptions( TESTCASE, new String[] { CREATE_NEW_OPTION } );
694
695 if( dialog.show() )
696 {
697 String targetTestSuiteName = dialog.getValue( TESTSUITE );
698 String targetTestCaseName = dialog.getValue( TESTCASE );
699
700 WsdlTestSuite testSuite = getProject().getTestSuiteByName( targetTestSuiteName );
701 if( testSuite == null )
702 {
703 targetTestSuiteName = ModelSupport.promptForUniqueName( "TestSuite", getProject(), "" );
704 if( targetTestSuiteName == null )
705 return;
706
707 testSuite = getProject().addNewTestSuite( targetTestSuiteName );
708 }
709
710 WsdlTestCase testCase = testSuite.getTestCaseByName( targetTestCaseName );
711 if( testCase == null )
712 {
713 targetTestCaseName = ModelSupport.promptForUniqueName( "TestCase", testSuite, "" );
714 if( targetTestCaseName == null )
715 return;
716
717 testCase = testSuite.addNewTestCase( targetTestCaseName );
718 }
719
720 for( int row : rows )
721 {
722 WsdlMonitorMessageExchange me = tableModel.getMessageExchangeAt( row );
723
724 WsdlTestRequestStep test = ( WsdlTestRequestStep ) testCase.insertTestStep( WsdlTestRequestStepFactory
725 .createConfig( me.getOperation(), "Monitor Request " + ( row + 1 ) ), -1 );
726
727 WsdlTestRequest request = test.getTestRequest();
728 request.setRequestContent( me.getRequestContent() );
729 request.setEndpoint( me.getTargetUrl().toString() );
730
731 Attachment[] requestAttachments = me.getRequestAttachments();
732 if( requestAttachments != null )
733 {
734 for( Attachment attachment : requestAttachments )
735 {
736 request.importAttachment( attachment );
737 }
738 }
739 }
740
741 if( dialog.getBooleanValue( OPENEDITOR ))
742 UISupport.selectAndShow( testCase );
743 }
744 }
745 }
746
747 private final class CreateRequestsAction implements ActionListener
748 {
749 public void actionPerformed( ActionEvent e )
750 {
751 int[] rows = logTable.getSelectedRows();
752 if( rows.length == 0 )
753 return;
754
755 if( UISupport.confirm( "Create " + rows.length + " requests", "Create Request" ) )
756 {
757 for( int row : rows )
758 {
759 WsdlMonitorMessageExchange me = tableModel.getMessageExchangeAt( row );
760 WsdlRequest request = me.getOperation().addNewRequest( "Monitor Request " + ( row + 1 ) );
761
762 request.setRequestContent( me.getRequestContent() );
763 request.setEndpoint( me.getTargetUrl().toString() );
764
765 Attachment[] requestAttachments = me.getRequestAttachments();
766 if( requestAttachments != null )
767 {
768 for( Attachment attachment : requestAttachments )
769 {
770 request.importAttachment( attachment );
771 }
772 }
773 }
774 }
775 }
776 }
777
778 private final class ClearAction implements ActionListener
779 {
780 public void actionPerformed( ActionEvent e )
781 {
782 if( logTable.getRowCount() == 0 )
783 return;
784
785 int[] rows = logTable.getSelectedRows();
786
787 if( rows.length == 0 )
788 {
789 if( UISupport.confirm( "Clear monitor log?", "Clear Log" ) )
790 tableModel.clear();
791 }
792 else if( UISupport.confirm( "Clear " + rows.length + " rows from monitor log?", "Clear Log" ) )
793 {
794 tableModel.clearRows( rows );
795 }
796 }
797 }
798
799 public class MonitorLogTableModel extends AbstractTableModel
800 {
801 private List<WsdlMonitorMessageExchange> exchanges = new LinkedList<WsdlMonitorMessageExchange>();
802 private DateFormat sdf;
803
804 public MonitorLogTableModel()
805 {
806 sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
807 }
808
809 public synchronized void clear()
810 {
811 int sz = exchanges.size();
812 while( exchanges.size() > 0 )
813 {
814 WsdlMonitorMessageExchange removed = exchanges.remove( 0 );
815 removed.discard();
816 }
817
818 fireTableRowsDeleted( 0, sz );
819
820 while( requestFilterModel.getSize() > 1 )
821 requestFilterModel.removeElementAt( 1 );
822
823 while( targetHostFilterModel.getSize() > 1 )
824 targetHostFilterModel.removeElementAt( 1 );
825
826 updateRowCountLabel();
827 }
828
829 public synchronized void clearRows( int[] indices )
830 {
831 for( int c = indices.length; c > 0; c-- )
832 {
833 int index = indices[c - 1];
834 WsdlMonitorMessageExchange removed = exchanges.remove( logTable.convertRowIndexToModel( index ) );
835 removed.discard();
836 fireTableRowsDeleted( index, index );
837 updateRowCountLabel();
838 }
839 }
840
841 public int getColumnCount()
842 {
843 return 8;
844 }
845
846 public WsdlMonitorMessageExchange getMessageExchangeAt( int tableRow )
847 {
848 return exchanges.get( logTable.convertRowIndexToModel( tableRow ) );
849 }
850
851 @Override
852 public String getColumnName( int column )
853 {
854 switch( column )
855 {
856 case 0:
857 return "Time";
858 case 1:
859 return "Request Host";
860 case 2:
861 return "Target Host";
862 case 3:
863 return "Interface";
864 case 4:
865 return "Operation";
866 case 5:
867 return "Time Taken";
868 case 6:
869 return "Req Sz";
870 case 7:
871 return "Resp Sz";
872 }
873
874 return null;
875 }
876
877 public int getRowCount()
878 {
879 return exchanges.size();
880 }
881
882 public Object getValueAt( int rowIndex, int columnIndex )
883 {
884 if( rowIndex < 0 || rowIndex >= exchanges.size() )
885 return null;
886
887 WsdlMonitorMessageExchange exchange = exchanges.get( rowIndex );
888
889 switch( columnIndex )
890 {
891 case 0:
892 return sdf.format( new Date( exchange.getTimestamp() ) );
893 case 1:
894 return exchange.getRequestHost();
895 case 2:
896 return exchange.getTargetUrl().getHost();
897 case 3:
898 return exchange.getOperation() == null ? "- unknown -" : exchange.getOperation().getInterface().getName();
899 case 4:
900 return exchange.getOperation() == null ? "- unknown -" : exchange.getOperation().getName();
901 case 5:
902 return String.valueOf( exchange.getTimeTaken() );
903 case 6:
904 return String.valueOf( exchange.getRequestContentLength() );
905 case 7:
906 return String.valueOf( exchange.getResponseContentLength() );
907 }
908
909 return null;
910 }
911
912 public synchronized void addMessageExchange( WsdlMonitorMessageExchange exchange )
913 {
914 exchanges.add( exchange );
915 int size = exchanges.size();
916 fireTableRowsInserted( size - 1, size );
917
918 fitSizeToMaxRows();
919
920 String requestHost = exchange.getRequestHost();
921 if( requestFilterModel.getIndexOf( requestHost ) == -1 )
922 {
923 requestFilterModel.addElement( requestHost );
924 }
925
926 String host = exchange.getTargetUrl().getHost();
927 if( targetHostFilterModel.getIndexOf( host ) == -1 )
928 {
929 targetHostFilterModel.addElement( host );
930 }
931
932 updateRowCountLabel();
933 }
934
935 public void fitSizeToMaxRows()
936 {
937 int removeCnt = 0;
938
939 while( exchanges.size() > maxRows )
940 {
941 WsdlMonitorMessageExchange removed = exchanges.remove( 0 );
942 removed.discard();
943 removeCnt++;
944 }
945
946 if( removeCnt > 0 )
947 {
948 fireTableDataChanged();
949 updateRowCountLabel();
950 }
951 }
952 }
953
954 protected String getHttpProxyHost()
955 {
956 return httpProxyHost;
957 }
958
959 protected void setHttpProxyHost( String proxyHost )
960 {
961 httpProxyHost = proxyHost;
962 }
963
964 protected int getHttpProxyPort()
965 {
966 return httpProxyPort;
967 }
968
969 protected void setHttpProxyPort( int proxyPort )
970 {
971 httpProxyPort = proxyPort;
972 }
973
974 protected SlowLinkSimulator getSlowLink()
975 {
976 return slowLink;
977 }
978
979 public String getTargetHost()
980 {
981 String host = targetEndpoint;
982
983 try
984 {
985 URL url = new URL( host );
986 return url.getHost();
987 }
988 catch( MalformedURLException e )
989 {
990 return host;
991 }
992 }
993
994 public String getTargetEndpoint()
995 {
996 return targetEndpoint;
997 }
998
999 public int getTargetPort()
1000 {
1001 try
1002 {
1003 URL url = new URL( targetEndpoint );
1004 return url.getPort() == -1 ? 80 : url.getPort();
1005 }
1006 catch( MalformedURLException e )
1007 {
1008 return 80;
1009 }
1010 }
1011
1012 public int getLocalPort()
1013 {
1014 return listenPort;
1015 }
1016
1017 public boolean isProxy()
1018 {
1019 return isProxy;
1020 }
1021
1022 public synchronized void addMessageExchange( WsdlMonitorMessageExchange messageExchange )
1023 {
1024 messageExchangeStack.push( messageExchange );
1025
1026 if( !stackProcessor.isRunning() )
1027 new Thread( stackProcessor, "SoapMonitor StackProcessor for project [" + getProject().getName() + "]" )
1028 .start();
1029 }
1030
1031 private class StackProcessor implements Runnable
1032 {
1033 private boolean canceled;
1034 private boolean running;
1035
1036 public void run()
1037 {
1038 running = true;
1039 SoapUI.log.info( "Started stackprocessor for soapmonitor in project [" + getProject().getName() + "]" );
1040 while( !canceled && messageExchangeStack.size() > 0 )
1041 {
1042 WsdlMonitorMessageExchange messageExchange = messageExchangeStack.pop();
1043 if( messageExchange != null )
1044 {
1045 processMessage( messageExchange );
1046 }
1047
1048 try
1049 {
1050 Thread.sleep( 100 );
1051 }
1052 catch( InterruptedException e )
1053 {
1054 e.printStackTrace();
1055 }
1056 }
1057 running = false;
1058 }
1059
1060 private synchronized void processMessage( WsdlMonitorMessageExchange messageExchange )
1061 {
1062 messageExchange.prepare(
1063 project.getWssContainer().getIncomingByName( incomingRequestWss ),
1064 project.getWssContainer().getIncomingByName( incomingResponseWss ));
1065
1066 tableModel.addMessageExchange( messageExchange );
1067 if( logTable.getSelectedRow() == logTable.getRowCount() - 2 )
1068 {
1069 logTable.setRowSelectionInterval( logTable.getRowCount() - 1, logTable.getRowCount() - 1 );
1070 }
1071
1072 fireOnMessageExchange( messageExchange );
1073 }
1074
1075 public void cancel()
1076 {
1077 canceled = true;
1078 }
1079
1080 protected boolean isCanceled()
1081 {
1082 return canceled;
1083 }
1084
1085 protected boolean isRunning()
1086 {
1087 return running;
1088 }
1089 }
1090
1091 public MonitorLogTableModel getLogModel()
1092 {
1093 return tableModel;
1094 }
1095
1096 public void addSoapMonitorListener( SoapMonitorListener listener )
1097 {
1098 listeners.add( listener );
1099 }
1100
1101 public void fireOnMessageExchange( WsdlMonitorMessageExchange messageExchange )
1102 {
1103 for( SoapMonitorListener listener : listeners.toArray( new SoapMonitorListener[listeners.size()] ) )
1104 {
1105 listener.onMessageExchange( messageExchange );
1106 }
1107 }
1108
1109 public void removeSoapMonitorListener( SoapMonitorListener listener )
1110 {
1111 listeners.remove( listener );
1112 }
1113
1114 public WsdlProject getProject()
1115 {
1116 return project;
1117 }
1118
1119 public class SoapMonitorOptionsAction extends AbstractAction
1120 {
1121 private static final String CREATE_TCP_TUNNEL = "Create TCP Tunnel";
1122 private static final String CREATE_HTTP_PROXY = "Create HTTP Proxy";
1123
1124 public SoapMonitorOptionsAction()
1125 {
1126 putValue( SMALL_ICON, UISupport.createImageIcon( "/options.gif" ) );
1127 }
1128
1129 public void actionPerformed( ActionEvent e )
1130 {
1131 if( optionsDialog == null )
1132 {
1133 optionsDialog = ADialogBuilder.buildDialog( OptionsForm.class );
1134 optionsDialog.getFormField( OptionsForm.MODE ).addFormFieldListener( new XFormFieldListener()
1135 {
1136
1137 public void valueChanged( XFormField sourceField, String newValue, String oldValue )
1138 {
1139 optionsDialog.getFormField( OptionsForm.TARGET_HOST ).setEnabled( !newValue.equals( CREATE_HTTP_PROXY ) );
1140 optionsDialog.getFormField( OptionsForm.ADD_ENDPOINT ).setEnabled( !newValue.equals( CREATE_HTTP_PROXY ) );
1141 }
1142 } );
1143 }
1144
1145 StringList endpoints = new StringList();
1146 endpoints.add( null );
1147
1148 for( Interface iface : getProject().getInterfaceList() )
1149 {
1150 endpoints.addAll( iface.getEndpoints() );
1151 }
1152
1153 optionsDialog.setOptions( OptionsForm.TARGET_HOST, endpoints.toStringArray() );
1154
1155 optionsDialog.setIntValue( OptionsForm.PORT, listenPort );
1156 optionsDialog.setValue( OptionsForm.TARGET_HOST, targetEndpoint );
1157 optionsDialog.setValue( OptionsForm.MODE, isProxy ? "Create HTTP Proxy" : "Create TCP Tunnel" );
1158 optionsDialog.setIntValue( OptionsForm.MAXROWS, maxRows );
1159 optionsDialog.setBooleanValue( OptionsForm.ADD_ENDPOINT, addEndpoint );
1160
1161 optionsDialog.setOptions( OptionsForm.REQUEST_WSS,
1162 StringUtils.merge( project.getWssContainer().getIncomingNames(), "<none>" ) );
1163 optionsDialog.setOptions( OptionsForm.RESPONSE_WSS,
1164 StringUtils.merge( project.getWssContainer().getIncomingNames(), "<none>" ) );
1165
1166 optionsDialog.setValue( OptionsForm.REQUEST_WSS, incomingRequestWss );
1167 optionsDialog.setValue( OptionsForm.RESPONSE_WSS, incomingResponseWss );
1168
1169 optionsDialog.getFormField( OptionsForm.TARGET_HOST ).setEnabled( !isProxy );
1170 optionsDialog.getFormField( OptionsForm.ADD_ENDPOINT ).setEnabled( !isProxy );
1171
1172 if( optionsDialog.show() )
1173 {
1174 Settings settings = getProject().getSettings();
1175
1176 settings.setLong( OptionsForm.PORT, listenPort = optionsDialog.getIntValue( OptionsForm.PORT, listenPort ) );
1177 settings.setLong( OptionsForm.MAXROWS, maxRows = optionsDialog.getIntValue( OptionsForm.MAXROWS, maxRows ) );
1178 settings.setString( OptionsForm.TARGET_HOST, targetEndpoint = optionsDialog.getValue( OptionsForm.TARGET_HOST ) );
1179 String mode = optionsDialog.getValue( OptionsForm.MODE );
1180 isProxy = mode.equals( "Create HTTP Proxy" );
1181 settings.setString( OptionsForm.MODE, mode );
1182
1183 incomingRequestWss = optionsDialog.getValue( OptionsForm.REQUEST_WSS );
1184 incomingResponseWss = optionsDialog.getValue( OptionsForm.RESPONSE_WSS );
1185
1186 tableModel.fitSizeToMaxRows();
1187 }
1188 }
1189
1190 @AForm( name = "MockService Options", description = "Set options for this MockService", helpUrl = HelpUrls.MOCKSERVICEOPTIONS_HELP_URL, icon = UISupport.OPTIONS_ICON_PATH )
1191 private class OptionsForm
1192 {
1193 @AField( description = "The local port to listen on", name = "Port", type = AFieldType.INT )
1194 public final static String PORT = "Port";
1195
1196 @AField( description = "Specifies monitor mode", name = "Mode", type = AFieldType.RADIOGROUP, values = {
1197 CREATE_TCP_TUNNEL, CREATE_HTTP_PROXY } )
1198 public final static String MODE = "Mode";
1199
1200 @AField( description = "The target host to invoke", name = "Target Host", type = AFieldType.ENUMERATION )
1201 public final static String TARGET_HOST = "Target Host";
1202
1203 @AField( description = "Adds an endpoint for the Tcp Tunnel", name = "Add Endpoint", type = AFieldType.BOOLEAN )
1204 public final static String ADD_ENDPOINT = "Add Endpoint";
1205
1206 @AField( description = "The maximum number of exchanges to log", name = "Max Log", type = AFieldType.INT )
1207 public final static String MAXROWS = "Max Log";
1208
1209 @AField(description = "The Incoming WSS configuration to use for processing requests", name = "Incoming Request WSS", type=AFieldType.ENUMERATION )
1210 public final static String REQUEST_WSS = "Incoming Request WSS";
1211
1212 @AField(description = "The Outgoing WSS configuration to use for processing responses", name = "Incoming Response WSS", type=AFieldType.ENUMERATION )
1213 public final static String RESPONSE_WSS = "Incoming Response WSS";
1214 }
1215 }
1216
1217 public void release()
1218 {
1219 requestViewer.release();
1220 responseViewer.release();
1221
1222 if( optionsDialog != null )
1223 {
1224 optionsDialog.release();
1225 optionsDialog = null;
1226 }
1227 }
1228 }