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.event.ActionEvent;
18  import java.beans.PropertyChangeEvent;
19  import java.util.Date;
20  
21  import javax.swing.AbstractAction;
22  import javax.swing.Action;
23  import javax.swing.JButton;
24  import javax.swing.JComponent;
25  import javax.swing.JLabel;
26  import javax.swing.JPanel;
27  import javax.swing.JScrollPane;
28  import javax.swing.JSplitPane;
29  import javax.swing.JTextArea;
30  import javax.swing.JTextField;
31  import javax.swing.text.Document;
32  
33  import com.eviware.soapui.SoapUI;
34  import com.eviware.soapui.impl.support.components.ModelItemXmlEditor;
35  import com.eviware.soapui.impl.wsdl.mock.WsdlMockResponse;
36  import com.eviware.soapui.impl.wsdl.mock.WsdlMockResult;
37  import com.eviware.soapui.impl.wsdl.panels.mockoperation.AbstractWsdlMockResponseDesktopPanel;
38  import com.eviware.soapui.impl.wsdl.teststeps.WsdlMockResponseTestStep;
39  import com.eviware.soapui.model.ModelItem;
40  import com.eviware.soapui.model.propertyexpansion.PropertyExpander;
41  import com.eviware.soapui.model.support.TestRunListenerAdapter;
42  import com.eviware.soapui.model.testsuite.Assertable;
43  import com.eviware.soapui.model.testsuite.AssertionError;
44  import com.eviware.soapui.model.testsuite.AssertionsListener;
45  import com.eviware.soapui.model.testsuite.LoadTestRunner;
46  import com.eviware.soapui.model.testsuite.TestAssertion;
47  import com.eviware.soapui.model.testsuite.TestCaseRunContext;
48  import com.eviware.soapui.model.testsuite.TestCaseRunner;
49  import com.eviware.soapui.model.testsuite.TestStep;
50  import com.eviware.soapui.model.testsuite.TestStepResult;
51  import com.eviware.soapui.monitor.support.TestMonitorListenerAdapter;
52  import com.eviware.soapui.support.DocumentListenerAdapter;
53  import com.eviware.soapui.support.ModelItemPropertyEditorModel;
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.JXToolBar;
60  import com.eviware.soapui.support.xml.XmlUtils;
61  
62  public class WsdlMockResponseStepDesktopPanel extends
63  		AbstractWsdlMockResponseDesktopPanel<WsdlMockResponseTestStep, WsdlMockResponse>
64  {
65  	private JTextArea logArea;
66  	private AssertionsPanel assertionsPanel;
67  	private JTextField portField;
68  	private JTextField pathField;
69  	private InternalTestRunListener testRunListener;
70  	private InternalTestMonitorListener testMonitorListener = new InternalTestMonitorListener();
71  	private InternalAssertionsListener assertionsListener = new InternalAssertionsListener();
72  	private JInspectorPanel inspectorPanel;
73  	private JComponentInspector<JComponent> assertionInspector;
74  	private JComponentInspector<JComponent> logInspector;
75  	private ModelItemPropertyEditorModel<WsdlMockResponseTestStep> queryEditorModel;
76  	private ModelItemPropertyEditorModel<WsdlMockResponseTestStep> matchEditorModel;
77  
78  	public WsdlMockResponseStepDesktopPanel( WsdlMockResponseTestStep mockResponseStep )
79  	{
80  		super( mockResponseStep );
81  		init( mockResponseStep.getMockResponse() );
82  
83  		testRunListener = new InternalTestRunListener();
84  		mockResponseStep.getTestCase().addTestRunListener( testRunListener );
85  
86  		SoapUI.getTestMonitor().addTestMonitorListener( testMonitorListener );
87  		setEnabled( !SoapUI.getTestMonitor().hasRunningTest( mockResponseStep.getTestCase() ) );
88  		
89  		mockResponseStep.addAssertionsListener( assertionsListener );
90  	}
91  
92  	@Override
93  	protected JComponent buildContent()
94  	{
95  		inspectorPanel = JInspectorPanelFactory.build( super.buildContent() );
96  
97  		assertionsPanel = buildAssertionsPanel();
98  
99  		assertionInspector = new JComponentInspector<JComponent>( assertionsPanel, "Assertions ("
100 				+ getModelItem().getAssertionCount() + ")", "Assertions for this Test Request", true );
101 
102 		inspectorPanel.addInspector( assertionInspector );
103 
104 		logInspector = new JComponentInspector<JComponent>( buildLogPanel(), "Request Log (0)", "Log of requests", true );
105 		inspectorPanel.addInspector( logInspector );
106 
107 		inspectorPanel.addInspector( new JComponentInspector<JComponent>( buildQueryMatchPanel(), "Query/Match",
108 				"Query/Match configuration", true ) );
109 
110 		inspectorPanel.setDefaultDividerLocation( 0.6F );
111 		inspectorPanel.setCurrentInspector( "Assertions" );
112 
113 		updateStatusIcon();
114 
115 		return inspectorPanel.getComponent();
116 	}
117 
118 	private void updateStatusIcon()
119 	{
120 		Assertable.AssertionStatus status = getModelItem().getAssertionStatus();
121 		switch( status )
122 		{
123 		case FAILED :
124 		{
125 			assertionInspector.setIcon( UISupport.createImageIcon( "/failed_assertion.gif" ) );
126 			inspectorPanel.activate( assertionInspector );
127 			break;
128 		}
129 		case UNKNOWN :
130 		{
131 			assertionInspector.setIcon( UISupport.createImageIcon( "/unknown_assertion.gif" ) );
132 			break;
133 		}
134 		case VALID :
135 		{
136 			assertionInspector.setIcon( UISupport.createImageIcon( "/valid_assertion.gif" ) );
137 			inspectorPanel.deactivate();
138 			break;
139 		}
140 		}
141 	}
142 
143 	private JComponent buildLogPanel()
144 	{
145 		logArea = new JTextArea();
146 		logArea.setEditable( false );
147 		logArea.setToolTipText( "Response Log" );
148 
149 		JPanel panel = new JPanel( new BorderLayout() );
150 		panel.add( new JScrollPane( logArea ), BorderLayout.CENTER );
151 
152 		return panel;
153 	}
154 
155 	public void setContent( JComponent content )
156 	{
157 		inspectorPanel.setContentComponent( content );
158 	}
159 
160 	public void removeContent( JComponent content )
161 	{
162 		inspectorPanel.setContentComponent( null );
163 	}
164 
165 	@Override
166 	protected void createToolbar( JXToolBar toolbar )
167 	{
168 		toolbar.addUnrelatedGap();
169 		toolbar.addFixed( new JLabel( "Path" ) );
170 		toolbar.addRelatedGap();
171 		pathField = new JTextField( getModelItem().getPath(), 15 );
172 		pathField.getDocument().addDocumentListener( new DocumentListenerAdapter()
173 		{
174 
175 			@Override
176 			public void update( Document document )
177 			{
178 				getModelItem().setPath( pathField.getText() );
179 			}
180 		} );
181 
182 		toolbar.addFixed( pathField );
183 
184 		toolbar.addUnrelatedGap();
185 		toolbar.addFixed( new JLabel( "Port" ) );
186 		toolbar.addRelatedGap();
187 		portField = new JTextField( String.valueOf( getModelItem().getPort() ), 5 );
188 		portField.getDocument().addDocumentListener( new DocumentListenerAdapter()
189 		{
190 
191 			@Override
192 			public void update( Document document )
193 			{
194 				try
195 				{
196 					getModelItem().setPort( Integer.parseInt( portField.getText() ) );
197 				}
198 				catch( NumberFormatException e )
199 				{
200 				}
201 			}
202 		} );
203 
204 		toolbar.addFixed( portField );
205 	}
206 
207 	private JComponent buildQueryMatchPanel()
208 	{
209 		JPanel panel = new JPanel( new BorderLayout() );
210 		panel.add( buildQueryMatchToolbar(), BorderLayout.NORTH );
211 		JSplitPane splitPane = UISupport.createHorizontalSplit( buildQueryEditor(), buildMatchEditor() );
212 		panel.add( splitPane, BorderLayout.CENTER );
213 		splitPane.setDividerLocation( 200 );
214 		return panel;
215 	}
216 	
217 	private Component buildMatchEditor()
218 	{
219 		JPanel panel = new JPanel( new BorderLayout() );
220 
221 		matchEditorModel = new ModelItemPropertyEditorModel<WsdlMockResponseTestStep>( getModelItem(), "match" );
222 		panel.add( UISupport.getEditorFactory().buildXmlEditor( matchEditorModel ), BorderLayout.CENTER );
223 
224 		UISupport.addTitledBorder( panel, "Matching Value" );
225 
226 		return panel;
227 	}
228 
229 	private Component buildQueryEditor()
230 	{
231 		JPanel panel = new JPanel( new BorderLayout() );
232 
233 		queryEditorModel = new ModelItemPropertyEditorModel<WsdlMockResponseTestStep>( getModelItem(), "query" );
234 		panel.add( UISupport.getEditorFactory().buildXPathEditor( queryEditorModel ), BorderLayout.CENTER );
235 
236 		UISupport.addTitledBorder( panel, "XPath Query" );
237 
238 		return panel;
239 	}
240 
241 	protected JXToolBar buildQueryMatchToolbar()
242 	{
243 		JXToolBar toolBar = UISupport.createSmallToolbar();
244 		toolBar.addFixed( new JButton( new SelectFromCurrentAction() ) );
245 		return toolBar;
246 	}
247 	
248 	public class SelectFromCurrentAction extends AbstractAction
249 	{
250 		public SelectFromCurrentAction()
251 		{
252 			super( "Select from current" );
253 			putValue( Action.SHORT_DESCRIPTION,
254 					"Selects the Query XPath expression from the last request Match field" );
255 		}
256 
257 		public void actionPerformed( ActionEvent arg0 )
258 		{
259 			if( getModelItem().getLastResult() != null && 
260 					getModelItem().getLastResult().getMockRequest() != null && StringUtils.hasContent(  getModelItem().getQuery() ) )
261 			{
262 				getModelItem().setMatch( XmlUtils.getXPathValue( getModelItem().getLastResult().getMockRequest().getRequestContent(), 
263 						PropertyExpander.expandProperties( getModelItem(), getModelItem().getQuery() )));
264 			}
265 		}
266 	}
267 
268 	private AssertionsPanel buildAssertionsPanel()
269 	{
270 		assertionsPanel = new AssertionsPanel( getModelItem() )
271 		{
272 			protected void selectError( AssertionError error )
273 			{
274 				ModelItemXmlEditor<?, ?> editor = getResponseEditor();
275 				editor.requestFocus();
276 			}
277 		};
278 
279 		return assertionsPanel;
280 	}
281 
282 	@Override
283 	public boolean onClose( boolean canCancel )
284 	{
285 		getModelItem().getTestCase().removeTestRunListener( testRunListener );
286 		SoapUI.getTestMonitor().removeTestMonitorListener( testMonitorListener );
287 		assertionsPanel.release();
288 
289 		queryEditorModel.release();
290 		matchEditorModel.release();
291 
292 		inspectorPanel.release();
293 
294 		getModelItem().removeAssertionsListener( assertionsListener );
295 		return super.onClose( canCancel );
296 	}
297 
298 	public void setEnabled( boolean enabled )
299 	{
300 		super.setEnabled( enabled );
301 
302 		pathField.setEnabled( enabled );
303 		portField.setEnabled( enabled );
304 	}
305 
306 	public boolean dependsOn( ModelItem modelItem )
307 	{
308 		return modelItem == getModelItem() || modelItem == getModelItem().getTestCase()
309 				|| modelItem == getModelItem().getOperation() || modelItem == getModelItem().getOperation().getInterface()
310 				|| modelItem == getModelItem().getTestCase().getTestSuite()
311 				|| modelItem == getModelItem().getTestCase().getTestSuite().getProject();
312 	}
313 
314 	public class InternalTestRunListener extends TestRunListenerAdapter
315 	{
316 		@Override
317 		public void afterRun( TestCaseRunner testRunner, TestCaseRunContext runContext )
318 		{
319 			setEnabled( true );
320 		}
321 
322 		@Override
323 		public void beforeRun( TestCaseRunner testRunner, TestCaseRunContext runContext )
324 		{
325 			setEnabled( false );
326 		}
327 
328 		@Override
329 		public void beforeStep( TestCaseRunner testRunner, TestCaseRunContext runContext, TestStep testStep )
330 		{
331 			if( testStep == getModelItem() )
332 			{
333 				logArea.setText( logArea.getText() + new Date( System.currentTimeMillis() ).toString()
334 						+ ": Waiting for request on http://127.0.0.1:" + getModelItem().getPort() + getModelItem().getPath()
335 						+ "\r\n" );
336 			}
337 		}
338 
339 		@Override
340 		public void afterStep( TestCaseRunner testRunner, TestCaseRunContext runContext, TestStepResult result )
341 		{
342 			if( result.getTestStep() == getModelItem() )
343 			{
344 				String msg = new Date( result.getTimeStamp() ).toString() + ": Handled request in " + result.getTimeTaken()
345 						+ "ms";
346 				logArea.setText( logArea.getText() + msg + "\r\n" );
347 			}
348 		}
349 	}
350 
351 	private class InternalTestMonitorListener extends TestMonitorListenerAdapter
352 	{
353 		public void loadTestFinished( LoadTestRunner runner )
354 		{
355 			setEnabled( !SoapUI.getTestMonitor().hasRunningTest( getModelItem().getTestCase() ) );
356 		}
357 
358 		public void loadTestStarted( LoadTestRunner runner )
359 		{
360 			if( runner.getLoadTest().getTestCase() == getModelItem().getTestCase() )
361 				setEnabled( false );
362 		}
363 
364 		public void testCaseFinished( TestCaseRunner runner )
365 		{
366 			setEnabled( !SoapUI.getTestMonitor().hasRunningTest( getModelItem().getTestCase() ) );
367 		}
368 
369 		public void testCaseStarted( TestCaseRunner runner )
370 		{
371 			if( runner.getTestCase() == getModelItem().getTestCase() )
372 				setEnabled( false );
373 		}
374 	}
375 
376 	public void propertyChange( PropertyChangeEvent evt )
377 	{
378 		super.propertyChange( evt );
379 		
380 		if( evt.getPropertyName().equals( WsdlMockResponseTestStep.STATUS_PROPERTY ) )
381 			updateStatusIcon();
382 	}
383 
384 	@SuppressWarnings("unused")
385 	private final class DeclareNamespacesAction extends AbstractAction
386 	{
387 		public DeclareNamespacesAction()
388 		{
389 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/declareNs.gif" ) );
390 			putValue( Action.SHORT_DESCRIPTION,
391 					"Declare available response/request namespaces in source/target expressions" );
392 		}
393 
394 		public void actionPerformed( ActionEvent e )
395 		{
396 			try
397 			{
398 				WsdlMockResult lastResult = getMockResponse().getMockResult();
399 				String content = null;
400 				if( lastResult == null )
401 				{
402 					if( !UISupport.confirm( "Missing last result, declare from default request instead?",
403 							"Declare Namespaces" ) )
404 					{
405 						return;
406 					}
407 
408 					content = getMockResponse().getMockOperation().getOperation().createRequest( true );
409 				}
410 				else
411 				{
412 					content = lastResult.getMockRequest().getRequestContent();
413 				}
414 
415 				String path = getModelItem().getQuery();
416 				if( path == null )
417 					path = "";
418 
419 				getModelItem().setQuery( XmlUtils.declareXPathNamespaces( content ) + path );
420 			}
421 			catch( Exception e1 )
422 			{
423 				UISupport.showErrorMessage( e1 );
424 			}
425 		}
426 	}
427 
428 	private final class InternalAssertionsListener implements AssertionsListener
429 	{
430 		public void assertionAdded( TestAssertion assertion )
431 		{
432 			assertionInspector.setTitle( "Assertions (" + getModelItem().getAssertionCount() + ")" );
433 		}
434 
435 		public void assertionRemoved( TestAssertion assertion )
436 		{
437 			assertionInspector.setTitle( "Assertions (" + getModelItem().getAssertionCount() + ")" );
438 		}
439 
440 		public void assertionMoved( TestAssertion assertion, int ix, int offset )
441 		{
442 			assertionInspector.setTitle( "Assertions (" + getModelItem().getAssertionCount() + ")" );
443 		}
444 	}
445 }