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