View Javadoc

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