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.io.File;
    16  import java.io.IOException;
    17  import java.util.ArrayList;
    18  import java.util.Arrays;
    19  import java.util.List;
    20  import java.util.zip.GZIPOutputStream;
    21
    22  import javax.activation.DataHandler;
    23  import javax.mail.MessagingException;
    24  import javax.mail.internet.MimeBodyPart;
    25  import javax.mail.internet.MimeMessage;
    26  import javax.mail.internet.MimeMultipart;
    27  import javax.mail.internet.PreencodedMimeBodyPart;
    28  import javax.swing.ImageIcon;
    29  import javax.wsdl.BindingOperation;
    30  import javax.wsdl.Message;
    31
    32  import org.apache.log4j.Logger;
    33  import org.apache.xmlbeans.SchemaType;
    34
    35  import com.eviware.soapui.SoapUI;
    36  import com.eviware.soapui.config.AttachmentConfig;
    37  import com.eviware.soapui.config.HeaderConfig;
    38  import com.eviware.soapui.config.MockResponseConfig;
    39  import com.eviware.soapui.impl.wsdl.AbstractWsdlModelItem;
    40  import com.eviware.soapui.impl.wsdl.AttachmentContainer;
    41  import com.eviware.soapui.impl.wsdl.WsdlAttachmentPart;
    42  import com.eviware.soapui.impl.wsdl.WsdlContentPart;
    43  import com.eviware.soapui.impl.wsdl.WsdlHeaderPart;
    44  import com.eviware.soapui.impl.wsdl.WsdlOperation;
    45  import com.eviware.soapui.impl.wsdl.WsdlSubmitContext;
    46  import com.eviware.soapui.impl.wsdl.submit.filters.PropertyExpansionRequestFilter;
    47  import com.eviware.soapui.impl.wsdl.submit.filters.RemoveEmptyContentRequestFilter;
    48  import com.eviware.soapui.impl.wsdl.submit.transports.http.AttachmentUtils;
    49  import com.eviware.soapui.impl.wsdl.submit.transports.http.BodyPartAttachment;
    50  import com.eviware.soapui.impl.wsdl.submit.transports.http.MimeMessageMockResponseEntity;
    51  import com.eviware.soapui.impl.wsdl.submit.transports.http.MockResponseDataSource;
    52  import com.eviware.soapui.impl.wsdl.support.CompressedStringSupport;
    53  import com.eviware.soapui.impl.wsdl.support.FileAttachment;
    54  import com.eviware.soapui.impl.wsdl.support.MessageXmlObject;
    55  import com.eviware.soapui.impl.wsdl.support.MessageXmlPart;
    56  import com.eviware.soapui.impl.wsdl.support.MockFileAttachment;
    57  import com.eviware.soapui.impl.wsdl.support.ModelItemIconAnimator;
    58  import com.eviware.soapui.impl.wsdl.support.WsdlAttachment;
    59  import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
    60  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlContext;
    61  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils;
    62  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils.SoapHeader;
    63  import com.eviware.soapui.model.iface.Attachment;
    64  import com.eviware.soapui.model.iface.MessagePart;
    65  import com.eviware.soapui.model.mock.MockResponse;
    66  import com.eviware.soapui.model.mock.MockRunContext;
    67  import com.eviware.soapui.settings.WsdlSettings;
    68  import com.eviware.soapui.support.Tools;
    69  import com.eviware.soapui.support.UISupport;
    70  import com.eviware.soapui.support.scripting.ScriptEnginePool;
    71  import com.eviware.soapui.support.scripting.SoapUIScriptEngine;
    72  import com.eviware.soapui.support.types.StringToStringMap;
    73  import com.eviware.soapui.support.xml.XmlUtils;
    74
    75  /***
    76   * A WsdlMockResponse contained by a WsdlMockOperation
    77   *
    78   * @author ole.matzura
    79   */
    80
    81  public class WsdlMockResponse extends AbstractWsdlModelItem<MockResponseConfig> implements MockResponse,
    82  			AttachmentContainer
    83  {
    84  	private final static Logger log = Logger.getLogger( WsdlMockResponse.class );
    85
    86  	public final static String MOCKRESULT_PROPERTY = WsdlMockResponse.class.getName() + "@mockresult";
    87  	public final static String SCRIPT_PROPERTY = WsdlMockResponse.class.getName() + "@script";
    88  	public final static String HEADERS_PROPERTY = WsdlMockResponse.class.getName() + "@headers";
    89  	public final static String DISABLE_MULTIPART_ATTACHMENTS = WsdlMockResponse.class.getName()
    90  				+ "@disable-multipart-attachments";
    91  	public final static String RESPONSE_DELAY_PROPERTY = WsdlMockResponse.class.getName() + "@response-delay";
    92  	public static final String STRIP_WHITESPACES = WsdlMockResponse.class.getName() + "@strip-whitespaces";
    93  	public static final String REMOVE_EMPTY_CONTENT = WsdlMockResponse.class.getName() + "@remove_empty_content";
    94  	public static final String ENCODE_ATTACHMENTS = WsdlMockResponse.class.getName() + "@encode_attachments";
    95
    96  	protected List<FileAttachment> attachments = new ArrayList<FileAttachment>();
    97  	private List<WsdlAttachmentPart> definedAttachmentParts;
    98  	private ModelItemIconAnimator iconAnimator;
    99  	private WsdlMockResult mockResult;
    100 	private String responseContent;
    101 	private ScriptEnginePool scriptEnginePool;
    102
    103 	public WsdlMockResponse( WsdlMockOperation operation, MockResponseConfig config )
    104 	{
    105 		super( config, operation, "/mockResponse.gif" );
    106
    107 		for( AttachmentConfig ac : getConfig().getAttachmentList() )
    108 		{
    109 			attachments.add( new MockFileAttachment( ac, this ) );
    110 		}
    111
    112 		if( !config.isSetEncoding() )
    113 			config.setEncoding( "UTF-8" );
    114
    115 		iconAnimator = new ModelItemIconAnimator( this, "/mockResponse.gif", new String[] { "/exec_request_1.gif",
    116 					"/exec_request_2.gif", "/exec_request_3.gif", "/exec_request_4.gif" } );
    117
    118 		scriptEnginePool = new ScriptEnginePool( this );
    119 		scriptEnginePool.setScript( getScript() );
    120 	}
    121
    122 	public Attachment[] getAttachments()
    123 	{
    124 		return attachments.toArray( new Attachment[attachments.size()] );
    125 	}
    126
    127 	public String getScript()
    128 	{
    129 		return getConfig().isSetScript() ? getConfig().getScript().getStringValue() : null;
    130 	}
    131
    132 	public String getEncoding()
    133 	{
    134 		return getConfig().getEncoding();
    135 	}
    136
    137 	public void setEncoding( String encoding )
    138 	{
    139 		String old = getEncoding();
    140 		getConfig().setEncoding( encoding );
    141 		notifyPropertyChanged( ENCODING_PROPERTY, old, encoding );
    142 	}
    143
    144 	public String getResponseContent()
    145 	{
    146 		if( getConfig().getResponseContent() == null )
    147 			getConfig().addNewResponseContent();
    148
    149 		if( responseContent == null )
    150 			responseContent = CompressedStringSupport.getString( getConfig().getResponseContent() );
    151
    152 		return responseContent;
    153 	}
    154
    155 	public void setResponseContent( String responseContent )
    156 	{
    157 		String oldContent = getResponseContent();
    158 		if( !responseContent.equals( oldContent ) )
    159 		{
    160 			this.responseContent = responseContent;
    161 			notifyPropertyChanged( RESPONSECONTENT_PROPERTY, oldContent, responseContent );
    162 		}
    163 	}
    164
    165 	@Override
    166 	public ImageIcon getIcon()
    167 	{
    168 		return iconAnimator.getIcon();
    169 	}
    170
    171 	public WsdlMockOperation getMockOperation()
    172 	{
    173 		return ( WsdlMockOperation ) getParent();
    174 	}
    175
    176 	public WsdlMockResult execute( WsdlMockRequest request, WsdlMockResult result ) throws DispatchException
    177 	{
    178 		try
    179 		{
    180 			iconAnimator.start();
    181
    182 			long delay = getResponseDelay();
    183 			if( delay > 0 )
    184 				Thread.sleep( delay );
    185
    186 			String responseContent = getResponseContent();
    187 			String script = getScript();
    188 			if( script != null && script.trim().length() > 0 )
    189 			{
    190 				evaluateScript( request );
    191 			}
    192
    193 			// create merged context
    194 			WsdlSubmitContext context = new WsdlSubmitContext();
    195 			context.putAll( request.getContext() );
    196 			context.putAll( request.getRequestContext() );
    197
    198 			StringToStringMap responseHeaders = getResponseHeaders();
    199 			for( String name : responseHeaders.keySet() )
    200 			{
    201 				result.addHeader( name, PropertyExpansionRequestFilter.expandProperties( context,
    202 							responseHeaders.get( name ) ) );
    203 			}
    204
    205 			responseContent = PropertyExpansionRequestFilter.expandProperties( context, responseContent );
    206
    207 			if( !result.isCommitted() )
    208 			{
    209 				responseContent = writeResponse( result, responseContent );
    210 			}
    211
    212 			result.setResponseContent( responseContent );
    213
    214 			setMockResult( result );
    215
    216 			return mockResult;
    217 		}
    218 		catch( Throwable e )
    219 		{
    220 			throw new DispatchException( e );
    221 		}
    222 		finally
    223 		{
    224 			iconAnimator.stop();
    225 		}
    226 	}
    227
    228 	public void evaluateScript( WsdlMockRequest request ) throws Exception
    229 	{
    230 		String script = getScript();
    231 		if( script == null || script.trim().length() == 0 )
    232 			return;
    233
    234 		// unsatisfactory way of handling multiple threads -> create pool of
    235 		// scripts instead
    236 		WsdlMockService mockService = getMockOperation().getMockService();
    237 		WsdlMockRunner mockRunner = mockService.getMockRunner();
    238 		MockRunContext context = mockRunner == null ? new WsdlMockRunContext( mockService, null ) : mockRunner
    239 					.getMockContext();
    240
    241 		SoapUIScriptEngine scriptEngine = scriptEnginePool.getScriptEngine();
    242
    243 		try
    244 		{
    245 			scriptEngine.setVariable( "context", request.getContext() );
    246 			scriptEngine.setVariable( "requestContext", request.getRequestContext() );
    247 			scriptEngine.setVariable( "mockContext", context );
    248 			scriptEngine.setVariable( "mockRequest", request );
    249 			scriptEngine.setVariable( "mockResponse", this );
    250 			scriptEngine.setVariable( "log", SoapUI.ensureGroovyLog() );
    251
    252 			scriptEngine.run();
    253 		}
    254 		catch( RuntimeException e )
    255 		{
    256 			throw new Exception( e.getMessage(), e );
    257 		}
    258 		finally
    259 		{
    260 			scriptEnginePool.returnScriptEngine( scriptEngine );
    261 		}
    262 	}
    263
    264 	@Override
    265 	public void release()
    266 	{
    267 		super.release();
    268
    269 		scriptEnginePool.release();
    270 	}
    271
    272 	public void setScript( String script )
    273 	{
    274 		String oldScript = getScript();
    275 		if( !script.equals( oldScript ) )
    276 		{
    277 			if( !getConfig().isSetScript() )
    278 				getConfig().addNewScript();
    279 			getConfig().getScript().setStringValue( script );
    280
    281 			scriptEnginePool.setScript( script );
    282
    283 			notifyPropertyChanged( SCRIPT_PROPERTY, oldScript, script );
    284 		}
    285 	}
    286
    287 	public void setResponseHeaders( StringToStringMap headers )
    288 	{
    289 		StringToStringMap oldHeaders = getResponseHeaders();
    290
    291 		HeaderConfig[] headerConfigs = new HeaderConfig[headers.size()];
    292 		int ix = 0;
    293 		for( String header : headers.keySet() )
    294 		{
    295 			headerConfigs[ix] = HeaderConfig.Factory.newInstance();
    296 			headerConfigs[ix].setName( header );
    297 			headerConfigs[ix].setValue( headers.get( header ) );
    298 			ix++;
    299 		}
    300
    301 		getConfig().setHeaderArray( headerConfigs );
    302
    303 		notifyPropertyChanged( HEADERS_PROPERTY, oldHeaders, headers );
    304 	}
    305
    306 	public StringToStringMap getResponseHeaders()
    307 	{
    308 		StringToStringMap result = new StringToStringMap();
    309 		List<HeaderConfig> headerList = getConfig().getHeaderList();
    310 		for( HeaderConfig header : headerList )
    311 		{
    312 			result.put( header.getName(), header.getValue() );
    313 		}
    314
    315 		return result;
    316 	}
    317
    318 	public MessagePart[] getResponseParts()
    319 	{
    320 		try
    321 		{
    322 			// init
    323 			List<MessagePart> result = new ArrayList<MessagePart>();
    324 			WsdlOperation op = getMockOperation().getOperation();
    325 			WsdlContext wsdlContext = op.getInterface().getWsdlContext();
    326 			BindingOperation bindingOperation = op.findBindingOperation( wsdlContext.getDefinition() );
    327
    328 			if( bindingOperation == null )
    329 				return new MessagePart[0];
    330
    331 			// header parts
    332 			List<SoapHeader> headers = WsdlUtils.getSoapHeaders( bindingOperation.getBindingOutput()
    333 						.getExtensibilityElements() );
    334
    335 			for( int i = 0; i < headers.size(); i++ )
    336 			{
    337 				SoapHeader header = headers.get( i );
    338
    339 				Message message = wsdlContext.getDefinition().getMessage( header.getMessage() );
    340 				if( message == null )
    341 				{
    342 					log.error( "Missing message for header: " + header.getMessage() );
    343 					continue;
    344 				}
    345
    346 				javax.wsdl.Part part = message.getPart( header.getPart() );
    347
    348 				if( part != null )
    349 				{
    350 					SchemaType schemaType = WsdlUtils.getSchemaTypeForPart( wsdlContext, part );
    351 					if( schemaType != null )
    352 						result.add( new WsdlHeaderPart( part.getName(), schemaType, part.getElementName() ) );
    353 				}
    354 				else
    355 					log.error( "Missing part for header; " + header.getPart() );
    356 			}
    357
    358 			// content parts
    359 			javax.wsdl.Part[] parts = WsdlUtils.getOutputParts( bindingOperation );
    360
    361 			for( int i = 0; i < parts.length; i++ )
    362 			{
    363 				javax.wsdl.Part part = parts[i];
    364
    365 				if( !WsdlUtils.isAttachmentOutputPart( part, bindingOperation ) )
    366 				{
    367 					SchemaType schemaType = WsdlUtils.getSchemaTypeForPart( wsdlContext, part );
    368 					if( schemaType != null )
    369 						result.add( new WsdlContentPart( part.getName(), schemaType, part.getElementName() ) );
    370 				}
    371 			}
    372
    373 			result.addAll( Arrays.asList( getDefinedAttachmentParts() ) );
    374
    375 			return result.toArray( new MessagePart[result.size()] );
    376 		}
    377 		catch( Exception e )
    378 		{
    379 			SoapUI.logError( e );
    380 			return new MessagePart[0];
    381 		}
    382 	}
    383
    384 	public Attachment attachFile( File file, boolean cache )
    385 	{
    386 		try
    387 		{
    388 			FileAttachment fileAttachment = new MockFileAttachment( file, cache, this );
    389 			attachments.add( fileAttachment );
    390 			notifyPropertyChanged( ATTACHMENTS_PROPERTY, null, fileAttachment );
    391 			return fileAttachment;
    392 		}
    393 		catch( IOException e )
    394 		{
    395 			UISupport.showErrorMessage( e );
    396 			return null;
    397 		}
    398 	}
    399
    400 	public int getAttachmentCount()
    401 	{
    402 		return attachments.size();
    403 	}
    404
    405 	public WsdlAttachment getAttachmentAt( int index )
    406 	{
    407 		return attachments.get( index );
    408 	}
    409
    410 	public void removeAttachment( Attachment attachment )
    411 	{
    412 		int ix = attachments.indexOf( attachment );
    413 		attachments.remove( ix );
    414
    415 		try
    416 		{
    417 			notifyPropertyChanged( ATTACHMENTS_PROPERTY, attachment, null );
    418 		}
    419 		finally
    420 		{
    421 			getConfig().removeAttachment( ix );
    422 		}
    423 	}
    424
    425 	public WsdlAttachmentPart[] getDefinedAttachmentParts()
    426 	{
    427 		if( definedAttachmentParts == null )
    428 		{
    429 			try
    430 			{
    431 				WsdlOperation operation = getMockOperation().getOperation();
    432 				if( operation == null )
    433 				{
    434 					definedAttachmentParts = new ArrayList<WsdlAttachmentPart>();
    435 				}
    436 				else
    437 				{
    438 					UISupport.setHourglassCursor();
    439 					definedAttachmentParts = AttachmentUtils.extractAttachmentParts( operation, getResponseContent(), true,
    440 								true );
    441 				}
    442 			}
    443 			catch( Exception e )
    444 			{
    445 				log.warn( e.toString() );
    446 			}
    447 			finally
    448 			{
    449 				UISupport.resetCursor();
    450 			}
    451 		}
    452
    453 		return definedAttachmentParts.toArray( new WsdlAttachmentPart[definedAttachmentParts.size()] );
    454 	}
    455
    456 	public WsdlAttachmentPart getAttachmentPart( String partName )
    457 	{
    458 		WsdlAttachmentPart[] parts = getDefinedAttachmentParts();
    459 		for( WsdlAttachmentPart part : parts )
    460 		{
    461 			if( part.getName().equals( partName ) )
    462 				return part;
    463 		}
    464
    465 		return null;
    466 	}
    467
    468 	public Attachment[] getAttachmentsForPart( String partName )
    469 	{
    470 		List<Attachment> result = new ArrayList<Attachment>();
    471
    472 		for( Attachment attachment : attachments )
    473 		{
    474 			if( attachment.getPart().equals( partName ) )
    475 				result.add( attachment );
    476 		}
    477
    478 		return result.toArray( new Attachment[result.size()] );
    479 	}
    480
    481 	public boolean isMtomEnabled()
    482 	{
    483 		return getSettings().getBoolean( WsdlSettings.ENABLE_MTOM );
    484 	}
    485
    486 	public void setMtomEnabled( boolean mtomEnabled )
    487 	{
    488 		boolean old = isMtomEnabled();
    489 		getSettings().setBoolean( WsdlSettings.ENABLE_MTOM, mtomEnabled );
    490 		definedAttachmentParts = null;
    491 		notifyPropertyChanged( MTOM_NABLED_PROPERTY, old, mtomEnabled );
    492 	}
    493
    494 	private String writeResponse( WsdlMockResult response, String responseContent ) throws Exception
    495 	{
    496 		MimeMultipart mp = null;
    497 		WsdlOperation operation = getMockOperation().getOperation();
    498 		if( operation == null )
    499 			throw new Exception( "Missing WsdlOperation for mock response" );
    500
    501 		SoapVersion soapVersion = operation.getInterface().getSoapVersion();
    502
    503 		StringToStringMap contentIds = new StringToStringMap();
    504 		boolean isXOP = false;
    505
    506 		// preprocess only if neccessary
    507 		if( isMtomEnabled() || getAttachmentCount() > 0 )
    508 		{
    509 			try
    510 			{
    511 				mp = new MimeMultipart();
    512
    513 				MessageXmlObject requestXmlObject = new MessageXmlObject( ( WsdlOperation ) operation,
    514 							getResponseContent(), true );
    515 				MessageXmlPart[] requestParts = requestXmlObject.getMessageParts();
    516 				for( MessageXmlPart requestPart : requestParts )
    517 				{
    518 					if( AttachmentUtils.prepareMessagePart( this, mp, requestPart, contentIds ) )
    519 						isXOP = true;
    520 				}
    521 				responseContent = requestXmlObject.getMessageContent();
    522 			}
    523 			catch( Exception e )
    524 			{
    525 				log.warn( "Failed to process inline/MTOM attachments; " + e );
    526 			}
    527 		}
    528
    529 		response.initResponse();
    530
    531 		if( isRemoveEmptyContent() )
    532 		{
    533 			responseContent = RemoveEmptyContentRequestFilter.removeEmptyContent( responseContent );
    534 		}
    535
    536 		if( isStripWhitespaces() )
    537 		{
    538 			responseContent = XmlUtils.stripWhitespaces( responseContent );
    539 		}
    540
    541 		// non-multipart request?
    542 		if( !isXOP && ( mp == null || mp.getCount() == 0 ) && getAttachmentCount() == 0 )
    543 		{
    544 			String encoding = getEncoding();
    545 			byte[] content = encoding == null ? responseContent.getBytes() : responseContent.getBytes( encoding );
    546
    547 			response.setContentType( soapVersion.getContentTypeHttpHeader( encoding ) );
    548
    549 			String acceptEncoding = response.getMockRequest().getRequestHeaders().get( "Accept-Encoding" );
    550 			if( acceptEncoding != null && acceptEncoding.toUpperCase().contains( "GZIP" ) )
    551 			{
    552 				response.addHeader( "Content-Encoding", "gzip" );
    553 				GZIPOutputStream zipOut = new GZIPOutputStream( response.getOutputStream() );
    554 				zipOut.write( content );
    555 				zipOut.close();
    556 			}
    557 			else
    558 			{
    559 				response.getOutputStream().write( content );
    560 			}
    561 		}
    562 		else
    563 		{
    564 			// make sure..
    565 			if( mp == null )
    566 				mp = new MimeMultipart();
    567
    568 			// init root part
    569 			initRootPart( responseContent, mp, isXOP );
    570
    571 			// init mimeparts
    572 			AttachmentUtils.addMimeParts( this, mp, contentIds );
    573
    574 			// create request message
    575 			MimeMessage message = new MimeMessage( AttachmentUtils.JAVAMAIL_SESSION );
    576 			message.setContent( mp );
    577 			message.saveChanges();
    578 			MimeMessageMockResponseEntity mimeMessageRequestEntity = new MimeMessageMockResponseEntity( message, isXOP,
    579 						this );
    580
    581 			response.addHeader( "Content-Type", mimeMessageRequestEntity.getContentType() );
    582 			response.addHeader( "MIME-Version", "1.0" );
    583 			mimeMessageRequestEntity.writeRequest( response.getOutputStream() );
    584 		}
    585
    586 		return responseContent;
    587 	}
    588
    589 	private void initRootPart( String requestContent, MimeMultipart mp, boolean isXOP ) throws MessagingException
    590 	{
    591 		MimeBodyPart rootPart = new PreencodedMimeBodyPart( "8bit" );
    592 		rootPart.setContentID( AttachmentUtils.ROOTPART_SOAPUI_ORG );
    593 		mp.addBodyPart( rootPart, 0 );
    594
    595 		DataHandler dataHandler = new DataHandler( new MockResponseDataSource( this, requestContent, isXOP ) );
    596 		rootPart.setDataHandler( dataHandler );
    597 	}
    598
    599 	public Attachment addAttachment( Attachment attachment )
    600 	{
    601 		if( attachment instanceof BodyPartAttachment )
    602 		{
    603 			try
    604 			{
    605 				BodyPartAttachment att = ( BodyPartAttachment ) attachment;
    606
    607 				AttachmentConfig newConfig = ( AttachmentConfig ) getConfig().addNewAttachment();
    608 				newConfig.setData( Tools.readAll( att.getInputStream(), 0 ).toByteArray() );
    609 				newConfig.setContentId( att.getContentID() );
    610 				newConfig.setContentType( att.getContentType() );
    611 				newConfig.setName( att.getName() );
    612
    613 				FileAttachment newAttachment = new MockFileAttachment( newConfig, this );
    614 				attachments.add( newAttachment );
    615 				return newAttachment;
    616 			}
    617 			catch( Exception e )
    618 			{
    619 				SoapUI.logError( e );
    620 			}
    621 		}
    622 		else if( attachment instanceof FileAttachment )
    623 		{
    624 			AttachmentConfig oldConfig = ( ( FileAttachment ) attachment ).getConfig();
    625 			AttachmentConfig newConfig = ( AttachmentConfig ) getConfig().addNewAttachment().set( oldConfig );
    626 			FileAttachment newAttachment = new MockFileAttachment( newConfig, this );
    627 			attachments.add( newAttachment );
    628 			return newAttachment;
    629 		}
    630
    631 		return null;
    632 	}
    633
    634 	public void setResponseDelay( long delay )
    635 	{
    636 		long oldDelay = getResponseDelay();
    637
    638 		if( delay == 0 )
    639 			getSettings().clearSetting( RESPONSE_DELAY_PROPERTY );
    640 		else
    641 			getSettings().setLong( RESPONSE_DELAY_PROPERTY, delay );
    642
    643 		notifyPropertyChanged( RESPONSE_DELAY_PROPERTY, oldDelay, delay );
    644 	}
    645
    646 	public long getResponseDelay()
    647 	{
    648 		return getSettings().getLong( RESPONSE_DELAY_PROPERTY, 0 );
    649 	}
    650
    651 	public void setMockResult( WsdlMockResult mockResult )
    652 	{
    653 		WsdlMockResult oldResult = this.mockResult;
    654 		this.mockResult = mockResult;
    655 		notifyPropertyChanged( MOCKRESULT_PROPERTY, oldResult, mockResult );
    656 	}
    657
    658 	public WsdlMockResult getMockResult()
    659 	{
    660 		return mockResult;
    661 	}
    662
    663 	public long getContentLength()
    664 	{
    665 		return getResponseContent().length();
    666 	}
    667
    668 	public boolean isMultipartEnabled()
    669 	{
    670 		return !getSettings().getBoolean( DISABLE_MULTIPART_ATTACHMENTS );
    671 	}
    672
    673 	public void setMultipartEnabled( boolean multipartEnabled )
    674 	{
    675 		getSettings().setBoolean( DISABLE_MULTIPART_ATTACHMENTS, multipartEnabled );
    676 	}
    677
    678 	public boolean isRemoveEmptyContent()
    679 	{
    680 		return getSettings().getBoolean( REMOVE_EMPTY_CONTENT );
    681 	}
    682
    683 	public void setRemoveEmptyContent( boolean removeEmptyContent )
    684 	{
    685 		boolean old = getSettings().getBoolean( REMOVE_EMPTY_CONTENT );
    686 		getSettings().setBoolean( REMOVE_EMPTY_CONTENT, removeEmptyContent );
    687 		notifyPropertyChanged( REMOVE_EMPTY_CONTENT, old, removeEmptyContent );
    688 	}
    689
    690 	public boolean isEncodeAttachments()
    691 	{
    692 		return getSettings().getBoolean( ENCODE_ATTACHMENTS );
    693 	}
    694
    695 	public void setEncodeAttachments( boolean encodeAttachments )
    696 	{
    697 		boolean old = getSettings().getBoolean( ENCODE_ATTACHMENTS );
    698 		getSettings().setBoolean( ENCODE_ATTACHMENTS, encodeAttachments );
    699 		notifyPropertyChanged( ENCODE_ATTACHMENTS, old, encodeAttachments );
    700 	}
    701
    702 	public boolean isStripWhitespaces()
    703 	{
    704 		return getSettings().getBoolean( STRIP_WHITESPACES );
    705 	}
    706
    707 	public void setStripWhitespaces( boolean stripWhitespaces )
    708 	{
    709 		boolean old = getSettings().getBoolean( STRIP_WHITESPACES );
    710 		getSettings().setBoolean( STRIP_WHITESPACES, stripWhitespaces );
    711 		notifyPropertyChanged( STRIP_WHITESPACES, old, stripWhitespaces );
    712 	}
    713
    714 	@Override
    715 	public void onSave()
    716 	{
    717 		if( responseContent != null )
    718 		{
    719 			CompressedStringSupport.setString( getConfig().getResponseContent(), responseContent );
    720 			responseContent = null;
    721 		}
    722 	}
    723 }