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 groovy.lang.Binding;
16  import groovy.lang.Script;
17  
18  import java.io.File;
19  import java.io.IOException;
20  import java.util.ArrayList;
21  import java.util.List;
22  
23  import javax.activation.DataHandler;
24  import javax.mail.MessagingException;
25  import javax.mail.internet.MimeBodyPart;
26  import javax.mail.internet.MimeMessage;
27  import javax.mail.internet.MimeMultipart;
28  import javax.mail.internet.PreencodedMimeBodyPart;
29  import javax.swing.ImageIcon;
30  
31  import org.apache.log4j.Logger;
32  
33  import com.eviware.soapui.SoapUI;
34  import com.eviware.soapui.config.AttachmentConfig;
35  import com.eviware.soapui.config.HeaderConfig;
36  import com.eviware.soapui.config.MockResponseConfig;
37  import com.eviware.soapui.impl.actions.ShowDesktopPanelAction;
38  import com.eviware.soapui.impl.wsdl.AbstractWsdlModelItem;
39  import com.eviware.soapui.impl.wsdl.AttachmentContainer;
40  import com.eviware.soapui.impl.wsdl.WsdlAttachmentPart;
41  import com.eviware.soapui.impl.wsdl.WsdlOperation;
42  import com.eviware.soapui.impl.wsdl.actions.mockresponse.CloneMockResponseAction;
43  import com.eviware.soapui.impl.wsdl.actions.mockresponse.DeleteMockResponseAction;
44  import com.eviware.soapui.impl.wsdl.actions.mockresponse.RenameMockResponseAction;
45  import com.eviware.soapui.impl.wsdl.actions.support.ShowOnlineHelpAction;
46  import com.eviware.soapui.impl.wsdl.submit.filters.PropertyExpansionRequestFilter;
47  import com.eviware.soapui.impl.wsdl.submit.transports.http.AttachmentUtils;
48  import com.eviware.soapui.impl.wsdl.submit.transports.http.BodyPartAttachment;
49  import com.eviware.soapui.impl.wsdl.submit.transports.http.MimeMessageMockResponseEntity;
50  import com.eviware.soapui.impl.wsdl.submit.transports.http.MockResponseDataSource;
51  import com.eviware.soapui.impl.wsdl.support.FileAttachment;
52  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
53  import com.eviware.soapui.impl.wsdl.support.MessageXmlObject;
54  import com.eviware.soapui.impl.wsdl.support.MessageXmlPart;
55  import com.eviware.soapui.impl.wsdl.support.MockFileAttachment;
56  import com.eviware.soapui.impl.wsdl.support.ModelItemIconAnimator;
57  import com.eviware.soapui.impl.wsdl.support.WsdlAttachment;
58  import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
59  import com.eviware.soapui.model.iface.Attachment;
60  import com.eviware.soapui.model.mock.MockResponse;
61  import com.eviware.soapui.model.mock.MockRunContext;
62  import com.eviware.soapui.settings.WsdlSettings;
63  import com.eviware.soapui.support.Tools;
64  import com.eviware.soapui.support.UISupport;
65  import com.eviware.soapui.support.action.ActionSupport;
66  import com.eviware.soapui.support.types.StringToStringMap;
67  
68  public class WsdlMockResponse extends AbstractWsdlModelItem<MockResponseConfig> implements MockResponse, AttachmentContainer
69  {
70  	private final static Logger log = Logger.getLogger( WsdlMockResponse.class );
71  	
72  	public final static String MOCKRESULT_PROPERTY = WsdlMockResponse.class.getName() + "@mockresult";
73  	public final static String SCRIPT_PROPERTY = WsdlMockResponse.class.getName() + "@script";
74  	public final static String HEADERS_PROPERTY = WsdlMockResponse.class.getName() + "@headers";
75  	public static final String DISABLE_MULTIPART_ATTACHMENTS = WsdlMockResponse.class.getName() + "@disable-multipart-attachments";
76  	
77  	protected List<FileAttachment> attachments = new ArrayList<FileAttachment>();
78  	private List<WsdlAttachmentPart> definedAttachmentParts;
79  	private ModelItemIconAnimator iconAnimator;
80  	private WsdlMockResult mockResult;
81  	
82  	public WsdlMockResponse( WsdlMockOperation operation, MockResponseConfig config )
83  	{
84  		super( config, operation, "/mockResponse.gif" );
85  		
86  		for( AttachmentConfig ac : getConfig().getAttachmentList() )
87  		{
88  			attachments.add( new MockFileAttachment( ac, this ));
89  		}
90  		
91  		if( !config.isSetEncoding() )
92  			config.setEncoding( "UTF-8" );
93  		
94  		addAction( new ShowDesktopPanelAction( "Open MockResponse Editor", "Opens the MockResponse Editor for this MockResponse", this ));
95        addAction( ActionSupport.SEPARATOR_ACTION );
96  //      addAction( new AddMockResponseToTestCaseAction( this ));
97        addAction( new CloneMockResponseAction( this ));
98        addAction( ActionSupport.SEPARATOR_ACTION );
99        addAction( new RenameMockResponseAction( this ));
100       addAction( new DeleteMockResponseAction( this ));
101       addAction( ActionSupport.SEPARATOR_ACTION );
102       addAction( new ShowOnlineHelpAction( HelpUrls.MOCKRESPONSE_HELP_URL ));
103       
104       iconAnimator = new ModelItemIconAnimator( this, "/mockResponse.gif", 
105 					new String[] {"/exec_request_1.gif", "/exec_request_2.gif",
106 					"/exec_request_3.gif", "/exec_request_4.gif"} );
107 	}
108 
109 	public Attachment[] getAttachments()
110 	{
111 		return attachments.toArray( new Attachment[attachments.size()] );
112 	}
113 	
114 	public String getScript()
115 	{
116 		return getConfig().isSetScript() ? getConfig().getScript().getStringValue() : null;
117 	}
118 
119 	public String getEncoding()
120 	{
121 		return getConfig().getEncoding();
122 	}
123 	
124 	public void setEncoding( String encoding )
125 	{
126 		String old = getEncoding();
127 		getConfig().setEncoding( encoding );
128 		notifyPropertyChanged( ENCODING_PROPERTY, old, encoding );
129 	}
130 
131 	public String getResponseContent()
132 	{
133 		return getConfig().getResponseContent();
134 	}
135 
136 	public void setResponseContent( String responseContent )
137 	{
138 		String oldContent = getResponseContent();
139 		if( !responseContent.equals( oldContent ))
140 		{
141 			getConfig().setResponseContent( responseContent );
142 			notifyPropertyChanged( RESPONSECONTENT_PROPERTY, oldContent, responseContent );
143 		}
144 	}
145 	
146 	@Override
147 	public ImageIcon getIcon()
148 	{
149 		return iconAnimator.getIcon();
150 	}
151 
152 	public WsdlMockOperation getMockOperation()
153 	{
154 		return ( WsdlMockOperation ) getParent();
155 	}
156 	
157 	public WsdlMockResult execute( WsdlMockRequest request, WsdlMockResult result ) throws DispatchException
158 	{
159 		try
160 		{
161 			iconAnimator.start();
162 			StringToStringMap responseHeaders = getResponseHeaders();
163 			for( String name : responseHeaders.keySet() )
164 			{
165 				result.addHeader( name, PropertyExpansionRequestFilter.expandProperties( request.getContext(), responseHeaders.get( name ) ));
166 			}
167 			
168 			String responseContent = getResponseContent();
169 			String script = getScript();
170 			if( script != null && script.trim().length() > 0 )
171 			{
172 				evaluateScript( request );
173 			}
174 
175 			responseContent = PropertyExpansionRequestFilter.expandProperties( request.getContext(), responseContent );
176 			
177 			if( !result.isCommitted())
178 			{
179 				responseContent = writeResponse( result, responseContent );
180 			}
181 			
182 			result.setReponseContent( responseContent );
183 			
184 			setMockResult( result );
185 			
186 			return mockResult;
187 		}
188 		catch( Throwable e )
189 		{
190 			throw new DispatchException( e );
191 		}
192 		finally
193 		{
194 			iconAnimator.stop();
195 		}
196 	}
197 
198 	public void evaluateScript( WsdlMockRequest request )
199 	{
200 		String script = getScript();
201 		if( script == null || script.trim().length() == 0 )
202 			return ;
203 			
204 		// unsatisfactory way of handling multiple threads -> create pool of scripts instead
205 		Binding localBinding = new Binding();
206 		
207 		WsdlMockService mockService = getMockOperation().getMockService();
208 		WsdlMockRunner mockRunner = mockService.getMockRunner();
209 		MockRunContext context = mockRunner == null ? new WsdlMockRunContext( mockService, null ) : mockRunner.getMockContext(); 
210 		
211 		localBinding.setVariable( "context", context );
212 		localBinding.setVariable( "mockRequest", request);
213 		localBinding.setVariable( "mockResponse", this );
214 		localBinding.setVariable( "log", SoapUI.ensureGroovyLog() );
215 		
216 		Script localScript = mockService.getScriptShell().parse( script );
217 		localScript.setBinding( localBinding );
218 		localScript.run();
219 	}
220 
221 	public void setScript( String script )
222 	{
223 		String oldScript = getScript();
224 		if( !script.equals( oldScript ))
225 		{
226 			if( !getConfig().isSetScript())
227 				getConfig().addNewScript();
228 			getConfig().getScript().setStringValue( script );
229 			
230 			notifyPropertyChanged( SCRIPT_PROPERTY, oldScript, script );
231 		}
232 	}
233 
234 	public void setResponseHeaders( StringToStringMap headers )
235 	{
236 		StringToStringMap oldHeaders = getResponseHeaders();
237 		
238 		HeaderConfig [] headerConfigs = new HeaderConfig[headers.size()];
239 		int ix = 0;
240 		for( String header : headers.keySet() )
241 		{
242 			headerConfigs[ix] = HeaderConfig.Factory.newInstance();
243 			headerConfigs[ix].setName( header );
244 			headerConfigs[ix].setValue( headers.get( header ) );
245 			ix++;
246 		}
247 		
248 		getConfig().setHeaderArray( headerConfigs );
249 		
250 		notifyPropertyChanged( HEADERS_PROPERTY, oldHeaders, headers );
251 	}
252 
253 	public StringToStringMap getResponseHeaders()
254 	{
255 		StringToStringMap result = new StringToStringMap();
256 		List<HeaderConfig> headerList = getConfig().getHeaderList();
257 		for( HeaderConfig header : headerList )
258 		{
259 			result.put( header.getName(), header.getValue() );
260 		}
261 		
262 		return result;
263 	}
264 
265 	public Attachment attachFile( File file, boolean cache )
266 	{
267 		try
268 		{
269 			FileAttachment fileAttachment = new MockFileAttachment( file, cache, this );
270 			attachments.add( fileAttachment );
271 			notifyPropertyChanged(ATTACHMENTS_PROPERTY, null, fileAttachment );
272 			return fileAttachment;
273 		}
274 		catch (IOException e)
275 		{
276 			UISupport.showErrorMessage( e );
277 			return null;
278 		}
279 	}
280 
281 	public int getAttachmentCount()
282 	{
283 		return attachments.size();
284 	}
285 
286 	public WsdlAttachment getAttachmentAt( int index )
287 	{
288 		return attachments.get( index );
289 	}
290 
291 	public void removeAttachment( Attachment attachment )
292 	{
293 		int ix = attachments.indexOf( attachment );
294 		attachments.remove( ix );
295 		
296 		try
297 		{
298 			notifyPropertyChanged(ATTACHMENTS_PROPERTY, attachment, null );
299 		}
300 		finally
301 		{
302 			getConfig().removeAttachment( ix);
303 		}
304 	}
305 
306 	public WsdlAttachmentPart[] getDefinedAttachmentParts()
307 	{
308 		if( definedAttachmentParts == null )
309 		{
310 			try
311 			{
312 				WsdlOperation operation = getMockOperation().getOperation();
313 				if( operation == null )
314 				{
315 					definedAttachmentParts = new ArrayList<WsdlAttachmentPart>();
316 				}
317 				else
318 				{
319 					UISupport.setHourglassCursor();
320 					definedAttachmentParts = AttachmentUtils.extractAttachmentParts( 
321 								operation, getResponseContent(), true );
322 				}
323 			}
324 			catch (Exception e)
325 			{
326 				log.warn( e.toString() );
327 			}
328 			finally 
329 			{
330 				UISupport.resetCursor();
331 			}
332 		}
333 		
334 		return definedAttachmentParts.toArray( new WsdlAttachmentPart[definedAttachmentParts.size()] );
335 	}
336 
337 	public WsdlAttachmentPart getAttachmentPart( String partName )
338 	{
339 		WsdlAttachmentPart[] parts = getDefinedAttachmentParts();
340 		for( WsdlAttachmentPart part : parts )
341 		{
342 			if( part.getName().equals( partName ))
343 				return part;
344 		}
345 		
346 		return null;
347 	}
348 
349 	public Attachment[] getAttachmentsForPart( String partName )
350 	{
351 		List<Attachment> result = new ArrayList<Attachment>();
352 		
353 		for( Attachment attachment : attachments )
354 		{
355 			if( attachment.getPart().equals( partName ))
356 				result.add( attachment );
357 		}
358 		
359 		return result.toArray( new Attachment[result.size()]);
360 	}
361 
362 	public boolean isMtomEnabled()
363 	{
364 		return getSettings().getBoolean( WsdlSettings.ENABLE_MTOM );
365 	}
366 	
367 	public void setMtomEnabled( boolean mtomEnabled )
368 	{
369 		boolean old = isMtomEnabled();
370 		getSettings().setBoolean( WsdlSettings.ENABLE_MTOM, mtomEnabled );
371 		definedAttachmentParts = null;
372 		notifyPropertyChanged( MTOM_NABLED_PROPERTY, old, mtomEnabled );
373 	}
374 
375 	private String writeResponse(WsdlMockResult response, String responseContent) throws Exception
376 	{
377 		MimeMultipart mp = null;
378 		WsdlOperation operation = getMockOperation().getOperation();
379 		if( operation == null )
380 			throw new Exception( "Missing WsdlOperation for mock response");
381 		
382 		SoapVersion soapVersion = operation.getInterface().getSoapVersion();
383 		
384 		StringToStringMap contentIds = new StringToStringMap();
385 		boolean isXOP = false;
386 		
387 		// preprocess only if neccessary
388 		if( isMtomEnabled() || getAttachmentCount() > 0 )
389 		{
390 			try
391 			{
392 				mp = new MimeMultipart();
393 				
394 				MessageXmlObject requestXmlObject = new MessageXmlObject(( WsdlOperation ) operation, 
395 							getResponseContent(), true);
396 				MessageXmlPart[] requestParts = requestXmlObject.getMessageParts();
397 				for (MessageXmlPart requestPart : requestParts)
398 				{
399 					if (AttachmentUtils.prepareMessagePart(this, mp, requestPart, contentIds))
400 						isXOP = true;
401 				}
402 				responseContent = requestXmlObject.getMessageContent();
403 			}
404 			catch (Exception e)
405 			{
406 				log.warn( "Failed to process inline/MTOM attachments; " + e );
407 			}			
408 		}
409 		
410 		response.initResponse();
411 		
412 		// non-multipart request?
413 		if( !isXOP && (mp == null || mp.getCount() == 0 ) && getAttachmentCount() == 0 )
414 		{
415 			String encoding = getEncoding();
416 			byte[] content = encoding == null ? responseContent.getBytes() : responseContent.getBytes(encoding);
417 			
418 			response.setContentType( soapVersion.getContentTypeHttpHeader( encoding ));
419 			response.getOutputStream().write( content );
420 		}
421 		else
422 		{
423 			// make sure..
424 			if( mp == null )
425 				mp = new MimeMultipart();
426 			
427 			// init root part
428 			initRootPart(responseContent, mp, isXOP);
429 			
430 			// init mimeparts
431 			AttachmentUtils.addMimeParts(this, mp, contentIds);
432 			
433 			// create request message
434 			MimeMessage message = new MimeMessage( AttachmentUtils.JAVAMAIL_SESSION );
435 			message.setContent( mp );
436 			message.saveChanges();
437 			MimeMessageMockResponseEntity mimeMessageRequestEntity = new MimeMessageMockResponseEntity( message, isXOP, this );
438 			
439 			response.addHeader( "Content-Type", mimeMessageRequestEntity.getContentType() );
440 			response.addHeader( "MIME-Version", "1.0" );
441 			mimeMessageRequestEntity.writeRequest( response.getOutputStream() );
442 		}
443 		
444 		return responseContent;
445 	}
446 	
447 	private void initRootPart(String requestContent, MimeMultipart mp, boolean isXOP) throws MessagingException
448 	{
449 		MimeBodyPart rootPart = new PreencodedMimeBodyPart( "8bit" );
450 		rootPart.setContentID( AttachmentUtils.ROOTPART_SOAPUI_ORG  );
451 		mp.addBodyPart( rootPart, 0 );
452 		
453 		DataHandler dataHandler = new DataHandler( new MockResponseDataSource( this, requestContent, isXOP ) );
454 		rootPart.setDataHandler( dataHandler);
455 	}
456 
457 	public Attachment addAttachment( Attachment attachment )
458 	{
459 		if( attachment instanceof BodyPartAttachment )
460 		{
461 			try
462 			{
463 				BodyPartAttachment att = ( BodyPartAttachment ) attachment;
464 				
465 				AttachmentConfig newConfig = (AttachmentConfig) getConfig().addNewAttachment();
466 				newConfig.setData( Tools.readAll( att.getInputStream(), 0 ).toByteArray() );
467 				newConfig.setContentId( att.getContentID() );
468 				newConfig.setContentType( att.getContentType() );
469 				newConfig.setName( att.getName() );
470 				
471 				FileAttachment newAttachment = new MockFileAttachment( newConfig, this );
472 				attachments.add( newAttachment);
473 				return newAttachment;
474 			}
475 			catch( IOException e )
476 			{
477 				e.printStackTrace();
478 			}
479 		}
480 		else if( attachment instanceof FileAttachment )
481 		{
482 			AttachmentConfig oldConfig = ((FileAttachment)attachment).getConfig();
483 			AttachmentConfig newConfig = (AttachmentConfig) getConfig().addNewAttachment().set( oldConfig );
484 			FileAttachment newAttachment = new MockFileAttachment( newConfig, this );
485 			attachments.add( newAttachment);
486 			return newAttachment;
487 		}
488 
489 		return null;
490 	}
491 	
492 	public void setMockResult( WsdlMockResult mockResult )
493 	{
494 		WsdlMockResult oldResult = this.mockResult;
495 		this.mockResult = mockResult;
496 		notifyPropertyChanged( MOCKRESULT_PROPERTY, oldResult, mockResult );
497 	}
498 
499 	public WsdlMockResult getMockResult()
500 	{
501 		return mockResult;
502 	}
503 	
504 	public boolean isMultipartEnabled()
505 	{
506 		return !getSettings().getBoolean( DISABLE_MULTIPART_ATTACHMENTS );
507 	}
508 	
509 	public void setMultipartEnabled( boolean multipartEnabled )
510 	{
511 		getSettings().setBoolean( DISABLE_MULTIPART_ATTACHMENTS, multipartEnabled );
512 	}
513 }