/*
 *  soapUI, copyright (C) 2004-2012 smartbear.com 
 *
 *  soapUI is free software; you can redistribute it and/or modify it under the 
 *  terms of version 2.1 of the GNU Lesser General Public License as published by 
 *  the Free Software Foundation.
 *
 *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
 *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 *  See the GNU Lesser General Public License for more details at gnu.org.
 */

package com.eviware.soapui.impl.wsdl.teststeps;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import javax.swing.ImageIcon;
import javax.xml.namespace.QName;

import org.apache.log4j.Logger;
import org.apache.xmlbeans.SchemaType;
import org.apache.xmlbeans.XmlString;

import com.eviware.soapui.SoapUI;
import com.eviware.soapui.config.RequestStepConfig;
import com.eviware.soapui.config.TestStepConfig;
import com.eviware.soapui.impl.support.http.HttpRequestTestStep;
import com.eviware.soapui.impl.wsdl.AbstractWsdlModelItem;
import com.eviware.soapui.impl.wsdl.WsdlInterface;
import com.eviware.soapui.impl.wsdl.WsdlOperation;
import com.eviware.soapui.impl.wsdl.WsdlProject;
import com.eviware.soapui.impl.wsdl.WsdlRequest;
import com.eviware.soapui.impl.wsdl.WsdlSubmit;
import com.eviware.soapui.impl.wsdl.submit.transports.http.WsdlResponse;
import com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.WsdlSinglePartHttpResponse;
import com.eviware.soapui.impl.wsdl.support.assertions.AssertedXPathsContainer;
import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils;
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
import com.eviware.soapui.impl.wsdl.teststeps.assertions.TestAssertionRegistry.AssertableType;
import com.eviware.soapui.model.ModelItem;
import com.eviware.soapui.model.iface.Interface;
import com.eviware.soapui.model.iface.Operation;
import com.eviware.soapui.model.iface.Request.SubmitException;
import com.eviware.soapui.model.iface.Submit;
import com.eviware.soapui.model.project.Project;
import com.eviware.soapui.model.propertyexpansion.PropertyExpander;
import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContainer;
import com.eviware.soapui.model.propertyexpansion.PropertyExpansionsResult;
import com.eviware.soapui.model.support.DefaultTestStepProperty;
import com.eviware.soapui.model.support.InterfaceListenerAdapter;
import com.eviware.soapui.model.support.ModelSupport;
import com.eviware.soapui.model.support.ProjectListenerAdapter;
import com.eviware.soapui.model.support.TestStepBeanProperty;
import com.eviware.soapui.model.testsuite.Assertable;
import com.eviware.soapui.model.testsuite.AssertionError;
import com.eviware.soapui.model.testsuite.AssertionsListener;
import com.eviware.soapui.model.testsuite.OperationTestStep;
import com.eviware.soapui.model.testsuite.TestAssertion;
import com.eviware.soapui.model.testsuite.TestCaseRunContext;
import com.eviware.soapui.model.testsuite.TestCaseRunner;
import com.eviware.soapui.model.testsuite.TestStep;
import com.eviware.soapui.model.testsuite.TestStepResult;
import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus;
import com.eviware.soapui.security.Securable;
import com.eviware.soapui.support.resolver.ChangeOperationResolver;
import com.eviware.soapui.support.resolver.ImportInterfaceResolver;
import com.eviware.soapui.support.resolver.RemoveTestStepResolver;
import com.eviware.soapui.support.resolver.ResolveContext;
import com.eviware.soapui.support.resolver.ResolveContext.PathToResolve;
import com.eviware.soapui.support.types.StringToStringsMap;

/**
 * WsdlTestStep that executes a WsdlTestRequest
 * 
 * @author Ole.Matzura
 */

public class WsdlTestRequestStep extends WsdlTestStepWithProperties implements OperationTestStep,
		PropertyChangeListener, PropertyExpansionContainer, Assertable, HttpRequestTestStep, Securable
{
	private final static Logger log = Logger.getLogger( WsdlTestRequestStep.class );
	private RequestStepConfig requestStepConfig;
	private WsdlTestRequest testRequest;
	private WsdlOperation wsdlOperation;
	private final InternalProjectListener projectListener = new InternalProjectListener();
	private final InternalInterfaceListener interfaceListener = new InternalInterfaceListener();
	private WsdlSubmit<WsdlRequest> submit;

	public WsdlTestRequestStep( WsdlTestCase testCase, TestStepConfig config, boolean forLoadTest )
	{
		super( testCase, config, true, forLoadTest );

		if( getConfig().getConfig() != null )
		{
			requestStepConfig = ( RequestStepConfig )getConfig().getConfig().changeType( RequestStepConfig.type );

			wsdlOperation = findWsdlOperation();
			if( wsdlOperation == null )
			{
				log.error( "Could not find operation [" + requestStepConfig.getOperation() + "] in interface ["
						+ requestStepConfig.getInterface() + "] for test request [" + getName() + "] in TestCase ["
						+ getTestCase().getTestSuite().getName() + "/" + getTestCase().getName() + "]" );
				// requestStepConfig.setRequest(null);
				setDisabled( true );
			}
			else
			{
				initTestRequest( config, forLoadTest );
			}
		}
		else
		{
			requestStepConfig = ( RequestStepConfig )getConfig().addNewConfig().changeType( RequestStepConfig.type );
		}

		// init properties
		if( testRequest != null )
		{
			initRequestProperties();
		}
	}

	private void initRequestProperties()
	{
		addProperty( new TestStepBeanProperty( "Endpoint", false, testRequest, "endpoint", this, false ) );
		addProperty( new TestStepBeanProperty( "Username", false, testRequest, "username", this, true ) );
		addProperty( new TestStepBeanProperty( "Password", false, testRequest, "password", this, true ) );
		addProperty( new TestStepBeanProperty( "Domain", false, testRequest, "domain", this, false ) );
		addProperty( new TestStepBeanProperty( "AuthType", false, testRequest, "authType", this,true) {
			
			@Override
			public String getDefaultValue()
			{
				// TODO Auto-generated method stub
				return "XXX";
			}
		});
		
		addProperty( new TestStepBeanProperty( "Request", false, testRequest, "requestContent", this, true )
		{
			@Override
			public String getDefaultValue()
			{
				return getOperation().createRequest( true );
			}

			@Override
			public SchemaType getSchemaType()
			{
				try
				{
					WsdlInterface iface = getOperation().getInterface();
					if( WsdlUtils.isRpc( iface.getBinding() ) )
						return WsdlUtils.generateRpcBodyType( getOperation() );
					else
						return iface.getDefinitionContext().getSchemaTypeSystem()
								.findElement( getOperation().getRequestBodyElementQName() ).getType();
				}
				catch( Exception e )
				{
					SoapUI.logError( e );
					return XmlString.type;
				}
			}

			@Override
			public QName getType()
			{
				return getSchemaType().getName();
			}

		} );
		addProperty( new TestStepBeanProperty( "Response", true, testRequest, "responseContent", this )
		{
			@Override
			public String getDefaultValue()
			{
				return getOperation().createResponse( true );
			}
		} );

		addProperty( new DefaultTestStepProperty( "RawRequest", true, this )
		{
			@Override
			public String getValue()
			{
				WsdlResponse response = testRequest.getResponse();
				return response == null ? null : response.getRequestContent();
			}
		} );
	}

	private void initTestRequest( TestStepConfig config, boolean forLoadTest )
	{
		if( !forLoadTest )
		{
			wsdlOperation.getInterface().getProject().addProjectListener( projectListener );
			wsdlOperation.getInterface().addInterfaceListener( interfaceListener );

			// we need to listen for name changes which happen when
			// interfaces are updated..
			wsdlOperation.getInterface().addPropertyChangeListener( this );
			wsdlOperation.addPropertyChangeListener( this );
		}

		testRequest = new WsdlTestRequest( wsdlOperation, requestStepConfig.getRequest(), this, forLoadTest );
		testRequest.addPropertyChangeListener( this );

		if( config.isSetName() )
			testRequest.setName( config.getName() );
		else
			config.setName( testRequest.getName() );
	}

	@Override
	public WsdlTestStep clone( WsdlTestCase targetTestCase, String name )
	{
		beforeSave();

		TestStepConfig config = ( TestStepConfig )getConfig().copy();
		RequestStepConfig stepConfig = ( RequestStepConfig )config.getConfig().changeType( RequestStepConfig.type );

		while( stepConfig.getRequest().sizeOfAttachmentArray() > 0 )
			stepConfig.getRequest().removeAttachment( 0 );

		config.setName( name );
		stepConfig.getRequest().setName( name );

		WsdlTestRequestStep result = ( WsdlTestRequestStep )targetTestCase.addTestStep( config );
		testRequest.copyAttachmentsTo( result.getTestRequest() );

		return result;
	}

	private WsdlOperation findWsdlOperation()
	{
		WsdlTestCase testCase = getTestCase();
		if( testCase == null || testCase.getTestSuite() == null )
			return null;

		Project project = testCase.getTestSuite().getProject();
		WsdlOperation operation = null;
		for( int c = 0; c < project.getInterfaceCount(); c++ )
		{
			if( project.getInterfaceAt( c ).getName().equals( requestStepConfig.getInterface() ) )
			{
				WsdlInterface iface = ( WsdlInterface )project.getInterfaceAt( c );
				for( int i = 0; i < iface.getOperationCount(); i++ )
				{
					if( iface.getOperationAt( i ).getName().equals( requestStepConfig.getOperation() ) )
					{
						operation = iface.getOperationAt( i );
						break;
					}
				}

				if( operation != null )
					break;
			}
		}
		return operation;
	}

	public String getInterfaceName()
	{
		return requestStepConfig.getInterface();
	}

	public String getOperationName()
	{
		return requestStepConfig.getOperation();
	}

	@Override
	public void release()
	{
		super.release();

		if( wsdlOperation == null )
			wsdlOperation = findWsdlOperation();

		if( wsdlOperation != null )
		{
			wsdlOperation.removePropertyChangeListener( this );
			wsdlOperation.getInterface().getProject().removeProjectListener( projectListener );
			wsdlOperation.getInterface().removeInterfaceListener( interfaceListener );
			wsdlOperation.getInterface().removePropertyChangeListener( this );
		}

		// could be null if initialization failed..
		if( testRequest != null )
		{
			testRequest.removePropertyChangeListener( this );
			testRequest.release();
		}
	}

	@Override
	public void resetConfigOnMove( TestStepConfig config )
	{
		super.resetConfigOnMove( config );

		requestStepConfig = ( RequestStepConfig )config.getConfig().changeType( RequestStepConfig.type );
		testRequest.updateConfig( requestStepConfig.getRequest() );
	}

	@Override
	public ImageIcon getIcon()
	{
		return testRequest == null ? null : testRequest.getIcon();
	}

	public WsdlTestRequest getTestRequest()
	{
		return testRequest;
	}

	@Override
	public void setName( String name )
	{
		super.setName( name );
		testRequest.setName( name );
	}

	public void propertyChange( PropertyChangeEvent event )
	{
		// TODO Some of these properties should be pulled up as they are common for may steps
		// FIXME The property names shouldn't be hardcoded
		if( event.getSource() == testRequest )
		{
			if( event.getNewValue() instanceof WsdlSinglePartHttpResponse )
			{
				WsdlSinglePartHttpResponse response = ( WsdlSinglePartHttpResponse )event.getNewValue();
				WsdlRequest request = response.getRequest();
				byte[] rawRequest = response.getRawRequestData();

				firePropertyValueChanged( "Response", String.valueOf( response ), null );
				firePropertyValueChanged( "Request", String.valueOf( request ), null );
				firePropertyValueChanged( "RawRequest", String.valueOf( rawRequest ), null );
			}

			if( event.getPropertyName().equals( "domain" ) )
			{
				delegatePropertyChange( "Domain", event );
			}
			else if( event.getPropertyName().equals( "password" ) )
			{
				delegatePropertyChange( "Password", event );
			}
			else if( event.getPropertyName().equals( "username" ) )
			{
				delegatePropertyChange( "Username", event );
			}
			else if( event.getPropertyName().equals( "endpoint" ) )
			{
				delegatePropertyChange( "Endpoint", event );
			}
		}

		if( event.getSource() == wsdlOperation )
		{
			if( event.getPropertyName().equals( Operation.NAME_PROPERTY ) )
			{
				requestStepConfig.setOperation( ( String )event.getNewValue() );
			}
		}
		else if( event.getSource() == wsdlOperation.getInterface() )
		{
			if( event.getPropertyName().equals( Interface.NAME_PROPERTY ) )
			{
				requestStepConfig.setInterface( ( String )event.getNewValue() );
			}
		}
		else if( event.getPropertyName().equals( TestAssertion.CONFIGURATION_PROPERTY )
				|| event.getPropertyName().equals( TestAssertion.DISABLED_PROPERTY ) )
		{
			if( getTestRequest().getResponse() != null )
			{
				getTestRequest().assertResponse( new WsdlTestRunContext( this ) );
			}
		}
		else
		{
			if( event.getSource() == testRequest && event.getPropertyName().equals( WsdlTestRequest.NAME_PROPERTY ) )
			{
				if( !super.getName().equals( ( String )event.getNewValue() ) )
					super.setName( ( String )event.getNewValue() );
			}

			notifyPropertyChanged( event.getPropertyName(), event.getOldValue(), event.getNewValue() );
		}
	}

	private void delegatePropertyChange( String customPropertyname, PropertyChangeEvent event )
	{
		firePropertyValueChanged( customPropertyname, String.valueOf( event.getOldValue() ),
				String.valueOf( event.getNewValue() ) );

	}

	public TestStepResult run( TestCaseRunner runner, TestCaseRunContext runContext )
	{
		WsdlTestRequestStepResult testStepResult = new WsdlTestRequestStepResult( this );
		testStepResult.startTimer();
		runContext.setProperty( AssertedXPathsContainer.ASSERTEDXPATHSCONTAINER_PROPERTY, testStepResult );

		try
		{
			submit = testRequest.submit( runContext, false );
			WsdlResponse response = ( WsdlResponse )submit.getResponse();

			if( submit.getStatus() != Submit.Status.CANCELED )
			{
				if( submit.getStatus() == Submit.Status.ERROR )
				{
					testStepResult.setStatus( TestStepStatus.FAILED );
					testStepResult.addMessage( submit.getError().toString() );

					testRequest.setResponse( null, runContext );
				}
				else if( response == null )
				{
					testStepResult.setStatus( TestStepStatus.FAILED );
					testStepResult.addMessage( "Request is missing response" );

					testRequest.setResponse( null, runContext );
				}
				else
				{
					runContext.setProperty( AssertedXPathsContainer.ASSERTEDXPATHSCONTAINER_PROPERTY, testStepResult );
					testRequest.setResponse( response, runContext );

					testStepResult.setTimeTaken( response.getTimeTaken() );
					testStepResult.setSize( response.getContentLength() );

					switch( testRequest.getAssertionStatus() )
					{
					case FAILED :
						testStepResult.setStatus( TestStepStatus.FAILED );
						break;
					case VALID :
						testStepResult.setStatus( TestStepStatus.OK );
						break;
					case UNKNOWN :
						testStepResult.setStatus( TestStepStatus.UNKNOWN );
						break;
					}

					testStepResult.setResponse( response, testStepResult.getStatus() != TestStepStatus.FAILED );
				}
			}
			else
			{
				testStepResult.setStatus( TestStepStatus.CANCELED );
				testStepResult.addMessage( "Request was canceled" );
			}

			if( response != null )
				testStepResult.setRequestContent( response.getRequestContent(),
						testStepResult.getStatus() != TestStepStatus.FAILED );
			else
				testStepResult.setRequestContent( testRequest.getRequestContent(),
						testStepResult.getStatus() != TestStepStatus.FAILED );
			testStepResult.stopTimer();
		}
		catch( SubmitException e )
		{
			testStepResult.setStatus( TestStepStatus.FAILED );
			testStepResult.addMessage( "SubmitException: " + e );
			testStepResult.stopTimer();
		}
		finally
		{
			submit = null;
		}

		testStepResult.setDomain( PropertyExpander.expandProperties( runContext, testRequest.getDomain() ) );
		testStepResult.setUsername( PropertyExpander.expandProperties( runContext, testRequest.getUsername() ) );
		testStepResult.setPassword( PropertyExpander.expandProperties( runContext, testRequest.getPassword() ) );
		testStepResult.setEndpoint( PropertyExpander.expandProperties( runContext, testRequest.getEndpoint() ) );
		testStepResult.setEncoding( PropertyExpander.expandProperties( runContext, testRequest.getEncoding() ) );

		if( testStepResult.getStatus() != TestStepStatus.CANCELED )
		{
			AssertionStatus assertionStatus = testRequest.getAssertionStatus();
			switch( assertionStatus )
			{
			case FAILED :
			{
				testStepResult.setStatus( TestStepStatus.FAILED );
				if( getAssertionCount() == 0 )
				{
					testStepResult.addMessage( "Invalid/empty response" );
				}
				else
					for( int c = 0; c < getAssertionCount(); c++ )
					{
						WsdlMessageAssertion assertion = getAssertionAt( c );
						AssertionError[] errors = assertion.getErrors();
						if( errors != null )
						{
							for( AssertionError error : errors )
							{
								testStepResult.addMessage( "[" + assertion.getName() + "] " + error.getMessage() );
							}
						}
					}

				break;
			}
			// default : testStepResult.setStatus( TestStepStatus.OK ); break;
			}
		}

		if( testRequest.isDiscardResponse() && !SoapUI.getDesktop().hasDesktopPanel( this ) )
			testRequest.setResponse( null, runContext );

		return testStepResult;
	}

	public WsdlMessageAssertion getAssertionAt( int index )
	{
		return testRequest.getAssertionAt( index );
	}

	public int getAssertionCount()
	{
		return testRequest == null ? 0 : testRequest.getAssertionCount();
	}

	public WsdlTestRequest getHttpRequest()
	{
		return testRequest;
	}

	public class InternalProjectListener extends ProjectListenerAdapter
	{
		@Override
		public void interfaceRemoved( Interface iface )
		{
			if( wsdlOperation != null && wsdlOperation.getInterface().equals( iface ) )
			{
				log.debug( "Removing test step due to removed interface" );
				( getTestCase() ).removeTestStep( WsdlTestRequestStep.this );
			}
		}
	}

	public class InternalInterfaceListener extends InterfaceListenerAdapter
	{
		@Override
		public void operationRemoved( Operation operation )
		{
			if( operation == wsdlOperation )
			{
				log.debug( "Removing test step due to removed operation" );
				( getTestCase() ).removeTestStep( WsdlTestRequestStep.this );
			}
		}

		@Override
		public void operationUpdated( Operation operation )
		{
			if( operation == wsdlOperation )
			{
				requestStepConfig.setOperation( operation.getName() );
			}
		}
	}

	@Override
	public boolean cancel()
	{
		if( submit == null )
			return false;

		submit.cancel();

		return true;
	}

	@Override
	public Collection<Interface> getRequiredInterfaces()
	{
		ArrayList<Interface> result = new ArrayList<Interface>();
		result.add( findWsdlOperation().getInterface() );
		return result;
	}

	public String getDefaultSourcePropertyName()
	{
		return "Response";
	}

	public String getDefaultTargetPropertyName()
	{
		return "Request";
	}

	@Override
	public boolean dependsOn( AbstractWsdlModelItem<?> modelItem )
	{
		if( modelItem instanceof Interface && testRequest.getOperation().getInterface() == modelItem )
		{
			return true;
		}
		else if( modelItem instanceof Operation && testRequest.getOperation() == modelItem )
		{
			return true;
		}

		return false;
	}

	@Override
	public void beforeSave()
	{
		super.beforeSave();

		if( testRequest != null )
			testRequest.beforeSave();
	}

	@Override
	public String getDescription()
	{
		return testRequest == null ? "<missing>" : testRequest.getDescription();
	}

	@Override
	public void setDescription( String description )
	{
		if( testRequest != null )
			testRequest.setDescription( description );
	}

	public void setOperation( WsdlOperation operation )
	{
		if( wsdlOperation == operation )
			return;

		WsdlOperation oldOperation = wsdlOperation;
		wsdlOperation = operation;
		requestStepConfig.setInterface( operation.getInterface().getName() );
		requestStepConfig.setOperation( operation.getName() );

		if( oldOperation != null )
			oldOperation.removePropertyChangeListener( this );

		wsdlOperation.addPropertyChangeListener( this );

		initTestRequest( this.getConfig(), false );
		testRequest.setOperation( wsdlOperation );
	}

	@SuppressWarnings( "unchecked" )
	@Override
	public List<? extends ModelItem> getChildren()
	{
		return testRequest == null ? Collections.EMPTY_LIST : testRequest.getAssertionList();
	}

	public PropertyExpansion[] getPropertyExpansions()
	{
		if( testRequest == null )
			return new PropertyExpansion[0];

		PropertyExpansionsResult result = new PropertyExpansionsResult( this, testRequest );

		result.extractAndAddAll( "requestContent" );
		result.extractAndAddAll( "endpoint" );
		result.extractAndAddAll( "username" );
		result.extractAndAddAll( "password" );
		result.extractAndAddAll( "domain" );

		StringToStringsMap requestHeaders = testRequest.getRequestHeaders();
		for( String key : requestHeaders.keySet() )
		{
			for( String value : requestHeaders.get( key ) )
				result.extractAndAddAll( new HttpTestRequestStep.RequestHeaderHolder( key, value, testRequest ), "value" );
		}

		testRequest.addWsaPropertyExpansions( result, testRequest.getWsaConfig(), this );
		testRequest.addJMSHeaderExpansions( result, testRequest.getJMSHeaderConfig(), this );
		return result.toArray( new PropertyExpansion[result.size()] );
	}

	public TestAssertion addAssertion( String type )
	{
		WsdlMessageAssertion result = testRequest.addAssertion( type );
		return result;
	}

	public void addAssertionsListener( AssertionsListener listener )
	{
		testRequest.addAssertionsListener( listener );
	}

	public TestAssertion cloneAssertion( TestAssertion source, String name )
	{
		return testRequest.cloneAssertion( source, name );
	}

	public String getAssertableContent()
	{
		return testRequest.getAssertableContent();
	}

	public AssertableType getAssertableType()
	{
		return testRequest.getAssertableType();
	}

	public TestAssertion getAssertionByName( String name )
	{
		return testRequest.getAssertionByName( name );
	}

	public List<TestAssertion> getAssertionList()
	{
		return testRequest.getAssertionList();
	}

	public AssertionStatus getAssertionStatus()
	{
		return testRequest.getAssertionStatus();
	}

	public Interface getInterface()
	{
		return getOperation().getInterface();
	}

	public WsdlOperation getOperation()
	{
		return wsdlOperation;
	}

	public TestStep getTestStep()
	{
		return this;
	}

	public void removeAssertion( TestAssertion assertion )
	{
		testRequest.removeAssertion( assertion );
	}

	public TestAssertion moveAssertion( int ix, int whereTo )
	{
		return testRequest.moveAssertion( ix, whereTo );
	}

	public void removeAssertionsListener( AssertionsListener listener )
	{
		testRequest.removeAssertionsListener( listener );
	}

	public Map<String, TestAssertion> getAssertions()
	{
		return testRequest.getAssertions();
	}

	@Override
	public void prepare( TestCaseRunner testRunner, TestCaseRunContext testRunContext ) throws Exception
	{
		super.prepare( testRunner, testRunContext );

		testRequest.setResponse( null, testRunContext );

		for( TestAssertion assertion : testRequest.getAssertionList() )
		{
			assertion.prepare( testRunner, testRunContext );
		}
	}

	public String getDefaultAssertableContent()
	{
		return testRequest.getDefaultAssertableContent();
	}

	@SuppressWarnings( "unchecked" )
	public void resolve( ResolveContext<?> context )
	{
		super.resolve( context );

		if( wsdlOperation == null )
		{
			// not solved and we have it in list do not add it.
			if( context.hasThisModelItem( this, "Missing SOAP Operation in Project", requestStepConfig.getInterface()
					+ "/" + requestStepConfig.getOperation() ) )
				return;

			context.addPathToResolve( this, "Missing SOAP Operation in Project",
					requestStepConfig.getInterface() + "/" + requestStepConfig.getOperation() ).addResolvers(
					new RemoveTestStepResolver( this ), new ImportInterfaceResolver( this )
					{

						@Override
						protected boolean update()
						{
							wsdlOperation = findWsdlOperation();
							if( wsdlOperation == null )
								return false;

							initTestRequest( getConfig(), false );
							initRequestProperties();
							setDisabled( false );
							return true;
						}
					}, new ChangeOperationResolver( this, "Operation" )
					{

						@Override
						public boolean update()
						{
							WsdlOperation wsdlOperation = ( WsdlOperation )getSelectedOperation();
							if( wsdlOperation == null )
								return false;

							setOperation( wsdlOperation );
							initTestRequest( getConfig(), false );
							initRequestProperties();
							setDisabled( false );
							return true;
						}

						protected Interface[] getInterfaces( WsdlProject project )
						{
							List<WsdlInterface> interfaces = ModelSupport.getChildren( project, WsdlInterface.class );
							return interfaces.toArray( new Interface[interfaces.size()] );

						}

					} );
		}
		else
		{
			testRequest.resolve( context );
			if( context.hasThisModelItem( this, "Missing SOAP Operation in Project", requestStepConfig.getInterface()
					+ "/" + requestStepConfig.getOperation() ) )
			{
				PathToResolve path = context.getPath( this, "Missing SOAP Operation in Project",
						requestStepConfig.getInterface() + "/" + requestStepConfig.getOperation() );
				path.setSolved( true );
			}
		}
	}

}
