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.teststeps;
14  
15  import com.eviware.soapui.SoapUI;
16  import com.eviware.soapui.config.*;
17  import com.eviware.soapui.impl.wsdl.*;
18  import com.eviware.soapui.impl.wsdl.mock.WsdlMockOperation;
19  import com.eviware.soapui.impl.wsdl.mock.WsdlMockResponse;
20  import com.eviware.soapui.impl.wsdl.mock.WsdlMockResult;
21  import com.eviware.soapui.impl.wsdl.mock.WsdlMockRunner;
22  import com.eviware.soapui.impl.wsdl.mock.dispatch.QueryMatchMockOperationDispatcher;
23  import com.eviware.soapui.impl.wsdl.panels.mockoperation.WsdlMockResultMessageExchange;
24  import com.eviware.soapui.impl.wsdl.support.ModelItemIconAnimator;
25  import com.eviware.soapui.impl.wsdl.support.assertions.AssertableConfig;
26  import com.eviware.soapui.impl.wsdl.support.assertions.AssertedXPathsContainer;
27  import com.eviware.soapui.impl.wsdl.support.assertions.AssertionsSupport;
28  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
29  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
30  import com.eviware.soapui.impl.wsdl.teststeps.assertions.TestAssertionRegistry;
31  import com.eviware.soapui.impl.wsdl.teststeps.assertions.TestAssertionRegistry.AssertableType;
32  import com.eviware.soapui.model.ModelItem;
33  import com.eviware.soapui.model.iface.Interface;
34  import com.eviware.soapui.model.iface.Operation;
35  import com.eviware.soapui.model.iface.SubmitContext;
36  import com.eviware.soapui.model.mock.MockResult;
37  import com.eviware.soapui.model.mock.MockRunner;
38  import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
39  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils;
40  import com.eviware.soapui.model.support.*;
41  import com.eviware.soapui.model.testsuite.*;
42  import com.eviware.soapui.model.testsuite.AssertionError;
43  import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus;
44  import com.eviware.soapui.support.StringUtils;
45  import com.eviware.soapui.support.resolver.ChangeOperationResolver;
46  import com.eviware.soapui.support.resolver.ImportInterfaceResolver;
47  import com.eviware.soapui.support.resolver.RemoveTestStepResolver;
48  import com.eviware.soapui.support.resolver.ResolveContext;
49  import com.eviware.soapui.support.resolver.ResolveContext.PathToResolve;
50  import com.eviware.soapui.support.types.StringToStringMap;
51  import org.apache.log4j.Logger;
52  
53  import javax.swing.*;
54  import java.beans.PropertyChangeEvent;
55  import java.beans.PropertyChangeListener;
56  import java.util.*;
57  
58  public class WsdlMockResponseTestStep extends WsdlTestStepWithProperties implements OperationTestStep,
59          PropertyChangeListener, Assertable
60  {
61     private final static Logger log = Logger.getLogger( WsdlMockResponseTestStep.class );
62  
63     public static final String STATUS_PROPERTY = WsdlMockResponseTestStep.class.getName() + "@status";
64     public static final String TIMEOUT_PROPERTY = WsdlMockResponseTestStep.class.getName() + "@timeout";
65  
66     private MockResponseStepConfig mockResponseStepConfig;
67     private MockResponseConfig mockResponseConfig;
68     private WsdlMockOperation mockOperation;
69     private WsdlTestMockService mockService;
70     private WsdlMockRunner mockRunner;
71     private WsdlMockResponse mockResponse;
72  
73     private AssertionsSupport assertionsSupport;
74     private InternalMockRunListener mockRunListener;
75  
76     private final InternalProjectListener projectListener = new InternalProjectListener();
77     private final InternalInterfaceListener interfaceListener = new InternalInterfaceListener();
78     private final InternalTestRunListener testRunListener = new InternalTestRunListener();
79     private WsdlInterface iface;
80     private AssertionStatus oldStatus;
81  
82     private ModelItemIconAnimator<WsdlMockResponseTestStep> iconAnimator;
83     private WsdlMockResponse testMockResponse;
84     private WsdlTestStep startTestStep;
85  
86     public WsdlMockResponseTestStep( WsdlTestCase testCase, TestStepConfig config, boolean forLoadTest )
87     {
88        super( testCase, config, true, forLoadTest );
89  
90        if( config.getConfig() != null )
91        {
92           mockResponseStepConfig = (MockResponseStepConfig) config.getConfig().changeType( MockResponseStepConfig.type );
93           mockResponseConfig = mockResponseStepConfig.getResponse();
94        }
95        else
96        {
97           mockResponseStepConfig = (MockResponseStepConfig) config.addNewConfig()
98                   .changeType( MockResponseStepConfig.type );
99           mockResponseConfig = mockResponseStepConfig.addNewResponse();
100       }
101 
102       initAssertions();
103       initMockObjects( testCase );
104 
105       if( !forLoadTest )
106       {
107          if( iface != null )
108          {
109             iface.getProject().addProjectListener( projectListener );
110             iface.addInterfaceListener( interfaceListener );
111          }
112 
113          iconAnimator = new ModelItemIconAnimator<WsdlMockResponseTestStep>( this, "/mockResponseStep.gif",
114                  "/exec_mockResponse", 4, "gif" );
115       }
116 
117       // init properties
118       initProperties();
119 
120       testCase.addTestRunListener( testRunListener );
121 
122       startTestStep = testCase.getTestStepByName( getStartStep() );
123       if( startTestStep != null )
124       {
125          startTestStep.addPropertyChangeListener( this );
126       }
127 
128       testCase.addPropertyChangeListener( this );
129    }
130 
131    private void initProperties()
132    {
133       if( mockResponse != null )
134       {
135          addProperty( new TestStepBeanProperty( "Response", false, mockResponse, "responseContent", this ) );
136       }
137 
138       addProperty( new DefaultTestStepProperty( "Request", true, new DefaultTestStepProperty.PropertyHandlerAdapter()
139       {
140          public String getValue( DefaultTestStepProperty property )
141          {
142             WsdlMockResult mockResult = mockResponse == null ? null : mockResponse.getMockResult();
143             return mockResult == null ? null : mockResult.getMockRequest().getRequestContent();
144          }
145       }, this ) );
146    }
147 
148    @Override
149    public ImageIcon getIcon()
150    {
151       return iconAnimator == null ? null : iconAnimator.getIcon();
152    }
153 
154    private void initAssertions()
155    {
156       assertionsSupport = new AssertionsSupport( this, new AssertableConfig()
157       {
158 
159          public TestAssertionConfig addNewAssertion()
160          {
161             return mockResponseStepConfig.addNewAssertion();
162          }
163 
164          public List<TestAssertionConfig> getAssertionList()
165          {
166             return mockResponseStepConfig.getAssertionList();
167          }
168 
169          public void removeAssertion( int ix )
170          {
171             mockResponseStepConfig.removeAssertion( ix );
172          }
173       } );
174    }
175 
176    private void initMockObjects( WsdlTestCase testCase )
177    {
178       MockServiceConfig mockServiceConfig = MockServiceConfig.Factory.newInstance();
179       mockServiceConfig.setPath( mockResponseStepConfig.getPath() );
180       mockServiceConfig.setPort( mockResponseStepConfig.getPort() );
181 
182       mockService = new WsdlTestMockService( this, mockServiceConfig );
183       mockService.setName( getName() );
184 
185       iface = (WsdlInterface) testCase.getTestSuite().getProject().getInterfaceByName(
186               mockResponseStepConfig.getInterface() );
187       if( iface == null )
188       {
189       }
190       else
191       {
192          iface.addInterfaceListener( interfaceListener );
193 
194          mockOperation = mockService.addNewMockOperation( iface
195                  .getOperationByName( mockResponseStepConfig.getOperation() ) );
196 
197          if( mockResponseStepConfig.getHandleFault() )
198             mockService.setFaultMockOperation( mockOperation );
199 
200          if( mockResponseStepConfig.getHandleResponse() )
201             mockService.setDispatchResponseMessages( true );
202 
203          mockResponse = mockOperation.addNewMockResponse( "MockResponse", false );
204          mockResponse.setConfig( mockResponseConfig );
205 
206          mockOperation.setDefaultResponse( mockResponse.getName() );
207 
208          mockResponse.addPropertyChangeListener( this );
209       }
210    }
211 
212    public void resetConfigOnMove( TestStepConfig config )
213    {
214       super.resetConfigOnMove( config );
215 
216       mockResponseStepConfig = (MockResponseStepConfig) config.getConfig().changeType( MockResponseStepConfig.type );
217       mockResponseConfig = mockResponseStepConfig.getResponse();
218       mockResponse.setConfig( mockResponseConfig );
219       assertionsSupport.refresh();
220    }
221 
222    @Override
223    public boolean cancel()
224    {
225       if( mockRunner != null )
226       {
227          mockRunner.stop();
228          mockRunner = null;
229       }
230 
231       if( mockRunListener != null )
232          mockRunListener.cancel();
233 
234       return true;
235    }
236 
237    @Override
238    public void prepare( TestRunner testRunner, TestRunContext testRunContext ) throws Exception
239    {
240       super.prepare( testRunner, testRunContext );
241 
242       LoadTestRunner loadTestRunner = (LoadTestRunner) testRunContext.getProperty( TestRunContext.LOAD_TEST_RUNNER );
243       mockRunListener = new InternalMockRunListener();
244 
245       if( loadTestRunner == null )
246       {
247          mockService.addMockRunListener( mockRunListener );
248          mockRunner = mockService.start( (WsdlTestRunContext) testRunContext );
249       }
250       else
251       {
252          synchronized( STATUS_PROPERTY )
253          {
254             mockRunner = (WsdlMockRunner) testRunContext.getProperty( "sharedMockServiceRunner" );
255             if( mockRunner == null )
256             {
257                mockService.addMockRunListener( mockRunListener );
258                mockRunner = mockService.start( (WsdlTestRunContext) testRunContext );
259             }
260             else
261             {
262                mockRunner.getMockService().addMockRunListener( mockRunListener );
263             }
264          }
265       }
266    }
267 
268    protected void initTestMockResponse( TestRunContext testRunContext )
269    {
270       if( StringUtils.hasContent( getQuery() ) && StringUtils.hasContent( getMatch() ) )
271       {
272          testMockResponse = mockOperation.addNewMockResponse( "MockResponse" + Math.random(), false );
273          testMockResponse.setConfig( mockResponse.getConfig() );
274 
275          QueryMatchMockOperationDispatcher dispatcher = (QueryMatchMockOperationDispatcher) mockOperation.setDispatchStyle( MockOperationDispatchStyleConfig.QUERY_MATCH.toString() );
276          QueryMatchMockOperationDispatcher.Query query = dispatcher.addQuery( "Match" );
277          query.setQuery( PropertyExpansionUtils.expandProperties( testRunContext, getQuery() ) );
278          query.setMatch( PropertyExpansionUtils.expandProperties( testRunContext, getMatch() ) );
279          query.setResponse( testMockResponse.getName() );
280       }
281       else
282       {
283          testMockResponse = mockResponse;
284       }
285    }
286 
287    public TestStepResult run( TestRunner testRunner, TestRunContext context )
288    {
289       LoadTestRunner loadTestRunner = (LoadTestRunner) context.getProperty( TestRunContext.LOAD_TEST_RUNNER );
290       if( loadTestRunner == null )
291       {
292          return internalRun( (WsdlTestRunContext) context );
293       }
294       else
295       {
296          // block other threads during loadtesting -> this should be improved!
297          synchronized( STATUS_PROPERTY )
298          {
299             if( loadTestRunner.getStatus() == LoadTestRunner.Status.RUNNING )
300             {
301                return internalRun( (WsdlTestRunContext) context );
302             }
303             else
304             {
305                WsdlSingleMessageExchangeTestStepResult result = new WsdlSingleMessageExchangeTestStepResult( this );
306                result.setStatus( TestStepStatus.UNKNOWN );
307                return result;
308             }
309          }
310       }
311    }
312 
313    private TestStepResult internalRun( WsdlTestRunContext context )
314    {
315       iconAnimator.start();
316       WsdlSingleMessageExchangeTestStepResult result = new WsdlSingleMessageExchangeTestStepResult( this );
317 
318       try
319       {
320          if( !mockRunListener.hasResult() )
321          {
322             if( testMockResponse == null )
323                initTestMockResponse( context );
324 
325             result.startTimer();
326 
327             long timeout = getTimeout();
328             synchronized( mockRunListener )
329             {
330                mockRunListener.waitForRequest( timeout );
331             }
332          }
333 
334          result.stopTimer();
335 
336          AssertedWsdlMockResultMessageExchange messageExchange = new AssertedWsdlMockResultMessageExchange( mockRunListener
337                  .getResult() );
338          result.setMessageExchange( messageExchange );
339 
340          if( mockRunListener.getResult() != null )
341          {
342             context.setProperty( AssertedXPathsContainer.ASSERTEDXPATHSCONTAINER_PROPERTY, messageExchange );
343             assertResult( mockRunListener.getResult(), context );
344          }
345 
346          if( mockRunListener.getResult() == null )
347          {
348             if( mockRunListener.isCanceled() )
349             {
350                result.setStatus( TestStepStatus.CANCELED );
351             }
352             else
353             {
354                result.setStatus( TestStepStatus.FAILED );
355                result.addMessage( "Timeout occured after " + getTimeout() + " milliseconds" );
356             }
357          }
358          else
359          {
360             AssertionStatus status = getAssertionStatus();
361             if( status == AssertionStatus.FAILED )
362             {
363                result.setStatus( TestStepStatus.FAILED );
364 
365                if( getAssertionCount() == 0 )
366                {
367                   result.addMessage( "Invalid/empty request" );
368                }
369                else
370                   for( int c = 0; c < getAssertionCount(); c++ )
371                   {
372                      AssertionError[] errors = getAssertionAt( c ).getErrors();
373                      if( errors != null )
374                      {
375                         for( AssertionError error : errors )
376                         {
377                            result.addMessage( error.getMessage() );
378                         }
379                      }
380                   }
381             }
382             else
383             {
384                result.setStatus( TestStepStatus.OK );
385             }
386 
387             mockRunListener.setResult( null );
388          }
389       }
390       catch( Exception e )
391       {
392          result.stopTimer();
393          result.setStatus( TestStepStatus.FAILED );
394          result.setError( e );
395          SoapUI.logError( e );
396       }
397       finally
398       {
399          iconAnimator.stop();
400       }
401 
402       return result;
403    }
404 
405    private void assertResult( WsdlMockResult result, SubmitContext context )
406    {
407       if( oldStatus == null )
408          oldStatus = getAssertionStatus();
409 
410       for( int c = 0; c < getAssertionCount(); c++ )
411       {
412          WsdlMessageAssertion assertion = getAssertionAt( c );
413          if( !assertion.isDisabled() )
414          {
415             assertion.assertRequest( new WsdlMockResultMessageExchange( result, getMockResponse() ), context );
416          }
417       }
418 
419       AssertionStatus newStatus = getAssertionStatus();
420       if( newStatus != oldStatus )
421       {
422          notifyPropertyChanged( STATUS_PROPERTY, oldStatus, newStatus );
423          oldStatus = newStatus;
424       }
425    }
426 
427    @Override
428    public void finish( TestRunner testRunner, TestRunContext testRunContext )
429    {
430       if( mockRunListener != null )
431       {
432          mockService.removeMockRunListener( mockRunListener );
433          mockRunListener = null;
434       }
435 
436       if( testMockResponse != null )
437       {
438          if( testMockResponse != mockResponse )
439          {
440             mockOperation.removeMockResponse( testMockResponse );
441          }
442          
443          testMockResponse = null;
444       }
445 
446       if( mockRunner != null )
447       {
448          if( mockRunner.isRunning() )
449          {
450             mockRunner.stop();
451          }
452 
453          mockRunner = null;
454       }
455    }
456 
457    public class InternalMockRunListener extends MockRunListenerAdapter
458    {
459       private WsdlMockResult result;
460       private boolean canceled;
461       private boolean waiting;
462 
463       public void onMockResult( MockResult result )
464       {
465          // is this for us?
466          if( this.result == null && waiting && result.getMockResponse() == testMockResponse )
467          {
468             // save
469             this.setResult( (WsdlMockResult) result );
470 
471             // stop runner
472             mockRunner.stop();
473 
474             if( waiting )
475             {
476                synchronized( this )
477                {
478                   notifyAll();
479                }
480             }
481          }
482       }
483 
484       public void cancel()
485       {
486          canceled = true;
487         // mockRunListener.onMockResult( null );
488       }
489 
490       private void setResult( WsdlMockResult result )
491       {
492          this.result = result;
493       }
494 
495       public WsdlMockResult getResult()
496       {
497          return result;
498       }
499 
500       public boolean isCanceled()
501       {
502          return canceled;
503       }
504 
505       public boolean hasResult()
506       {
507          return result != null;
508       }
509 
510       public boolean isWaiting()
511       {
512          return waiting;
513       }
514 
515       public void setWaiting( boolean waiting )
516       {
517          this.waiting = waiting;
518       }
519 
520       public void waitForRequest( long timeout ) throws InterruptedException
521       {
522          waiting = true;
523          wait( timeout );
524       }
525 
526       @Override
527       public void onMockRunnerStart( MockRunner mockRunner )
528       {
529          waiting = false;
530          result = null;
531          canceled = false;
532       }
533    }
534 
535    public WsdlMockResponse getMockResponse()
536    {
537       return mockResponse;
538    }
539 
540    public void setPort( int port )
541    {
542       int old = getPort();
543       mockService.setPort( port );
544       mockResponseStepConfig.setPort( port );
545       notifyPropertyChanged( "port", old, port );
546    }
547 
548    public String getPath()
549    {
550       return mockResponseStepConfig.getPath();
551    }
552 
553    public long getContentLength()
554    {
555       return mockResponse == null ? 0 : mockResponse.getContentLength();
556    }
557 
558    public int getPort()
559    {
560       return mockResponseStepConfig.getPort();
561    }
562 
563    public String getEncoding()
564    {
565       return mockResponse.getEncoding();
566    }
567 
568    public void setEncoding( String encoding )
569    {
570       String old = getEncoding();
571       mockResponse.setEncoding( encoding );
572       notifyPropertyChanged( "encoding", old, encoding );
573    }
574 
575    public boolean isMtomEnabled()
576    {
577       return mockResponse.isMtomEnabled();
578    }
579 
580    public void setMtomEnabled( boolean enabled )
581    {
582       if( isMtomEnabled() == enabled )
583          return;
584       mockResponse.setMtomEnabled( enabled );
585 
586       notifyPropertyChanged( "mtomEnabled", !enabled, enabled );
587    }
588 
589    public String getOutgoingWss()
590    {
591       return mockResponse.getOutgoingWss();
592    }
593 
594    public void setOutgoingWss( String outgoingWss )
595    {
596       String old = getOutgoingWss();
597       mockResponse.setOutgoingWss( outgoingWss );
598       notifyPropertyChanged( "outgoingWss", old, outgoingWss );
599    }
600 
601    public void setQuery( String s )
602    {
603       String old = getQuery();
604       mockResponseStepConfig.setQuery( s );
605       notifyPropertyChanged( "query", old, s );
606    }
607 
608    public String getQuery()
609    {
610       return mockResponseStepConfig.getQuery();
611    }
612 
613    public String getMatch()
614    {
615       return mockResponseStepConfig.getMatch();
616    }
617 
618    public void setMatch( String s )
619    {
620       String old = getMatch();
621       mockResponseStepConfig.setMatch( s );
622       notifyPropertyChanged( "match", old, s );
623    }
624 
625    public boolean isForceMtom()
626    {
627       return mockResponse.isForceMtom();
628    }
629 
630    public void setForceMtom( boolean forceMtom )
631    {
632       mockResponse.setForceMtom( forceMtom );
633    }
634 
635    public boolean isInlineFilesEnabled()
636    {
637       return mockResponse.isInlineFilesEnabled();
638    }
639 
640    public void setInlineFilesEnabled( boolean inlineFilesEnabled )
641    {
642       mockResponse.setInlineFilesEnabled( inlineFilesEnabled );
643    }
644 
645    public String getStartStep()
646    {
647       return startTestStep == null ? "" : startTestStep.getName();
648    }
649 
650    public void setStartStep( String startStep )
651    {
652       String old = getStartStep();
653       if( startTestStep != null )
654       {
655          startTestStep.removePropertyChangeListener( this );
656          startTestStep = null;
657       }
658 
659       if( startStep != null )
660       {
661          startTestStep = getTestCase().getTestStepByName( startStep );
662          if( startTestStep != null )
663          {
664             startTestStep.addPropertyChangeListener( this );
665          }
666       }
667 
668       mockResponseStepConfig.setStartStep( startStep );
669       notifyPropertyChanged( "startStep", old, startStep );
670    }
671 
672    public boolean isMultipartEnabled()
673    {
674       return mockResponse.isMultipartEnabled();
675    }
676 
677    public void setMultipartEnabled( boolean enabled )
678    {
679       mockResponse.setMultipartEnabled( enabled );
680    }
681 
682    public boolean isHandleFault()
683    {
684       return mockResponseStepConfig.getHandleFault();
685    }
686 
687    public void setHandleFault( boolean handleFault )
688    {
689       mockResponseStepConfig.setHandleFault( handleFault );
690       if( mockService != null )
691          mockService.setFaultMockOperation( handleFault ? mockOperation : null );
692    }
693 
694    public boolean isHandleResponse()
695    {
696       return mockResponseStepConfig.getHandleResponse();
697    }
698 
699    public void setHandleResponse( boolean handleResponse )
700    {
701       mockResponseStepConfig.setHandleResponse( handleResponse );
702       if( mockService != null )
703          mockService.setDispatchResponseMessages( handleResponse );
704    }
705 
706    public long getResponseDelay()
707    {
708       return mockResponse.getResponseDelay();
709    }
710 
711    public void setResponseDelay( long delay )
712    {
713       mockResponse.setResponseDelay( delay );
714    }
715 
716    public String getResponseHttpStatus()
717    {
718       return mockResponse.getResponseHttpStatus();
719    }
720 
721    public void setResponseHttpStatus( String httpStatus )
722    {
723       mockResponse.setResponseHttpStatus( httpStatus );
724    }
725 
726    public boolean isEncodeAttachments()
727    {
728       return mockResponse.isEncodeAttachments();
729    }
730 
731    public boolean isRemoveEmptyContent()
732    {
733       return mockResponse.isRemoveEmptyContent();
734    }
735 
736    public boolean isStripWhitespaces()
737    {
738       return mockResponse.isStripWhitespaces();
739    }
740 
741    public void setEncodeAttachments( boolean encodeAttachments )
742    {
743       mockResponse.setEncodeAttachments( encodeAttachments );
744    }
745 
746    public void setRemoveEmptyContent( boolean removeEmptyContent )
747    {
748       mockResponse.setRemoveEmptyContent( removeEmptyContent );
749    }
750 
751    public void setStripWhitespaces( boolean stripWhitespaces )
752    {
753       mockResponse.setStripWhitespaces( stripWhitespaces );
754    }
755 
756    public void setPath( String path )
757    {
758       mockService.setPath( path );
759       mockResponseStepConfig.setPath( path );
760    }
761 
762    public void propertyChange( PropertyChangeEvent evt )
763    {
764       if( evt.getSource() == mockResponse )
765       {
766          mockResponseConfig.set( mockResponse.getConfig() );
767          notifyPropertyChanged( evt.getPropertyName(), evt.getOldValue(), evt.getNewValue() );
768       }
769       else if( evt.getSource() == getTestCase() && evt.getPropertyName().equals( "testSteps" ) &&
770               evt.getNewValue() == null && evt.getOldValue() == startTestStep && startTestStep != null )
771       {
772          setStartStep( null );
773       }
774       else if( evt.getSource() == startTestStep && evt.getPropertyName().equals( WsdlTestStep.NAME_PROPERTY ))
775       {
776          mockResponseStepConfig.setStartStep( String.valueOf( evt.getNewValue() ) );
777       }
778    }
779 
780    public WsdlMessageAssertion addAssertion( String assertionName )
781    {
782       PropertyChangeNotifier notifier = new PropertyChangeNotifier();
783 
784       try
785       {
786          TestAssertionConfig assertionConfig = mockResponseStepConfig.addNewAssertion();
787          assertionConfig.setType( TestAssertionRegistry.getInstance().getAssertionTypeForName( assertionName ) );
788 
789          WsdlMessageAssertion assertion = assertionsSupport.addWsdlAssertion( assertionConfig );
790          assertionsSupport.fireAssertionAdded( assertion );
791 
792          if( getMockResponse().getMockResult() != null )
793          {
794             assertion.assertRequest( new WsdlMockResultMessageExchange( getMockResponse().getMockResult(),
795                     getMockResponse() ), new WsdlSubmitContext( this ) );
796             notifier.notifyChange();
797          }
798 
799          return assertion;
800       }
801       catch( Exception e )
802       {
803          SoapUI.logError( e );
804          return null;
805       }
806    }
807 
808    public void addAssertionsListener( AssertionsListener listener )
809    {
810       assertionsSupport.addAssertionsListener( listener );
811    }
812 
813    public WsdlMessageAssertion getAssertionAt( int c )
814    {
815       return assertionsSupport.getAssertionAt( c );
816    }
817 
818    public int getAssertionCount()
819    {
820       return assertionsSupport.getAssertionCount();
821    }
822 
823    public void removeAssertionsListener( AssertionsListener listener )
824    {
825       assertionsSupport.removeAssertionsListener( listener );
826    }
827 
828    public AssertionStatus getAssertionStatus()
829    {
830       AssertionStatus currentStatus = AssertionStatus.UNKNOWN;
831       int cnt = getAssertionCount();
832       if( cnt == 0 )
833          return currentStatus;
834 
835        if( mockResponse.getMockResult() != null )
836       {
837          if( mockResponse.getMockResult().getMockRequest() == null )
838          {
839             currentStatus = AssertionStatus.FAILED;
840          }
841       }
842       else
843          return currentStatus;
844 
845       for( int c = 0; c < cnt; c++ )
846       {
847          WsdlMessageAssertion assertion = getAssertionAt( c );
848          if( assertion.isDisabled() )
849             continue;
850 
851          if( assertion.getStatus() == AssertionStatus.FAILED )
852          {
853             currentStatus = AssertionStatus.FAILED;
854             break;
855          }
856       }
857 
858       if( currentStatus == AssertionStatus.UNKNOWN )
859          currentStatus = AssertionStatus.VALID;
860 
861       return currentStatus;
862    }
863 
864    public void removeAssertion( TestAssertion assertion )
865    {
866       PropertyChangeNotifier notifier = new PropertyChangeNotifier();
867 
868       try
869       {
870          assertionsSupport.removeAssertion( (WsdlMessageAssertion) assertion );
871       }
872       finally
873       {
874          ( (WsdlMessageAssertion) assertion ).release();
875          notifier.notifyChange();
876       }
877    }
878 
879    public String getAssertableContent()
880    {
881       WsdlMockResult mockResult = getMockResponse().getMockResult();
882       return mockResult == null ? null : mockResult.getMockRequest().getRequestContent();
883    }
884 
885    public TestStep getTestStep()
886    {
887       return this;
888    }
889 
890    @Override
891    public void setName( String name )
892    {
893       super.setName( name );
894       if( mockService != null )
895          mockService.setName( getName() );
896    }
897 
898    public WsdlInterface getInterface()
899    {
900       return getOperation().getInterface();
901    }
902 
903    public WsdlOperation getOperation()
904    {
905       return getMockResponse().getMockOperation().getOperation();
906    }
907 
908    public void setInterface( String string )
909    {
910       WsdlInterface iface = (WsdlInterface) getTestCase().getTestSuite().getProject().getInterfaceByName( string );
911       if( iface != null )
912       {
913          mockResponseStepConfig.setInterface( iface.getName() );
914          WsdlOperation operation = iface.getOperationAt( 0 );
915          mockResponseStepConfig.setOperation( operation.getName() );
916          mockOperation.setOperation( operation );
917       }
918    }
919 
920    public void setOperation( String string )
921    {
922       WsdlOperation operation = getInterface().getOperationByName( string );
923       if( operation != null )
924       {
925          mockResponseStepConfig.setOperation( string );
926          mockOperation.setOperation( operation );
927       }
928    }
929 
930    private class PropertyChangeNotifier
931    {
932       private AssertionStatus oldStatus;
933       private ImageIcon oldIcon;
934 
935       public PropertyChangeNotifier()
936       {
937          oldStatus = getAssertionStatus();
938          oldIcon = getIcon();
939       }
940 
941       public void notifyChange()
942       {
943          AssertionStatus newStatus = getAssertionStatus();
944          ImageIcon newIcon = getIcon();
945 
946          if( oldStatus != newStatus )
947             notifyPropertyChanged( STATUS_PROPERTY, oldStatus, newStatus );
948 
949          if( oldIcon != newIcon )
950             notifyPropertyChanged( ICON_PROPERTY, oldIcon, getIcon() );
951       }
952    }
953 
954    @Override
955    public void release()
956    {
957       super.release();
958       assertionsSupport.release();
959 
960       if( mockResponse != null )
961          mockResponse.removePropertyChangeListener( this );
962 
963       if( mockService != null )
964          mockService.release();
965 
966       if( iface != null )
967       {
968          iface.getProject().removeProjectListener( projectListener );
969          iface.removeInterfaceListener( interfaceListener );
970       }
971 
972       getTestCase().removeTestRunListener( testRunListener );
973       getTestCase().removePropertyChangeListener( this );
974    }
975 
976    public AssertableType getAssertableType()
977    {
978       return AssertableType.REQUEST;
979    }
980 
981    @Override
982    public Collection<WsdlInterface> getRequiredInterfaces()
983    {
984       ArrayList<WsdlInterface> result = new ArrayList<WsdlInterface>();
985       result.add( getInterface() );
986       return result;
987    }
988 
989    public String getDefaultSourcePropertyName()
990    {
991       return "Response";
992    }
993 
994    public String getDefaultTargetPropertyName()
995    {
996       return "Request";
997    }
998 
999    @Override
1000    public void beforeSave()
1001    {
1002       super.beforeSave();
1003 
1004       if( mockResponse != null )
1005       {
1006          mockResponse.beforeSave();
1007          mockResponseConfig.set( mockResponse.getConfig() );
1008       }
1009    }
1010 
1011    public long getTimeout()
1012    {
1013       return mockResponseStepConfig.getTimeout();
1014    }
1015 
1016    public void setTimeout( long timeout )
1017    {
1018       long old = getTimeout();
1019       mockResponseStepConfig.setTimeout( timeout );
1020       notifyPropertyChanged( TIMEOUT_PROPERTY, old, timeout );
1021    }
1022 
1023    @Override
1024    public boolean dependsOn( AbstractWsdlModelItem<?> modelItem )
1025    {
1026       return modelItem == getOperation().getInterface();
1027    }
1028 
1029    public class InternalProjectListener extends ProjectListenerAdapter
1030    {
1031       public void interfaceRemoved( Interface iface )
1032       {
1033          if( getOperation() != null && getOperation().getInterface().equals( iface ) )
1034          {
1035             log.debug( "Removing test step due to removed interface" );
1036             ( getTestCase() ).removeTestStep( WsdlMockResponseTestStep.this );
1037          }
1038       }
1039    }
1040 
1041    public class InternalInterfaceListener extends InterfaceListenerAdapter
1042    {
1043       public void operationRemoved( Operation operation )
1044       {
1045          if( operation == getOperation() )
1046          {
1047             log.debug( "Removing test step due to removed operation" );
1048             ( getTestCase() ).removeTestStep( WsdlMockResponseTestStep.this );
1049          }
1050       }
1051 
1052       @Override
1053       public void operationUpdated( Operation operation )
1054       {
1055          if( operation == getOperation() )
1056          {
1057             setOperation( operation.getName() );
1058          }
1059       }
1060    }
1061 
1062    public WsdlMessageAssertion cloneAssertion( TestAssertion source, String name )
1063    {
1064       TestAssertionConfig conf = mockResponseStepConfig.addNewAssertion();
1065       conf.set( ( (WsdlMessageAssertion) source ).getConfig() );
1066       conf.setName( name );
1067 
1068       WsdlMessageAssertion result = assertionsSupport.addWsdlAssertion( conf );
1069       assertionsSupport.fireAssertionAdded( result );
1070       return result;
1071    }
1072 
1073    public List<TestAssertion> getAssertionList()
1074    {
1075       return new ArrayList<TestAssertion>( assertionsSupport.getAssertionList() );
1076    }
1077 
1078    @Override
1079    public List<? extends ModelItem> getChildren()
1080    {
1081       return assertionsSupport.getAssertionList();
1082    }
1083 
1084    public PropertyExpansion[] getPropertyExpansions()
1085    {
1086       List<PropertyExpansion> result = new ArrayList<PropertyExpansion>();
1087 
1088       result.addAll( PropertyExpansionUtils.extractPropertyExpansions( this, mockResponse, "responseContent" ) );
1089 
1090       StringToStringMap responseHeaders = mockResponse.getResponseHeaders();
1091       for( String key : responseHeaders.keySet() )
1092       {
1093          result.addAll( PropertyExpansionUtils.extractPropertyExpansions( this, new ResponseHeaderHolder( responseHeaders,
1094                  key ), "value" ) );
1095       }
1096 
1097       return result.toArray( new PropertyExpansion[result.size()] );
1098    }
1099 
1100    public class ResponseHeaderHolder
1101    {
1102       private final StringToStringMap valueMap;
1103       private final String key;
1104 
1105       public ResponseHeaderHolder( StringToStringMap valueMap, String key )
1106       {
1107          this.valueMap = valueMap;
1108          this.key = key;
1109       }
1110 
1111       public String getValue()
1112       {
1113          return valueMap.get( key );
1114       }
1115 
1116       public void setValue( String value )
1117       {
1118          valueMap.put( key, value );
1119          mockResponse.setResponseHeaders( valueMap );
1120       }
1121    }
1122 
1123    public WsdlMessageAssertion getAssertionByName( String name )
1124    {
1125       return assertionsSupport.getAssertionByName( name );
1126    }
1127 
1128    public Map<String, TestAssertion> getAssertions()
1129    {
1130       Map<String, TestAssertion> result = new HashMap<String, TestAssertion>();
1131 
1132       for( TestAssertion assertion : getAssertionList() )
1133          result.put( assertion.getName(), assertion );
1134 
1135       return result;
1136    }
1137 
1138    private class AssertedWsdlMockResultMessageExchange extends WsdlMockResultMessageExchange implements
1139            RequestAssertedMessageExchange, AssertedXPathsContainer
1140    {
1141       private List<AssertedXPath> assertedXPaths;
1142 
1143       public AssertedWsdlMockResultMessageExchange( WsdlMockResult mockResult )
1144       {
1145          super( mockResult, mockResult == null ? null : mockResult.getMockResponse() );
1146       }
1147 
1148       public AssertedXPath[] getAssertedXPathsForRequest()
1149       {
1150          return assertedXPaths == null ? new AssertedXPath[0] : assertedXPaths.toArray( new AssertedXPath[assertedXPaths
1151                  .size()] );
1152       }
1153 
1154       public void addAssertedXPath( AssertedXPath assertedXPath )
1155       {
1156          if( assertedXPaths == null )
1157             assertedXPaths = new ArrayList<AssertedXPath>();
1158 
1159          assertedXPaths.add( assertedXPath );
1160       }
1161    }
1162 
1163    public String getDefaultAssertableContent()
1164    {
1165       return getOperation().createRequest( true );
1166    }
1167 
1168    @SuppressWarnings( "unchecked" )
1169    @Override
1170    public void resolve( ResolveContext context )
1171    {
1172       super.resolve( context );
1173 
1174       if( mockOperation == null )
1175       {
1176          if( context.hasThisModelItem( this, "Missing Operation in Project", mockResponseStepConfig.getInterface() + "/"
1177                  + mockResponseStepConfig.getOperation() ) )
1178             return;
1179          context.addPathToResolve( this, "Missing Operation in Project",
1180                  mockResponseStepConfig.getInterface() + "/" + mockResponseStepConfig.getOperation() ).addResolvers(
1181                  new RemoveTestStepResolver( this ), new ImportInterfaceResolver( this )
1182                  {
1183 
1184                     @Override
1185                     protected boolean update()
1186                     {
1187                        initMockObjects( getTestCase() );
1188                        initProperties();
1189                        setDisabled( false );
1190                        return true;
1191                     }
1192                  }, new ChangeOperationResolver( this, "Operation" )
1193                  {
1194 
1195                     @Override
1196                     public boolean update()
1197                     {
1198                        WsdlOperation operation = (WsdlOperation) getSelectedOperation();
1199                        setInterface( operation.getInterface().getName() );
1200                        setOperation( operation.getName() );
1201                        initMockObjects( getTestCase() );
1202                        initProperties();
1203                        setDisabled( false );
1204                        return true;
1205                     }
1206 
1207                     protected Interface[] getInterfaces( WsdlProject project )
1208                     {
1209                        List<WsdlInterface> interfaces = ModelSupport.getChildren( project, WsdlInterface.class );
1210                        return interfaces.toArray( new Interface[interfaces.size()] );
1211 
1212                     }
1213 
1214                  } );
1215       }
1216       else
1217       {
1218          mockOperation.resolve( context );
1219          if( context.hasThisModelItem( this, "Missing Operation in Project", mockResponseStepConfig.getInterface() + "/"
1220                  + mockResponseStepConfig.getOperation() ) )
1221          {
1222             PathToResolve path = context.getPath( this, "Missing Operation in Project", mockResponseStepConfig.getInterface() + "/"
1223                     + mockResponseStepConfig.getOperation() );
1224             path.setSolved( true );
1225          }
1226       }
1227    }
1228 
1229    private class InternalTestRunListener extends TestRunListenerAdapter
1230    {
1231       @Override
1232       public void beforeStep( TestRunner testRunner, TestRunContext runContext )
1233       {
1234          if( runContext.getCurrentStep() == startTestStep && testMockResponse == null )
1235          {
1236             initTestMockResponse( runContext );
1237             mockRunListener.setWaiting( true );
1238          }
1239       }
1240    }
1241 
1242 }