View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2010 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.impl.wsdl.mock;
14  
15  import java.beans.PropertyChangeListener;
16  import java.io.ByteArrayOutputStream;
17  import java.io.File;
18  import java.io.IOException;
19  import java.io.StringWriter;
20  import java.util.ArrayList;
21  import java.util.Arrays;
22  import java.util.List;
23  import java.util.Map;
24  
25  import javax.activation.DataHandler;
26  import javax.mail.MessagingException;
27  import javax.mail.internet.MimeBodyPart;
28  import javax.mail.internet.MimeMessage;
29  import javax.mail.internet.MimeMultipart;
30  import javax.mail.internet.PreencodedMimeBodyPart;
31  import javax.servlet.http.HttpServletResponse;
32  import javax.swing.ImageIcon;
33  import javax.wsdl.BindingOperation;
34  import javax.wsdl.BindingOutput;
35  import javax.wsdl.Message;
36  
37  import org.apache.log4j.Logger;
38  import org.apache.xmlbeans.SchemaGlobalElement;
39  import org.apache.xmlbeans.SchemaType;
40  import org.w3c.dom.Document;
41  
42  import com.eviware.soapui.SoapUI;
43  import com.eviware.soapui.config.AttachmentConfig;
44  import com.eviware.soapui.config.HeaderConfig;
45  import com.eviware.soapui.config.MockResponseConfig;
46  import com.eviware.soapui.impl.wsdl.AbstractWsdlModelItem;
47  import com.eviware.soapui.impl.wsdl.HttpAttachmentPart;
48  import com.eviware.soapui.impl.wsdl.MutableWsdlAttachmentContainer;
49  import com.eviware.soapui.impl.wsdl.WsdlContentPart;
50  import com.eviware.soapui.impl.wsdl.WsdlHeaderPart;
51  import com.eviware.soapui.impl.wsdl.WsdlOperation;
52  import com.eviware.soapui.impl.wsdl.submit.filters.RemoveEmptyContentRequestFilter;
53  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.AttachmentUtils;
54  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.BodyPartAttachment;
55  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.MimeMessageMockResponseEntity;
56  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.MockResponseDataSource;
57  import com.eviware.soapui.impl.wsdl.support.CompressedStringSupport;
58  import com.eviware.soapui.impl.wsdl.support.CompressionSupport;
59  import com.eviware.soapui.impl.wsdl.support.FileAttachment;
60  import com.eviware.soapui.impl.wsdl.support.MapTestPropertyHolder;
61  import com.eviware.soapui.impl.wsdl.support.MessageXmlObject;
62  import com.eviware.soapui.impl.wsdl.support.MessageXmlPart;
63  import com.eviware.soapui.impl.wsdl.support.MockFileAttachment;
64  import com.eviware.soapui.impl.wsdl.support.ModelItemIconAnimator;
65  import com.eviware.soapui.impl.wsdl.support.WsdlAttachment;
66  import com.eviware.soapui.impl.wsdl.support.soap.SoapUtils;
67  import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
68  import com.eviware.soapui.impl.wsdl.support.wsa.WsaConfig;
69  import com.eviware.soapui.impl.wsdl.support.wsa.WsaContainer;
70  import com.eviware.soapui.impl.wsdl.support.wsa.WsaUtils;
71  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlContext;
72  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils;
73  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils.SoapHeader;
74  import com.eviware.soapui.impl.wsdl.support.wss.OutgoingWss;
75  import com.eviware.soapui.model.ModelItem;
76  import com.eviware.soapui.model.TestPropertyHolder;
77  import com.eviware.soapui.model.iface.Attachment;
78  import com.eviware.soapui.model.iface.MessagePart;
79  import com.eviware.soapui.model.iface.Attachment.AttachmentEncoding;
80  import com.eviware.soapui.model.mock.MockResponse;
81  import com.eviware.soapui.model.mock.MockRunContext;
82  import com.eviware.soapui.model.propertyexpansion.PropertyExpander;
83  import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
84  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContainer;
85  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils;
86  import com.eviware.soapui.model.testsuite.TestProperty;
87  import com.eviware.soapui.model.testsuite.TestPropertyListener;
88  import com.eviware.soapui.settings.CommonSettings;
89  import com.eviware.soapui.settings.WsdlSettings;
90  import com.eviware.soapui.support.StringUtils;
91  import com.eviware.soapui.support.Tools;
92  import com.eviware.soapui.support.UISupport;
93  import com.eviware.soapui.support.scripting.ScriptEnginePool;
94  import com.eviware.soapui.support.scripting.SoapUIScriptEngine;
95  import com.eviware.soapui.support.types.StringToStringMap;
96  import com.eviware.soapui.support.xml.XmlUtils;
97  
98  /***
99   * A WsdlMockResponse contained by a WsdlMockOperation
100  * 
101  * @author ole.matzura
102  */
103 
104 public class WsdlMockResponse extends AbstractWsdlModelItem<MockResponseConfig> implements MockResponse,
105 		MutableWsdlAttachmentContainer, PropertyExpansionContainer, TestPropertyHolder, WsaContainer
106 {
107 	public static final String AUTO_RESPONSE_COMPRESSION = "<auto>";
108 	public static final String NO_RESPONSE_COMPRESSION = "<none>";
109 
110 	private final static Logger log = Logger.getLogger( WsdlMockResponse.class );
111 
112 	public final static String MOCKRESULT_PROPERTY = WsdlMockResponse.class.getName() + "@mockresult";
113 	public final static String SCRIPT_PROPERTY = WsdlMockResponse.class.getName() + "@script";
114 	public final static String HEADERS_PROPERTY = WsdlMockResponse.class.getName() + "@headers";
115 	public final static String DISABLE_MULTIPART_ATTACHMENTS = WsdlMockResponse.class.getName()
116 			+ "@disable-multipart-attachments";
117 	public static final String FORCE_MTOM = WsdlMockResponse.class.getName() + "@force_mtom";
118 	public static final String ENABLE_INLINE_FILES = WsdlMockResponse.class.getName() + "@enable_inline_files";
119 	public final static String RESPONSE_DELAY_PROPERTY = WsdlMockResponse.class.getName() + "@response-delay";
120 	public static final String STRIP_WHITESPACES = WsdlMockResponse.class.getName() + "@strip-whitespaces";
121 	public static final String REMOVE_EMPTY_CONTENT = WsdlMockResponse.class.getName() + "@remove_empty_content";
122 	public static final String ENCODE_ATTACHMENTS = WsdlMockResponse.class.getName() + "@encode_attachments";
123 	public static final String RESPONSE_HTTP_STATUS = WsdlMockResponse.class.getName() + "@response-http-status";
124 	public static final String OUGOING_WSS = WsdlMockResponse.class.getName() + "@outgoing-wss";
125 
126 	protected List<FileAttachment<WsdlMockResponse>> attachments = new ArrayList<FileAttachment<WsdlMockResponse>>();
127 	private List<HttpAttachmentPart> definedAttachmentParts;
128 	private ModelItemIconAnimator<WsdlMockResponse> iconAnimator;
129 	private WsdlMockResult mockResult;
130 	private String responseContent;
131 	private ScriptEnginePool scriptEnginePool;
132 	private MapTestPropertyHolder propertyHolder;
133 	private WsaConfig wsaConfig;
134 
135 	public WsdlMockResponse( WsdlMockOperation operation, MockResponseConfig config )
136 	{
137 		super( config, operation, "/mockResponse.gif" );
138 
139 		for( AttachmentConfig ac : getConfig().getAttachmentList() )
140 		{
141 			attachments.add( new MockFileAttachment( ac, this ) );
142 		}
143 
144 		if( !config.isSetEncoding() )
145 			config.setEncoding( "UTF-8" );
146 
147 		iconAnimator = new ModelItemIconAnimator<WsdlMockResponse>( this, "/mockResponse.gif", "/exec_request", 4, "gif" );
148 
149 		scriptEnginePool = new ScriptEnginePool( this );
150 		scriptEnginePool.setScript( getScript() );
151 
152 		propertyHolder = new MapTestPropertyHolder( this );
153 		propertyHolder.addProperty( "Request" );
154 	}
155 
156 	@Override
157 	public void setConfig( MockResponseConfig config )
158 	{
159 		super.setConfig( config );
160 
161 		if( wsaConfig != null )
162 		{
163 			if( config.isSetWsaConfig() )
164 				wsaConfig.setConfig( config.getWsaConfig() );
165 			else
166 				wsaConfig = null;
167 		}
168 
169 		if( scriptEnginePool != null )
170 			scriptEnginePool.setScript( getScript() );
171 	}
172 
173 	public Attachment[] getAttachments()
174 	{
175 		return attachments.toArray( new Attachment[attachments.size()] );
176 	}
177 
178 	public String getScript()
179 	{
180 		return getConfig().isSetScript() ? getConfig().getScript().getStringValue() : null;
181 	}
182 
183 	public String getEncoding()
184 	{
185 		return getConfig().getEncoding();
186 	}
187 
188 	public void setEncoding( String encoding )
189 	{
190 		String old = getEncoding();
191 		getConfig().setEncoding( encoding );
192 		notifyPropertyChanged( ENCODING_PROPERTY, old, encoding );
193 	}
194 
195 	public String getResponseContent()
196 	{
197 		if( getConfig().getResponseContent() == null )
198 			getConfig().addNewResponseContent();
199 
200 		if( responseContent == null )
201 			responseContent = CompressedStringSupport.getString( getConfig().getResponseContent() );
202 
203 		return responseContent;
204 	}
205 
206 	public void setResponseContent( String responseContent )
207 	{
208 		String oldContent = getResponseContent();
209 		if( responseContent.equals( oldContent ) )
210 			return;
211 
212 		this.responseContent = responseContent;
213 		notifyPropertyChanged( RESPONSE_CONTENT_PROPERTY, oldContent, responseContent );
214 	}
215 
216 	public void setResponseCompression( String compression )
217 	{
218 		if( CompressionSupport.ALG_DEFLATE.equals( compression ) || CompressionSupport.ALG_GZIP.equals( compression )
219 				|| NO_RESPONSE_COMPRESSION.equals( compression ) )
220 		{
221 			getConfig().setCompression( compression );
222 		}
223 		else if( getConfig().isSetCompression() )
224 		{
225 			getConfig().unsetCompression();
226 		}
227 	}
228 
229 	public String getResponseCompression()
230 	{
231 		if( getConfig().isSetCompression() )
232 			return getConfig().getCompression();
233 		else
234 			return AUTO_RESPONSE_COMPRESSION;
235 	}
236 
237 	@Override
238 	public ImageIcon getIcon()
239 	{
240 		return iconAnimator.getIcon();
241 	}
242 
243 	public WsdlMockOperation getMockOperation()
244 	{
245 		return ( WsdlMockOperation )getParent();
246 	}
247 
248 	public WsdlMockResult execute( WsdlMockRequest request, WsdlMockResult result ) throws DispatchException
249 	{
250 		try
251 		{
252 			iconAnimator.start();
253 
254 			getProperty( "Request" ).setValue( request.getRequestContent() );
255 
256 			long delay = getResponseDelay();
257 			if( delay > 0 )
258 				Thread.sleep( delay );
259 
260 			String script = getScript();
261 			if( script != null && script.trim().length() > 0 )
262 			{
263 				evaluateScript( request );
264 			}
265 
266 			String responseContent = getResponseContent();
267 
268 			// create merged context
269 			WsdlMockRunContext context = new WsdlMockRunContext( request.getContext().getMockService(), null );
270 			context.setMockResponse( this );
271 
272 			context.putAll( request.getContext() );
273 			context.putAll( request.getRequestContext() );
274 
275 			StringToStringMap responseHeaders = getResponseHeaders();
276 			for( String name : responseHeaders.keySet() )
277 			{
278 				result.addHeader( name, PropertyExpander.expandProperties( context, responseHeaders.get( name ) ) );
279 			}
280 
281 			responseContent = PropertyExpander.expandProperties( context, responseContent, isEntitizeProperties() );
282 
283 			if( this.getWsaConfig().isWsaEnabled() )
284 			{
285 				responseContent = new WsaUtils( responseContent, getSoapVersion(), getMockOperation().getOperation(),
286 						context ).addWSAddressingMockResponse( this, request );
287 			}
288 
289 			String outgoingWss = getOutgoingWss();
290 			if( StringUtils.isNullOrEmpty( outgoingWss ) )
291 				outgoingWss = getMockOperation().getMockService().getOutgoingWss();
292 
293 			if( StringUtils.hasContent( outgoingWss ) )
294 			{
295 				OutgoingWss outgoing = getMockOperation().getMockService().getProject().getWssContainer()
296 						.getOutgoingWssByName( outgoingWss );
297 				if( outgoing != null )
298 				{
299 					Document dom = XmlUtils.parseXml( responseContent );
300 					outgoing.processOutgoing( dom, context );
301 					StringWriter writer = new StringWriter();
302 					XmlUtils.serialize( dom, writer );
303 					responseContent = writer.toString();
304 				}
305 			}
306 
307 			if( !result.isCommitted() )
308 			{
309 				responseContent = writeResponse( result, responseContent );
310 			}
311 
312 			result.setResponseContent( responseContent );
313 
314 			setMockResult( result );
315 
316 			return mockResult;
317 		}
318 		catch( Throwable e )
319 		{
320 			SoapUI.logError( e );
321 			throw new DispatchException( e );
322 		}
323 		finally
324 		{
325 			iconAnimator.stop();
326 		}
327 	}
328 
329 	public void evaluateScript( WsdlMockRequest request ) throws Exception
330 	{
331 		String script = getScript();
332 		if( script == null || script.trim().length() == 0 )
333 			return;
334 
335 		WsdlMockService mockService = getMockOperation().getMockService();
336 		WsdlMockRunner mockRunner = mockService.getMockRunner();
337 		MockRunContext context = mockRunner == null ? new WsdlMockRunContext( mockService, null ) : mockRunner
338 				.getMockContext();
339 
340 		SoapUIScriptEngine scriptEngine = scriptEnginePool.getScriptEngine();
341 
342 		try
343 		{
344 			scriptEngine.setVariable( "context", context );
345 			scriptEngine.setVariable( "requestContext", request == null ? null : request.getRequestContext() );
346 			scriptEngine.setVariable( "mockContext", context );
347 			scriptEngine.setVariable( "mockRequest", request );
348 			scriptEngine.setVariable( "mockResponse", this );
349 			scriptEngine.setVariable( "log", SoapUI.ensureGroovyLog() );
350 
351 			scriptEngine.run();
352 		}
353 		catch( RuntimeException e )
354 		{
355 			throw new Exception( e.getMessage(), e );
356 		}
357 		finally
358 		{
359 			scriptEnginePool.returnScriptEngine( scriptEngine );
360 		}
361 	}
362 
363 	@Override
364 	public void release()
365 	{
366 		super.release();
367 		scriptEnginePool.release();
368 	}
369 
370 	public void setScript( String script )
371 	{
372 		String oldScript = getScript();
373 		if( !script.equals( oldScript ) )
374 		{
375 			if( !getConfig().isSetScript() )
376 				getConfig().addNewScript();
377 			getConfig().getScript().setStringValue( script );
378 
379 			scriptEnginePool.setScript( script );
380 
381 			notifyPropertyChanged( SCRIPT_PROPERTY, oldScript, script );
382 		}
383 	}
384 
385 	public void setResponseHeaders( StringToStringMap headers )
386 	{
387 		StringToStringMap oldHeaders = getResponseHeaders();
388 
389 		HeaderConfig[] headerConfigs = new HeaderConfig[headers.size()];
390 		int ix = 0;
391 		for( String header : headers.keySet() )
392 		{
393 			headerConfigs[ix] = HeaderConfig.Factory.newInstance();
394 			headerConfigs[ix].setName( header );
395 			headerConfigs[ix].setValue( headers.get( header ) );
396 			ix++ ;
397 		}
398 
399 		getConfig().setHeaderArray( headerConfigs );
400 
401 		notifyPropertyChanged( HEADERS_PROPERTY, oldHeaders, headers );
402 	}
403 
404 	public StringToStringMap getResponseHeaders()
405 	{
406 		StringToStringMap result = new StringToStringMap();
407 		List<HeaderConfig> headerList = getConfig().getHeaderList();
408 		for( HeaderConfig header : headerList )
409 		{
410 			result.put( header.getName(), header.getValue() );
411 		}
412 
413 		return result;
414 	}
415 
416 	public MessagePart[] getRequestParts()
417 	{
418 		try
419 		{
420 			List<MessagePart> result = new ArrayList<MessagePart>();
421 			result.addAll( Arrays.asList( getMockOperation().getOperation().getDefaultRequestParts() ) );
422 
423 			if( getMockResult() != null )
424 				result.addAll( AttachmentUtils.extractAttachmentParts( getMockOperation().getOperation(), getMockResult()
425 						.getMockRequest().getRequestContent(), true, false, isMtomEnabled() ) );
426 
427 			return result.toArray( new MessagePart[result.size()] );
428 		}
429 		catch( Exception e )
430 		{
431 			SoapUI.logError( e );
432 			return new MessagePart[0];
433 		}
434 	}
435 
436 	public MessagePart[] getResponseParts()
437 	{
438 		try
439 		{
440 			// init
441 			WsdlOperation op = getMockOperation().getOperation();
442 			if( op == null || op.isUnidirectional() )
443 				return new MessagePart[0];
444 
445 			List<MessagePart> result = new ArrayList<MessagePart>();
446 			WsdlContext wsdlContext = op.getInterface().getWsdlContext();
447 			BindingOperation bindingOperation = op.findBindingOperation( wsdlContext.getDefinition() );
448 
449 			if( bindingOperation == null )
450 				return new MessagePart[0];
451 
452 			// header parts
453 			BindingOutput bindingOutput = bindingOperation.getBindingOutput();
454 			List<SoapHeader> headers = bindingOutput == null ? new ArrayList<SoapHeader>() : WsdlUtils
455 					.getSoapHeaders( bindingOutput.getExtensibilityElements() );
456 
457 			for( int i = 0; i < headers.size(); i++ )
458 			{
459 				SoapHeader header = headers.get( i );
460 
461 				Message message = wsdlContext.getDefinition().getMessage( header.getMessage() );
462 				if( message == null )
463 				{
464 					log.error( "Missing message for header: " + header.getMessage() );
465 					continue;
466 				}
467 
468 				javax.wsdl.Part part = message.getPart( header.getPart() );
469 
470 				if( part != null )
471 				{
472 					SchemaType schemaType = WsdlUtils.getSchemaTypeForPart( wsdlContext, part );
473 					SchemaGlobalElement schemaElement = WsdlUtils.getSchemaElementForPart( wsdlContext, part );
474 					if( schemaType != null )
475 						result.add( new WsdlHeaderPart( part.getName(), schemaType, part.getElementName(), schemaElement ) );
476 				}
477 				else
478 					log.error( "Missing part for header; " + header.getPart() );
479 			}
480 
481 			// content parts
482 			javax.wsdl.Part[] parts = WsdlUtils.getOutputParts( bindingOperation );
483 
484 			for( int i = 0; i < parts.length; i++ )
485 			{
486 				javax.wsdl.Part part = parts[i];
487 
488 				if( !WsdlUtils.isAttachmentOutputPart( part, bindingOperation ) )
489 				{
490 					SchemaType schemaType = WsdlUtils.getSchemaTypeForPart( wsdlContext, part );
491 					SchemaGlobalElement schemaElement = WsdlUtils.getSchemaElementForPart( wsdlContext, part );
492 					if( schemaType != null )
493 						result.add( new WsdlContentPart( part.getName(), schemaType, part.getElementName(), schemaElement ) );
494 				}
495 			}
496 
497 			result.addAll( Arrays.asList( getDefinedAttachmentParts() ) );
498 
499 			return result.toArray( new MessagePart[result.size()] );
500 		}
501 		catch( Exception e )
502 		{
503 			SoapUI.logError( e );
504 			return new MessagePart[0];
505 		}
506 	}
507 
508 	public Attachment attachFile( File file, boolean cache ) throws IOException
509 	{
510 		FileAttachment<WsdlMockResponse> fileAttachment = new MockFileAttachment( file, cache, this );
511 		attachments.add( fileAttachment );
512 		notifyPropertyChanged( ATTACHMENTS_PROPERTY, null, fileAttachment );
513 		return fileAttachment;
514 	}
515 
516 	public int getAttachmentCount()
517 	{
518 		return attachments.size();
519 	}
520 
521 	public WsdlAttachment getAttachmentAt( int index )
522 	{
523 		return attachments.get( index );
524 	}
525 
526 	public void removeAttachment( Attachment attachment )
527 	{
528 		int ix = attachments.indexOf( attachment );
529 		attachments.remove( ix );
530 
531 		try
532 		{
533 			notifyPropertyChanged( ATTACHMENTS_PROPERTY, attachment, null );
534 		}
535 		finally
536 		{
537 			getConfig().removeAttachment( ix );
538 		}
539 	}
540 
541 	public HttpAttachmentPart[] getDefinedAttachmentParts()
542 	{
543 		if( definedAttachmentParts == null )
544 		{
545 			try
546 			{
547 				WsdlOperation operation = getMockOperation().getOperation();
548 				if( operation == null )
549 				{
550 					definedAttachmentParts = new ArrayList<HttpAttachmentPart>();
551 				}
552 				else
553 				{
554 					UISupport.setHourglassCursor();
555 					definedAttachmentParts = AttachmentUtils.extractAttachmentParts( operation, getResponseContent(), true,
556 							true, isMtomEnabled() );
557 				}
558 			}
559 			catch( Exception e )
560 			{
561 				log.warn( e.toString() );
562 			}
563 			finally
564 			{
565 				UISupport.resetCursor();
566 			}
567 		}
568 
569 		return definedAttachmentParts.toArray( new HttpAttachmentPart[definedAttachmentParts.size()] );
570 	}
571 
572 	public HttpAttachmentPart getAttachmentPart( String partName )
573 	{
574 		HttpAttachmentPart[] parts = getDefinedAttachmentParts();
575 		for( HttpAttachmentPart part : parts )
576 		{
577 			if( part.getName().equals( partName ) )
578 				return part;
579 		}
580 
581 		return null;
582 	}
583 
584 	public Attachment[] getAttachmentsForPart( String partName )
585 	{
586 		List<Attachment> result = new ArrayList<Attachment>();
587 
588 		for( Attachment attachment : attachments )
589 		{
590 			if( attachment.getPart().equals( partName ) )
591 				result.add( attachment );
592 		}
593 
594 		return result.toArray( new Attachment[result.size()] );
595 	}
596 
597 	public boolean isMtomEnabled()
598 	{
599 		return getSettings().getBoolean( WsdlSettings.ENABLE_MTOM );
600 	}
601 
602 	public void setMtomEnabled( boolean mtomEnabled )
603 	{
604 		boolean old = isMtomEnabled();
605 		getSettings().setBoolean( WsdlSettings.ENABLE_MTOM, mtomEnabled );
606 		definedAttachmentParts = null;
607 		notifyPropertyChanged( MTOM_NABLED_PROPERTY, old, mtomEnabled );
608 	}
609 
610 	private String writeResponse( WsdlMockResult response, String responseContent ) throws Exception
611 	{
612 		MimeMultipart mp = null;
613 		WsdlOperation operation = getMockOperation().getOperation();
614 		if( operation == null )
615 			throw new Exception( "Missing WsdlOperation for mock response" );
616 
617 		SoapVersion soapVersion = operation.getInterface().getSoapVersion();
618 
619 		StringToStringMap contentIds = new StringToStringMap();
620 		boolean isXOP = isMtomEnabled() && isForceMtom();
621 
622 		// preprocess only if neccessary
623 		if( isMtomEnabled() || isInlineFilesEnabled() || getAttachmentCount() > 0 )
624 		{
625 			try
626 			{
627 				mp = new MimeMultipart();
628 
629 				MessageXmlObject requestXmlObject = new MessageXmlObject( operation, responseContent, false );
630 				MessageXmlPart[] requestParts = requestXmlObject.getMessageParts();
631 				for( MessageXmlPart requestPart : requestParts )
632 				{
633 					if( AttachmentUtils.prepareMessagePart( this, mp, requestPart, contentIds ) )
634 						isXOP = true;
635 				}
636 				responseContent = requestXmlObject.getMessageContent();
637 			}
638 			catch( Exception e )
639 			{
640 				e.printStackTrace();
641 			}
642 		}
643 
644 		if( isRemoveEmptyContent() )
645 		{
646 			responseContent = RemoveEmptyContentRequestFilter.removeEmptyContent( responseContent, getSoapVersion()
647 					.getEnvelopeNamespace(), true );
648 		}
649 
650 		if( isStripWhitespaces() )
651 		{
652 			responseContent = XmlUtils.stripWhitespaces( responseContent );
653 		}
654 
655 		String status = getResponseHttpStatus();
656 		WsdlMockRequest request = response.getMockRequest();
657 
658 		if( status == null || status.trim().length() == 0 )
659 		{
660 			if( SoapUtils.isSoapFault( responseContent, request.getSoapVersion() ) )
661 			{
662 				request.getHttpResponse().setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
663 				response.setResponseStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
664 			}
665 			else
666 			{
667 				request.getHttpResponse().setStatus( HttpServletResponse.SC_OK );
668 				response.setResponseStatus( HttpServletResponse.SC_OK );
669 			}
670 		}
671 		else
672 		{
673 			try
674 			{
675 				int statusCode = Integer.parseInt( status );
676 				request.getHttpResponse().setStatus( statusCode );
677 				response.setResponseStatus( statusCode );
678 			}
679 			catch( RuntimeException e )
680 			{
681 				SoapUI.logError( e );
682 			}
683 		}
684 
685 		ByteArrayOutputStream outData = new ByteArrayOutputStream();
686 
687 		// non-multipart request?
688 		String responseCompression = getResponseCompression();
689 		if( !isXOP && ( mp == null || mp.getCount() == 0 ) && getAttachmentCount() == 0 )
690 		{
691 			String encoding = getEncoding();
692 			if( responseContent == null )
693 				responseContent = "";
694 
695 			byte[] content = encoding == null ? responseContent.getBytes() : responseContent.getBytes( encoding );
696 
697 			if( !response.getResponseHeaders().containsKeyIgnoreCase( "Content-Type" ) )
698 				response.setContentType( soapVersion.getContentTypeHttpHeader( encoding, null ) );
699 
700 			String acceptEncoding = response.getMockRequest().getRequestHeaders().get( "Accept-Encoding" );
701 			if( AUTO_RESPONSE_COMPRESSION.equals( responseCompression ) && acceptEncoding != null
702 					&& acceptEncoding.toUpperCase().contains( "GZIP" ) )
703 			{
704 				response.addHeader( "Content-Encoding", "gzip" );
705 				outData.write( CompressionSupport.compress( CompressionSupport.ALG_GZIP, content ) );
706 			}
707 			else if( AUTO_RESPONSE_COMPRESSION.equals( responseCompression ) && acceptEncoding != null
708 					&& acceptEncoding.toUpperCase().contains( "DEFLATE" ) )
709 			{
710 				response.addHeader( "Content-Encoding", "deflate" );
711 				outData.write( CompressionSupport.compress( CompressionSupport.ALG_DEFLATE, content ) );
712 			}
713 			else
714 			{
715 				outData.write( content );
716 			}
717 		}
718 		else
719 		{
720 			// make sure..
721 			if( mp == null )
722 				mp = new MimeMultipart();
723 
724 			// init root part
725 			initRootPart( responseContent, mp, isXOP );
726 
727 			// init mimeparts
728 			AttachmentUtils.addMimeParts( this, Arrays.asList( getAttachments() ), mp, contentIds );
729 
730 			// create request message
731 			MimeMessage message = new MimeMessage( AttachmentUtils.JAVAMAIL_SESSION );
732 			message.setContent( mp );
733 			message.saveChanges();
734 			MimeMessageMockResponseEntity mimeMessageRequestEntity = new MimeMessageMockResponseEntity( message, isXOP,
735 					this );
736 
737 			response.addHeader( "Content-Type", mimeMessageRequestEntity.getContentType() );
738 			response.addHeader( "MIME-Version", "1.0" );
739 			mimeMessageRequestEntity.writeRequest( outData );
740 		}
741 
742 		if( outData.size() > 0 )
743 		{
744 			byte[] data = outData.toByteArray();
745 
746 			if( responseCompression.equals( CompressionSupport.ALG_DEFLATE )
747 					|| responseCompression.equals( CompressionSupport.ALG_GZIP ) )
748 			{
749 				response.addHeader( "Content-Encoding", responseCompression );
750 				data = CompressionSupport.compress( responseCompression, data );
751 			}
752 
753 			response.writeRawResponseData( data );
754 		}
755 
756 		return responseContent;
757 	}
758 
759 	private void initRootPart( String requestContent, MimeMultipart mp, boolean isXOP ) throws MessagingException
760 	{
761 		MimeBodyPart rootPart = new PreencodedMimeBodyPart( "8bit" );
762 		rootPart.setContentID( AttachmentUtils.ROOTPART_SOAPUI_ORG );
763 		mp.addBodyPart( rootPart, 0 );
764 
765 		DataHandler dataHandler = new DataHandler( new MockResponseDataSource( this, requestContent, isXOP ) );
766 		rootPart.setDataHandler( dataHandler );
767 	}
768 
769 	@SuppressWarnings( "unchecked" )
770 	public Attachment addAttachment( Attachment attachment )
771 	{
772 		if( attachment instanceof BodyPartAttachment )
773 		{
774 			try
775 			{
776 				BodyPartAttachment att = ( BodyPartAttachment )attachment;
777 
778 				AttachmentConfig newConfig = getConfig().addNewAttachment();
779 				newConfig.setData( Tools.readAll( att.getInputStream(), 0 ).toByteArray() );
780 				newConfig.setContentId( att.getContentID() );
781 				newConfig.setContentType( att.getContentType() );
782 				newConfig.setName( att.getName() );
783 
784 				FileAttachment<WsdlMockResponse> newAttachment = new MockFileAttachment( newConfig, this );
785 				attachments.add( newAttachment );
786 				return newAttachment;
787 			}
788 			catch( Exception e )
789 			{
790 				SoapUI.logError( e );
791 			}
792 		}
793 		else if( attachment instanceof FileAttachment )
794 		{
795 			AttachmentConfig oldConfig = ( ( FileAttachment<WsdlMockResponse> )attachment ).getConfig();
796 			AttachmentConfig newConfig = ( AttachmentConfig )getConfig().addNewAttachment().set( oldConfig );
797 			FileAttachment<WsdlMockResponse> newAttachment = new MockFileAttachment( newConfig, this );
798 			attachments.add( newAttachment );
799 			return newAttachment;
800 		}
801 
802 		return null;
803 	}
804 
805 	public void setResponseDelay( long delay )
806 	{
807 		long oldDelay = getResponseDelay();
808 
809 		if( delay == 0 )
810 			getSettings().clearSetting( RESPONSE_DELAY_PROPERTY );
811 		else
812 			getSettings().setLong( RESPONSE_DELAY_PROPERTY, delay );
813 
814 		notifyPropertyChanged( RESPONSE_DELAY_PROPERTY, oldDelay, delay );
815 	}
816 
817 	public long getResponseDelay()
818 	{
819 		return getSettings().getLong( RESPONSE_DELAY_PROPERTY, 0 );
820 	}
821 
822 	public void setResponseHttpStatus( String httpStatus )
823 	{
824 		String oldStatus = getResponseHttpStatus();
825 
826 		getConfig().setHttpResponseStatus( httpStatus );
827 
828 		notifyPropertyChanged( RESPONSE_HTTP_STATUS, oldStatus, httpStatus );
829 	}
830 
831 	public String getResponseHttpStatus()
832 	{
833 		return getConfig().getHttpResponseStatus();
834 	}
835 
836 	public void setMockResult( WsdlMockResult mockResult )
837 	{
838 		WsdlMockResult oldResult = this.mockResult;
839 		this.mockResult = mockResult;
840 		notifyPropertyChanged( MOCKRESULT_PROPERTY, oldResult, mockResult );
841 	}
842 
843 	public WsdlMockResult getMockResult()
844 	{
845 		return mockResult;
846 	}
847 
848 	public long getContentLength()
849 	{
850 		return getResponseContent() == null ? 0 : getResponseContent().length();
851 	}
852 
853 	public boolean isMultipartEnabled()
854 	{
855 		return !getSettings().getBoolean( DISABLE_MULTIPART_ATTACHMENTS );
856 	}
857 
858 	public void setMultipartEnabled( boolean multipartEnabled )
859 	{
860 		getSettings().setBoolean( DISABLE_MULTIPART_ATTACHMENTS, multipartEnabled );
861 	}
862 
863 	public boolean isEntitizeProperties()
864 	{
865 		return getSettings().getBoolean( CommonSettings.ENTITIZE_PROPERTIES );
866 	}
867 
868 	public void setEntitizeProperties( boolean entitizeProperties )
869 	{
870 		getSettings().setBoolean( CommonSettings.ENTITIZE_PROPERTIES, entitizeProperties );
871 	}
872 
873 	public boolean isForceMtom()
874 	{
875 		return getSettings().getBoolean( FORCE_MTOM );
876 	}
877 
878 	public void setForceMtom( boolean forceMtom )
879 	{
880 		boolean old = getSettings().getBoolean( FORCE_MTOM );
881 		getSettings().setBoolean( FORCE_MTOM, forceMtom );
882 		notifyPropertyChanged( FORCE_MTOM, old, forceMtom );
883 	}
884 
885 	public boolean isRemoveEmptyContent()
886 	{
887 		return getSettings().getBoolean( REMOVE_EMPTY_CONTENT );
888 	}
889 
890 	public void setRemoveEmptyContent( boolean removeEmptyContent )
891 	{
892 		boolean old = getSettings().getBoolean( REMOVE_EMPTY_CONTENT );
893 		getSettings().setBoolean( REMOVE_EMPTY_CONTENT, removeEmptyContent );
894 		notifyPropertyChanged( REMOVE_EMPTY_CONTENT, old, removeEmptyContent );
895 	}
896 
897 	public boolean isEncodeAttachments()
898 	{
899 		return getSettings().getBoolean( ENCODE_ATTACHMENTS );
900 	}
901 
902 	public void setEncodeAttachments( boolean encodeAttachments )
903 	{
904 		boolean old = getSettings().getBoolean( ENCODE_ATTACHMENTS );
905 		getSettings().setBoolean( ENCODE_ATTACHMENTS, encodeAttachments );
906 		notifyPropertyChanged( ENCODE_ATTACHMENTS, old, encodeAttachments );
907 	}
908 
909 	public boolean isStripWhitespaces()
910 	{
911 		return getSettings().getBoolean( STRIP_WHITESPACES );
912 	}
913 
914 	public void setStripWhitespaces( boolean stripWhitespaces )
915 	{
916 		boolean old = getSettings().getBoolean( STRIP_WHITESPACES );
917 		getSettings().setBoolean( STRIP_WHITESPACES, stripWhitespaces );
918 		notifyPropertyChanged( STRIP_WHITESPACES, old, stripWhitespaces );
919 	}
920 
921 	public boolean isInlineFilesEnabled()
922 	{
923 		return getSettings().getBoolean( WsdlMockResponse.ENABLE_INLINE_FILES );
924 	}
925 
926 	public void setInlineFilesEnabled( boolean inlineFilesEnabled )
927 	{
928 		getSettings().setBoolean( WsdlMockResponse.ENABLE_INLINE_FILES, inlineFilesEnabled );
929 	}
930 
931 	@Override
932 	public void beforeSave()
933 	{
934 		super.beforeSave();
935 
936 		if( responseContent != null )
937 		{
938 			CompressedStringSupport.setString( getConfig().getResponseContent(), responseContent );
939 		}
940 	}
941 
942 	public void addAttachmentsChangeListener( PropertyChangeListener listener )
943 	{
944 		addPropertyChangeListener( ATTACHMENTS_PROPERTY, listener );
945 	}
946 
947 	public boolean isReadOnly()
948 	{
949 		return false;
950 	}
951 
952 	public void removeAttachmentsChangeListener( PropertyChangeListener listener )
953 	{
954 		removePropertyChangeListener( ATTACHMENTS_PROPERTY, listener );
955 	}
956 
957 	public SoapVersion getSoapVersion()
958 	{
959 		return getMockOperation().getOperation() == null ? SoapVersion.Soap11 : getMockOperation().getOperation()
960 				.getInterface().getSoapVersion();
961 	}
962 
963 	public PropertyExpansion[] getPropertyExpansions()
964 	{
965 		List<PropertyExpansion> result = new ArrayList<PropertyExpansion>();
966 
967 		result.addAll( PropertyExpansionUtils.extractPropertyExpansions( this, this, "responseContent" ) );
968 
969 		StringToStringMap responseHeaders = getResponseHeaders();
970 		for( String key : responseHeaders.keySet() )
971 		{
972 			result.addAll( PropertyExpansionUtils.extractPropertyExpansions( this, new ResponseHeaderHolder(
973 					responseHeaders, key ), "value" ) );
974 		}
975 
976 		addWsaPropertyExpansions( result, getWsaConfig(), this );
977 		return result.toArray( new PropertyExpansion[result.size()] );
978 	}
979 
980 	public void addWsaPropertyExpansions( List<PropertyExpansion> result, WsaConfig wsaConfig, ModelItem modelItem )
981 	{
982 		result.addAll( PropertyExpansionUtils.extractPropertyExpansions( modelItem, wsaConfig, "action" ) );
983 		result.addAll( PropertyExpansionUtils.extractPropertyExpansions( modelItem, wsaConfig, "from" ) );
984 		result.addAll( PropertyExpansionUtils.extractPropertyExpansions( modelItem, wsaConfig, "to" ) );
985 		result.addAll( PropertyExpansionUtils.extractPropertyExpansions( modelItem, wsaConfig, "replyTo" ) );
986 		result.addAll( PropertyExpansionUtils.extractPropertyExpansions( modelItem, wsaConfig, "replyToRefParams" ) );
987 		result.addAll( PropertyExpansionUtils.extractPropertyExpansions( modelItem, wsaConfig, "faultTo" ) );
988 		result.addAll( PropertyExpansionUtils.extractPropertyExpansions( modelItem, wsaConfig, "faultToRefParams" ) );
989 		result.addAll( PropertyExpansionUtils.extractPropertyExpansions( modelItem, wsaConfig, "relatesTo" ) );
990 		result.addAll( PropertyExpansionUtils.extractPropertyExpansions( modelItem, wsaConfig, "relationshipType" ) );
991 		result.addAll( PropertyExpansionUtils.extractPropertyExpansions( modelItem, wsaConfig, "messageID" ) );
992 	}
993 
994 	public class ResponseHeaderHolder
995 	{
996 		private final StringToStringMap valueMap;
997 		private final String key;
998 
999 		public ResponseHeaderHolder( StringToStringMap valueMap, String key )
1000 		{
1001 			this.valueMap = valueMap;
1002 			this.key = key;
1003 		}
1004 
1005 		public String getValue()
1006 		{
1007 			return valueMap.get( key );
1008 		}
1009 
1010 		public void setValue( String value )
1011 		{
1012 			valueMap.put( key, value );
1013 			setResponseHeaders( valueMap );
1014 		}
1015 	}
1016 
1017 	public void addTestPropertyListener( TestPropertyListener listener )
1018 	{
1019 		propertyHolder.addTestPropertyListener( listener );
1020 	}
1021 
1022 	public ModelItem getModelItem()
1023 	{
1024 		return propertyHolder.getModelItem();
1025 	}
1026 
1027 	public Map<String, TestProperty> getProperties()
1028 	{
1029 		return propertyHolder.getProperties();
1030 	}
1031 
1032 	public TestProperty getProperty( String name )
1033 	{
1034 		return propertyHolder.getProperty( name );
1035 	}
1036 
1037 	public String[] getPropertyNames()
1038 	{
1039 		return propertyHolder.getPropertyNames();
1040 	}
1041 
1042 	public String getPropertyValue( String name )
1043 	{
1044 		return propertyHolder.getPropertyValue( name );
1045 	}
1046 
1047 	public boolean hasProperty( String name )
1048 	{
1049 		return propertyHolder.hasProperty( name );
1050 	}
1051 
1052 	public void removeTestPropertyListener( TestPropertyListener listener )
1053 	{
1054 		propertyHolder.removeTestPropertyListener( listener );
1055 	}
1056 
1057 	public void setPropertyValue( String name, String value )
1058 	{
1059 		propertyHolder.setPropertyValue( name, value );
1060 	}
1061 
1062 	public String getOutgoingWss()
1063 	{
1064 		return getConfig().getOutgoingWss();
1065 	}
1066 
1067 	public void setOutgoingWss( String outgoingWss )
1068 	{
1069 		String old = getOutgoingWss();
1070 		getConfig().setOutgoingWss( outgoingWss );
1071 		notifyPropertyChanged( OUGOING_WSS, old, outgoingWss );
1072 	}
1073 
1074 	public TestProperty getPropertyAt( int index )
1075 	{
1076 		return propertyHolder.getPropertyAt( index );
1077 	}
1078 
1079 	public int getPropertyCount()
1080 	{
1081 		return propertyHolder.getPropertyCount();
1082 	}
1083 
1084 	public List<TestProperty> getPropertyList()
1085 	{
1086 		return propertyHolder.getPropertyList();
1087 	}
1088 
1089 	public String getPropertiesLabel()
1090 	{
1091 		return "Custom Properties";
1092 	}
1093 
1094 	public AttachmentEncoding getAttachmentEncoding( String partName )
1095 	{
1096 		HttpAttachmentPart attachmentPart = getAttachmentPart( partName );
1097 		if( attachmentPart == null )
1098 			return AttachmentUtils.getAttachmentEncoding( getOperation(), partName, true );
1099 		else
1100 			return AttachmentUtils.getAttachmentEncoding( getOperation(), attachmentPart, true );
1101 	}
1102 
1103 	public WsaConfig getWsaConfig()
1104 	{
1105 		if( wsaConfig == null )
1106 		{
1107 			if( !getConfig().isSetWsaConfig() )
1108 			{
1109 				getConfig().addNewWsaConfig();
1110 			}
1111 			wsaConfig = new WsaConfig( getConfig().getWsaConfig(), this );
1112 			// wsaConfig.setGenerateMessageId(true);
1113 		}
1114 		return wsaConfig;
1115 	}
1116 
1117 	public boolean isWsAddressing()
1118 	{
1119 		return getConfig().getUseWsAddressing();
1120 	}
1121 
1122 	public void setWsAddressing( boolean wsAddressing )
1123 	{
1124 		boolean old = getConfig().getUseWsAddressing();
1125 		getConfig().setUseWsAddressing( wsAddressing );
1126 		notifyPropertyChanged( "wsAddressing", old, wsAddressing );
1127 	}
1128 
1129 	public boolean isWsaEnabled()
1130 	{
1131 		return isWsAddressing();
1132 	}
1133 
1134 	public void setWsaEnabled( boolean arg0 )
1135 	{
1136 		setWsAddressing( arg0 );
1137 
1138 	}
1139 
1140 	public WsdlOperation getOperation()
1141 	{
1142 		return getMockOperation().getOperation();
1143 	}
1144 
1145 	public void setOperation( WsdlOperation operation )
1146 	{
1147 		getMockOperation().setOperation( operation );
1148 	}
1149 
1150 }