/*
* soapUI, copyright (C) 2004-2011 eviware.com
*
* soapUI is free software; you can redistribute it and/or modify it under the
* terms of version 2.1 of the GNU Lesser General Public License as published by
* the Free Software Foundation.
*
* soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details at gnu.org.
*/
package com.eviware.soapui.impl.wsdl.panels.teststeps;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.util.Date;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.text.Document;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
import com.eviware.soapui.impl.wsdl.panels.support.TestRunComponentEnabler;
import com.eviware.soapui.impl.wsdl.panels.teststeps.support.GotoTestStepsComboBoxModel;
import com.eviware.soapui.impl.wsdl.support.HelpUrls;
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
import com.eviware.soapui.impl.wsdl.teststeps.WsdlGotoTestStep;
import com.eviware.soapui.impl.wsdl.teststeps.WsdlGotoTestStep.GotoCondition;
import com.eviware.soapui.model.ModelItem;
import com.eviware.soapui.model.iface.Response;
import com.eviware.soapui.model.support.TestRunListenerAdapter;
import com.eviware.soapui.model.testsuite.SamplerTestStep;
import com.eviware.soapui.model.testsuite.TestCaseRunContext;
import com.eviware.soapui.model.testsuite.TestCaseRunner;
import com.eviware.soapui.model.testsuite.TestStepResult;
import com.eviware.soapui.support.DocumentListenerAdapter;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.components.JComponentInspector;
import com.eviware.soapui.support.components.JInspectorPanel;
import com.eviware.soapui.support.components.JInspectorPanelFactory;
import com.eviware.soapui.support.components.JUndoableTextArea;
import com.eviware.soapui.support.components.JXToolBar;
import com.eviware.soapui.support.log.JLogList;
import com.eviware.soapui.support.xml.XmlUtils;
import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
/**
* DesktopPanel for WsdlGotoTestSteps
*
* @author Ole.Matzura
*/
public class GotoStepDesktopPanel extends ModelItemDesktopPanel<WsdlGotoTestStep>
{
private final WsdlGotoTestStep gotoStep;
private DefaultListModel listModel;
private JList conditionList;
private JTextArea expressionArea;
private JButton copyButton;
private JButton deleteButton;
private JButton declareButton;
private GotoTestStepsComboBoxModel testStepsModel;
private JComboBox testStepsCombo;
private JButton testConditionButton;
private TestRunComponentEnabler componentEnabler;
private GotoCondition currentCondition;
private JButton renameButton;
private JButton runButton;
private JButton addButton;
private JLogList logList;
private InternalTestRunListener testRunListener = new InternalTestRunListener();
private JInspectorPanel inspectorPanel;
public GotoStepDesktopPanel( WsdlGotoTestStep testStep )
{
super( testStep );
this.gotoStep = testStep;
componentEnabler = new TestRunComponentEnabler( testStep.getTestCase() );
gotoStep.getTestCase().addTestRunListener( testRunListener );
buildUI();
}
public TestRunComponentEnabler getComponentEnabler()
{
return componentEnabler;
}
public JList getConditionList()
{
return conditionList;
}
public JButton getCopyButton()
{
return copyButton;
}
public JButton getDeclareButton()
{
return declareButton;
}
public JButton getDeleteButton()
{
return deleteButton;
}
public JTextArea getExpressionArea()
{
return expressionArea;
}
public WsdlGotoTestStep getGotoStep()
{
return gotoStep;
}
public DefaultListModel getListModel()
{
return listModel;
}
public JButton getTestConditionButton()
{
return testConditionButton;
}
public JComboBox getTestStepsCombo()
{
return testStepsCombo;
}
public GotoTestStepsComboBoxModel getTestStepsModel()
{
return testStepsModel;
}
private void buildUI()
{
JSplitPane splitPane = UISupport.createHorizontalSplit();
splitPane.setLeftComponent( buildConditionList() );
splitPane.setRightComponent( buildExpressionArea() );
splitPane.setResizeWeight( 0.1 );
splitPane.setDividerLocation( 120 );
inspectorPanel = JInspectorPanelFactory.build( splitPane );
inspectorPanel.addInspector( new JComponentInspector<JComponent>( buildLog(), "Log",
"A log of evaluated conditions", true ) );
add( inspectorPanel.getComponent(), BorderLayout.CENTER );
setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) );
setPreferredSize( new Dimension( 550, 300 ) );
if( listModel.getSize() > 0 )
conditionList.setSelectedIndex( 0 );
componentEnabler.add( conditionList );
componentEnabler.add( expressionArea );
componentEnabler.add( testStepsCombo );
componentEnabler.add( testConditionButton );
componentEnabler.add( copyButton );
componentEnabler.add( declareButton );
componentEnabler.add( deleteButton );
componentEnabler.add( addButton );
componentEnabler.add( runButton );
componentEnabler.add( renameButton );
}
private JComponent buildLog()
{
logList = new JLogList( "Condition Log for [" + getModelItem().getName() + "]" );
return logList;
}
private JPanel buildExpressionArea()
{
expressionArea = new JUndoableTextArea();
expressionArea.setEnabled( false );
expressionArea.getDocument().addDocumentListener( new SourceAreaDocumentListener() );
JPanel expressionPanel = new JPanel( new BorderLayout() );
JScrollPane scrollPane = new JScrollPane( expressionArea );
UISupport.addTitledBorder( scrollPane, "Condition XPath Expression" );
expressionPanel.add( scrollPane, BorderLayout.CENTER );
expressionPanel.add( buildConditionToolbar(), BorderLayout.NORTH );
expressionPanel.add( buildTargetToolbar(), BorderLayout.SOUTH );
return expressionPanel;
}
private JPanel buildConditionList()
{
listModel = new DefaultListModel();
for( int c = 0; c < gotoStep.getConditionCount(); c++ )
{
listModel.addElement( gotoStep.getConditionAt( c ).getName() );
}
conditionList = new JList( listModel );
conditionList.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
conditionList.addListSelectionListener( new ConditionListSelectionListener() );
JScrollPane listScrollPane = new JScrollPane( conditionList );
UISupport.addTitledBorder( listScrollPane, "Conditions" );
JPanel p = new JPanel( new BorderLayout() );
p.add( buildConditionListToolbar(), BorderLayout.NORTH );
p.add( listScrollPane, BorderLayout.CENTER );
return p;
}
private Component buildConditionListToolbar()
{
JXToolBar toolbar = UISupport.createSmallToolbar();
addButton = UISupport.createToolbarButton( new AddAction() );
toolbar.addFixed( addButton );
copyButton = UISupport.createToolbarButton( new CopyAction() );
copyButton.setEnabled( false );
toolbar.addFixed( copyButton );
deleteButton = UISupport.createToolbarButton( new DeleteAction() );
deleteButton.setEnabled( false );
toolbar.addFixed( deleteButton );
renameButton = UISupport.createToolbarButton( new RenameAction() );
renameButton.setEnabled( false );
toolbar.addFixed( renameButton );
return toolbar;
}
private Component buildConditionToolbar()
{
JXToolBar toolbar = UISupport.createSmallToolbar();
declareButton = UISupport.createToolbarButton( new DeclareNamespacesAction() );
declareButton.setEnabled( false );
toolbar.addFixed( declareButton );
runButton = UISupport.createToolbarButton( new RunAction() );
toolbar.addFixed( runButton );
toolbar.addGlue();
toolbar.addFixed( UISupport.createToolbarButton( new ShowOnlineHelpAction( HelpUrls.GOTOSTEPEDITOR_HELP_URL ) ) );
return toolbar;
}
protected JXToolBar buildTargetToolbar()
{
JXToolBar builder = UISupport.createSmallToolbar();
testStepsModel = new GotoTestStepsComboBoxModel( gotoStep.getTestCase(), null );
testStepsCombo = new JComboBox( testStepsModel );
testStepsCombo.setToolTipText( "The step the test case will go to if the current condition is true" );
testStepsCombo.setEnabled( false );
UISupport.setFixedSize( testStepsCombo, 280, 20 );
builder.addFixed( new JLabel( "<html><b>Target step:</b></html>" ) );
builder.addRelatedGap();
builder.addFixed( testStepsCombo );
builder.addGlue();
testConditionButton = new JButton( new TestConditionAction() );
testConditionButton.setEnabled( false );
builder.addFixed( testConditionButton );
builder.setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) );
return builder;
}
private final class SourceAreaDocumentListener extends DocumentListenerAdapter
{
@Override
public void update( Document document )
{
int ix = conditionList.getSelectedIndex();
if( ix != -1 )
{
gotoStep.getConditionAt( ix ).setExpression( expressionArea.getText() );
}
}
}
private final class ConditionListSelectionListener implements ListSelectionListener
{
public void valueChanged( ListSelectionEvent e )
{
int ix = conditionList.getSelectedIndex();
if( ix == -1 )
{
expressionArea.setText( "" );
testStepsModel.setCondition( null );
currentCondition = null;
}
else
{
currentCondition = gotoStep.getConditionAt( ix );
expressionArea.setText( currentCondition.getExpression() );
testStepsModel.setCondition( currentCondition );
}
boolean b = ix != -1;
enableEditComponents( b );
}
}
private final class AddAction extends AbstractAction
{
public AddAction()
{
putValue( Action.SHORT_DESCRIPTION, "Adds a new Condition" );
putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/add_property.gif" ) );
}
public void actionPerformed( ActionEvent e )
{
String name = UISupport.prompt( "Specify name for condition", "Add Condition",
"Condition " + ( gotoStep.getConditionCount() + 1 ) );
if( name == null || name.trim().length() == 0 )
return;
gotoStep.addCondition( name );
listModel.addElement( name );
conditionList.setSelectedIndex( listModel.getSize() - 1 );
}
}
private final class CopyAction extends AbstractAction
{
public CopyAction()
{
putValue( Action.SHORT_DESCRIPTION, "Copies the selected Condition" );
putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/clone_request.gif" ) );
}
public void actionPerformed( ActionEvent e )
{
int ix = conditionList.getSelectedIndex();
GotoCondition config = gotoStep.getConditionAt( ix );
String name = UISupport.prompt( "Specify name for condition", "Copy Condition", config.getName() );
if( name == null || name.trim().length() == 0 )
return;
GotoCondition condition = gotoStep.addCondition( name );
condition.setExpression( config.getExpression() );
condition.setTargetStep( config.getTargetStep() );
condition.setType( config.getType() );
listModel.addElement( name );
conditionList.setSelectedIndex( listModel.getSize() - 1 );
}
}
private final class DeleteAction extends AbstractAction
{
public DeleteAction()
{
putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/remove_property.gif" ) );
putValue( Action.SHORT_DESCRIPTION, "Deletes the selected Condition" );
}
public void actionPerformed( ActionEvent e )
{
if( UISupport.confirm( "Delete selected condition", "Delete Condition" ) )
{
int ix = conditionList.getSelectedIndex();
conditionList.setSelectedIndex( -1 );
gotoStep.removeConditionAt( ix );
listModel.remove( ix );
if( listModel.getSize() > 0 )
{
conditionList.setSelectedIndex( ix > listModel.getSize() - 1 ? listModel.getSize() - 1 : ix );
}
}
}
}
private final class RenameAction extends AbstractAction
{
public RenameAction()
{
putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/rename.gif" ) );
putValue( Action.SHORT_DESCRIPTION, "Renames the selected Condition" );
}
public void actionPerformed( ActionEvent e )
{
int ix = conditionList.getSelectedIndex();
GotoCondition config = gotoStep.getConditionAt( ix );
String name = UISupport.prompt( "Specify name for condition", "Rename Condition", config.getName() );
if( name == null || name.trim().length() == 0 )
return;
config.setName( name );
listModel.setElementAt( name, ix );
}
}
private final class DeclareNamespacesAction extends AbstractAction
{
public DeclareNamespacesAction()
{
putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/declareNs.gif" ) );
putValue( Action.SHORT_DESCRIPTION, "Declare available response namespaces in condition expression" );
}
public void actionPerformed( ActionEvent e )
{
try
{
SamplerTestStep previousStep = ( SamplerTestStep )gotoStep.getTestCase().findPreviousStepOfType( gotoStep,
SamplerTestStep.class );
if( previousStep != null )
{
Response response = previousStep.getTestRequest().getResponse();
String xml = response == null ? null : response.getContentAsString();
if( XmlUtils.seemsToBeXml( xml ) )
{
expressionArea.setText( XmlUtils.declareXPathNamespaces( xml ) + expressionArea.getText() );
}
else
{
UISupport.showErrorMessage( "Missing response in previous request step [" + previousStep.getName()
+ "]" );
}
}
else
{
UISupport.showErrorMessage( "Missing previous request step" );
}
}
catch( Exception e1 )
{
SoapUI.logError( e1 );
}
}
}
private final class RunAction extends AbstractAction
{
public RunAction()
{
putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/run_all.gif" ) );
putValue( Action.SHORT_DESCRIPTION, "Runs the current conditions against the previous response" );
}
public void actionPerformed( ActionEvent e )
{
if( listModel.getSize() == 0 )
{
UISupport.showErrorMessage( "Missing conditions!" );
return;
}
SamplerTestStep previousStep = gotoStep.getTestCase().findPreviousStepOfType( gotoStep, SamplerTestStep.class );
if( previousStep == null )
{
UISupport.showErrorMessage( "Missing previous request step" );
}
else
{
if( previousStep.getTestRequest().getResponse() == null
|| !XmlUtils.seemsToBeXml( previousStep.getTestRequest().getResponse().getContentAsXml() ) )
{
UISupport.showErrorMessage( "Missing response in previous message" );
return;
}
WsdlTestRunContext context = new WsdlTestRunContext( gotoStep );
GotoCondition target = gotoStep.runConditions( previousStep, context );
if( target == null )
{
logList.addLine( "No condition true for current response in [" + previousStep.getName() + "]" );
}
else
{
logList.addLine( "Condition triggered for go to [" + target.getTargetStep() + "]" );
}
inspectorPanel.setCurrentInspector( "Log" );
}
}
}
private final class TestConditionAction extends AbstractAction
{
public TestConditionAction()
{
putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/run.gif" ) );
putValue( Action.SHORT_DESCRIPTION,
"Runs the current condition against the previous response and shows the result" );
}
public void actionPerformed( ActionEvent e )
{
SamplerTestStep previousStep = gotoStep.getTestCase().findPreviousStepOfType( gotoStep, SamplerTestStep.class );
if( previousStep == null )
{
UISupport.showErrorMessage( "Missing previous request step" );
}
else
{
if( previousStep.getTestRequest().getResponse() == null
|| !XmlUtils.seemsToBeXml( previousStep.getTestRequest().getResponse().getContentAsXml() ) )
{
UISupport
.showErrorMessage( "Missing response in previous request step [" + previousStep.getName() + "]" );
return;
}
try
{
GotoCondition condition = gotoStep.getConditionAt( conditionList.getSelectedIndex() );
WsdlTestRunContext context = new WsdlTestRunContext( gotoStep );
boolean evaluate = condition.evaluate( previousStep, context );
if( !evaluate )
{
UISupport.showInfoMessage( "Condition not true for current response in [" + previousStep.getName()
+ "]" );
}
else
{
UISupport.showInfoMessage( "Condition true for current response in [" + previousStep.getName() + "]" );
}
}
catch( Exception e1 )
{
UISupport.showErrorMessage( "Error checking condition: " + e1.getMessage() );
}
}
}
}
public boolean onClose( boolean canCancel )
{
componentEnabler.release();
gotoStep.getTestCase().removeTestRunListener( testRunListener );
testStepsModel.release();
inspectorPanel.release();
return release();
}
public JComponent getComponent()
{
return this;
}
public boolean dependsOn( ModelItem modelItem )
{
return modelItem == gotoStep || modelItem == gotoStep.getTestCase()
|| modelItem == gotoStep.getTestCase().getTestSuite()
|| modelItem == gotoStep.getTestCase().getTestSuite().getProject();
}
public GotoCondition getCurrentCondition()
{
return currentCondition;
}
protected void enableEditComponents( boolean b )
{
expressionArea.setEnabled( b );
testStepsCombo.setEnabled( b );
copyButton.setEnabled( b );
deleteButton.setEnabled( b );
declareButton.setEnabled( b );
testConditionButton.setEnabled( b );
renameButton.setEnabled( b );
}
private class InternalTestRunListener extends TestRunListenerAdapter
{
@Override
public void afterStep( TestCaseRunner testRunner, TestCaseRunContext runContext, TestStepResult result )
{
if( result.getTestStep() == gotoStep )
{
logList.addLine( new Date( result.getTimeStamp() ).toString() + ": " + result.getMessages()[0] );
inspectorPanel.setCurrentInspector( "Log" );
}
}
}
}