1
2
3
4
5
6
7
8
9
10
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.LinkedList;
27 import java.util.List;
28
29 import javax.swing.AbstractAction;
30 import javax.swing.AbstractListModel;
31 import javax.swing.Action;
32 import javax.swing.BorderFactory;
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.WsdlMockRunner;
50 import com.eviware.soapui.impl.wsdl.mock.WsdlMockService;
51 import com.eviware.soapui.impl.wsdl.support.HelpUrls;
52 import com.eviware.soapui.model.ModelItem;
53 import com.eviware.soapui.model.mock.MockOperation;
54 import com.eviware.soapui.model.mock.MockResponse;
55 import com.eviware.soapui.model.mock.MockResult;
56 import com.eviware.soapui.model.mock.MockServiceListener;
57 import com.eviware.soapui.model.support.MockRunListenerAdapter;
58 import com.eviware.soapui.support.DocumentListenerAdapter;
59 import com.eviware.soapui.support.UISupport;
60 import com.eviware.soapui.support.action.swing.ActionList;
61 import com.eviware.soapui.support.components.JXToolBar;
62 import com.eviware.soapui.support.swing.ListMouseListener;
63 import com.eviware.soapui.support.swing.ModelItemListMouseListener;
64 import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
65
66 /***
67 * DesktopPanel for WsdlMockServices
68 *
69 * @author ole.matzura
70 */
71
72 public class WsdlMockServiceDesktopPanel extends ModelItemDesktopPanel<WsdlMockService>
73 {
74 private static final String LOG_TITLE = "Message Log";
75 private JButton runButton;
76 private WsdlMockRunner mockRunner;
77 private JButton stopButton;
78 private JProgressBar progressBar;
79 private LogListModel logListModel;
80 private JList testLogList;
81 private JCheckBox enableLogCheckBox;
82 private JScrollPane logScrollPane;
83 private JList operationList;
84 private InternalMockRunListener mockRunListener;
85
86 private JTextField pathTextField;
87 private JTextField portTextField;
88
89 public WsdlMockServiceDesktopPanel( WsdlMockService mockService )
90 {
91 super( mockService );
92 buildUI();
93
94 setPreferredSize( new Dimension( 400, 500 ) );
95
96 mockRunListener = new InternalMockRunListener();
97 mockService.addMockRunListener( mockRunListener );
98 }
99
100 public boolean onClose( boolean canCancel )
101 {
102 if( mockRunner != null && canCancel )
103 {
104 if( !UISupport.confirm( "Close and stop MockService", "Close MockService" ))
105 {
106 return false;
107 }
108 }
109
110 if( mockRunner != null )
111 {
112 mockRunner.stop();
113 mockRunner.release();
114 }
115
116 getModelItem().removeMockRunListener( mockRunListener );
117 ((OperationListModel)operationList.getModel()).release();
118
119 logListModel.clear();
120
121 return release();
122 }
123
124 public boolean dependsOn(ModelItem modelItem)
125 {
126 return modelItem == getModelItem() || modelItem == getModelItem().getProject();
127 }
128
129 private void buildUI()
130 {
131 add( buildToolbar(), BorderLayout.NORTH );
132
133 JSplitPane splitPane = UISupport.createVerticalSplit();
134 splitPane.setTopComponent( buildOperationList() );
135 splitPane.setBottomComponent( buildLog() );
136 splitPane.setDividerLocation( 0.7 );
137 splitPane.setDividerLocation( 250 );
138
139 add( splitPane, BorderLayout.CENTER );
140 add( new JLabel( "--"), BorderLayout.PAGE_END );
141 }
142
143 public boolean logIsEnabled()
144 {
145 return enableLogCheckBox.isSelected();
146 }
147
148 private Component buildOperationList()
149 {
150 operationList = new JList( new OperationListModel() );
151 operationList.addMouseListener( new ModelItemListMouseListener() );
152 operationList.setCellRenderer( new OperationListCellRenderer() );
153
154 JScrollPane scrollPane = new JScrollPane( operationList );
155 UISupport.addTitledBorder( scrollPane, "Operations" );
156 return scrollPane;
157 }
158
159 private Component buildLog()
160 {
161 JPanel panel = new JPanel( new BorderLayout() );
162 JXToolBar builder = UISupport.createToolbar();
163
164 enableLogCheckBox = new JCheckBox( " ", true);
165 enableLogCheckBox.addActionListener( new ActionListener() {
166
167 public void actionPerformed( ActionEvent arg0 )
168 {
169 testLogList.setEnabled( enableLogCheckBox.isSelected() );
170
171
172 logScrollPane.repaint();
173 }} );
174
175 builder.addFixed( enableLogCheckBox );
176 builder.addRelatedGap();
177 builder.addFixed( new JLabel( "Enable"));
178 builder.addRelatedGap();
179 builder.addFixed( new JButton( new ClearLogAction() ) );
180 builder.addRelatedGap();
181 builder.addFixed( new JButton( new SetLogOptionsAction() ) );
182
183 builder.addGlue();
184 builder.setBorder( BorderFactory.createEmptyBorder( 2, 3, 3, 3 ) );
185
186 panel.add( builder, BorderLayout.NORTH );
187
188 logListModel = new LogListModel();
189 testLogList = new JList(logListModel);
190 testLogList.setCellRenderer(new LogCellRenderer());
191 testLogList.setPrototypeCellValue( "Testing 123" );
192 testLogList.setFixedCellWidth( -1 );
193 testLogList.addMouseListener(new LogListMouseListener());
194 testLogList.setBorder( BorderFactory.createLineBorder( Color.GRAY ) );
195
196 logScrollPane = new JScrollPane(testLogList);
197 logScrollPane.setBorder( null );
198 UISupport.addTitledBorder( logScrollPane, LOG_TITLE );
199
200 panel.add( logScrollPane, BorderLayout.CENTER );
201
202 return panel;
203 }
204
205 private Component buildToolbar()
206 {
207 JXToolBar toolbar = UISupport.createToolbar();
208
209 runButton = createActionButton(new RunMockServiceAction(), true);
210 stopButton = createActionButton(new StopMockServiceAction(), false);
211
212
213 toolbar.addFixed( runButton );
214 toolbar.addFixed( stopButton );
215 toolbar.addUnrelatedGap();
216
217 pathTextField = new JTextField(10);
218 pathTextField.setToolTipText( "The URL path to listen on for this service" );
219 pathTextField.setText( getModelItem().getPath() );
220 pathTextField.setCaretPosition( 0 );
221 pathTextField.getDocument().addDocumentListener( new DocumentListenerAdapter() {
222
223 @Override
224 public void update( Document document )
225 {
226 getModelItem().setPath( pathTextField.getText() );
227 }} );
228
229 toolbar.addLabeledFixed( "Path:", pathTextField );
230 toolbar.addUnrelatedGap();
231
232 portTextField = new JTextField(5);
233 portTextField.setToolTipText( "The local port to listen on for this service" );
234 portTextField.setText( String.valueOf( getModelItem().getPort() ));
235 portTextField.getDocument().addDocumentListener( new DocumentListenerAdapter() {
236
237 @Override
238 public void update( Document document )
239 {
240 try
241 {
242 getModelItem().setPort( Integer.parseInt( portTextField.getText() ) );
243 }
244 catch( Exception e )
245 {
246 }
247 }} );
248
249 toolbar.addLabeledFixed( "Port:", portTextField );
250
251 toolbar.addGlue();
252 progressBar = new JProgressBar();
253 JPanel progressBarPanel = UISupport.createProgressBarPanel( progressBar, 2, false );
254 progressBarPanel.setPreferredSize( new Dimension( 60, 20 ) );
255
256 toolbar.addFixed( progressBarPanel);
257 toolbar.addRelatedGap();
258
259
260 toolbar.addFixed( createActionButton( new ShowOnlineHelpAction(HelpUrls.MOCKSERVICE_HELP_URL), true ) );
261
262 return toolbar;
263 }
264
265 public void startMockService()
266 {
267 if( mockRunner != null || SoapUI.getMockEngine().hasRunningMock( getModelItem() ) )
268 {
269 UISupport.showErrorMessage( "MockService is already running" );
270 }
271 else
272 {
273 try
274 {
275 mockRunner = getModelItem().start();
276 mockRunner.setMaxResults( logListModel.getMaxSize() );
277 }
278 catch( Exception e )
279 {
280 UISupport.showErrorMessage( e );
281 return;
282 }
283 }
284
285 progressBar.setIndeterminate( true );
286
287 runButton.setEnabled( false );
288 stopButton.setEnabled( true );
289 pathTextField.setEnabled( false );
290 portTextField.setEnabled( false );
291 }
292
293 private final class InternalMockRunListener extends MockRunListenerAdapter
294 {
295 public void onMockResult( MockResult result )
296 {
297 if( logIsEnabled() )
298 {
299 logListModel.addElement( result );
300 }
301 }
302 }
303
304 public class OperationListModel extends AbstractListModel implements ListModel, MockServiceListener, PropertyChangeListener
305 {
306 private List<WsdlMockOperation> operations = new ArrayList<WsdlMockOperation>();
307
308 public OperationListModel()
309 {
310 for( int c = 0; c < getModelItem().getMockOperationCount(); c++ )
311 {
312 WsdlMockOperation mockOperation = ( WsdlMockOperation ) getModelItem().getMockOperationAt( c );
313 mockOperation.addPropertyChangeListener( this );
314
315 operations.add( mockOperation);
316 }
317
318 getModelItem().addMockServiceListener( this );
319 }
320
321 public Object getElementAt( int arg0 )
322 {
323 return operations.get( arg0 );
324 }
325
326 public int getSize()
327 {
328 return operations.size();
329 }
330
331 public void mockOperationAdded( MockOperation operation )
332 {
333 operations.add( ( WsdlMockOperation ) operation );
334 operation.addPropertyChangeListener( this );
335 fireIntervalAdded( this, operations.size()-1, operations.size()-1 );
336 }
337
338 public void mockOperationRemoved( MockOperation operation )
339 {
340 int ix = operations.indexOf( operation );
341 operations.remove( ix );
342 operation.removePropertyChangeListener( this );
343 fireIntervalRemoved( this, ix, ix );
344 }
345
346 public void mockResponseAdded( MockResponse request )
347 {
348 }
349
350 public void mockResponseRemoved( MockResponse request )
351 {
352 }
353
354 public void propertyChange( PropertyChangeEvent arg0 )
355 {
356 if( arg0.getPropertyName().equals( WsdlMockOperation.NAME_PROPERTY ))
357 {
358 int ix = operations.indexOf( arg0.getSource() );
359 fireContentsChanged( this, ix, ix );
360 }
361 }
362
363 public void release()
364 {
365 for( WsdlMockOperation operation : operations )
366 {
367 operation.removePropertyChangeListener( this );
368 }
369
370 getModelItem().removeMockServiceListener( this );
371 }
372 }
373
374 private final static class OperationListCellRenderer extends JLabel implements ListCellRenderer
375 {
376 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
377 boolean cellHasFocus)
378 {
379 MockOperation testStep = (MockOperation) value;
380 setText(testStep.getName());
381 setIcon(testStep.getIcon());
382
383 if (isSelected)
384 {
385 setBackground(list.getSelectionBackground());
386 setForeground(list.getSelectionForeground());
387 }
388 else
389 {
390 setBackground(list.getBackground());
391 setForeground(list.getForeground());
392 }
393
394 setEnabled(list.isEnabled());
395 setFont(list.getFont());
396 setOpaque(true);
397 setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
398
399 return this;
400 }
401 }
402
403 public class RunMockServiceAction extends AbstractAction
404 {
405 public RunMockServiceAction()
406 {
407 putValue(Action.SMALL_ICON, UISupport.createImageIcon("/submit_request.gif"));
408 putValue(Action.SHORT_DESCRIPTION, "Starts this MockService on the specified port and endpoint");
409 putValue(Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "alt ENTER" ));
410 }
411
412 public void actionPerformed( ActionEvent arg0 )
413 {
414 startMockService();
415 }
416 }
417
418 public class StopMockServiceAction extends AbstractAction
419 {
420 public StopMockServiceAction()
421 {
422 putValue(Action.SMALL_ICON, UISupport.createImageIcon("/cancel_request.gif"));
423 putValue(Action.SHORT_DESCRIPTION, "Stops this MockService on the specified port and endpoint");
424 }
425
426 public void actionPerformed( ActionEvent arg0 )
427 {
428 if( mockRunner == null )
429 {
430 UISupport.showErrorMessage( "MockService is not running" );
431 }
432 else
433 {
434 mockRunner.stop();
435 mockRunner.release();
436 mockRunner = null;
437 }
438
439 progressBar.setIndeterminate( false );
440
441 runButton.setEnabled( true );
442 stopButton.setEnabled( false );
443 pathTextField.setEnabled( true );
444 portTextField.setEnabled( true );
445 }
446 }
447
448 private static final class LogCellRenderer extends JLabel implements ListCellRenderer
449 {
450 private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
451
452 public LogCellRenderer()
453 {
454 setOpaque(true);
455 setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
456 }
457
458 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
459 boolean cellHasFocus)
460 {
461 if (value instanceof String)
462 {
463 setText(value.toString());
464 }
465 else if (value instanceof MockResult)
466 {
467 MockResult result = ( MockResult ) value;
468 String msg = dateFormat.format( new Date( result.getTimestamp()) );
469 MockResponse mockResponse = result.getMockResponse();
470
471 if( mockResponse == null )
472 {
473 msg += ": [dispatch error; missing response]";
474 }
475 else
476 {
477 msg += ": [" + mockResponse.getMockOperation().getName();
478 msg += "] " + result.getTimeTaken() + "ms";
479 }
480
481 setText( msg);
482 }
483
484 if (isSelected)
485 {
486 setBackground(list.getSelectionBackground());
487 setForeground(list.getSelectionForeground());
488 }
489 else
490 {
491 setBackground(list.getBackground());
492 setForeground(list.getForeground());
493 }
494
495 setEnabled(list.isEnabled());
496
497 return this;
498 }
499 }
500
501 private class LogListModel extends AbstractListModel
502 {
503 private List<MockResult> elements = new LinkedList<MockResult>();
504 private long maxSize = 100;
505
506 public synchronized void addElement( MockResult result )
507 {
508 elements.add( result );
509 fireIntervalAdded( this, elements.size()-1, elements.size()-1 );
510
511 while( elements.size() > maxSize )
512 {
513 removeElementAt( 0 );
514 }
515 }
516
517 public Object getElementAt( int index )
518 {
519 return elements.get( index );
520 }
521
522 public synchronized void removeElementAt( int index )
523 {
524 elements.remove( index );
525 fireIntervalRemoved( this, index, index );
526 }
527
528 public synchronized void clear()
529 {
530 int sz = elements.size();
531 if( sz > 0 )
532 {
533 elements.clear();
534 fireIntervalRemoved( this, 0, sz-1 );
535 }
536 }
537
538 public int getSize()
539 {
540 return elements.size();
541 }
542
543 public long getMaxSize()
544 {
545 return maxSize;
546 }
547
548 public synchronized void setMaxSize( long l )
549 {
550 this.maxSize = l;
551
552 while( elements.size() > maxSize )
553 {
554 removeElementAt( 0 );
555 }
556 }
557 }
558
559 private class SetLogOptionsAction extends AbstractAction
560 {
561 public SetLogOptionsAction()
562 {
563 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/options.gif" ));
564 putValue( Action.SHORT_DESCRIPTION, "Sets MockService Log Options");
565 }
566
567 public void actionPerformed( ActionEvent e )
568 {
569 String s = UISupport.prompt( "Enter maximum number of rows for MockService Log", "Log Options", String.valueOf( logListModel.getMaxSize() ) );
570 if( s != null )
571 {
572 try
573 {
574 logListModel.setMaxSize( Long.parseLong( s ));
575 if( mockRunner != null )
576 mockRunner.setMaxResults( logListModel.getMaxSize() );
577 }
578 catch( NumberFormatException e1 )
579 {
580 }
581 }
582 }}
583
584 private class ClearLogAction extends AbstractAction
585 {
586 public ClearLogAction()
587 {
588 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/clear_loadtest.gif" ));
589 putValue( Action.SHORT_DESCRIPTION, "Clears the MockService Log");
590 }
591
592 public void actionPerformed( ActionEvent e )
593 {
594 logListModel.clear();
595 if( mockRunner != null )
596 mockRunner.clearResults();
597 }}
598
599 /***
600 * Mouse Listener for triggering default action and showing popup for log list items
601 *
602 * @author Ole.Matzura
603 */
604
605 private final class LogListMouseListener extends ListMouseListener
606 {
607 @Override
608 protected ActionList getActionsForRow( JList list, int row )
609 {
610 MockResult result = ( MockResult ) logListModel.getElementAt( row );
611 return result == null ? null : result.getActions();
612 }
613 }
614 }