View Javadoc

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