View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2010 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.teststeps;
14  
15  import java.awt.BorderLayout;
16  import java.awt.Component;
17  import java.awt.Dimension;
18  import java.awt.event.ActionEvent;
19  import java.util.Date;
20  
21  import javax.swing.AbstractAction;
22  import javax.swing.Action;
23  import javax.swing.BorderFactory;
24  import javax.swing.DefaultListModel;
25  import javax.swing.JButton;
26  import javax.swing.JComboBox;
27  import javax.swing.JComponent;
28  import javax.swing.JLabel;
29  import javax.swing.JList;
30  import javax.swing.JPanel;
31  import javax.swing.JScrollPane;
32  import javax.swing.JSplitPane;
33  import javax.swing.JTextArea;
34  import javax.swing.ListSelectionModel;
35  import javax.swing.event.ListSelectionEvent;
36  import javax.swing.event.ListSelectionListener;
37  import javax.swing.text.Document;
38  
39  import com.eviware.soapui.SoapUI;
40  import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
41  import com.eviware.soapui.impl.support.http.HttpRequestTestStep;
42  import com.eviware.soapui.impl.wsdl.panels.support.TestRunComponentEnabler;
43  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.GotoTestStepsComboBoxModel;
44  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
45  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
46  import com.eviware.soapui.impl.wsdl.teststeps.WsdlGotoTestStep;
47  import com.eviware.soapui.impl.wsdl.teststeps.WsdlGotoTestStep.GotoCondition;
48  import com.eviware.soapui.model.ModelItem;
49  import com.eviware.soapui.model.support.TestRunListenerAdapter;
50  import com.eviware.soapui.model.testsuite.TestCaseRunContext;
51  import com.eviware.soapui.model.testsuite.TestCaseRunner;
52  import com.eviware.soapui.model.testsuite.TestStepResult;
53  import com.eviware.soapui.support.DocumentListenerAdapter;
54  import com.eviware.soapui.support.StringUtils;
55  import com.eviware.soapui.support.UISupport;
56  import com.eviware.soapui.support.components.JComponentInspector;
57  import com.eviware.soapui.support.components.JInspectorPanel;
58  import com.eviware.soapui.support.components.JInspectorPanelFactory;
59  import com.eviware.soapui.support.components.JUndoableTextArea;
60  import com.eviware.soapui.support.components.JXToolBar;
61  import com.eviware.soapui.support.log.JLogList;
62  import com.eviware.soapui.support.xml.XmlUtils;
63  import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
64  
65  /***
66   * DesktopPanel for WsdlGotoTestSteps
67   * 
68   * @author Ole.Matzura
69   */
70  
71  public class GotoStepDesktopPanel extends ModelItemDesktopPanel<WsdlGotoTestStep>
72  {
73  	private final WsdlGotoTestStep gotoStep;
74  	private DefaultListModel listModel;
75  	private JList conditionList;
76  	private JTextArea expressionArea;
77  	private JButton copyButton;
78  	private JButton deleteButton;
79  	private JButton declareButton;
80  	private GotoTestStepsComboBoxModel testStepsModel;
81  	private JComboBox testStepsCombo;
82  	private JButton testConditionButton;
83  	private TestRunComponentEnabler componentEnabler;
84  	private GotoCondition currentCondition;
85  	private JButton renameButton;
86  	private JButton runButton;
87  	private JButton addButton;
88  	private JLogList logList;
89  	private InternalTestRunListener testRunListener = new InternalTestRunListener();
90  	private JInspectorPanel inspectorPanel;
91  
92  	public GotoStepDesktopPanel( WsdlGotoTestStep testStep )
93  	{
94  		super( testStep );
95  		this.gotoStep = testStep;
96  		componentEnabler = new TestRunComponentEnabler( testStep.getTestCase() );
97  		gotoStep.getTestCase().addTestRunListener( testRunListener );
98  
99  		buildUI();
100 	}
101 
102 	public TestRunComponentEnabler getComponentEnabler()
103 	{
104 		return componentEnabler;
105 	}
106 
107 	public JList getConditionList()
108 	{
109 		return conditionList;
110 	}
111 
112 	public JButton getCopyButton()
113 	{
114 		return copyButton;
115 	}
116 
117 	public JButton getDeclareButton()
118 	{
119 		return declareButton;
120 	}
121 
122 	public JButton getDeleteButton()
123 	{
124 		return deleteButton;
125 	}
126 
127 	public JTextArea getExpressionArea()
128 	{
129 		return expressionArea;
130 	}
131 
132 	public WsdlGotoTestStep getGotoStep()
133 	{
134 		return gotoStep;
135 	}
136 
137 	public DefaultListModel getListModel()
138 	{
139 		return listModel;
140 	}
141 
142 	public JButton getTestConditionButton()
143 	{
144 		return testConditionButton;
145 	}
146 
147 	public JComboBox getTestStepsCombo()
148 	{
149 		return testStepsCombo;
150 	}
151 
152 	public GotoTestStepsComboBoxModel getTestStepsModel()
153 	{
154 		return testStepsModel;
155 	}
156 
157 	private void buildUI()
158 	{
159 		JSplitPane splitPane = UISupport.createHorizontalSplit();
160 		splitPane.setLeftComponent( buildConditionList() );
161 
162 		splitPane.setRightComponent( buildExpressionArea() );
163 		splitPane.setResizeWeight( 0.1 );
164 		splitPane.setDividerLocation( 120 );
165 
166 		inspectorPanel = JInspectorPanelFactory.build( splitPane );
167 		inspectorPanel.addInspector( new JComponentInspector<JComponent>( buildLog(), "Log",
168 				"A log of evaluated conditions", true ) );
169 
170 		add( inspectorPanel.getComponent(), BorderLayout.CENTER );
171 
172 		setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) );
173 		setPreferredSize( new Dimension( 550, 300 ) );
174 
175 		if( listModel.getSize() > 0 )
176 			conditionList.setSelectedIndex( 0 );
177 
178 		componentEnabler.add( conditionList );
179 		componentEnabler.add( expressionArea );
180 		componentEnabler.add( testStepsCombo );
181 		componentEnabler.add( testConditionButton );
182 		componentEnabler.add( copyButton );
183 		componentEnabler.add( declareButton );
184 		componentEnabler.add( deleteButton );
185 		componentEnabler.add( addButton );
186 		componentEnabler.add( runButton );
187 		componentEnabler.add( renameButton );
188 	}
189 
190 	private JComponent buildLog()
191 	{
192 		logList = new JLogList( "ConditionLog" + getModelItem().getName() );
193 		return logList;
194 	}
195 
196 	private JPanel buildExpressionArea()
197 	{
198 		expressionArea = new JUndoableTextArea();
199 		expressionArea.setEnabled( false );
200 		expressionArea.getDocument().addDocumentListener( new SourceAreaDocumentListener() );
201 
202 		JPanel expressionPanel = new JPanel( new BorderLayout() );
203 		JScrollPane scrollPane = new JScrollPane( expressionArea );
204 		UISupport.addTitledBorder( scrollPane, "Condition XPath Expression" );
205 
206 		expressionPanel.add( scrollPane, BorderLayout.CENTER );
207 		expressionPanel.add( buildConditionToolbar(), BorderLayout.NORTH );
208 		expressionPanel.add( buildTargetToolbar(), BorderLayout.SOUTH );
209 		return expressionPanel;
210 	}
211 
212 	private JPanel buildConditionList()
213 	{
214 		listModel = new DefaultListModel();
215 
216 		for( int c = 0; c < gotoStep.getConditionCount(); c++ )
217 		{
218 			listModel.addElement( gotoStep.getConditionAt( c ).getName() );
219 		}
220 
221 		conditionList = new JList( listModel );
222 		conditionList.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
223 		conditionList.addListSelectionListener( new ConditionListSelectionListener() );
224 
225 		JScrollPane listScrollPane = new JScrollPane( conditionList );
226 		UISupport.addTitledBorder( listScrollPane, "Conditions" );
227 
228 		JPanel p = new JPanel( new BorderLayout() );
229 		p.add( buildConditionListToolbar(), BorderLayout.NORTH );
230 		p.add( listScrollPane, BorderLayout.CENTER );
231 		return p;
232 	}
233 
234 	private Component buildConditionListToolbar()
235 	{
236 		JXToolBar toolbar = UISupport.createSmallToolbar();
237 
238 		addButton = UISupport.createToolbarButton( new AddAction() );
239 		toolbar.addFixed( addButton );
240 		copyButton = UISupport.createToolbarButton( new CopyAction() );
241 		copyButton.setEnabled( false );
242 		toolbar.addFixed( copyButton );
243 		deleteButton = UISupport.createToolbarButton( new DeleteAction() );
244 		deleteButton.setEnabled( false );
245 		toolbar.addFixed( deleteButton );
246 		renameButton = UISupport.createToolbarButton( new RenameAction() );
247 		renameButton.setEnabled( false );
248 		toolbar.addFixed( renameButton );
249 		return toolbar;
250 	}
251 
252 	private Component buildConditionToolbar()
253 	{
254 		JXToolBar toolbar = UISupport.createSmallToolbar();
255 
256 		declareButton = UISupport.createToolbarButton( new DeclareNamespacesAction() );
257 		declareButton.setEnabled( false );
258 		toolbar.addFixed( declareButton );
259 		runButton = UISupport.createToolbarButton( new RunAction() );
260 		toolbar.addFixed( runButton );
261 
262 		toolbar.addGlue();
263 		toolbar.addFixed( UISupport.createToolbarButton( new ShowOnlineHelpAction( HelpUrls.GOTOSTEPEDITOR_HELP_URL ) ) );
264 		return toolbar;
265 	}
266 
267 	protected JXToolBar buildTargetToolbar()
268 	{
269 		JXToolBar builder = UISupport.createSmallToolbar();
270 		testStepsModel = new GotoTestStepsComboBoxModel( gotoStep.getTestCase(), null );
271 		testStepsCombo = new JComboBox( testStepsModel );
272 		testStepsCombo.setToolTipText( "The step the test case will go to if the current condition is true" );
273 		testStepsCombo.setEnabled( false );
274 		builder.addFixed( new JLabel( "<html><b>Target step:</b></html>" ) );
275 		builder.addRelatedGap();
276 		builder.addFixed( testStepsCombo );
277 		builder.addGlue();
278 		testConditionButton = new JButton( new TestConditionAction() );
279 		testConditionButton.setEnabled( false );
280 		builder.addFixed( testConditionButton );
281 		builder.setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) );
282 		return builder;
283 	}
284 
285 	private final class SourceAreaDocumentListener extends DocumentListenerAdapter
286 	{
287 		@Override
288 		public void update( Document document )
289 		{
290 			int ix = conditionList.getSelectedIndex();
291 			if( ix != -1 )
292 			{
293 				gotoStep.getConditionAt( ix ).setExpression( expressionArea.getText() );
294 			}
295 		}
296 	}
297 
298 	private final class ConditionListSelectionListener implements ListSelectionListener
299 	{
300 		public void valueChanged( ListSelectionEvent e )
301 		{
302 			int ix = conditionList.getSelectedIndex();
303 			if( ix == -1 )
304 			{
305 				expressionArea.setText( "" );
306 				testStepsModel.setCondition( null );
307 				currentCondition = null;
308 			}
309 			else
310 			{
311 				currentCondition = gotoStep.getConditionAt( ix );
312 				expressionArea.setText( currentCondition.getExpression() );
313 				testStepsModel.setCondition( currentCondition );
314 			}
315 
316 			boolean b = ix != -1;
317 			enableEditComponents( b );
318 		}
319 	}
320 
321 	private final class AddAction extends AbstractAction
322 	{
323 		public AddAction()
324 		{
325 			putValue( Action.SHORT_DESCRIPTION, "Adds a new Conditionr" );
326 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/add_property.gif" ) );
327 		}
328 
329 		public void actionPerformed( ActionEvent e )
330 		{
331 			String name = UISupport.prompt( "Specify name for condition", "Add Condition", "Condition "
332 					+ ( gotoStep.getConditionCount() + 1 ) );
333 			if( name == null || name.trim().length() == 0 )
334 				return;
335 
336 			gotoStep.addCondition( name );
337 
338 			listModel.addElement( name );
339 			conditionList.setSelectedIndex( listModel.getSize() - 1 );
340 		}
341 	}
342 
343 	private final class CopyAction extends AbstractAction
344 	{
345 		public CopyAction()
346 		{
347 			putValue( Action.SHORT_DESCRIPTION, "Copies the selected Condition" );
348 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/clone_request.gif" ) );
349 		}
350 
351 		public void actionPerformed( ActionEvent e )
352 		{
353 			int ix = conditionList.getSelectedIndex();
354 			GotoCondition config = gotoStep.getConditionAt( ix );
355 
356 			String name = UISupport.prompt( "Specify name for condition", "Copy Condition", config.getName() );
357 			if( name == null || name.trim().length() == 0 )
358 				return;
359 
360 			GotoCondition condition = gotoStep.addCondition( name );
361 			condition.setExpression( config.getExpression() );
362 			condition.setTargetStep( config.getTargetStep() );
363 			condition.setType( config.getType() );
364 
365 			listModel.addElement( name );
366 			conditionList.setSelectedIndex( listModel.getSize() - 1 );
367 		}
368 	}
369 
370 	private final class DeleteAction extends AbstractAction
371 	{
372 		public DeleteAction()
373 		{
374 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/remove_property.gif" ) );
375 			putValue( Action.SHORT_DESCRIPTION, "Deletes the selected Condition" );
376 		}
377 
378 		public void actionPerformed( ActionEvent e )
379 		{
380 			if( UISupport.confirm( "Delete selected condition", "Delete Condition" ) )
381 			{
382 				int ix = conditionList.getSelectedIndex();
383 
384 				conditionList.setSelectedIndex( -1 );
385 
386 				gotoStep.removeConditionAt( ix );
387 				listModel.remove( ix );
388 
389 				if( listModel.getSize() > 0 )
390 				{
391 					conditionList.setSelectedIndex( ix > listModel.getSize() - 1 ? listModel.getSize() - 1 : ix );
392 				}
393 			}
394 		}
395 	}
396 
397 	private final class RenameAction extends AbstractAction
398 	{
399 		public RenameAction()
400 		{
401 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/rename.gif" ) );
402 			putValue( Action.SHORT_DESCRIPTION, "Renames the selected Condition" );
403 		}
404 
405 		public void actionPerformed( ActionEvent e )
406 		{
407 			int ix = conditionList.getSelectedIndex();
408 			GotoCondition config = gotoStep.getConditionAt( ix );
409 
410 			String name = UISupport.prompt( "Specify name for condition", "Copy Condition", config.getName() );
411 			if( name == null || name.trim().length() == 0 )
412 				return;
413 
414 			config.setName( name );
415 			listModel.setElementAt( name, ix );
416 		}
417 	}
418 
419 	private final class DeclareNamespacesAction extends AbstractAction
420 	{
421 		public DeclareNamespacesAction()
422 		{
423 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/declareNs.gif" ) );
424 			putValue( Action.SHORT_DESCRIPTION, "Declare available response namespaces in condition expression" );
425 		}
426 
427 		public void actionPerformed( ActionEvent e )
428 		{
429 			try
430 			{
431 				HttpRequestTestStep previousStep = ( HttpRequestTestStep )gotoStep.getTestCase().findPreviousStepOfType(
432 						gotoStep, HttpRequestTestStep.class );
433 
434 				if( previousStep != null )
435 				{
436 					String xml = previousStep.getHttpRequest().getResponse().getContentAsString();
437 					if( StringUtils.hasContent( xml ) )
438 					{
439 						expressionArea.setText( XmlUtils.declareXPathNamespaces( xml ) + expressionArea.getText() );
440 					}
441 					else
442 					{
443 						UISupport.showErrorMessage( "Missing response in previous request step [" + previousStep.getName()
444 								+ "]" );
445 					}
446 				}
447 				else
448 				{
449 					UISupport.showErrorMessage( "Missing previous request step" );
450 				}
451 			}
452 			catch( Exception e1 )
453 			{
454 				SoapUI.logError( e1 );
455 			}
456 		}
457 	}
458 
459 	private final class RunAction extends AbstractAction
460 	{
461 		public RunAction()
462 		{
463 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/run_all.gif" ) );
464 			putValue( Action.SHORT_DESCRIPTION, "Runs the current conditions against the previous response" );
465 		}
466 
467 		public void actionPerformed( ActionEvent e )
468 		{
469 			if( listModel.getSize() == 0 )
470 			{
471 				UISupport.showErrorMessage( "Missing conditions!" );
472 				return;
473 			}
474 
475 			HttpRequestTestStep previousStep = gotoStep.getTestCase().findPreviousStepOfType( gotoStep,
476 					HttpRequestTestStep.class );
477 
478 			if( previousStep == null )
479 			{
480 				UISupport.showErrorMessage( "Missing previous request step" );
481 			}
482 			else
483 			{
484 				if( previousStep.getHttpRequest().getResponse() == null
485 						|| StringUtils.isNullOrEmpty( previousStep.getHttpRequest().getResponse().getContentAsXml() ) )
486 				{
487 					UISupport.showErrorMessage( "Missing response in previous message" );
488 					return;
489 				}
490 
491 				WsdlTestRunContext context = new WsdlTestRunContext( gotoStep );
492 				GotoCondition target = gotoStep.runConditions( previousStep, context );
493 				if( target == null )
494 				{
495 					logList.addLine( "No condition true for current response in [" + previousStep.getName() + "]" );
496 				}
497 				else
498 				{
499 					logList.addLine( "Condition triggered for go to [" + target.getTargetStep() + "]" );
500 				}
501 
502 				inspectorPanel.setCurrentInspector( "Log" );
503 			}
504 		}
505 	}
506 
507 	private final class TestConditionAction extends AbstractAction
508 	{
509 		public TestConditionAction()
510 		{
511 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/run.gif" ) );
512 			putValue( Action.SHORT_DESCRIPTION,
513 					"Runs the current condition against the previous response and shows the result" );
514 		}
515 
516 		public void actionPerformed( ActionEvent e )
517 		{
518 			HttpRequestTestStep previousStep = gotoStep.getTestCase().findPreviousStepOfType( gotoStep,
519 					HttpRequestTestStep.class );
520 
521 			if( previousStep == null )
522 			{
523 				UISupport.showErrorMessage( "Missing previous request step" );
524 			}
525 			else
526 			{
527 				if( previousStep.getHttpRequest().getResponse() == null
528 						|| !StringUtils.hasContent( previousStep.getHttpRequest().getResponse().getContentAsXml() ) )
529 				{
530 					UISupport
531 							.showErrorMessage( "Missing response in previous request step [" + previousStep.getName() + "]" );
532 					return;
533 				}
534 
535 				try
536 				{
537 					GotoCondition condition = gotoStep.getConditionAt( conditionList.getSelectedIndex() );
538 					WsdlTestRunContext context = new WsdlTestRunContext( gotoStep );
539 					boolean evaluate = condition.evaluate( previousStep, context );
540 					if( !evaluate )
541 					{
542 						UISupport.showInfoMessage( "Condition not true for current response in [" + previousStep.getName()
543 								+ "]" );
544 					}
545 					else
546 					{
547 						UISupport.showInfoMessage( "Condition true for current response in [" + previousStep.getName() + "]" );
548 					}
549 				}
550 				catch( Exception e1 )
551 				{
552 					UISupport.showErrorMessage( "Error checking condition: " + e1.getMessage() );
553 				}
554 			}
555 		}
556 	}
557 
558 	public boolean onClose( boolean canCancel )
559 	{
560 		super.release();
561 		componentEnabler.release();
562 		gotoStep.getTestCase().removeTestRunListener( testRunListener );
563 		testStepsModel.release();
564 		inspectorPanel.release();
565 
566 		return true;
567 	}
568 
569 	public JComponent getComponent()
570 	{
571 		return this;
572 	}
573 
574 	public boolean dependsOn( ModelItem modelItem )
575 	{
576 		return modelItem == gotoStep || modelItem == gotoStep.getTestCase()
577 				|| modelItem == gotoStep.getTestCase().getTestSuite()
578 				|| modelItem == gotoStep.getTestCase().getTestSuite().getProject();
579 	}
580 
581 	public GotoCondition getCurrentCondition()
582 	{
583 		return currentCondition;
584 	}
585 
586 	protected void enableEditComponents( boolean b )
587 	{
588 		expressionArea.setEnabled( b );
589 		testStepsCombo.setEnabled( b );
590 		copyButton.setEnabled( b );
591 		deleteButton.setEnabled( b );
592 		declareButton.setEnabled( b );
593 		testConditionButton.setEnabled( b );
594 		renameButton.setEnabled( b );
595 	}
596 
597 	private class InternalTestRunListener extends TestRunListenerAdapter
598 	{
599 		@Override
600 		public void afterStep( TestCaseRunner testRunner, TestCaseRunContext runContext, TestStepResult result )
601 		{
602 			if( result.getTestStep() == gotoStep )
603 			{
604 				logList.addLine( new Date( result.getTimeStamp() ).toString() + ": " + result.getMessages()[0] );
605 				inspectorPanel.setCurrentInspector( "Log" );
606 			}
607 		}
608 	}
609 }