View Javadoc

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