View Javadoc

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