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.panels.mockoperation;
14  
15  import java.awt.BorderLayout;
16  import java.awt.Component;
17  import java.awt.Dimension;
18  import java.awt.event.ActionEvent;
19  import java.awt.event.ItemEvent;
20  import java.awt.event.ItemListener;
21  import java.beans.PropertyChangeEvent;
22  import java.beans.PropertyChangeListener;
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  import javax.swing.AbstractAction;
27  import javax.swing.AbstractListModel;
28  import javax.swing.Action;
29  import javax.swing.BorderFactory;
30  import javax.swing.DefaultComboBoxModel;
31  import javax.swing.JComboBox;
32  import javax.swing.JLabel;
33  import javax.swing.JList;
34  import javax.swing.JPanel;
35  import javax.swing.JScrollPane;
36  import javax.swing.JSplitPane;
37  import javax.swing.ListCellRenderer;
38  import javax.swing.ListModel;
39  
40  import org.apache.xmlbeans.XmlObject;
41  
42  import com.eviware.soapui.SoapUI;
43  import com.eviware.soapui.config.DispatchStyleConfig;
44  import com.eviware.soapui.impl.wsdl.WsdlInterface;
45  import com.eviware.soapui.impl.wsdl.WsdlOperation;
46  import com.eviware.soapui.impl.wsdl.actions.mockoperation.NewMockResponseAction;
47  import com.eviware.soapui.impl.wsdl.actions.mockoperation.OpenRequestForMockOperationAction;
48  import com.eviware.soapui.impl.wsdl.actions.support.ShowOnlineHelpAction;
49  import com.eviware.soapui.impl.wsdl.mock.WsdlMockOperation;
50  import com.eviware.soapui.impl.wsdl.mock.WsdlMockRequest;
51  import com.eviware.soapui.impl.wsdl.mock.WsdlMockResponse;
52  import com.eviware.soapui.impl.wsdl.mock.WsdlMockResult;
53  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.GroovyEditor;
54  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.GroovyEditorModel;
55  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
56  import com.eviware.soapui.model.ModelItem;
57  import com.eviware.soapui.model.iface.Interface;
58  import com.eviware.soapui.model.iface.Operation;
59  import com.eviware.soapui.model.mock.MockOperation;
60  import com.eviware.soapui.model.mock.MockResponse;
61  import com.eviware.soapui.model.mock.MockServiceListener;
62  import com.eviware.soapui.model.settings.Settings;
63  import com.eviware.soapui.model.support.InterfaceListenerAdapter;
64  import com.eviware.soapui.model.support.ProjectListenerAdapter;
65  import com.eviware.soapui.model.util.ModelItemNames;
66  import com.eviware.soapui.support.UISupport;
67  import com.eviware.soapui.support.action.swing.SwingActionDelegate;
68  import com.eviware.soapui.support.components.JXToolBar;
69  import com.eviware.soapui.support.swing.ExtendedComboBoxModel;
70  import com.eviware.soapui.support.swing.ModelItemListMouseListener;
71  import com.eviware.soapui.support.types.StringList;
72  import com.eviware.soapui.support.xml.XmlUtils;
73  import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
74  import com.jgoodies.forms.builder.ButtonBarBuilder;
75  
76  /***
77   * DesktopPanel for WsdlGroovyTestSteps
78   * 
79   * @author Ole.Matzura
80   */
81  
82  public class WsdlMockOperationDesktopPanel extends ModelItemDesktopPanel<WsdlMockOperation>
83  {
84  	private JList responseList;
85  	private JComboBox interfaceCombo;
86  	private JComboBox operationCombo;
87  	private JComboBox dispatchCombo;
88  	private JPanel dispatchPanel;
89  	private InternalInterfaceListener interfaceListener = new InternalInterfaceListener();
90  	private InternalProjectListener projectListener = new InternalProjectListener();
91  	private WsdlInterface currentInterface;
92  	private JPanel groovyEditorPanel;
93  	private JPanel xpathEditorPanel;
94  	private JComboBox defaultResponseCombo;
95  	private JSplitPane splitPane;
96  	private ResponseListModel responseListModel;
97  	private GroovyEditor xpathEditor;
98  	private GroovyEditor groovyEditor;
99  
100 	public WsdlMockOperationDesktopPanel(WsdlMockOperation mockOperation)
101 	{
102 		super( mockOperation );
103 		
104 		buildUI();
105 		setPreferredSize( new Dimension( 600, 440 ));
106 		
107 		mockOperation.getMockService().getProject().addProjectListener( projectListener );
108 		
109 		WsdlOperation operation = getModelItem().getOperation();
110 		if( operation != null )
111 		{
112 			currentInterface = operation.getInterface();
113 			currentInterface.addInterfaceListener( interfaceListener );
114 		}
115 	}
116 
117 	private void buildUI()
118 	{
119 		add( buildToolbar(), BorderLayout.NORTH );
120 		
121 		splitPane = UISupport.createVerticalSplit();
122 		splitPane.setTopComponent( buildResponseList() );
123       splitPane.setBottomComponent( buildDispatchEditor() );
124       splitPane.setDividerLocation( 0.5 );
125       splitPane.setDividerLocation( 150 );
126 		
127 		add( splitPane, BorderLayout.CENTER );
128 	}
129 
130 	private Component buildResponseList()
131 	{
132 		responseListModel = new ResponseListModel();
133 		responseList = new JList( responseListModel );
134 		responseList.addMouseListener( new ModelItemListMouseListener() );
135 		responseList.setCellRenderer( new ResponseListCellRenderer() );
136 		
137 		JScrollPane scrollPane = new JScrollPane( responseList );
138 		UISupport.addTitledBorder( scrollPane, "Reponses" );
139 		return scrollPane;
140 	}
141 
142 	private Component buildDispatchEditor()
143 	{
144 		buildGroovyEditor();
145 		buildXPathEditor();
146 		
147 		dispatchPanel = new JPanel( new BorderLayout() );
148 		dispatchPanel.setOpaque( true );
149 		ButtonBarBuilder builder = new ButtonBarBuilder();
150 		builder.addFixed( new JLabel( "Dispatch: ") );
151 		builder.addRelatedGap();
152 		dispatchCombo = new JComboBox( new Object[] { "Sequence", "Random", "XPath", "Script"} );
153 		
154 		dispatchCombo.addItemListener( new ItemListener() {
155 
156 			public void itemStateChanged( ItemEvent e )
157 			{
158 				if( dispatchPanel.getComponentCount() > 1 )
159 					dispatchPanel.remove( 1 );
160 				
161 				String item = ( String ) dispatchCombo.getSelectedItem();
162 				if( item.equalsIgnoreCase( "Script" ))
163 				{
164 					getModelItem().setDispatchStyle( DispatchStyleConfig.SCRIPT );
165 					dispatchPanel.add( groovyEditorPanel );
166 					groovyEditor.getEditArea().setText( getModelItem().getDispatchPath() );
167 					defaultResponseCombo.setEnabled( true );
168 				}
169 				else if( item.equalsIgnoreCase( "XPath" ))
170 				{
171 					getModelItem().setDispatchStyle( DispatchStyleConfig.XPATH );
172 					dispatchPanel.add( xpathEditorPanel );
173 					xpathEditor.getEditArea().setText( getModelItem().getDispatchPath() );
174 					defaultResponseCombo.setEnabled( true );
175 				}
176 				else if( item.equalsIgnoreCase( "Sequence" ))
177 				{
178 					getModelItem().setDispatchStyle( DispatchStyleConfig.SEQUENCE );
179 					defaultResponseCombo.setEnabled( false );
180 				}
181 				else if( item.equalsIgnoreCase( "Random" ))
182 				{
183 					getModelItem().setDispatchStyle( DispatchStyleConfig.RANDOM );
184 					defaultResponseCombo.setEnabled( false );
185 				}
186 				
187 				dispatchPanel.revalidate();
188 				dispatchPanel.repaint();
189 				
190 			}} );
191 		
192 		builder.addFixed( dispatchCombo );
193 		
194 		builder.addUnrelatedGap();
195 		builder.addFixed( new JLabel( "Default Response: ") );
196 		builder.addRelatedGap();
197 		
198 		ModelItemNames<MockResponse> names = new ModelItemNames<MockResponse>(getModelItem().getMockResponses());
199 		defaultResponseCombo = new JComboBox( new ExtendedComboBoxModel( names.getNames() ) );
200 		defaultResponseCombo.setPreferredSize( new Dimension( 150, 20 ) );
201 		defaultResponseCombo.addItemListener( new ItemListener() {
202 
203 			public void itemStateChanged( ItemEvent e )
204 			{
205 				Object selectedItem = defaultResponseCombo.getSelectedItem();
206 				getModelItem().setDefaultResponse( ( String ) selectedItem );
207 			}} );
208 		
209 		builder.addFixed( defaultResponseCombo );
210 		builder.setBorder( BorderFactory.createEmptyBorder( 2, 3, 3, 3 ) );
211 		
212 		dispatchPanel.add( builder.getPanel(), BorderLayout.NORTH );
213 		
214 		// init data
215 		defaultResponseCombo.setSelectedItem( getModelItem().getDefaultResponse() );
216 		DispatchStyleConfig.Enum dispatchStyle = getModelItem().getDispatchStyle();
217 		if( dispatchStyle.equals( DispatchStyleConfig.SEQUENCE ))
218 		{
219 			dispatchCombo.setSelectedItem( "Sequence" );
220 			defaultResponseCombo.setEnabled( false );
221 		}
222 		else if( dispatchStyle.equals( DispatchStyleConfig.RANDOM ))
223 		{
224 			dispatchCombo.setSelectedItem( "Random" );
225 			defaultResponseCombo.setEnabled( false );
226 		}
227 		else if( dispatchStyle.equals( DispatchStyleConfig.SCRIPT ))
228 		{
229 			dispatchCombo.setSelectedItem( "Script" );
230 		}
231 		else if( dispatchStyle.equals( DispatchStyleConfig.XPATH ))
232 		{
233 			dispatchCombo.setSelectedItem( "XPath" );
234 		}
235 		
236 		return dispatchPanel;
237 	}
238 
239 	private void buildXPathEditor()
240 	{
241 		xpathEditorPanel = new JPanel( new BorderLayout() );
242 		DispatchXPathGroovyEditorModel editorModel = new DispatchXPathGroovyEditorModel();
243 		xpathEditor = new GroovyEditor( editorModel );
244 		xpathEditorPanel.add( new JScrollPane( xpathEditor), BorderLayout.CENTER );
245 		xpathEditorPanel.add( buildXPathEditorToolbar( editorModel ), BorderLayout.PAGE_START );
246 	}
247 	
248 	public GroovyEditor getXPathEditor()
249 	{
250 		return xpathEditor;
251 	}
252 
253 	protected JXToolBar buildXPathEditorToolbar( DispatchXPathGroovyEditorModel editorModel )
254 	{
255 		JXToolBar toolbar = UISupport.createToolbar();
256 		toolbar.addSpace( 3 );
257 		toolbar.addFixed( UISupport.createToolbarButton( editorModel.getRunAction() ));
258 		toolbar.addGlue();
259 		toolbar.addFixed( createActionButton( new ShowOnlineHelpAction(HelpUrls.MOCKOPERATION_XPATHDISPATCH_HELP_URL), true ) );
260 		return toolbar;
261 	}
262 
263 	private void buildGroovyEditor()
264 	{
265 		groovyEditorPanel = new JPanel( new BorderLayout() );
266 		DispatchScriptGroovyEditorModel editorModel = new DispatchScriptGroovyEditorModel();
267 		groovyEditor = new GroovyEditor( editorModel );
268 		groovyEditorPanel.add( new JScrollPane( groovyEditor ), BorderLayout.CENTER );
269 		groovyEditorPanel.add( buildGroovyEditorToolbar( editorModel ), BorderLayout.PAGE_START );
270 	}
271 
272 	protected JXToolBar buildGroovyEditorToolbar( DispatchScriptGroovyEditorModel editorModel )
273 	{
274 		JXToolBar toolbar = UISupport.createToolbar();
275 		toolbar.addSpace( 3 );
276 		toolbar.addFixed( UISupport.createToolbarButton( editorModel.getRunAction() ));
277 		toolbar.addGlue();
278 		
279 		JLabel label = new JLabel("<html>Script is invoked with <code>log</code>, <code>context</code>, " +
280 				"<code>requestContext</code>, <code>mockRequest</code> and <code>mockOperation</code> variables</html>");
281 		label.setToolTipText( label.getText() );
282 		label.setMaximumSize( label.getPreferredSize() );
283 		
284 		toolbar.add( label);
285 		toolbar.addFixed( createActionButton( new ShowOnlineHelpAction(HelpUrls.MOCKOPERATION_SCRIPTDISPATCH_HELP_URL), true ) );
286 		return toolbar;
287 	}
288 
289 	private Component buildToolbar()
290 	{
291 		JXToolBar toolbar = UISupport.createToolbar();
292 		toolbar.addSpace( 3 );
293 		
294 		toolbar.addFixed( UISupport.createToolbarButton( 
295 					SwingActionDelegate.createDelegate( NewMockResponseAction.SOAPUI_ACTION_ID, getModelItem(), null, 
296 							"/addToMockService.gif"	)));
297 		toolbar.addFixed( UISupport.createToolbarButton(
298 					SwingActionDelegate.createDelegate( OpenRequestForMockOperationAction.SOAPUI_ACTION_ID, getModelItem(), null, 
299 								"/open_request.gif") ));
300 		toolbar.addUnrelatedGap();
301 		
302 		ModelItemNames<Interface> names = new ModelItemNames<Interface>(getModelItem().getMockService().getProject().getInterfaces());
303 		interfaceCombo = new JComboBox( names.getNames() );
304 		interfaceCombo.setSelectedIndex( -1 );
305 		interfaceCombo.addItemListener( new InterfaceComboListener() );
306 		
307 		toolbar.addLabeledFixed( "Interface", interfaceCombo );
308 		toolbar.addUnrelatedGap();
309 		operationCombo = new JComboBox( new ExtendedComboBoxModel() );
310 		operationCombo.setPreferredSize( new Dimension( 150, 20 ) );
311 		operationCombo.addItemListener( new OperationComboListener() );
312 		
313 		toolbar.addLabeledFixed( "Operation", operationCombo );
314 		
315 		WsdlOperation operation = getModelItem().getOperation();
316 		interfaceCombo.setSelectedItem( operation == null ? null : operation.getInterface().getName() );
317 		operationCombo.setSelectedItem( operation == null ? null : operation.getName() );
318 		
319 		toolbar.addGlue();
320 		toolbar.addFixed( createActionButton( new ShowOnlineHelpAction(HelpUrls.MOCKOPERATION_HELP_URL), true ) );
321 			
322 		return toolbar;
323 	}
324 	
325 	public boolean onClose( boolean canCancel )
326 	{
327 		if( currentInterface != null )
328 			currentInterface.removeInterfaceListener( interfaceListener );
329 		
330 		getModelItem().getMockService().getProject().removeProjectListener( projectListener );
331 		responseListModel.release();
332 		
333 		groovyEditor.release();
334 		xpathEditor.release();
335 		
336 		return release();
337 	}
338 	
339 	public boolean dependsOn(ModelItem modelItem)
340 	{
341 		return modelItem == getModelItem() || modelItem == getModelItem().getMockService()
342 				|| modelItem == getModelItem().getMockService().getProject();
343 	}
344 	
345 	private final class OperationComboListener implements ItemListener
346 	{
347 		public void itemStateChanged( ItemEvent e )
348 		{
349 			WsdlInterface iface = getModelItem().getMockService().getProject().getInterfaceByName( interfaceCombo.getSelectedItem().toString() );
350 			WsdlOperation operation = iface.getOperationByName( operationCombo.getSelectedItem().toString() );
351 			getModelItem().setOperation( operation );
352 		}
353 	}
354 
355 	private final class InterfaceComboListener implements ItemListener
356 	{
357 		public void itemStateChanged( ItemEvent e )
358 		{
359 			if( currentInterface != null )
360 			{
361 				currentInterface.removeInterfaceListener( interfaceListener );
362 			}
363 			
364 			Object selectedItem = interfaceCombo.getSelectedItem();
365 			if( selectedItem == null )
366 			{
367 				operationCombo.setModel( new DefaultComboBoxModel() );
368 				currentInterface = null;
369 			}
370 			else
371 			{
372 				currentInterface = getModelItem().getMockService().getProject().getInterfaceByName( selectedItem.toString() );
373 				ModelItemNames<Operation> names = new ModelItemNames<Operation>( currentInterface.getOperations() );
374 				operationCombo.setModel( new DefaultComboBoxModel( names.getNames()) );
375 				
376 				currentInterface.addInterfaceListener( interfaceListener );
377 			}
378 		}
379 	}
380 
381 	private final class InternalProjectListener extends ProjectListenerAdapter
382 	{
383 		@Override
384 		public void interfaceAdded( Interface iface )
385 		{
386 			interfaceCombo.addItem( iface.getName() );
387 		}
388 
389 		@Override
390 		public void interfaceRemoved( Interface iface )
391 		{
392 			if( interfaceCombo.getSelectedItem().equals( iface.getName() ))
393 			{
394 				getModelItem().setOperation( null );
395 			}
396 		}
397 	}
398 
399 	private final class InternalInterfaceListener extends InterfaceListenerAdapter
400 	{
401 		@Override
402 		public void operationAdded( Operation operation )
403 		{
404 			operationCombo.addItem( operation.getName() );
405 		}
406 
407 		@Override
408 		public void operationRemoved( Operation operation )
409 		{
410 			Object selectedItem = operationCombo.getSelectedItem();
411 			operationCombo.removeItem( operation.getName() );
412 			
413 			if( selectedItem.equals( operation.getName() ))
414 			{
415 				getModelItem().setOperation( null );
416 				interfaceCombo.setSelectedIndex( -1 );
417 			}
418 		}
419 
420 		@Override
421 		public void operationUpdated( Operation operation )
422 		{
423 			ExtendedComboBoxModel model = ((ExtendedComboBoxModel)operationCombo.getModel());
424 			int ix = model.getIndexOf( operation.getName() );
425 			if( ix != -1 )
426 			{
427 				model.setElementAt( operation.getName(), ix );
428 			}
429 		}
430 	}
431 
432 	public class DispatchScriptGroovyEditorModel implements GroovyEditorModel
433 	{
434 		private RunScriptAction runScriptAction = new RunScriptAction();
435 		
436 		public String[] getKeywords()
437 		{
438 			return new String[] { "mockRequest", "context", "requestContext", "log", "mockOperation" };
439 		}
440 
441 		public Action getRunAction()
442 		{
443 			return runScriptAction;
444 		}
445 
446 		public String getScript()
447 		{
448 			return getModelItem().getDispatchPath();
449 		}
450 
451 		public Settings getSettings()
452 		{
453 			return getModelItem().getSettings();
454 		}
455 
456 		public void setScript( String text )
457 		{
458 			getModelItem().setDispatchPath( text );
459 		}
460 	}
461 	
462 	public class DispatchXPathGroovyEditorModel implements GroovyEditorModel
463 	{
464 		private RunXPathAction runXPathAction = new RunXPathAction();
465 
466 		public String[] getKeywords()
467 		{
468 			return new String[] { "define", "namespace"};
469 		}
470 
471 		public Action getRunAction()
472 		{
473 			return runXPathAction;
474 		}
475 
476 		public String getScript()
477 		{
478 			return getModelItem().getDispatchPath();
479 		}
480 
481 		public Settings getSettings()
482 		{
483 			return getModelItem().getSettings();
484 		}
485 
486 		public void setScript( String text )
487 		{
488 			getModelItem().setDispatchPath( text );
489 		}
490 	}
491 	
492 
493 	public class ResponseListModel extends AbstractListModel implements ListModel, MockServiceListener, PropertyChangeListener
494 	{
495 		private List<WsdlMockResponse> responses = new ArrayList<WsdlMockResponse>();
496 		
497 		public ResponseListModel()
498 		{
499 			for( int c = 0; c < getModelItem().getMockResponseCount(); c++ )
500 			{
501 				WsdlMockResponse mockResponse = ( WsdlMockResponse ) getModelItem().getMockResponseAt( c );
502 				mockResponse.addPropertyChangeListener( this );
503 				
504 				responses.add( mockResponse);
505 			}
506 			
507 			getModelItem().getMockService().addMockServiceListener( this );
508 		}
509 		
510 		public Object getElementAt( int arg0 )
511 		{
512 			return responses.get( arg0 );
513 		}
514 
515 		public int getSize()
516 		{
517 			return responses.size();
518 		}
519 
520 		public void mockOperationAdded( MockOperation operation )
521 		{
522 			
523 		}
524 
525 		public void mockOperationRemoved( MockOperation operation )
526 		{
527 			
528 		}
529 
530 		public void mockResponseAdded( MockResponse response )
531 		{
532 			if( response.getMockOperation() != getModelItem() )
533 				return;
534 			
535 			responses.add( ( WsdlMockResponse ) response );
536 			response.addPropertyChangeListener( this );
537 			fireIntervalAdded( this, responses.size()-1, responses.size()-1 );
538 			
539 			defaultResponseCombo.addItem( response.getName() );
540 		}
541 
542 		public void mockResponseRemoved( MockResponse response )
543 		{
544 			if( response.getMockOperation() != getModelItem() )
545 				return;
546 			
547 			int ix = responses.indexOf( response );
548 			responses.remove( ix );
549 			response.removePropertyChangeListener( this );
550 			fireIntervalRemoved( this, ix, ix );
551 			
552 			defaultResponseCombo.removeItem( response.getName() );
553 		}
554 
555 		public void propertyChange( PropertyChangeEvent arg0 )
556 		{
557 			if( arg0.getPropertyName().equals( WsdlMockOperation.NAME_PROPERTY ))
558 			{
559 				int ix = responses.indexOf( arg0.getSource() );
560 				fireContentsChanged( this, ix, ix );
561 				
562 				ExtendedComboBoxModel model = ( ExtendedComboBoxModel ) defaultResponseCombo.getModel();
563 				model.setElementAt( arg0.getNewValue(), ix );
564 				
565 				if( model.getSelectedItem().equals( arg0.getOldValue()  ))
566 						model.setSelectedItem( arg0.getNewValue() );
567 			}
568 		}
569 		
570 		public void release()
571 		{
572 			for( WsdlMockResponse operation : responses )
573 			{
574 				operation.removePropertyChangeListener( this );
575 			}
576 			
577 			getModelItem().getMockService().removeMockServiceListener( this );
578 		}
579 	}
580 	
581 	private final static class ResponseListCellRenderer extends JLabel implements ListCellRenderer
582 	{
583 		public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
584 				boolean cellHasFocus)
585 		{
586 			MockResponse testStep = (MockResponse) value;
587 			setText(testStep.getName());
588 			setIcon(testStep.getIcon());
589 
590 			if (isSelected)
591 			{
592 				setBackground(list.getSelectionBackground());
593 				setForeground(list.getSelectionForeground());
594 			}
595 			else
596 			{
597 				setBackground(list.getBackground());
598 				setForeground(list.getForeground());
599 			}
600 
601 			setEnabled(list.isEnabled());
602 			setFont(list.getFont());
603 			setOpaque(true);
604 			setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
605 
606 			return this;
607 		}
608 	}
609 	
610 	private class RunScriptAction extends AbstractAction
611 	{
612 		public RunScriptAction()
613 		{
614 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/run_groovy_script.gif" ));
615 			putValue( Action.SHORT_DESCRIPTION, "Runs this script using a mockRequest and context" );
616 		}
617 		
618 		public void actionPerformed( ActionEvent e )
619 		{
620 			WsdlMockResult lastMockResult = getModelItem().getLastMockResult();
621 			WsdlMockRequest mockRequest = lastMockResult == null ? null : lastMockResult.getMockRequest();
622 
623 			try
624 			{
625 				Object retVal = getModelItem().evaluateDispatchScript( mockRequest );
626 				UISupport.showInfoMessage( "Script returned [" + retVal + "]" );
627 			}
628 			catch( Exception e1 )
629 			{
630 				UISupport.showErrorMessage( e1 );
631 			}
632 		}}
633 	
634 	private class RunXPathAction extends AbstractAction
635 	{
636 		public RunXPathAction()
637 		{
638 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/run_groovy_script.gif" ));
639 			putValue( Action.SHORT_DESCRIPTION, "Evaluates this xpath expression against the latest request" );
640 		}
641 		
642 		public void actionPerformed( ActionEvent e )
643 		{
644 			WsdlMockResult lastMockResult = getModelItem().getLastMockResult();
645 			if( lastMockResult == null )
646 			{
647 				UISupport.showErrorMessage( "Missing last request to select from" );
648 				return;
649 			}
650 			
651 			try
652 			{
653 				XmlObject[] retVal = getModelItem().evaluateDispatchXPath( lastMockResult.getMockRequest() );
654 				StringList list = new StringList();
655 				for( XmlObject xmlObject : retVal )
656 				{
657 					list.add( XmlUtils.getNodeValue( xmlObject.getDomNode() ) );
658 				}
659 				
660 				UISupport.showInfoMessage( "XPath returned " + list.toString() );
661 			}
662 			catch( Exception e1 )
663 			{
664 				SoapUI.logError( e1 );
665 			}
666 		}}
667 }