View Javadoc

1   /*
2    *  soapUI, copyright (C) 2006 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of the GNU Lesser General Public License as published by the Free Software Foundation; 
6    *  either version 2.1 of the License, or (at your option) any later version.
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.Date;
26  import java.util.List;
27  
28  import javax.swing.AbstractAction;
29  import javax.swing.AbstractListModel;
30  import javax.swing.Action;
31  import javax.swing.BorderFactory;
32  import javax.swing.DefaultListModel;
33  import javax.swing.JButton;
34  import javax.swing.JCheckBox;
35  import javax.swing.JLabel;
36  import javax.swing.JList;
37  import javax.swing.JPanel;
38  import javax.swing.JProgressBar;
39  import javax.swing.JScrollPane;
40  import javax.swing.JSplitPane;
41  import javax.swing.JTextField;
42  import javax.swing.ListCellRenderer;
43  import javax.swing.ListModel;
44  import javax.swing.text.Document;
45  
46  import com.eviware.soapui.SoapUI;
47  import com.eviware.soapui.impl.wsdl.actions.support.ShowOnlineHelpAction;
48  import com.eviware.soapui.impl.wsdl.mock.WsdlMockOperation;
49  import com.eviware.soapui.impl.wsdl.mock.WsdlMockService;
50  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
51  import com.eviware.soapui.model.mock.MockOperation;
52  import com.eviware.soapui.model.mock.MockResponse;
53  import com.eviware.soapui.model.mock.MockResult;
54  import com.eviware.soapui.model.mock.MockRunner;
55  import com.eviware.soapui.model.mock.MockServiceListener;
56  import com.eviware.soapui.model.support.MockRunListenerAdapter;
57  import com.eviware.soapui.support.DocumentListenerAdapter;
58  import com.eviware.soapui.support.UISupport;
59  import com.eviware.soapui.support.action.ActionList;
60  import com.eviware.soapui.support.components.JXToolBar;
61  import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
62  import com.jgoodies.forms.builder.ButtonBarBuilder;
63  
64  public class WsdlMockServiceDesktopPanel extends ModelItemDesktopPanel<WsdlMockService>
65  {
66  	private static final String LOG_TITLE = "Request Log";
67  	private JButton runButton;
68  	private MockRunner mockRunner;
69  	private JButton stopButton;
70  	private JProgressBar progressBar;
71  	private DefaultListModel logListModel;
72  	private JList testLogList;
73  	private JCheckBox enableLogCheckBox;
74  	private JScrollPane logScrollPane;
75  	private JList operationList;
76  	private InternalMockRunListener mockRunListener;
77  //	private JButton optionsButton;
78  	private JTextField pathTextField;
79  	private JTextField portTextField;
80  
81  	public WsdlMockServiceDesktopPanel( WsdlMockService mockService )
82  	{
83  		super( mockService );
84  		buildUI();
85  		
86  		setPreferredSize( new Dimension( 350, 500 ) );
87  		
88  		mockRunListener = new InternalMockRunListener();
89  		mockService.addMockRunListener( mockRunListener  );
90  	}
91  	
92  	public boolean onClose( boolean canCancel )
93  	{
94  		if( mockRunner != null && canCancel )
95  		{
96  			if( !UISupport.confirm( "Close and stop MockService", "Close MockService" ))
97  			{
98  				return false;
99  			}
100 		}
101 		
102 		if( mockRunner != null )
103 		{
104 			mockRunner.stop();
105 		}
106 		
107 		getModelItem().removeMockRunListener( mockRunListener );
108 		((OperationListModel)operationList.getModel()).release();
109 		
110 		return release();
111 	}
112 
113 	private void buildUI()
114 	{
115       add( buildToolbar(), BorderLayout.NORTH );
116       
117       JSplitPane splitPane = UISupport.createVerticalSplit();
118 		splitPane.setTopComponent( buildOperationList() );
119       splitPane.setBottomComponent( buildLog() );
120       splitPane.setDividerLocation( 0.7 );
121       splitPane.setDividerLocation( 250 );
122 
123       add( splitPane, BorderLayout.CENTER );
124       add( new JLabel( "--"), BorderLayout.PAGE_END );
125 	}
126 
127    public boolean logIsEnabled()
128    {
129    	return enableLogCheckBox.isSelected();
130    }
131    
132 	private Component buildOperationList()
133 	{
134 		JPanel panel = new JPanel( new BorderLayout() );
135 		ButtonBarBuilder builder = new ButtonBarBuilder();
136 		
137 		enableLogCheckBox = new JCheckBox("Enable Log", true);
138 		enableLogCheckBox.addActionListener( new ActionListener() {
139 
140 			public void actionPerformed( ActionEvent arg0 )
141 			{
142 				testLogList.setEnabled( !enableLogCheckBox.isSelected() );
143 				
144 				// border needs to be repainted..
145 				logScrollPane.repaint();
146 			}}  );
147 		
148 		builder.addFixed( enableLogCheckBox );
149 		builder.addGlue();
150 		
151 		progressBar = new JProgressBar();
152       JPanel progressBarPanel = UISupport.createProgressBarPanel( progressBar, 2, false );
153       progressBarPanel.setPreferredSize( new Dimension( 60, 20 ) );
154       
155 		builder.addFixed( progressBarPanel);
156 		builder.setBorder( BorderFactory.createEmptyBorder( 2, 3, 3, 3 ) );
157 
158 		panel.add( builder.getPanel(), BorderLayout.NORTH );
159 		
160 		operationList = new JList( new OperationListModel() );
161 		operationList.addMouseListener( new ModelItemListMouseListener() );
162 		operationList.setCellRenderer( new OperationListCellRenderer() );
163 		
164 		JScrollPane scrollPane = new JScrollPane( operationList );
165 		UISupport.addTitledBorder( scrollPane, "Operations" );
166 		panel.add( scrollPane, BorderLayout.CENTER );
167 		
168 		return panel;
169 	}
170 	
171 	private Component buildLog()
172 	{
173 		logListModel = new DefaultListModel();
174 		testLogList = new JList(logListModel);
175 		testLogList.setCellRenderer(new LogCellRenderer());
176 		testLogList.addMouseListener(new LogListMouseListener());
177 		testLogList.setBorder( BorderFactory.createLineBorder(  Color.GRAY ) );
178 
179 		logScrollPane = new JScrollPane(testLogList);
180 		logScrollPane.setBorder( null );
181 		UISupport.addTitledBorder( logScrollPane, LOG_TITLE );
182 		return logScrollPane;
183 	}
184 
185 	private Component buildToolbar()
186 	{
187 		JXToolBar toolbar = UISupport.createToolbar();
188 		
189 		runButton = createActionButton(new RunMockServiceAction(), true);
190 		stopButton = createActionButton(new StopMockServiceAction(), false);
191 //		optionsButton = createActionButton( new MockServiceOptionsAction( getModelItem() ), true );
192 		
193 		toolbar.addFixed( runButton );
194 		toolbar.addFixed( stopButton );
195 		toolbar.addUnrelatedGap();
196 		
197 		pathTextField = new JTextField(15);
198 		pathTextField.setToolTipText( "The URL path to listen on for this service" );
199 		pathTextField.setText( getModelItem().getPath() );
200 		pathTextField.setCaretPosition( 0 );
201 		pathTextField.getDocument().addDocumentListener( new DocumentListenerAdapter() {
202 
203 			@Override
204 			public void update( Document document )
205 			{
206 				getModelItem().setPath( pathTextField.getText() );
207 			}}  );
208 		
209 		toolbar.addLabeledFixed( "Path:", pathTextField );
210 		toolbar.addUnrelatedGap();
211 		
212 		portTextField = new JTextField(5);
213 		portTextField.setToolTipText( "The local port to listen on for this service" );
214 		portTextField.setText( String.valueOf( getModelItem().getPort() ));
215 		portTextField.getDocument().addDocumentListener( new DocumentListenerAdapter() {
216 
217 			@Override
218 			public void update( Document document )
219 			{
220 				try
221 				{
222 					getModelItem().setPort( Integer.parseInt( portTextField.getText() ) );
223 				}
224 				catch( Exception e )
225 				{
226 				}				
227 			}}  );
228 		
229 		toolbar.addLabeledFixed( "Port:", portTextField );
230 		
231 		toolbar.addGlue();
232 	//	toolbar.addFixed( optionsButton );
233 		toolbar.addFixed( createActionButton( new ShowOnlineHelpAction(HelpUrls.MOCKSERVICE_HELP_URL), true ) );
234 			
235 		return toolbar;
236 	}
237 	
238 	private final class InternalMockRunListener extends MockRunListenerAdapter
239 	{
240 		public void onMockResult( MockResult result )
241 		{
242 			if( logIsEnabled() )
243 			{
244 				logListModel.addElement( result );
245 			}
246 		}
247 	}
248 
249 	public class OperationListModel extends AbstractListModel implements ListModel, MockServiceListener, PropertyChangeListener
250 	{
251 		private List<WsdlMockOperation> operations = new ArrayList<WsdlMockOperation>();
252 		
253 		public OperationListModel()
254 		{
255 			for( int c = 0; c < getModelItem().getMockOperationCount(); c++ )
256 			{
257 				WsdlMockOperation mockOperation = ( WsdlMockOperation ) getModelItem().getMockOperationAt( c );
258 				mockOperation.addPropertyChangeListener( this );
259 				
260 				operations.add( mockOperation);
261 			}
262 			
263 			getModelItem().addMockServiceListener( this );
264 		}
265 		
266 		public Object getElementAt( int arg0 )
267 		{
268 			return operations.get( arg0 );
269 		}
270 
271 		public int getSize()
272 		{
273 			return operations.size();
274 		}
275 
276 		public void mockOperationAdded( MockOperation operation )
277 		{
278 			operations.add( ( WsdlMockOperation ) operation );
279 			operation.addPropertyChangeListener( this );
280 			fireIntervalAdded( this, operations.size()-1, operations.size()-1 );
281 		}
282 
283 		public void mockOperationRemoved( MockOperation operation )
284 		{
285 			int ix = operations.indexOf( operation );
286 			operations.remove( ix );
287 			operation.removePropertyChangeListener( this );
288 			fireIntervalRemoved( this, ix, ix );
289 		}
290 
291 		public void mockResponseAdded( MockResponse request )
292 		{
293 		}
294 
295 		public void mockResponseRemoved( MockResponse request )
296 		{
297 		}
298 
299 		public void propertyChange( PropertyChangeEvent arg0 )
300 		{
301 			if( arg0.getPropertyName().equals( WsdlMockOperation.NAME_PROPERTY ))
302 			{
303 				int ix = operations.indexOf( arg0.getSource() );
304 				fireContentsChanged( this, ix, ix );
305 			}
306 		}
307 		
308 		public void release()
309 		{
310 			for( WsdlMockOperation operation : operations )
311 			{
312 				operation.removePropertyChangeListener( this );
313 			}
314 			
315 			getModelItem().removeMockServiceListener( this );
316 		}
317 	}
318 	
319 	private final static class OperationListCellRenderer extends JLabel implements ListCellRenderer
320 	{
321 		public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
322 				boolean cellHasFocus)
323 		{
324 			MockOperation testStep = (MockOperation) value;
325 			setText(testStep.getName());
326 			setIcon(testStep.getIcon());
327 
328 			if (isSelected)
329 			{
330 				setBackground(list.getSelectionBackground());
331 				setForeground(list.getSelectionForeground());
332 			}
333 			else
334 			{
335 				setBackground(list.getBackground());
336 				setForeground(list.getForeground());
337 			}
338 
339 			setEnabled(list.isEnabled());
340 			setFont(list.getFont());
341 			setOpaque(true);
342 			setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
343 
344 			return this;
345 		}
346 	}
347 	
348 	public class RunMockServiceAction extends AbstractAction
349 	{
350 		public RunMockServiceAction()
351 		{
352 			putValue(Action.SMALL_ICON, UISupport.createImageIcon("/submit_request.gif"));
353 			putValue(Action.SHORT_DESCRIPTION, "Starts this MockService on the specified port and endpoint");
354 			putValue(Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "alt ENTER" ));
355 		}
356 		
357 		public void actionPerformed( ActionEvent arg0 )
358 		{
359 			if( mockRunner != null || SoapUI.getMockEngine().hasRunningMock( getModelItem() ) )
360 			{
361 				UISupport.showErrorMessage( "MockService is already running" );
362 			}
363 			else
364 			{
365 				try
366 				{
367 					mockRunner = getModelItem().start();
368 				}
369 				catch( Exception e )
370 				{
371 					UISupport.showErrorMessage( e );
372 					e.printStackTrace();
373 					return;
374 				}
375 			}
376 			
377 			progressBar.setIndeterminate( true );
378 			
379 			runButton.setEnabled( false );
380 			stopButton.setEnabled( true );
381 			pathTextField.setEnabled( false );
382 			portTextField.setEnabled( false );
383 		}
384 	}
385 	
386 	public class StopMockServiceAction extends AbstractAction
387 	{
388 		public StopMockServiceAction()
389 		{
390 			putValue(Action.SMALL_ICON, UISupport.createImageIcon("/cancel_request.gif"));
391 			putValue(Action.SHORT_DESCRIPTION, "Stops this MockService on the specified port and endpoint");
392 		}
393 		
394 		public void actionPerformed( ActionEvent arg0 )
395 		{
396 			if( mockRunner == null )
397 			{
398 				UISupport.showErrorMessage( "MockService is not running" );
399 			}
400 			else
401 			{
402 				mockRunner.stop();
403 				mockRunner = null;
404 			}
405 			
406 			progressBar.setIndeterminate( false );
407 			
408 			runButton.setEnabled( true );
409 			stopButton.setEnabled( false );
410 			pathTextField.setEnabled( true );
411 			portTextField.setEnabled( true );
412 		}
413 	}
414 	
415 	private static final class LogCellRenderer extends JLabel implements ListCellRenderer
416 	{
417 		private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
418 		
419 		public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
420 				boolean cellHasFocus)
421 		{
422 			setIcon(null);
423 
424 			if (value instanceof String)
425 			{
426 				setText(value.toString());
427 			}
428 			else if (value instanceof MockResult)
429 			{
430 				MockResult result = ( MockResult ) value;
431 				setIcon(null);
432 				String msg = dateFormat.format( new Date( result.getTimestamp()) );
433 				MockResponse mockResponse = result.getMockResponse();
434 				
435 				if( mockResponse == null )
436 				{
437 					msg += ": [dispatch error; missing response]";
438 				}
439 				else
440 				{
441 					msg += ": [" + mockResponse.getMockOperation().getName();
442 					msg += "] " + result.getTimeTaken() + "ms";
443 				}
444 				
445 				setText( msg);
446 			}
447 
448 			if (isSelected)
449 			{
450 				setBackground(list.getSelectionBackground());
451 				setForeground(list.getSelectionForeground());
452 			}
453 			else
454 			{
455 				setBackground(list.getBackground());
456 				setForeground(list.getForeground());
457 			}
458 
459 			setEnabled(list.isEnabled());
460 			setFont(list.getFont());
461 			setOpaque(true);
462 			setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
463 
464 			return this;
465 		}
466 	}
467 	
468 	/***
469 	 * Mouse Listener for triggering default action and showing popup for log list items
470 	 * 
471 	 * @author Ole.Matzura
472 	 */
473 
474 	private final class LogListMouseListener extends ListMouseListener
475 	{
476 		@Override
477 		protected ActionList getActionsForRow( JList list, int row )
478 		{
479 			MockResult result = ( MockResult ) logListModel.getElementAt( row );
480 			return result == null ? null : result.getActions();
481 		}
482 	}
483 }