View Javadoc

    1   /*
    2    *  soapUI, copyright (C) 2004-2007 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.mock;
    14
    15  import java.beans.PropertyChangeEvent;
    16  import java.beans.PropertyChangeListener;
    17  import java.util.ArrayList;
    18  import java.util.List;
    19
    20  import javax.servlet.http.HttpServletResponse;
    21
    22  import org.apache.xmlbeans.XmlException;
    23  import org.apache.xmlbeans.XmlObject;
    24
    25  import com.eviware.soapui.SoapUI;
    26  import com.eviware.soapui.config.DispatchStyleConfig;
    27  import com.eviware.soapui.config.MockOperationConfig;
    28  import com.eviware.soapui.config.MockResponseConfig;
    29  import com.eviware.soapui.config.DispatchStyleConfig.Enum;
    30  import com.eviware.soapui.impl.wsdl.AbstractWsdlModelItem;
    31  import com.eviware.soapui.impl.wsdl.WsdlOperation;
    32  import com.eviware.soapui.impl.wsdl.support.CompressedStringSupport;
    33  import com.eviware.soapui.model.iface.Interface;
    34  import com.eviware.soapui.model.mock.MockOperation;
    35  import com.eviware.soapui.model.mock.MockResponse;
    36  import com.eviware.soapui.model.mock.MockRunContext;
    37  import com.eviware.soapui.settings.WsdlSettings;
    38  import com.eviware.soapui.support.scripting.ScriptEnginePool;
    39  import com.eviware.soapui.support.scripting.SoapUIScriptEngine;
    40  import com.eviware.soapui.support.xml.XmlUtils;
    41
    42  /***
    43   * A WsdlMockOperation in a WsdlMockService
    44   *
    45   * @author ole.matzura
    46   */
    47
    48  public class WsdlMockOperation extends AbstractWsdlModelItem<MockOperationConfig> implements MockOperation, PropertyChangeListener
    49  {
    50  	public final static String DISPATCH_STYLE_PROPERTY = WsdlMockOperation.class.getName() + "@dispatchstyle";
    51  	public final static String DEFAULT_RESPONSE_PROPERTY = WsdlMockOperation.class.getName() + "@defaultresponse";
    52  	public final static String DISPATCH_PATH_PROPERTY = WsdlMockOperation.class.getName() + "@dispatchpath";
    53
    54  	private WsdlOperation operation;
    55  	private List<WsdlMockResponse> responses = new ArrayList<WsdlMockResponse>();
    56  	private int currentDispatchIndex;
    57  	private ScriptEnginePool scriptEnginePool;
    58
    59  	public WsdlMockOperation(WsdlMockService mockService, MockOperationConfig config)
    60     {
    61     	super( config, mockService, "/mockOperation.gif" );
    62
    63     	Interface iface = mockService.getProject().getInterfaceByName( config.getInterface() );
    64     	operation = ( WsdlOperation ) iface.getOperationByName( config.getOperation() );
    65
    66     	List<MockResponseConfig> responseConfigs = config.getResponseList();
    67     	for( MockResponseConfig responseConfig : responseConfigs )
    68     	{
    69     		WsdlMockResponse wsdlMockResponse = new WsdlMockResponse( this, responseConfig );
    70     		wsdlMockResponse.addPropertyChangeListener( this );
    71  			responses.add( wsdlMockResponse );
    72     	}
    73
    74     	initData( config );
    75     }
    76
    77  	private void initData( MockOperationConfig config )
    78  	{
    79  		if( !config.isSetName() )
    80     		config.setName( operation.getName() );
    81
    82     	if( !config.isSetDispatchStyle())
    83     		config.setDispatchStyle( DispatchStyleConfig.SEQUENCE );
    84
    85     	if( !config.isSetDefaultResponse() && responses.size() > 0 )
    86     		setDefaultResponse( responses.get( 0 ).getName() );
    87
    88     	scriptEnginePool = new ScriptEnginePool( this );
    89     	scriptEnginePool.setScript( getDispatchPath() );
    90  	}
    91
    92  	public WsdlMockOperation( WsdlMockService mockService, MockOperationConfig config, WsdlOperation operation )
    93  	{
    94  		super( config, mockService, "/mockOperation.gif" );
    95  		this.operation = operation;
    96
    97  		config.setInterface( operation.getInterface().getName() );
    98  		config.setOperation( operation.getName() );
    99
    100 		initData( config );
    101 	}
    102
    103 	public WsdlMockService getMockService()
    104 	{
    105 		return ( WsdlMockService ) getParent();
    106 	}
    107
    108 	public WsdlMockResponse getMockResponseAt( int index )
    109 	{
    110 		return responses.get( index );
    111 	}
    112
    113 	public WsdlOperation getOperation()
    114 	{
    115 		return operation;
    116 	}
    117
    118 	public WsdlMockResponse getMockResponseByName( String name )
    119 	{
    120 		return ( WsdlMockResponse ) getWsdlModelItemByName( responses, name );
    121 	}
    122
    123 	public int getMockResponseCount()
    124 	{
    125 		return responses.size();
    126 	}
    127
    128 	public WsdlMockResponse addNewMockResponse( MockResponseConfig responseConfig )
    129 	{
    130 		WsdlMockResponse mockResponse = new WsdlMockResponse( this, responseConfig );
    131
    132 		responses.add( mockResponse );
    133 		if( responses.size() == 1 )
    134 			setDefaultResponse( mockResponse.getName() );
    135
    136 		((WsdlMockService)getMockService()).fireMockResponseAdded( mockResponse );
    137
    138 		return mockResponse;
    139 	}
    140
    141 	public WsdlMockResponse addNewMockResponse( String name, boolean createResponse )
    142 	{
    143 		MockResponseConfig responseConfig = getConfig().addNewResponse();
    144 		responseConfig.setName( name );
    145 		responseConfig.addNewResponseContent();
    146
    147 		if( createResponse && getOperation() != null )
    148 		{
    149 			boolean createOptional = SoapUI.getSettings().getBoolean( WsdlSettings.XML_GENERATION_ALWAYS_INCLUDE_OPTIONAL_ELEMENTS );
    150 			CompressedStringSupport.setString( responseConfig.getResponseContent(), getOperation().createResponse( createOptional ));
    151 		}
    152
    153 		return addNewMockResponse( responseConfig );
    154 	}
    155
    156 	public void removeMockResponse( WsdlMockResponse mockResponse )
    157    {
    158       int ix = responses.indexOf( mockResponse );
    159       responses.remove( ix );
    160       mockResponse.removePropertyChangeListener( this );
    161
    162       try
    163       {
    164       	((WsdlMockService)getMockService()).fireMockResponseRemoved( mockResponse );
    165       }
    166       finally
    167       {
    168 	      mockResponse.release();
    169 	      getConfig().removeResponse( ix );
    170       }
    171    }
    172
    173 	public WsdlMockResult dispatchRequest( WsdlMockRequest request, HttpServletResponse response ) throws DispatchException
    174 	{
    175 		try
    176 		{
    177 			request.setOperation( getOperation() );
    178 			WsdlMockResult result = new WsdlMockResult( request, response );
    179
    180 			if( getMockResponseCount() == 0 )
    181 				throw new DispatchException( "Missing MockResponse(s) in MockOperation [" + getName() + "]" );
    182
    183 			if( getDispatchStyle() == DispatchStyleConfig.XPATH )
    184 			{
    185 				XmlObject[] items = evaluateDispatchXPath( request );
    186 				for( XmlObject item : items )
    187 				{
    188 					WsdlMockResponse mockResponse = getMockResponseByName( XmlUtils.getNodeValue( item.getDomNode() ));
    189
    190 					if( mockResponse == null )
    191 						mockResponse = getMockResponseByName( getDefaultResponse() );
    192
    193 					if( mockResponse != null )
    194 					{
    195 						result.setMockResponse( mockResponse );
    196 						mockResponse.execute( request, result );
    197
    198 						return result;
    199 					}
    200 				}
    201
    202 				throw new DispatchException( "Missing matching response message" );
    203 			}
    204 			else if( getDispatchStyle() == DispatchStyleConfig.SCRIPT )
    205 			{
    206 				Object retVal = evaluateDispatchScript( request );
    207
    208 				WsdlMockResponse mockResponse = retVal == null ? getMockResponseByName( getDefaultResponse() )
    209 							: getMockResponseByName( retVal.toString() );
    210
    211 				if( mockResponse != null )
    212 				{
    213 					result.setMockResponse( mockResponse );
    214 					mockResponse.execute( request, result );
    215
    216 					return result;
    217 				}
    218 				else
    219 				{
    220 					throw new DispatchException( "Missing matching response message [" + retVal + "]" );
    221 				}
    222 			}
    223 			else
    224 			{
    225 				WsdlMockResponse mockResponse = null;
    226 				synchronized( this )
    227 				{
    228 					if( getDispatchStyle() == DispatchStyleConfig.RANDOM )
    229 					{
    230 						currentDispatchIndex = ( int ) ( (Math.random() * getMockResponseCount()) + 0.5F );
    231 					}
    232
    233 					if( currentDispatchIndex >= getMockResponseCount() )
    234 						currentDispatchIndex = 0;
    235
    236 					mockResponse = getMockResponseAt( currentDispatchIndex );
    237 					result.setMockResponse( mockResponse );
    238
    239 					currentDispatchIndex++;
    240 				}
    241
    242 				mockResponse.execute( request, result );
    243 			}
    244
    245 			return result;
    246 		}
    247 		catch( Exception e )
    248 		{
    249 			throw new DispatchException( e );
    250 		}
    251 	}
    252
    253 	public void release()
    254 	{
    255 		super.release();
    256
    257 		for( WsdlMockResponse response : responses )
    258 		{
    259 			response.removePropertyChangeListener( this );
    260 			response.release();
    261 		}
    262
    263 		scriptEnginePool.release();
    264 	}
    265
    266 	public XmlObject[] evaluateDispatchXPath( WsdlMockRequest request ) throws XmlException
    267 	{
    268 		XmlObject xmlObject = request.getRequestXmlObject();
    269 		XmlObject[] items = xmlObject.selectPath( getDispatchPath() );
    270 		return items;
    271 	}
    272
    273 	public Object evaluateDispatchScript( WsdlMockRequest request ) throws DispatchException
    274 	{
    275 		String dispatchPath = getDispatchPath();
    276 		if( dispatchPath == null || dispatchPath.trim().length() == 0 )
    277 		{
    278 			throw new DispatchException( "Dispatch Script is empty" );
    279 		}
    280
    281 		SoapUIScriptEngine scriptEngine = scriptEnginePool.getScriptEngine();
    282
    283 		try
    284 		{
    285 			WsdlMockService mockService = getMockService();
    286 			WsdlMockRunner mockRunner = mockService.getMockRunner();
    287 			MockRunContext context = mockRunner == null ? new WsdlMockRunContext( mockService, null ) : mockRunner.getMockContext();
    288
    289 			scriptEngine.setVariable( "context", context );
    290 			scriptEngine.setVariable( "requestContext", request.getRequestContext() );
    291 			scriptEngine.setVariable( "mockRequest", request);
    292 			scriptEngine.setVariable( "mockOperation", this );
    293 			scriptEngine.setVariable( "log", SoapUI.ensureGroovyLog() );
    294
    295 			scriptEngine.setScript( dispatchPath );
    296 			Object retVal = scriptEngine.run();
    297 			return retVal;
    298 		}
    299 		catch( Throwable e )
    300 		{
    301 			SoapUI.logError( e );
    302 			throw new DispatchException( "Failed to dispatch using script; " + e );
    303 		}
    304 		finally
    305 		{
    306 			scriptEnginePool.returnScriptEngine( scriptEngine );
    307 		}
    308 	}
    309
    310 	public DispatchStyleConfig.Enum getDispatchStyle()
    311 	{
    312 		return getConfig().getDispatchStyle();
    313 	}
    314
    315 	public void setDispatchStyle( DispatchStyleConfig.Enum dispatchStyle )
    316 	{
    317 		Enum old = getDispatchStyle();
    318 		getConfig().setDispatchStyle( dispatchStyle );
    319 		notifyPropertyChanged( DISPATCH_STYLE_PROPERTY, old, dispatchStyle );
    320 	}
    321
    322 	public String getDispatchPath()
    323 	{
    324 		return getConfig().getDispatchPath();
    325 	}
    326
    327 	public void setDispatchPath( String dispatchPath )
    328 	{
    329 		String old = getDispatchPath();
    330 		getConfig().setDispatchPath( dispatchPath );
    331 		notifyPropertyChanged( DISPATCH_PATH_PROPERTY, old, dispatchPath );
    332
    333 		scriptEnginePool.setScript( dispatchPath );
    334 	}
    335
    336 	public String getWsdlOperationName()
    337 	{
    338 		return operation == null ? null : operation.getName();
    339 	}
    340
    341 	public String getDefaultResponse()
    342 	{
    343 		return getConfig().getDefaultResponse();
    344 	}
    345
    346 	public void setDefaultResponse( String defaultResponse )
    347 	{
    348 		String old = getDefaultResponse();
    349 		getConfig().setDefaultResponse( defaultResponse );
    350 		notifyPropertyChanged( DEFAULT_RESPONSE_PROPERTY, old, defaultResponse );
    351 	}
    352
    353 	public List<MockResponse> getMockResponses()
    354 	{
    355 		return new ArrayList<MockResponse>( responses );
    356 	}
    357
    358 	public void propertyChange( PropertyChangeEvent arg0 )
    359 	{
    360 		if( arg0.getPropertyName().equals( WsdlMockResponse.NAME_PROPERTY ))
    361 		{
    362 			if( arg0.getOldValue().equals( getDefaultResponse() ))
    363 				setDefaultResponse( arg0.getNewValue().toString() );
    364 		}
    365 	}
    366
    367 	public WsdlMockResult getLastMockResult()
    368 	{
    369 		WsdlMockResult result = null;
    370
    371 		for( WsdlMockResponse response : responses )
    372 		{
    373 			WsdlMockResult mockResult = response.getMockResult();
    374 			if( mockResult != null )
    375 			{
    376 				if( result == null || result.getTimestamp() > mockResult.getTimestamp() )
    377 					result = mockResult;
    378 			}
    379 		}
    380
    381 		return result;
    382 	}
    383
    384 	public void setOperation( WsdlOperation operation )
    385 	{
    386 		if( operation == null )
    387 		{
    388 			getConfig().unsetInterface();
    389 			getConfig().unsetOperation();
    390 		}
    391 		else
    392 		{
    393 			getConfig().setInterface( operation.getInterface().getName() );
    394 			getConfig().setOperation( operation.getName() );
    395 		}
    396
    397 		this.operation = operation;
    398 	}
    399
    400 	@Override
    401 	public void onSave()
    402 	{
    403 		for( WsdlMockResponse mockResponse : responses )
    404 			mockResponse.onSave();
    405 	}
    406 }