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.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  //	private JButton optionsButton;
    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 				// border needs to be repainted..
    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 //		optionsButton = createActionButton( new MockServiceOptionsAction( getModelItem() ), true );
    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 	//	toolbar.addFixed( optionsButton );
    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 }