View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2009 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.mock;
14  
15  import java.awt.BorderLayout;
16  import java.awt.Color;
17  import java.awt.Component;
18  import java.awt.Dimension;
19  import java.awt.event.ActionEvent;
20  import java.awt.event.ActionListener;
21  import java.beans.PropertyChangeEvent;
22  import java.beans.PropertyChangeListener;
23  import java.text.SimpleDateFormat;
24  import java.util.ArrayList;
25  import java.util.Collections;
26  import java.util.Date;
27  import java.util.LinkedList;
28  import java.util.List;
29  
30  import javax.swing.AbstractAction;
31  import javax.swing.AbstractListModel;
32  import javax.swing.Action;
33  import javax.swing.BorderFactory;
34  import javax.swing.JButton;
35  import javax.swing.JCheckBox;
36  import javax.swing.JComponent;
37  import javax.swing.JLabel;
38  import javax.swing.JList;
39  import javax.swing.JPanel;
40  import javax.swing.JProgressBar;
41  import javax.swing.JScrollPane;
42  import javax.swing.JTabbedPane;
43  import javax.swing.ListCellRenderer;
44  import javax.swing.ListModel;
45  import javax.swing.SwingConstants;
46  import javax.swing.text.Document;
47  
48  import com.eviware.soapui.SoapUI;
49  import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
50  import com.eviware.soapui.impl.wsdl.actions.mockservice.AddNewMockOperationAction;
51  import com.eviware.soapui.impl.wsdl.actions.mockservice.MockServiceOptionsAction;
52  import com.eviware.soapui.impl.wsdl.mock.WsdlMockOperation;
53  import com.eviware.soapui.impl.wsdl.mock.WsdlMockRunContext;
54  import com.eviware.soapui.impl.wsdl.mock.WsdlMockRunner;
55  import com.eviware.soapui.impl.wsdl.mock.WsdlMockService;
56  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.AbstractGroovyEditorModel;
57  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.PropertyHolderTable;
58  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
59  import com.eviware.soapui.model.ModelItem;
60  import com.eviware.soapui.model.mock.MockOperation;
61  import com.eviware.soapui.model.mock.MockResponse;
62  import com.eviware.soapui.model.mock.MockResult;
63  import com.eviware.soapui.model.mock.MockRunner;
64  import com.eviware.soapui.model.mock.MockServiceListener;
65  import com.eviware.soapui.model.support.MockRunListenerAdapter;
66  import com.eviware.soapui.settings.UISettings;
67  import com.eviware.soapui.support.DocumentListenerAdapter;
68  import com.eviware.soapui.support.StringUtils;
69  import com.eviware.soapui.support.Tools;
70  import com.eviware.soapui.support.UISupport;
71  import com.eviware.soapui.support.action.swing.ActionList;
72  import com.eviware.soapui.support.action.swing.DefaultActionList;
73  import com.eviware.soapui.support.action.swing.SwingActionDelegate;
74  import com.eviware.soapui.support.components.GroovyEditorComponent;
75  import com.eviware.soapui.support.components.GroovyEditorInspector;
76  import com.eviware.soapui.support.components.JComponentInspector;
77  import com.eviware.soapui.support.components.JFocusableComponentInspector;
78  import com.eviware.soapui.support.components.JInspectorPanel;
79  import com.eviware.soapui.support.components.JInspectorPanelFactory;
80  import com.eviware.soapui.support.components.JUndoableTextArea;
81  import com.eviware.soapui.support.components.JXToolBar;
82  import com.eviware.soapui.support.swing.AbstractListMouseListener;
83  import com.eviware.soapui.support.swing.ModelItemListKeyListener;
84  import com.eviware.soapui.support.swing.ModelItemListMouseListener;
85  import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
86  
87  /***
88   * DesktopPanel for WsdlMockServices
89   * 
90   * @author ole.matzura
91   */
92  
93  public class WsdlMockServiceDesktopPanel extends ModelItemDesktopPanel<WsdlMockService>
94  {
95  	private JButton runButton;
96  	private WsdlMockRunner mockRunner;
97  	private JButton stopButton;
98  	private JProgressBar progressBar;
99  	private LogListModel logListModel;
100 	private JList testLogList;
101 	private JCheckBox enableLogCheckBox;
102 	private JScrollPane logScrollPane;
103 	private JList operationList;
104 	private InternalMockRunListener mockRunListener;
105 	private PropertyHolderTable propertiesTable;
106 	private JUndoableTextArea descriptionArea;
107 	private JButton showWsdlButton;
108 	private JButton optionsButton;
109 	private JLabel runInfoLabel;
110 	private GroovyEditorComponent startGroovyEditor;
111 	private GroovyEditorComponent stopGroovyEditor;
112 	private GroovyEditorComponent onRequestGroovyEditor;
113 	private GroovyEditorComponent afterRequestGroovyEditor;
114 	private JInspectorPanel inspectorPanel;
115 	private JInspectorPanel contentInspector;
116 
117 	public WsdlMockServiceDesktopPanel( WsdlMockService mockService )
118 	{
119 		super( mockService );
120 		buildUI();
121 
122 		setPreferredSize( new Dimension( 400, 500 ) );
123 
124 		mockRunListener = new InternalMockRunListener();
125 		mockService.addMockRunListener( mockRunListener );
126 	}
127 
128 	public boolean onClose( boolean canCancel )
129 	{
130 		if( mockRunner != null && mockRunner.isRunning() && canCancel )
131 		{
132 			if( !UISupport.confirm( "Close and stop MockService", "Close MockService" ) )
133 			{
134 				return false;
135 			}
136 		}
137 
138 		if( mockRunner != null )
139 		{
140 			if( mockRunner.isRunning() )
141 				mockRunner.stop();
142 
143 			mockRunner.release();
144 		}
145 
146 		getModelItem().removeMockRunListener( mockRunListener );
147 		( ( OperationListModel )operationList.getModel() ).release();
148 
149 		logListModel.clear();
150 		propertiesTable.release();
151 
152 		startGroovyEditor.getEditor().release();
153 		stopGroovyEditor.getEditor().release();
154 
155 		inspectorPanel.release();
156 		contentInspector.release();
157 		return release();
158 	}
159 
160 	public boolean dependsOn( ModelItem modelItem )
161 	{
162 		return modelItem == getModelItem() || modelItem == getModelItem().getProject();
163 	}
164 
165 	private void buildUI()
166 	{
167 		add( buildToolbar(), BorderLayout.NORTH );
168 
169 		contentInspector = JInspectorPanelFactory.build( buildContent() );
170 		contentInspector.setDefaultDividerLocation( 0.5F );
171 		contentInspector.addInspector( new JComponentInspector<JComponent>( buildLog(), "Message Log",
172 				"A log of processed requests and their responses", true ) );
173 
174 		contentInspector.setCurrentInspector( "Message Log" );
175 
176 		add( contentInspector.getComponent(), BorderLayout.CENTER );
177 		add( new JLabel( "--" ), BorderLayout.PAGE_END );
178 	}
179 
180 	public boolean logIsEnabled()
181 	{
182 		return enableLogCheckBox.isSelected();
183 	}
184 
185 	private JComponent buildContent()
186 	{
187 		JTabbedPane tabs = new JTabbedPane();
188 		inspectorPanel = JInspectorPanelFactory.build( buildOperationList() );
189 
190 		tabs.addTab( "Operations", inspectorPanel.getComponent() );
191 		addTabs( tabs, inspectorPanel );
192 
193 		if( StringUtils.hasContent( getModelItem().getDescription() )
194 				&& getModelItem().getSettings().getBoolean( UISettings.SHOW_DESCRIPTIONS ) )
195 		{
196 			inspectorPanel.setCurrentInspector( "Description" );
197 		}
198 
199 		return UISupport.createTabPanel( tabs, true );
200 	}
201 
202 	protected void addTabs( JTabbedPane tabs, JInspectorPanel inspectorPanel )
203 	{
204 		inspectorPanel.addInspector( new JFocusableComponentInspector<JPanel>( buildDescriptionPanel(), descriptionArea,
205 				"Description", "A description for this MockService", true ) );
206 		inspectorPanel.addInspector( new JComponentInspector<JComponent>( buildPropertiesPanel(), "Properties",
207 				"Properties for this MockService", true ) );
208 		inspectorPanel.addInspector( new GroovyEditorInspector( buildStartScriptPanel(), "Start Script",
209 				"A Groovy script to run when starting the MockService" ) );
210 		inspectorPanel.addInspector( new GroovyEditorInspector( buildStopScriptPanel(), "Stop Script",
211 				"A Groovy script to run when stopping the MockService" ) );
212 		inspectorPanel.addInspector( new GroovyEditorInspector( buildOnRequestScriptPanel(), "OnRequest Script",
213 				"A Groovy script to run when receiving a request before it is dispatched" ) );
214 		inspectorPanel.addInspector( new GroovyEditorInspector( buildAfterRequestScriptPanel(), "AfterRequest Script",
215 				"A Groovy script to run after a request has been dispatched" ) );
216 	}
217 
218 	protected JComponent buildOperationList()
219 	{
220 		operationList = new JList( new OperationListModel() );
221 		operationList.addMouseListener( new ModelItemListMouseListener()
222 		{
223 			private ActionList defaultActions;
224 
225 			protected ActionList getDefaultActions()
226 			{
227 				if( defaultActions == null )
228 				{
229 					defaultActions = new DefaultActionList();
230 					defaultActions.addAction( SwingActionDelegate.createDelegate(
231 							AddNewMockOperationAction.SOAPUI_ACTION_ID, getModelItem(), null, null ) );
232 				}
233 
234 				return defaultActions;
235 			}
236 		} );
237 		operationList.setCellRenderer( new OperationListCellRenderer() );
238 		operationList.addKeyListener( new ModelItemListKeyListener()
239 		{
240 
241 			@Override
242 			public ModelItem getModelItemAt( int ix )
243 			{
244 				return getModelItem().getMockOperationAt( ix );
245 			}
246 		} );
247 
248 		JScrollPane scrollPane = new JScrollPane( operationList );
249 		return UISupport.buildPanelWithToolbar( buildMockOperationListToolbar(), scrollPane );
250 	}
251 
252 	private JComponent buildMockOperationListToolbar()
253 	{
254 		JXToolBar toolbar = UISupport.createToolbar();
255 		toolbar.add( UISupport.createToolbarButton( SwingActionDelegate.createDelegate(
256 				AddNewMockOperationAction.SOAPUI_ACTION_ID, getModelItem(), null, "/mockOperation.gif" ) ) );
257 
258 		return toolbar;
259 	}
260 
261 	protected JComponent buildPropertiesPanel()
262 	{
263 		JPanel panel = new JPanel( new BorderLayout() );
264 		propertiesTable = new PropertyHolderTable( getModelItem() );
265 		panel.add( new JScrollPane( propertiesTable ), BorderLayout.CENTER );
266 		return panel;
267 	}
268 
269 	protected GroovyEditorComponent buildStartScriptPanel()
270 	{
271 		startGroovyEditor = new GroovyEditorComponent( new StartScriptGroovyEditorModel(), null );
272 		return startGroovyEditor;
273 	}
274 
275 	protected GroovyEditorComponent buildStopScriptPanel()
276 	{
277 		stopGroovyEditor = new GroovyEditorComponent( new StopScriptGroovyEditorModel(), null );
278 		return stopGroovyEditor;
279 	}
280 
281 	protected GroovyEditorComponent buildOnRequestScriptPanel()
282 	{
283 		onRequestGroovyEditor = new GroovyEditorComponent( new OnRequestScriptGroovyEditorModel(), null );
284 		return onRequestGroovyEditor;
285 	}
286 
287 	protected GroovyEditorComponent buildAfterRequestScriptPanel()
288 	{
289 		afterRequestGroovyEditor = new GroovyEditorComponent( new AfterRequestScriptGroovyEditorModel(), null );
290 		return afterRequestGroovyEditor;
291 	}
292 
293 	protected JPanel buildDescriptionPanel()
294 	{
295 		JPanel panel = new JPanel( new BorderLayout() );
296 		descriptionArea = new JUndoableTextArea( getModelItem().getDescription() );
297 		descriptionArea.getDocument().addDocumentListener( new DocumentListenerAdapter()
298 		{
299 			public void update( Document document )
300 			{
301 				getModelItem().setDescription( descriptionArea.getText() );
302 			}
303 		} );
304 
305 		panel.setBorder( BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) );
306 		UISupport.addTitledBorder( panel, "MockService Description" );
307 		panel.add( new JScrollPane( descriptionArea ), BorderLayout.CENTER );
308 
309 		return panel;
310 	}
311 
312 	protected JComponent buildLog()
313 	{
314 		JPanel panel = new JPanel( new BorderLayout() );
315 		JXToolBar builder = UISupport.createToolbar();
316 
317 		enableLogCheckBox = new JCheckBox( " ", true );
318 		enableLogCheckBox.addActionListener( new ActionListener()
319 		{
320 
321 			public void actionPerformed( ActionEvent arg0 )
322 			{
323 				testLogList.setEnabled( enableLogCheckBox.isSelected() );
324 				if( mockRunner != null )
325 					mockRunner.setLogEnabled( enableLogCheckBox.isSelected() );
326 
327 				// border needs to be repainted..
328 				logScrollPane.repaint();
329 			}
330 		} );
331 		enableLogCheckBox.setOpaque( false );
332 
333 		builder.addFixed( enableLogCheckBox );
334 		builder.addRelatedGap();
335 		builder.addFixed( new JLabel( "Enable" ) );
336 		builder.addRelatedGap();
337 		addLogActions( builder );
338 
339 		builder.addGlue();
340 		builder.setBorder( BorderFactory.createEmptyBorder( 2, 3, 3, 3 ) );
341 
342 		panel.add( builder, BorderLayout.NORTH );
343 
344 		logListModel = new LogListModel();
345 		testLogList = new JList( logListModel );
346 		testLogList.setCellRenderer( new LogCellRenderer() );
347 		testLogList.setPrototypeCellValue( "Testing 123" );
348 		testLogList.setFixedCellWidth( -1 );
349 		testLogList.addMouseListener( new LogListMouseListener() );
350 		testLogList.setBorder( BorderFactory.createLineBorder( Color.GRAY ) );
351 
352 		logScrollPane = new JScrollPane( testLogList );
353 
354 		panel.add( logScrollPane, BorderLayout.CENTER );
355 
356 		return panel;
357 	}
358 
359 	protected void addLogActions( JXToolBar builder )
360 	{
361 		builder.addFixed( UISupport.createToolbarButton( new ClearLogAction() ) );
362 		builder.addRelatedGap();
363 		builder.addFixed( UISupport.createToolbarButton( new SetLogOptionsAction() ) );
364 	}
365 
366 	protected JXToolBar buildToolbar()
367 	{
368 		JXToolBar toolbar = UISupport.createToolbar();
369 
370 		runButton = createActionButton( new RunMockServiceAction(), true );
371 		stopButton = createActionButton( new StopMockServiceAction(), false );
372 		optionsButton = createActionButton( SwingActionDelegate.createDelegate( new MockServiceOptionsAction(),
373 				getModelItem(), null, "/options.gif" ), true );
374 		showWsdlButton = createActionButton( new ShowWsdlAction(), false );
375 
376 		toolbar.addFixed( runButton );
377 		toolbar.addFixed( stopButton );
378 		toolbar.addFixed( showWsdlButton );
379 		toolbar.addFixed( optionsButton );
380 
381 		toolbar.addGlue();
382 
383 		runInfoLabel = new JLabel( "", SwingConstants.RIGHT );
384 		toolbar.addFixed( UISupport.setFixedSize( runInfoLabel, 200, 20 ) );
385 		toolbar.addRelatedGap();
386 
387 		progressBar = new JProgressBar();
388 		JPanel progressBarPanel = UISupport.createProgressBarPanel( progressBar, 2, false );
389 		progressBarPanel.setPreferredSize( new Dimension( 60, 20 ) );
390 
391 		toolbar.addFixed( progressBarPanel );
392 		toolbar.addRelatedGap();
393 
394 		toolbar.addFixed( createActionButton( new ShowOnlineHelpAction( HelpUrls.MOCKSERVICE_HELP_URL ), true ) );
395 
396 		return toolbar;
397 	}
398 
399 	public void startMockService()
400 	{
401 		if( ( mockRunner != null && mockRunner.isRunning() ) || SoapUI.getMockEngine().hasRunningMock( getModelItem() ) )
402 		{
403 			UISupport.showErrorMessage( "MockService is already running" );
404 		}
405 		else
406 		{
407 			if( mockRunner != null )
408 				mockRunner.release();
409 
410 			try
411 			{
412 				getModelItem().start();
413 			}
414 			catch( Exception e )
415 			{
416 				UISupport.showErrorMessage( e );
417 				return;
418 			}
419 		}
420 	}
421 
422 	private final class InternalMockRunListener extends MockRunListenerAdapter
423 	{
424 		@Override
425 		public void onMockRunnerStart( MockRunner runner )
426 		{
427 			mockRunner = ( WsdlMockRunner )runner;
428 			mockRunner.setMaxResults( logListModel.getMaxSize() );
429 			mockRunner.setLogEnabled( enableLogCheckBox.isSelected() );
430 
431 			progressBar.setIndeterminate( true );
432 
433 			runButton.setEnabled( false );
434 			stopButton.setEnabled( true );
435 			optionsButton.setEnabled( false );
436 			showWsdlButton.setEnabled( true );
437 
438 			runInfoLabel.setText( "running on port " + getModelItem().getPort() );
439 		}
440 
441 		@Override
442 		public void onMockRunnerStop( MockRunner mockRunner )
443 		{
444 			progressBar.setIndeterminate( false );
445 
446 			runButton.setEnabled( true );
447 			stopButton.setEnabled( false );
448 			optionsButton.setEnabled( true );
449 			showWsdlButton.setEnabled( false );
450 
451 			runInfoLabel.setText( "" );
452 		}
453 
454 		public void onMockResult( MockResult result )
455 		{
456 			if( logIsEnabled() )
457 			{
458 				logListModel.addElement( result );
459 			}
460 		}
461 	}
462 
463 	public class OperationListModel extends AbstractListModel implements ListModel, MockServiceListener,
464 			PropertyChangeListener
465 	{
466 		private List<WsdlMockOperation> operations = new ArrayList<WsdlMockOperation>();
467 
468 		public OperationListModel()
469 		{
470 			for( int c = 0; c < getModelItem().getMockOperationCount(); c++ )
471 			{
472 				WsdlMockOperation mockOperation = getModelItem().getMockOperationAt( c );
473 				mockOperation.addPropertyChangeListener( this );
474 
475 				operations.add( mockOperation );
476 			}
477 
478 			getModelItem().addMockServiceListener( this );
479 		}
480 
481 		public Object getElementAt( int arg0 )
482 		{
483 			return operations.get( arg0 );
484 		}
485 
486 		public int getSize()
487 		{
488 			return operations.size();
489 		}
490 
491 		public void mockOperationAdded( MockOperation operation )
492 		{
493 			operations.add( ( WsdlMockOperation )operation );
494 			operation.addPropertyChangeListener( this );
495 			fireIntervalAdded( this, operations.size() - 1, operations.size() - 1 );
496 		}
497 
498 		public void mockOperationRemoved( MockOperation operation )
499 		{
500 			int ix = operations.indexOf( operation );
501 			operations.remove( ix );
502 			operation.removePropertyChangeListener( this );
503 			fireIntervalRemoved( this, ix, ix );
504 		}
505 
506 		public void mockResponseAdded( MockResponse request )
507 		{
508 		}
509 
510 		public void mockResponseRemoved( MockResponse request )
511 		{
512 		}
513 
514 		public void propertyChange( PropertyChangeEvent arg0 )
515 		{
516 			if( arg0.getPropertyName().equals( WsdlMockOperation.NAME_PROPERTY ) )
517 			{
518 				int ix = operations.indexOf( arg0.getSource() );
519 				fireContentsChanged( this, ix, ix );
520 			}
521 		}
522 
523 		public void release()
524 		{
525 			for( WsdlMockOperation operation : operations )
526 			{
527 				operation.removePropertyChangeListener( this );
528 			}
529 
530 			getModelItem().removeMockServiceListener( this );
531 		}
532 	}
533 
534 	private final static class OperationListCellRenderer extends JLabel implements ListCellRenderer
535 	{
536 		public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected,
537 				boolean cellHasFocus )
538 		{
539 			MockOperation testStep = ( MockOperation )value;
540 			setText( testStep.getName() );
541 			setIcon( testStep.getIcon() );
542 
543 			if( isSelected )
544 			{
545 				setBackground( list.getSelectionBackground() );
546 				setForeground( list.getSelectionForeground() );
547 			}
548 			else
549 			{
550 				setBackground( list.getBackground() );
551 				setForeground( list.getForeground() );
552 			}
553 
554 			setEnabled( list.isEnabled() );
555 			setFont( list.getFont() );
556 			setOpaque( true );
557 			setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) );
558 
559 			return this;
560 		}
561 	}
562 
563 	public class RunMockServiceAction extends AbstractAction
564 	{
565 		public RunMockServiceAction()
566 		{
567 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/submit_request.gif" ) );
568 			putValue( Action.SHORT_DESCRIPTION, "Starts this MockService on the specified port and endpoint" );
569 			putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "alt ENTER" ) );
570 		}
571 
572 		public void actionPerformed( ActionEvent arg0 )
573 		{
574 			startMockService();
575 		}
576 	}
577 
578 	public class ShowWsdlAction extends AbstractAction
579 	{
580 		public ShowWsdlAction()
581 		{
582 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/interface.gif" ) );
583 			putValue( Action.SHORT_DESCRIPTION, "Opens the root WSDL page in a browser" );
584 		}
585 
586 		public void actionPerformed( ActionEvent arg0 )
587 		{
588 			WsdlMockService mockService = getModelItem();
589 			Tools.openURL( mockService.getLocalEndpoint() + "?WSDL" );
590 		}
591 	}
592 
593 	public class StopMockServiceAction extends AbstractAction
594 	{
595 		public StopMockServiceAction()
596 		{
597 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/cancel_request.gif" ) );
598 			putValue( Action.SHORT_DESCRIPTION, "Stops this MockService on the specified port and endpoint" );
599 		}
600 
601 		public void actionPerformed( ActionEvent arg0 )
602 		{
603 			if( mockRunner == null )
604 			{
605 				UISupport.showErrorMessage( "MockService is not running" );
606 			}
607 			else
608 			{
609 				mockRunner.stop();
610 				mockRunner.release();
611 				mockRunner = null;
612 			}
613 		}
614 	}
615 
616 	private static final class LogCellRenderer extends JLabel implements ListCellRenderer
617 	{
618 		private SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.SSS" );
619 
620 		public LogCellRenderer()
621 		{
622 			setOpaque( true );
623 			setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) );
624 		}
625 
626 		public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected,
627 				boolean cellHasFocus )
628 		{
629 			if( value instanceof String )
630 			{
631 				setText( value.toString() );
632 			}
633 			else if( value instanceof MockResult )
634 			{
635 				MockResult result = ( MockResult )value;
636 				String msg = dateFormat.format( new Date( result.getTimestamp() ) );
637 				MockResponse mockResponse = result.getMockResponse();
638 
639 				if( mockResponse == null )
640 				{
641 					msg += ": [dispatch error; missing response]";
642 				}
643 				else
644 				{
645 					try
646 					{
647 						msg += ": [" + mockResponse.getMockOperation().getName();
648 					}
649 					catch( Throwable e )
650 					{
651 						msg += ": [removed operation?]";
652 					}
653 
654 					msg += "] " + result.getTimeTaken() + "ms";
655 				}
656 
657 				setText( msg );
658 			}
659 
660 			if( isSelected )
661 			{
662 				setBackground( list.getSelectionBackground() );
663 				setForeground( list.getSelectionForeground() );
664 			}
665 			else
666 			{
667 				setBackground( list.getBackground() );
668 				setForeground( list.getForeground() );
669 			}
670 
671 			setEnabled( list.isEnabled() );
672 
673 			return this;
674 		}
675 	}
676 
677 	private long getDefaultMaxSize()
678 	{
679 		return getModelItem().getSettings().getLong( LogListModel.class.getName() + "@maxSize", 100 );
680 	}
681 
682 	protected long getMaxLogSize()
683 	{
684 		if( logListModel != null )
685 			return logListModel.getMaxSize();
686 		else
687 			return getDefaultMaxSize();
688 	}
689 
690 	protected void setMaxLogSize( long size )
691 	{
692 		logListModel.setMaxSize( size );
693 		if( mockRunner != null )
694 			mockRunner.setMaxResults( logListModel.getMaxSize() );
695 	}
696 
697 	private class LogListModel extends AbstractListModel
698 	{
699 		private List<MockResult> elements = Collections.synchronizedList( new LinkedList<MockResult>() );
700 		private long maxSize;
701 
702 		public LogListModel()
703 		{
704 			maxSize = getDefaultMaxSize();
705 		}
706 
707 		public void addElement( MockResult result )
708 		{
709 			elements.add( result );
710 			fireIntervalAdded( this, elements.size() - 1, elements.size() - 1 );
711 
712 			synchronized( this )
713 			{
714 				while( elements.size() > maxSize )
715 				{
716 					removeElementAt( 0 );
717 				}
718 			}
719 		}
720 
721 		public Object getElementAt( int index )
722 		{
723 			synchronized( this )
724 			{
725 				if(elements.size() <= index) return null;
726 				return elements.get( index );
727 			}
728 		}
729 
730 		public void removeElementAt( int index )
731 		{
732 			elements.remove( index );
733 			fireIntervalRemoved( this, index, index );
734 		}
735 
736 		public void clear()
737 		{
738 			synchronized( this )
739 			{
740 				int sz = elements.size();
741 				if( sz > 0 )
742 				{
743 					elements.clear();
744 					fireIntervalRemoved( this, 0, sz - 1 );
745 				}
746 			}
747 		}
748 
749 		public int getSize()
750 		{
751 			return elements.size();
752 		}
753 
754 		public long getMaxSize()
755 		{
756 			return maxSize;
757 		}
758 
759 		public synchronized void setMaxSize( long l )
760 		{
761 			this.maxSize = l;
762 
763 			while( elements.size() > 0 && elements.size() > maxSize )
764 			{
765 				removeElementAt( 0 );
766 			}
767 
768 			getModelItem().getSettings().setLong( LogListModel.class.getName() + "@maxSize", maxSize );
769 		}
770 	}
771 
772 	private class SetLogOptionsAction extends AbstractAction
773 	{
774 		public SetLogOptionsAction()
775 		{
776 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/options.gif" ) );
777 			putValue( Action.SHORT_DESCRIPTION, "Sets MockService Log Options" );
778 		}
779 
780 		public void actionPerformed( ActionEvent e )
781 		{
782 			String s = UISupport.prompt( "Enter maximum number of rows for MockService Log", "Log Options", String
783 					.valueOf( logListModel.getMaxSize() ) );
784 			if( s != null )
785 			{
786 				try
787 				{
788 					long newMaxSize = Long.parseLong( s );
789 					if( newMaxSize > 0 )
790 						setMaxLogSize( newMaxSize );
791 				}
792 				catch( NumberFormatException e1 )
793 				{
794 				}
795 			}
796 		}
797 	}
798 
799 	private class ClearLogAction extends AbstractAction
800 	{
801 		public ClearLogAction()
802 		{
803 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/clear_loadtest.gif" ) );
804 			putValue( Action.SHORT_DESCRIPTION, "Clears the MockService Log" );
805 		}
806 
807 		public void actionPerformed( ActionEvent e )
808 		{
809 			logListModel.clear();
810 			if( mockRunner != null )
811 				mockRunner.clearResults();
812 		}
813 	}
814 
815 	/***
816 	 * Mouse Listener for triggering default action and showing popup for log
817 	 * list items
818 	 * 
819 	 * @author Ole.Matzura
820 	 */
821 
822 	private final class LogListMouseListener extends AbstractListMouseListener
823 	{
824 		@Override
825 		protected ActionList getActionsForRow( JList list, int row )
826 		{
827 			MockResult result = ( MockResult )logListModel.getElementAt( row );
828 			return result == null ? null : result.getActions();
829 		}
830 	}
831 
832 	private class StartScriptGroovyEditorModel extends AbstractGroovyEditorModel
833 	{
834 		public StartScriptGroovyEditorModel()
835 		{
836 			super( new String[] { "log", "context", "mockRunner" }, getModelItem().getSettings(), "Start" );
837 		}
838 
839 		public String getScript()
840 		{
841 			return getModelItem().getStartScript();
842 		}
843 
844 		public void setScript( String text )
845 		{
846 			getModelItem().setStartScript( text );
847 		}
848 
849 		@Override
850 		public Action createRunAction()
851 		{
852 			return new AbstractAction()
853 			{
854 
855 				public void actionPerformed( ActionEvent e )
856 				{
857 					try
858 					{
859 						WsdlMockRunContext context = mockRunner == null ? new WsdlMockRunContext( getModelItem(), null )
860 								: mockRunner.getMockContext();
861 						getModelItem().runStartScript( context, mockRunner );
862 					}
863 					catch( Exception e1 )
864 					{
865 						UISupport.showErrorMessage( e1 );
866 					}
867 				}
868 			};
869 		}
870 	}
871 
872 	private class StopScriptGroovyEditorModel extends AbstractGroovyEditorModel
873 	{
874 		public StopScriptGroovyEditorModel()
875 		{
876 			super( new String[] { "log", "context", "mockRunner" }, getModelItem().getSettings(), "Stop" );
877 		}
878 
879 		public String getScript()
880 		{
881 			return getModelItem().getStopScript();
882 		}
883 
884 		public void setScript( String text )
885 		{
886 			getModelItem().setStopScript( text );
887 		}
888 
889 		@Override
890 		public Action createRunAction()
891 		{
892 			return new AbstractAction()
893 			{
894 
895 				public void actionPerformed( ActionEvent e )
896 				{
897 					try
898 					{
899 						WsdlMockRunContext context = mockRunner == null ? new WsdlMockRunContext( getModelItem(), null )
900 								: mockRunner.getMockContext();
901 						getModelItem().runStopScript( context, mockRunner );
902 					}
903 					catch( Exception e1 )
904 					{
905 						UISupport.showErrorMessage( e1 );
906 					}
907 				}
908 			};
909 		}
910 	}
911 
912 	private class OnRequestScriptGroovyEditorModel extends AbstractGroovyEditorModel
913 	{
914 		public OnRequestScriptGroovyEditorModel()
915 		{
916 			super( new String[] { "log", "context", "mockRequest", "mockRunner" }, getModelItem().getSettings(),
917 					"OnRequest" );
918 		}
919 
920 		public String getScript()
921 		{
922 			return getModelItem().getOnRequestScript();
923 		}
924 
925 		public void setScript( String text )
926 		{
927 			getModelItem().setOnRequestScript( text );
928 		}
929 
930 		@Override
931 		public Action createRunAction()
932 		{
933 			return new AbstractAction()
934 			{
935 
936 				public void actionPerformed( ActionEvent e )
937 				{
938 					try
939 					{
940 						WsdlMockRunContext context = mockRunner == null ? new WsdlMockRunContext( getModelItem(), null )
941 								: mockRunner.getMockContext();
942 						getModelItem().runOnRequestScript( context, mockRunner, null );
943 					}
944 					catch( Exception e1 )
945 					{
946 						UISupport.showErrorMessage( e1 );
947 					}
948 				}
949 			};
950 		}
951 	}
952 
953 	private class AfterRequestScriptGroovyEditorModel extends AbstractGroovyEditorModel
954 	{
955 		public AfterRequestScriptGroovyEditorModel()
956 		{
957 			super( new String[] { "log", "context", "mockResult", "mockRunner" }, getModelItem().getSettings(),
958 					"AfterRequest" );
959 		}
960 
961 		public String getScript()
962 		{
963 			return getModelItem().getAfterRequestScript();
964 		}
965 
966 		public void setScript( String text )
967 		{
968 			getModelItem().setAfterRequestScript( text );
969 		}
970 
971 		@Override
972 		public Action createRunAction()
973 		{
974 			return new AbstractAction()
975 			{
976 
977 				public void actionPerformed( ActionEvent e )
978 				{
979 					try
980 					{
981 						WsdlMockRunContext context = mockRunner == null ? new WsdlMockRunContext( getModelItem(), null )
982 								: mockRunner.getMockContext();
983 						getModelItem().runAfterRequestScript( context, mockRunner, null );
984 					}
985 					catch( Exception e1 )
986 					{
987 						UISupport.showErrorMessage( e1 );
988 					}
989 				}
990 			};
991 		}
992 	}
993 }