View Javadoc

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