View Javadoc

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