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