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.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.wsdl.actions.support.ShowOnlineHelpAction;
41  import com.eviware.soapui.impl.wsdl.panels.support.TestRunComponentEnabler;
42  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.GotoTestStepsComboBoxModel;
43  import com.eviware.soapui.impl.wsdl.submit.transports.http.WsdlResponse;
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.WsdlTestRequestStep;
48  import com.eviware.soapui.impl.wsdl.teststeps.WsdlGotoTestStep.GotoCondition;
49  import com.eviware.soapui.model.ModelItem;
50  import com.eviware.soapui.model.support.TestRunListenerAdapter;
51  import com.eviware.soapui.model.testsuite.TestRunContext;
52  import com.eviware.soapui.model.testsuite.TestRunner;
53  import com.eviware.soapui.model.testsuite.TestStepResult;
54  import com.eviware.soapui.support.DocumentListenerAdapter;
55  import com.eviware.soapui.support.StringUtils;
56  import com.eviware.soapui.support.UISupport;
57  import com.eviware.soapui.support.components.JComponentInspector;
58  import com.eviware.soapui.support.components.JInspectorPanel;
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 = new JInspectorPanel( splitPane );
167 		inspectorPanel.addInspector( new JComponentInspector( buildLog(), "Log", "A log of evaluated conditions", true ) );
168 		
169 		add( inspectorPanel, BorderLayout.CENTER );
170 		
171 		setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ));
172 		setPreferredSize( new Dimension( 550, 300 ));
173 		
174 		if( listModel.getSize() > 0 ) 
175 			conditionList.setSelectedIndex( 0 );
176 		
177 		componentEnabler.add( conditionList );
178 		componentEnabler.add( expressionArea );
179 		componentEnabler.add( testStepsCombo );
180 		componentEnabler.add( testConditionButton );
181 		componentEnabler.add( copyButton );
182 		componentEnabler.add( declareButton );
183 		componentEnabler.add( deleteButton );
184 		componentEnabler.add( addButton );
185 		componentEnabler.add( runButton );
186 		componentEnabler.add( renameButton );
187 	}
188 
189 	private JComponent buildLog()
190 	{
191 		logList = new JLogList( "ConditionLog" + getModelItem().getName() );
192 		return logList;
193 	}
194 
195 	private JPanel buildExpressionArea()
196 	{
197 		expressionArea = new JUndoableTextArea();
198 		expressionArea.setEnabled( false );
199 		expressionArea.getDocument().addDocumentListener( new SourceAreaDocumentListener());
200 		
201 		JPanel expressionPanel = new JPanel( new BorderLayout() );
202 		JScrollPane scrollPane = new JScrollPane( expressionArea );
203 		UISupport.addTitledBorder( scrollPane, "Condition XPath Expression" );
204 		
205 		expressionPanel.add( scrollPane, BorderLayout.CENTER );
206 		expressionPanel.add( buildConditionToolbar(), BorderLayout.NORTH );
207 		expressionPanel.add( buildTargetToolbar(), BorderLayout.SOUTH );
208 		return expressionPanel;
209 	}
210 
211 	private JPanel buildConditionList()
212 	{
213 		listModel = new DefaultListModel();
214 		
215 		for( int c = 0; c < gotoStep.getConditionCount(); c++ )
216 		{
217 			listModel.addElement( gotoStep.getConditionAt( c  ).getName() );
218 		}
219 		
220 		conditionList = new JList( listModel );
221 		conditionList.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
222 		conditionList.addListSelectionListener( new ConditionListSelectionListener());
223 		
224 		JScrollPane listScrollPane = new JScrollPane( conditionList );
225 		UISupport.addTitledBorder( listScrollPane, "Conditions" );
226 		
227 		JPanel p = new JPanel( new BorderLayout() );
228 		p.add( buildConditionListToolbar(), BorderLayout.NORTH );
229 		p.add( listScrollPane, BorderLayout.CENTER );
230 		return p;
231 	}
232 
233 	private Component buildConditionListToolbar()
234 	{
235 		JXToolBar toolbar = UISupport.createSmallToolbar();
236 		
237 		addButton = UISupport.createToolbarButton( new AddAction() );
238 		toolbar.addFixed( addButton );
239 		copyButton = UISupport.createToolbarButton( new CopyAction() );
240 		copyButton.setEnabled( false );
241 		toolbar.addFixed( copyButton);
242 		deleteButton = UISupport.createToolbarButton( new DeleteAction() );
243 		deleteButton.setEnabled( false );
244 		toolbar.addFixed( deleteButton);
245 		renameButton = UISupport.createToolbarButton( new RenameAction() );
246 		renameButton.setEnabled( false );
247 		toolbar.addFixed( renameButton);
248 		return toolbar;
249 	}
250 
251 	private Component buildConditionToolbar()
252 	{
253 		JXToolBar toolbar = UISupport.createSmallToolbar();
254 		
255 		declareButton = UISupport.createToolbarButton( new DeclareNamespacesAction() );
256 		declareButton.setEnabled( false );
257 		toolbar.addFixed( declareButton);
258 		runButton = UISupport.createToolbarButton( new RunAction() );
259 		toolbar.addFixed( runButton);
260 		
261 		toolbar.addGlue();
262 		toolbar.addFixed( UISupport.createToolbarButton( new ShowOnlineHelpAction( HelpUrls.GOTOSTEPEDITOR_HELP_URL )));
263 		return toolbar;
264 	}
265 
266 	protected JXToolBar buildTargetToolbar()
267 	{
268 		JXToolBar builder = UISupport.createSmallToolbar();
269 		testStepsModel = new GotoTestStepsComboBoxModel( gotoStep.getTestCase(), null );
270 		testStepsCombo = new JComboBox( testStepsModel );
271 		testStepsCombo.setToolTipText( "The step the test case will go to if the current condition is true" );
272 		testStepsCombo.setEnabled( false );
273 		builder.addFixed( new JLabel( "<html><b>Target step:</b></html>"));
274 		builder.addRelatedGap();
275 		builder.addFixed( testStepsCombo );
276 		builder.addGlue();
277 		testConditionButton = new JButton( new TestConditionAction() );
278 		testConditionButton.setEnabled( false );
279 		builder.addFixed( testConditionButton);
280 		builder.setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ));
281 		return builder;
282 	}
283 	
284 	private final class SourceAreaDocumentListener extends DocumentListenerAdapter
285 	{
286 		@Override
287 		public void update( Document document )
288 		{
289 			int ix = conditionList.getSelectedIndex();
290 			if( ix != -1 )
291 			{
292 				gotoStep.getConditionAt( ix ).setExpression( expressionArea.getText() );
293 			}
294 		}
295 	}
296 	
297 	private final class ConditionListSelectionListener implements ListSelectionListener
298 	{
299 		public void valueChanged(ListSelectionEvent e)
300 		{
301 			int ix = conditionList.getSelectedIndex();
302 			if( ix == -1 )
303 			{
304 				expressionArea.setText( "" );
305 				testStepsModel.setCondition( null );
306 				currentCondition = null;
307 			}
308 			else
309 			{
310 				currentCondition = gotoStep.getConditionAt( ix );
311 				expressionArea.setText( currentCondition.getExpression() );
312 				testStepsModel.setCondition( currentCondition );
313 			}
314 
315 			boolean b = ix != -1;
316 			enableEditComponents( b );
317 		}
318 	}
319 
320 	private final class AddAction extends AbstractAction
321 	{
322 		public AddAction()
323 		{
324 			putValue( Action.SHORT_DESCRIPTION, "Adds a new Conditionr" );
325 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/add_property.gif" ));
326 		}
327 		
328 		public void actionPerformed(ActionEvent e)
329 		{
330 			String name = UISupport.prompt( "Specify name for condition", "Add Condition", "Condition " + 
331 					(gotoStep.getConditionCount()+1) );
332 			if( name == null || name.trim().length() == 0 ) return;
333 			
334 			gotoStep.addCondition( name );
335 			
336 			listModel.addElement( name );
337 			conditionList.setSelectedIndex( listModel.getSize()-1 );
338 		}
339 	}
340 	
341 	private final class CopyAction extends AbstractAction
342 	{
343 		public CopyAction()
344 		{
345 			putValue( Action.SHORT_DESCRIPTION, "Copies the selected Condition" );
346 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/clone_request.gif" ));
347 		}
348 		
349 		public void actionPerformed(ActionEvent e)
350 		{
351 			int ix = conditionList.getSelectedIndex();
352 			GotoCondition config = gotoStep.getConditionAt( ix );
353 			
354 			String name = UISupport.prompt( "Specify name for condition", "Copy Condition", config.getName() );
355 			if( name == null || name.trim().length() == 0 ) return;
356 			
357 			GotoCondition condition = gotoStep.addCondition( name );
358 			condition.setExpression( config.getExpression() );
359 			condition.setTargetStep( config.getTargetStep() );
360 			condition.setType( config.getType() );
361 			
362 			listModel.addElement( name );
363 			conditionList.setSelectedIndex( listModel.getSize()-1 );
364 		}
365 	}
366 	
367 	private final class DeleteAction extends AbstractAction
368 	{
369 		public DeleteAction()
370 		{
371 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/remove_property.gif" ));
372 			putValue( Action.SHORT_DESCRIPTION, "Deletes the selected Condition" );
373 		}
374 		
375 		public void actionPerformed(ActionEvent e)
376 		{
377 			if( UISupport.confirm( "Delete selected condition", "Delete Condition" )) 
378 			{
379 				int ix = conditionList.getSelectedIndex();
380 				
381 				conditionList.setSelectedIndex( -1 );
382 				
383 				gotoStep.removeConditionAt( ix );
384 				listModel.remove( ix );
385 				
386 				if( listModel.getSize() > 0 )
387 				{
388 					conditionList.setSelectedIndex( ix > listModel.getSize()-1 ? listModel.getSize()-1 : ix );
389 				}
390 			}
391 		}
392 	}
393 	
394 	private final class RenameAction extends AbstractAction
395 	{
396 		public RenameAction()
397 		{
398 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/rename.gif" ));
399 			putValue( Action.SHORT_DESCRIPTION, "Renames the selected Condition" );
400 		}
401 		
402 		public void actionPerformed(ActionEvent e)
403 		{
404 			int ix = conditionList.getSelectedIndex();
405 			GotoCondition config = gotoStep.getConditionAt( ix );
406 			
407 			String name = UISupport.prompt( "Specify name for condition", "Copy Condition", config.getName() );
408 			if( name == null || name.trim().length() == 0 ) return;
409 			
410 			config.setName( name );
411 			listModel.setElementAt( name, ix );
412 		}
413 	}
414 	
415 	private final class DeclareNamespacesAction extends AbstractAction
416 	{
417 		public DeclareNamespacesAction()
418 		{
419 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/declareNs.gif" ));
420 			putValue( Action.SHORT_DESCRIPTION, "Declare available response namespaces in condition expression" );
421 		}
422 		
423 		public void actionPerformed(ActionEvent e)
424 		{
425 			try
426 			{
427 				WsdlTestRequestStep previousStep = (WsdlTestRequestStep) gotoStep.getTestCase().findPreviousStepOfType( 
428 						gotoStep, WsdlTestRequestStep.class );
429 				
430 				if (previousStep  != null )
431 				{
432 					WsdlResponse response = previousStep.getTestRequest().getResponse();
433 					String xml = response == null ? null : response.getContentAsString();
434 					if ( xml != null && xml.trim().length() > 0)
435 					{
436 						expressionArea.setText(XmlUtils.declareXPathNamespaces(xml)
437 								+ expressionArea.getText());
438 					}
439 					else
440 					{
441 						UISupport.showErrorMessage( "Missing response in previous request step [" + previousStep.getName() + "]" );
442 					}
443 				}
444 				else
445 				{
446 					UISupport.showErrorMessage( "Missing previous request step" );
447 				}
448 			}
449 			catch (Exception e1)
450 			{
451 				SoapUI.logError( e1 );
452 			}
453 		}
454 	}
455 	
456 	private final class RunAction extends AbstractAction
457 	{
458 		public RunAction()
459 		{
460 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/run_all.gif" ));
461 			putValue( Action.SHORT_DESCRIPTION, "Runs the current conditions against the previous response" );
462 		}
463 		
464 		public void actionPerformed(ActionEvent e)
465 		{
466 			if( listModel.getSize() == 0 )
467 			{
468 				UISupport.showErrorMessage( "Missing conditions!" );
469 				return;
470 			}
471 
472 			WsdlTestRequestStep previousStep = (WsdlTestRequestStep) gotoStep.getTestCase().findPreviousStepOfType( 
473 					gotoStep, WsdlTestRequestStep.class );
474 			
475 			if( previousStep == null ) 
476 			{
477 				UISupport.showErrorMessage( "Missing previous request step" );
478 			}
479 			else
480 			{
481 				if( previousStep.getTestRequest().getResponse() == null || 
482 					 StringUtils.isNullOrEmpty( previousStep.getTestRequest().getResponse().getContentAsString()) )
483 				{
484 					UISupport.showErrorMessage( "Missing response in previous message" );
485 					return;
486 				}
487 				
488 				WsdlTestRunContext context = new WsdlTestRunContext( gotoStep );
489 				GotoCondition target = gotoStep.runConditions( previousStep, context );
490 				if( target == null )
491 				{
492 					logList.addLine( "No condition true for current response in [" + previousStep.getName() + "]" );
493 				}
494 				else
495 				{
496 					logList.addLine( "Condition triggered for go to [" + target.getTargetStep() + "]" );
497 				}
498 				
499 				inspectorPanel.setCurrentInspector( "Log" );
500 			}
501 		}
502 	}
503 	
504 	private final class TestConditionAction extends AbstractAction
505 	{
506 		public TestConditionAction()
507 		{
508 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/run.gif" ));
509 			putValue( Action.SHORT_DESCRIPTION, "Runs the current condition against the previous response and shows the result" );
510 		}
511 		
512 		public void actionPerformed(ActionEvent e)
513 		{
514 			WsdlTestRequestStep previousStep = (WsdlTestRequestStep) gotoStep.getTestCase().findPreviousStepOfType( 
515 					gotoStep, WsdlTestRequestStep.class );
516 			
517 			if( previousStep == null ) 
518 			{
519 				UISupport.showErrorMessage( "Missing previous request step" );
520 			}
521 			else
522 			{
523 				if( previousStep.getTestRequest().getResponse() == null || 
524 					 previousStep.getTestRequest().getResponse().getContentAsString().trim().length() == 0 )
525 				{
526 					UISupport.showErrorMessage( "Missing response in previous request step [" + 
527 							previousStep.getName() + "]" );
528 					return;
529 				}
530 				
531 				try
532 				{
533 					GotoCondition condition = gotoStep.getConditionAt( conditionList.getSelectedIndex() );
534 					WsdlTestRunContext context = new WsdlTestRunContext( gotoStep );
535 					boolean evaluate = condition.evaluate( previousStep, context );
536 					if( !evaluate )
537 					{
538 						UISupport.showInfoMessage( "Condition not true for current response in [" + previousStep.getName() + "]" );
539 					}
540 					else
541 					{
542 						UISupport.showInfoMessage( "Condition true for current response in [" + previousStep.getName() + "]" );
543 					}
544 				}
545 				catch (Exception e1)
546 				{
547 					UISupport.showErrorMessage( "Error checking condition: " + e1.getMessage() );
548 				}
549 			}
550 		}
551 	}
552 	
553 	public boolean onClose( boolean canCancel )
554 	{
555 		super.release();
556 		componentEnabler.release();
557 		gotoStep.getTestCase().removeTestRunListener( testRunListener );
558 
559 		return true;
560 	}
561 
562 	public JComponent getComponent()
563 	{
564 		return this;
565 	}
566 
567 	public boolean dependsOn(ModelItem modelItem)
568 	{
569 		return modelItem == gotoStep || modelItem == gotoStep.getTestCase() ||
570 				modelItem == gotoStep.getTestCase().getTestSuite() ||
571 				modelItem == gotoStep.getTestCase().getTestSuite().getProject();
572 	}
573 
574 	public GotoCondition getCurrentCondition()
575 	{
576 		return currentCondition;
577 	}
578 
579 	protected void enableEditComponents( boolean b )
580 	{
581 		expressionArea.setEnabled( b );
582 		testStepsCombo.setEnabled( b );
583 		copyButton.setEnabled( b );
584 		deleteButton.setEnabled( b );
585 		declareButton.setEnabled( b );
586 		testConditionButton.setEnabled( b );
587 		renameButton.setEnabled( b );
588 	}
589 	
590 	private class InternalTestRunListener extends TestRunListenerAdapter
591 	{
592 		@Override
593 		public void afterStep( TestRunner testRunner, TestRunContext runContext, TestStepResult result )
594 		{
595 			if( result.getTestStep() == gotoStep )
596 			{
597 				logList.addLine( new Date( result.getTimeStamp() ).toString() + ": " + result.getMessages()[0] );
598 				inspectorPanel.setCurrentInspector( "Log" );
599 			}
600 		}
601 	}
602 }