View Javadoc

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