View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2010 eviware.com
3    */
4   
5   package com.eviware.soapui.impl.wsdl.panels.teststeps.amf;
6   
7   import java.awt.BorderLayout;
8   import java.awt.Dimension;
9   import java.awt.dnd.DnDConstants;
10  import java.awt.dnd.DropTarget;
11  import java.awt.event.ActionEvent;
12  import java.awt.event.FocusAdapter;
13  import java.awt.event.FocusEvent;
14  import java.awt.event.FocusListener;
15  import java.beans.PropertyChangeEvent;
16  import java.beans.PropertyChangeListener;
17  import java.util.ArrayList;
18  import java.util.HashMap;
19  import java.util.List;
20  
21  import javax.swing.AbstractAction;
22  import javax.swing.Action;
23  import javax.swing.BorderFactory;
24  import javax.swing.Box;
25  import javax.swing.DefaultCellEditor;
26  import javax.swing.JButton;
27  import javax.swing.JComponent;
28  import javax.swing.JLabel;
29  import javax.swing.JPanel;
30  import javax.swing.JSplitPane;
31  import javax.swing.JTabbedPane;
32  import javax.swing.JTable;
33  import javax.swing.JTextField;
34  import javax.swing.JToggleButton;
35  import javax.swing.SwingUtilities;
36  import javax.swing.TransferHandler;
37  import javax.swing.event.ChangeEvent;
38  import javax.swing.event.ChangeListener;
39  import javax.swing.event.ListSelectionEvent;
40  import javax.swing.event.ListSelectionListener;
41  import javax.swing.text.Document;
42  
43  import org.apache.log4j.Logger;
44  
45  import com.eviware.soapui.SoapUI;
46  import com.eviware.soapui.config.AMFRequestTestStepConfig;
47  import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
48  import com.eviware.soapui.impl.support.components.ModelItemXmlEditor;
49  import com.eviware.soapui.impl.support.components.RequestMessageXmlEditor;
50  import com.eviware.soapui.impl.support.components.ResponseMessageXmlEditor;
51  import com.eviware.soapui.impl.support.panels.AbstractHttpRequestDesktopPanel;
52  import com.eviware.soapui.impl.wsdl.panels.support.TestRunComponentEnabler;
53  import com.eviware.soapui.impl.wsdl.panels.teststeps.AssertionsPanel;
54  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.DefaultPropertyTableHolderModel;
55  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.GroovyEditor;
56  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.GroovyEditorModel;
57  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.PropertyHolderTable;
58  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
59  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
60  import com.eviware.soapui.impl.wsdl.teststeps.AMFRequestTestStep;
61  import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStepWithProperties;
62  import com.eviware.soapui.impl.wsdl.teststeps.actions.AddAssertionAction;
63  import com.eviware.soapui.model.ModelItem;
64  import com.eviware.soapui.model.iface.Submit;
65  import com.eviware.soapui.model.iface.SubmitContext;
66  import com.eviware.soapui.model.iface.SubmitListener;
67  import com.eviware.soapui.model.iface.Request.SubmitException;
68  import com.eviware.soapui.model.iface.Submit.Status;
69  import com.eviware.soapui.model.settings.Settings;
70  import com.eviware.soapui.model.testsuite.Assertable;
71  import com.eviware.soapui.model.testsuite.AssertionsListener;
72  import com.eviware.soapui.model.testsuite.LoadTestRunner;
73  import com.eviware.soapui.model.testsuite.TestAssertion;
74  import com.eviware.soapui.model.testsuite.TestCaseRunner;
75  import com.eviware.soapui.model.testsuite.Assertable.AssertionStatus;
76  import com.eviware.soapui.monitor.support.TestMonitorListenerAdapter;
77  import com.eviware.soapui.settings.UISettings;
78  import com.eviware.soapui.support.DocumentListenerAdapter;
79  import com.eviware.soapui.support.StringUtils;
80  import com.eviware.soapui.support.UISupport;
81  import com.eviware.soapui.support.actions.ChangeSplitPaneOrientationAction;
82  import com.eviware.soapui.support.components.JComponentInspector;
83  import com.eviware.soapui.support.components.JEditorStatusBarWithProgress;
84  import com.eviware.soapui.support.components.JInspectorPanel;
85  import com.eviware.soapui.support.components.JInspectorPanelFactory;
86  import com.eviware.soapui.support.components.JUndoableTextField;
87  import com.eviware.soapui.support.components.JXToolBar;
88  import com.eviware.soapui.support.components.SimpleForm;
89  import com.eviware.soapui.support.editor.Editor;
90  import com.eviware.soapui.support.editor.EditorView;
91  import com.eviware.soapui.support.editor.support.AbstractEditorView;
92  import com.eviware.soapui.support.editor.xml.support.AbstractXmlDocument;
93  import com.eviware.soapui.support.propertyexpansion.PropertyExpansionPopupListener;
94  import com.eviware.soapui.support.scripting.SoapUIScriptEngine;
95  import com.eviware.soapui.support.scripting.SoapUIScriptEngineRegistry;
96  import com.eviware.soapui.support.swing.SoapUISplitPaneUI;
97  import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
98  
99  @SuppressWarnings( "serial" )
100 public class AMFRequestTestStepDesktopPanel extends ModelItemDesktopPanel<AMFRequestTestStep> implements SubmitListener
101 {
102 	private static final String ENDPOINT = "Endpoint";
103 	private static final String AMF_CALL = "AMF Call";
104 	private final static Logger log = Logger.getLogger( AbstractHttpRequestDesktopPanel.class );
105 	private JPanel configPanel;
106 	private JButton addAssertionButton;
107 	private JInspectorPanel inspectorPanel;
108 	private AMFRequestTestStep amfRequestTestStep;
109 	protected AMFRequestTestStepConfig amfRequestTestStepConfig;
110 	private JComponentInspector<?> assertionInspector;
111 	private AssertionsPanel assertionsPanel;
112 	private InternalAssertionsListener assertionsListener = new InternalAssertionsListener();
113 	private InternalTestMonitorListener testMonitorListener = new InternalTestMonitorListener();
114 	private JComponent requestEditor;
115 	private ModelItemXmlEditor<?, ?> responseEditor;
116 	private Submit submit;
117 	private JButton submitButton;
118 	private JToggleButton tabsButton;
119 	private JTabbedPane requestTabs;
120 	private JPanel requestTabPanel;
121 	private boolean responseHasFocus;
122 	private JSplitPane requestSplitPane;
123 	private JEditorStatusBarWithProgress statusBar;
124 	private JButton cancelButton;
125 	private JButton splitButton;
126 	private JComponent propertiesTableComponent;
127 	private SoapUIScriptEngine scriptEngine;
128 	private RunAction runAction = new RunAction();
129 	private GroovyEditor groovyEditor;
130 	private JTextField amfCallField;
131 	public boolean updating;
132 	SimpleForm configForm;
133 	private JTextField endpointField;
134 	private TestRunComponentEnabler componentEnabler;
135 	protected PropertyHolderTable propertyHolderTable;
136 
137 	public AMFRequestTestStepDesktopPanel( AMFRequestTestStep modelItem )
138 	{
139 		super( modelItem );
140 		amfRequestTestStep = modelItem;
141 		componentEnabler = new TestRunComponentEnabler( amfRequestTestStep.getTestCase() );
142 		initConfig();
143 		initContent();
144 
145 		SoapUI.getTestMonitor().addTestMonitorListener( testMonitorListener );
146 		setEnabled( !SoapUI.getTestMonitor().hasRunningTest( amfRequestTestStep.getTestCase() ) );
147 
148 		amfRequestTestStep.addAssertionsListener( assertionsListener );
149 
150 		scriptEngine = SoapUIScriptEngineRegistry.create( modelItem );
151 		scriptEngine.setScript( amfRequestTestStep.getScript() );
152 
153 	}
154 
155 	protected void initConfig()
156 	{
157 		amfRequestTestStepConfig = amfRequestTestStep.getAMFRequestTestStepConfig();
158 	}
159 
160 	private JComponent buildContent()
161 	{
162 		requestSplitPane = UISupport.createHorizontalSplit();
163 		requestSplitPane.setResizeWeight( 0.5 );
164 		requestSplitPane.setBorder( null );
165 
166 		JComponent content;
167 		submitButton = createActionButton( new SubmitAction(), true );
168 		submitButton.setEnabled( enableSubmit() );
169 		cancelButton = createActionButton( new CancelAction(), false );
170 		tabsButton = new JToggleButton( new ChangeToTabsAction() );
171 		tabsButton.setPreferredSize( UISupport.TOOLBAR_BUTTON_DIMENSION );
172 		splitButton = createActionButton( new ChangeSplitPaneOrientationAction( requestSplitPane ), true );
173 
174 		addAssertionButton = UISupport.createToolbarButton( new AddAssertionAction( amfRequestTestStep ) );
175 		addAssertionButton.setEnabled( true );
176 
177 		requestTabs = new JTabbedPane();
178 		requestTabs.setTabPlacement( JTabbedPane.LEFT );
179 		requestTabs.addChangeListener( new ChangeListener()
180 		{
181 
182 			public void stateChanged( ChangeEvent e )
183 			{
184 				SwingUtilities.invokeLater( new Runnable()
185 				{
186 
187 					public void run()
188 					{
189 						int ix = requestTabs.getSelectedIndex();
190 						if( ix == 0 )
191 							requestEditor.requestFocus();
192 						else if( ix == 1 && responseEditor != null )
193 							responseEditor.requestFocus();
194 					}
195 				} );
196 			}
197 		} );
198 
199 		addFocusListener( new FocusAdapter()
200 		{
201 
202 			@Override
203 			public void focusGained( FocusEvent e )
204 			{
205 				if( requestTabs.getSelectedIndex() == 1 || responseHasFocus )
206 					responseEditor.requestFocusInWindow();
207 				else
208 					requestEditor.requestFocusInWindow();
209 			}
210 		} );
211 
212 		requestTabPanel = UISupport.createTabPanel( requestTabs, true );
213 
214 		requestEditor = ( JComponent )buildRequestConfigPanel();
215 		responseEditor = buildResponseEditor();
216 		if( amfRequestTestStep.getSettings().getBoolean( UISettings.START_WITH_REQUEST_TABS ) )
217 		{
218 			requestTabs.addTab( "Request", requestEditor );
219 			if( responseEditor != null )
220 				requestTabs.addTab( "Response", responseEditor );
221 			tabsButton.setSelected( true );
222 			splitButton.setEnabled( false );
223 
224 			content = requestTabPanel;
225 		}
226 		else
227 		{
228 			requestSplitPane.setTopComponent( requestEditor );
229 			requestSplitPane.setBottomComponent( responseEditor );
230 			requestSplitPane.setDividerLocation( 0.5 );
231 			content = requestSplitPane;
232 		}
233 
234 		inspectorPanel = JInspectorPanelFactory.build( content );
235 		inspectorPanel.setDefaultDividerLocation( 0.7F );
236 		add( buildToolbar(), BorderLayout.NORTH );
237 		add( inspectorPanel.getComponent(), BorderLayout.CENTER );
238 		assertionsPanel = buildAssertionsPanel();
239 
240 		assertionInspector = new JComponentInspector<JComponent>( assertionsPanel, "Assertions ("
241 				+ getModelItem().getAssertionCount() + ")", "Assertions for this Test Request", true );
242 
243 		inspectorPanel.addInspector( assertionInspector );
244 		// setPreferredSize(new Dimension(600, 450));
245 
246 		updateStatusIcon();
247 
248 		return inspectorPanel.getComponent();
249 	}
250 
251 	@SuppressWarnings( "unchecked" )
252 	protected JComponent buildRequestConfigPanel()
253 	{
254 		ModelItemXmlEditor<?, ?> reqEditor = buildRequestEditor();
255 
256 		configPanel = UISupport.addTitledBorder( new JPanel( new BorderLayout() ), "Script" );
257 		configPanel.add( buildToolbarButtonAndText(), BorderLayout.NORTH );
258 		groovyEditor = ( GroovyEditor )UISupport.getEditorFactory().buildGroovyEditor( new ScriptStepGroovyEditorModel() );
259 		configPanel.add( groovyEditor, BorderLayout.CENTER );
260 		propertiesTableComponent = buildProperties();
261 		final JSplitPane split = UISupport.createVerticalSplit( propertiesTableComponent, configPanel );
262 		split.setDividerLocation( 120 );
263 		reqEditor.addEditorView( ( EditorView )new AbstractEditorView<AMFRequestDocument>( "AMF",
264 				( Editor<AMFRequestDocument> )reqEditor, "amf" )
265 		{
266 			@Override
267 			public JComponent buildUI()
268 			{
269 				return split;
270 			}
271 		} );
272 		reqEditor.selectView( 1 );
273 		return reqEditor;
274 	}
275 
276 	private JComponent buildToolbarButtonAndText()
277 	{
278 		JXToolBar toolBar = UISupport.createToolbar();
279 		JButton runButton = UISupport.createToolbarButton( runAction );
280 		toolBar.add( runButton );
281 		toolBar.add( Box.createHorizontalGlue() );
282 		JLabel label = new JLabel( "<html>Script is invoked with <code>log</code>, <code>context</code> "
283 				+ ", <code>parameters</code> and <code>amfHeaders</code> variables</html>" );
284 		label.setToolTipText( label.getText() );
285 		label.setMinimumSize( label.getPreferredSize() );
286 		label.setMaximumSize( label.getPreferredSize() );
287 
288 		toolBar.add( label );
289 		toolBar.addRelatedGap();
290 		toolBar.add( UISupport.createToolbarButton( new ShowOnlineHelpAction( HelpUrls.GROOVYSTEPEDITOR_HELP_URL ) ) );
291 
292 		componentEnabler.add( runButton );
293 
294 		return toolBar;
295 	}
296 
297 	protected JComponent buildToolbar()
298 	{
299 
300 		JPanel panel = new JPanel( new BorderLayout() );
301 		panel.add( buildToolbar1(), BorderLayout.NORTH );
302 		panel.add( buildToolbar2(), BorderLayout.SOUTH );
303 		return panel;
304 
305 	}
306 
307 	protected void initContent()
308 	{
309 		amfRequestTestStep.getAMFRequest().addSubmitListener( this );
310 
311 		add( buildContent(), BorderLayout.CENTER );
312 		add( buildToolbar(), BorderLayout.NORTH );
313 		add( buildStatusLabel(), BorderLayout.SOUTH );
314 
315 		setPreferredSize( new Dimension( 600, 500 ) );
316 
317 		addFocusListener( new FocusAdapter()
318 		{
319 
320 			@Override
321 			public void focusGained( FocusEvent e )
322 			{
323 				if( requestTabs.getSelectedIndex() == 1 || responseHasFocus )
324 					responseEditor.requestFocusInWindow();
325 				else
326 					requestEditor.requestFocusInWindow();
327 			}
328 		} );
329 	}
330 
331 	protected JComponent buildStatusLabel()
332 	{
333 		statusBar = new JEditorStatusBarWithProgress();
334 		statusBar.setBorder( BorderFactory.createEmptyBorder( 1, 0, 0, 0 ) );
335 
336 		return statusBar;
337 	}
338 
339 	protected JComponent buildProperties()
340 	{
341 		propertyHolderTable = new PropertyHolderTable( getModelItem() )
342 		{
343 			protected JTable buildPropertiesTable()
344 			{
345 				propertiesModel = new DefaultPropertyTableHolderModel( holder )
346 				{
347 					@Override
348 					public String[] getPropertyNames()
349 					{
350 						List<String> propertyNamesList = new ArrayList<String>();
351 						for( String name : holder.getPropertyNames() )
352 						{
353 							if( name.equals( WsdlTestStepWithProperties.RESPONSE_AS_XML ) )
354 							{
355 								continue;
356 							}
357 							propertyNamesList.add( name );
358 						}
359 						return propertyNamesList.toArray( new String[propertyNamesList.size()] );
360 					}
361 				};
362 				propertiesTable = new PropertiesHolderJTable();
363 				propertiesTable.setSurrendersFocusOnKeystroke( true );
364 
365 				propertiesTable.putClientProperty( "terminateEditOnFocusLost", Boolean.TRUE );
366 				propertiesTable.getSelectionModel().addListSelectionListener( new ListSelectionListener()
367 				{
368 					public void valueChanged( ListSelectionEvent e )
369 					{
370 						int selectedRow = propertiesTable.getSelectedRow();
371 						if( removePropertyAction != null )
372 							removePropertyAction.setEnabled( selectedRow != -1 );
373 
374 						if( movePropertyUpAction != null )
375 							movePropertyUpAction.setEnabled( selectedRow > 0 );
376 
377 						if( movePropertyDownAction != null )
378 							movePropertyDownAction.setEnabled( selectedRow >= 0
379 									&& selectedRow < propertiesTable.getRowCount() - 1 );
380 					}
381 				} );
382 
383 				propertiesTable.setDragEnabled( true );
384 				propertiesTable.setTransferHandler( new TransferHandler( "testProperty" ) );
385 
386 				if( getHolder().getModelItem() != null )
387 				{
388 					DropTarget dropTarget = new DropTarget( propertiesTable,
389 							new PropertyHolderTablePropertyExpansionDropTarget() );
390 					dropTarget.setDefaultActions( DnDConstants.ACTION_COPY_OR_MOVE );
391 				}
392 
393 				return propertiesTable;
394 			}
395 		};
396 
397 		JUndoableTextField textField = new JUndoableTextField( true );
398 
399 		PropertyExpansionPopupListener.enable( textField, getModelItem() );
400 		propertyHolderTable.getPropertiesTable().setDefaultEditor( String.class, new DefaultCellEditor( textField ) );
401 
402 		return propertyHolderTable;
403 	}
404 
405 	protected JComponent buildToolbar1()
406 	{
407 		JXToolBar toolbar = UISupport.createToolbar();
408 
409 		toolbar.setBorder( BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) );
410 
411 		toolbar.addFixed( submitButton );
412 		toolbar.add( cancelButton );
413 		toolbar.addFixed( addAssertionButton );
414 
415 		toolbar.add( Box.createHorizontalGlue() );
416 		toolbar.add( tabsButton );
417 		toolbar.add( splitButton );
418 
419 		toolbar.addFixed( UISupport
420 				.createToolbarButton( new ShowOnlineHelpAction( HelpUrls.TRANSFERSTEPEDITOR_HELP_URL ) ) );
421 
422 		return toolbar;
423 
424 	}
425 
426 	protected JComponent buildToolbar2()
427 	{
428 		JXToolBar toolbar = UISupport.createToolbar();
429 
430 		toolbar.setBorder( BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) );
431 
432 		toolbar.addLabeledFixed( ENDPOINT, addEndpointField() );
433 		toolbar.addSeparator();
434 		toolbar.addLabeledFixed( AMF_CALL, addAmfCallField() );
435 
436 		return toolbar;
437 
438 	}
439 
440 	public AMFRequestTestStep getAMFRequestTestStep()
441 	{
442 		return amfRequestTestStep;
443 	}
444 
445 	protected AssertionsPanel buildAssertionsPanel()
446 	{
447 		return new AMFAssertionsPanel( amfRequestTestStep )
448 		{
449 		};
450 	}
451 
452 	protected class AMFAssertionsPanel extends AssertionsPanel
453 	{
454 		public AMFAssertionsPanel( Assertable assertable )
455 		{
456 			super( assertable );
457 		}
458 	}
459 
460 	private JTextField addAmfCallField()
461 	{
462 		amfCallField = new JTextField();
463 		amfCallField.setText( amfRequestTestStep.getAmfCall() );
464 		amfCallField.setColumns( 20 );
465 		amfCallField.setToolTipText( "object.methodName for amf method call" );
466 		PropertyExpansionPopupListener.enable( amfCallField, amfRequestTestStep );
467 		addAmfCallDocumentListener();
468 		return amfCallField;
469 	}
470 
471 	private JTextField addEndpointField()
472 	{
473 		endpointField = new JTextField();
474 		endpointField.setText( amfRequestTestStep.getEndpoint() );
475 		endpointField.setColumns( 35 );
476 		endpointField.setToolTipText( "http to connect" );
477 		PropertyExpansionPopupListener.enable( endpointField, amfRequestTestStep );
478 		addEndpointCallDocumentListener();
479 		return endpointField;
480 	}
481 
482 	protected void addAmfCallDocumentListener()
483 	{
484 		amfCallField.getDocument().addDocumentListener( new DocumentListenerAdapter()
485 		{
486 			@Override
487 			public void update( Document document )
488 			{
489 				if( !updating )
490 				{
491 					amfRequestTestStep.setAmfCall( amfCallField.getText() );
492 				}
493 			}
494 		} );
495 	}
496 
497 	protected void addEndpointCallDocumentListener()
498 	{
499 		endpointField.getDocument().addDocumentListener( new DocumentListenerAdapter()
500 		{
501 			@Override
502 			public void update( Document document )
503 			{
504 				if( !updating )
505 				{
506 					amfRequestTestStep.setEndpoint( endpointField.getText() );
507 				}
508 			}
509 		} );
510 	}
511 
512 	protected boolean enableSubmit()
513 	{
514 		return !StringUtils.isNullOrEmpty( amfRequestTestStep.getEndpoint() )
515 				&& !StringUtils.isNullOrEmpty( amfRequestTestStep.getAmfCall() );
516 	}
517 
518 	private class ScriptStepGroovyEditorModel implements GroovyEditorModel
519 	{
520 		public String[] getKeywords()
521 		{
522 			return new String[] { "log", "context", "property" };
523 		}
524 
525 		public Action getRunAction()
526 		{
527 			return runAction;
528 		}
529 
530 		public String getScript()
531 		{
532 			return amfRequestTestStep.getScript();
533 		}
534 
535 		public void setScript( String text )
536 		{
537 			if( updating )
538 				return;
539 
540 			updating = true;
541 			amfRequestTestStep.setScript( text );
542 			updating = false;
543 		}
544 
545 		public Settings getSettings()
546 		{
547 			return SoapUI.getSettings();
548 		}
549 
550 		public String getScriptName()
551 		{
552 			return null;
553 		}
554 
555 		public void addPropertyChangeListener( PropertyChangeListener listener )
556 		{
557 		}
558 
559 		public void removePropertyChangeListener( PropertyChangeListener listener )
560 		{
561 		}
562 
563 		public ModelItem getModelItem()
564 		{
565 			return amfRequestTestStep;
566 		}
567 	}
568 
569 	private class RunAction extends AbstractAction
570 	{
571 		public RunAction()
572 		{
573 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/run_groovy_script.gif" ) );
574 			putValue( Action.SHORT_DESCRIPTION,
575 					"Runs this script in a seperate thread using a mock testRunner and testContext" );
576 		}
577 
578 		public void actionPerformed( ActionEvent e )
579 		{
580 			SoapUI.getThreadPool().execute( new Runnable()
581 			{
582 				public void run()
583 				{
584 					SubmitContext context = new WsdlTestRunContext( getModelItem() );
585 					statusBar.setIndeterminate( true );
586 					amfRequestTestStep.initAmfRequest( context );
587 
588 					if( context.getProperty( AMFRequest.AMF_SCRIPT_ERROR ) != null )
589 					{
590 						UISupport.showInfoMessage( ( ( Throwable )context.getProperty( AMFRequest.AMF_SCRIPT_ERROR ) )
591 								.getMessage() );
592 					}
593 					else
594 					{
595 						UISupport.showInfoMessage( scriptInfo( context ) );
596 
597 					}
598 					statusBar.setIndeterminate( false );
599 					amfRequestTestStep.getAMFRequest().clearArguments();
600 				}
601 
602 				@SuppressWarnings( "unchecked" )
603 				private String scriptInfo( SubmitContext context )
604 				{
605 					HashMap<String, Object> parameters = ( HashMap<String, Object> )context
606 							.getProperty( AMFRequest.AMF_SCRIPT_PARAMETERS );
607 					HashMap<String, Object> amfHeaders = ( HashMap<String, Object> )context
608 							.getProperty( AMFRequest.AMF_SCRIPT_HEADERS );
609 					StringBuilder sb = new StringBuilder();
610 					sb.append( "parameters " + ( parameters != null ? parameters.toString() : "" ) );
611 					sb.append( "\n" );
612 					sb.append( "amfHeaders " + ( amfHeaders != null ? amfHeaders.toString() : "" ) );
613 					return sb.toString();
614 				}
615 			} );
616 		}
617 
618 	}
619 
620 	protected ModelItemXmlEditor<?, ?> buildResponseEditor()
621 	{
622 		return new AMFResponseMessageEditor();
623 	}
624 
625 	protected ModelItemXmlEditor<?, ?> buildRequestEditor()
626 	{
627 		return new AMFRequestMessageEditor();
628 	}
629 
630 	public class AMFResponseMessageEditor extends ResponseMessageXmlEditor<AMFRequestTestStep, AMFResponseDocument>
631 	{
632 		public AMFResponseMessageEditor()
633 		{
634 			super( new AMFResponseDocument(), amfRequestTestStep );
635 		}
636 
637 		@Override
638 		public void release()
639 		{
640 			getDocument().release();
641 			super.release();
642 		}
643 	}
644 
645 	public class AMFRequestMessageEditor extends RequestMessageXmlEditor<AMFRequestTestStep, AMFRequestDocument>
646 	{
647 		public AMFRequestMessageEditor()
648 		{
649 			super( new AMFRequestDocument(), amfRequestTestStep );
650 		}
651 
652 		@Override
653 		public void release()
654 		{
655 			getDocument().release();
656 			super.release();
657 		}
658 
659 	}
660 
661 	public boolean dependsOn( ModelItem modelItem )
662 	{
663 		return modelItem == getModelItem() || modelItem == getModelItem().getTestCase()
664 				|| modelItem == getModelItem().getTestCase().getTestSuite()
665 				|| modelItem == getModelItem().getTestCase().getTestSuite().getProject();
666 	}
667 
668 	public boolean onClose( boolean canCancel )
669 	{
670 		configPanel.removeAll();
671 		inspectorPanel.release();
672 
673 		requestEditor.removeAll();
674 		( ( ModelItemXmlEditor<?, ?> )requestEditor ).release();
675 		responseEditor.release();
676 		responseEditor.removeAll();
677 		responseEditor = null;
678 		assertionsPanel.release();
679 		SoapUI.getTestMonitor().removeTestMonitorListener( testMonitorListener );
680 		amfRequestTestStep.removeAssertionsListener( assertionsListener );
681 		amfRequestTestStep.getAMFRequest().removeSubmitListener( this );
682 		componentEnabler.release();
683 		groovyEditor.release();
684 		amfRequestTestStep.release();
685 		propertyHolderTable.release();
686 		this.removeAll();
687 		return release();
688 	}
689 
690 	public class AMFResponseDocument extends AbstractXmlDocument implements PropertyChangeListener
691 	{
692 		public AMFResponseDocument()
693 		{
694 			amfRequestTestStep.addPropertyChangeListener( AMFRequestTestStep.RESPONSE_PROPERTY, this );
695 		}
696 
697 		public void propertyChange( PropertyChangeEvent evt )
698 		{
699 			fireXmlChanged( evt.getOldValue() == null ? null : ( ( AMFResponse )evt.getOldValue() ).getContentAsString(),
700 					getXml() );
701 		}
702 
703 		public String getXml()
704 		{
705 			AMFResponse response = amfRequestTestStep.getAMFRequest().getResponse();
706 			return response == null ? null : response.getResponseContentXML();
707 		}
708 
709 		public void setXml( String xml )
710 		{
711 			if( amfRequestTestStep.getAMFRequest().getResponse() != null )
712 				amfRequestTestStep.getAMFRequest().getResponse().setResponseContentXML( xml );
713 		}
714 
715 		public void release()
716 		{
717 			super.release();
718 			amfRequestTestStep.removePropertyChangeListener( AMFRequestTestStep.RESPONSE_PROPERTY, this );
719 		}
720 	}
721 
722 	public class AMFRequestDocument extends AbstractXmlDocument implements PropertyChangeListener
723 	{
724 		public AMFRequestDocument()
725 		{
726 			amfRequestTestStep.addPropertyChangeListener( AMFRequestTestStep.REQUEST_PROPERTY, this );
727 		}
728 
729 		public void propertyChange( PropertyChangeEvent evt )
730 		{
731 			fireXmlChanged( evt.getOldValue() == null ? null : ( ( AMFRequest )evt.getOldValue() ).requestAsXML(),
732 					getXml() );
733 		}
734 
735 		public String getXml()
736 		{
737 			AMFRequest request = amfRequestTestStep.getAMFRequest();
738 			return request == null ? null : request.requestAsXML();
739 		}
740 
741 		public void setXml( String xml )
742 		{
743 		}
744 
745 		public void release()
746 		{
747 			super.release();
748 			amfRequestTestStep.removePropertyChangeListener( AMFRequestTestStep.REQUEST_PROPERTY, this );
749 		}
750 	}
751 
752 	private class InternalTestMonitorListener extends TestMonitorListenerAdapter
753 	{
754 		public void loadTestFinished( LoadTestRunner runner )
755 		{
756 			setEnabled( !SoapUI.getTestMonitor().hasRunningTest( getModelItem().getTestCase() ) );
757 		}
758 
759 		public void loadTestStarted( LoadTestRunner runner )
760 		{
761 			if( runner.getLoadTest().getTestCase() == getModelItem().getTestCase() )
762 				setEnabled( false );
763 		}
764 
765 		public void testCaseFinished( TestCaseRunner runner )
766 		{
767 			setEnabled( !SoapUI.getTestMonitor().hasRunningTest( getModelItem().getTestCase() ) );
768 		}
769 
770 		public void testCaseStarted( TestCaseRunner runner )
771 		{
772 			if( runner.getTestCase() == getModelItem().getTestCase() )
773 				setEnabled( false );
774 		}
775 	}
776 
777 	public class SubmitAction extends AbstractAction
778 	{
779 		public SubmitAction()
780 		{
781 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/submit_request.gif" ) );
782 			putValue( Action.SHORT_DESCRIPTION, "Submit request to specified endpoint URL" );
783 			putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "alt ENTER" ) );
784 		}
785 
786 		public void actionPerformed( ActionEvent e )
787 		{
788 			onSubmit();
789 		}
790 	}
791 
792 	protected void onSubmit()
793 	{
794 		if( submit != null && submit.getStatus() == Submit.Status.RUNNING )
795 		{
796 			if( UISupport.confirm( "Cancel current request?", "Submit Request" ) )
797 			{
798 				submit.cancel();
799 			}
800 			else
801 				return;
802 		}
803 
804 		try
805 		{
806 			submit = doSubmit();
807 		}
808 		catch( SubmitException e1 )
809 		{
810 			SoapUI.logError( e1 );
811 		}
812 	}
813 
814 	protected Submit doSubmit() throws SubmitException
815 	{
816 
817 		SubmitContext submitContext = new WsdlTestRunContext( getModelItem() );
818 		if( !amfRequestTestStep.initAmfRequest( submitContext ) )
819 		{
820 			throw new SubmitException( "AMF request is not initialised properly !" );
821 		}
822 
823 		return amfRequestTestStep.getAMFRequest().submit( submitContext, true );
824 	}
825 
826 	protected final class InputAreaFocusListener implements FocusListener
827 	{
828 		public InputAreaFocusListener( JComponent editor )
829 		{
830 		}
831 
832 		public void focusGained( FocusEvent e )
833 		{
834 			responseHasFocus = false;
835 
836 			// statusBar.setTarget(sourceEditor.getInputArea());
837 			if( !splitButton.isEnabled() )
838 			{
839 				requestTabs.setSelectedIndex( 0 );
840 				return;
841 			}
842 
843 			// if
844 			// (getModelItem().getSettings().getBoolean(UISettings.NO_RESIZE_REQUEST_EDITOR))
845 			// return;
846 
847 			// // dont resize if split has been dragged
848 			// if (requestSplitPane.getUI() instanceof SoapUISplitPaneUI
849 			// && ((SoapUISplitPaneUI) requestSplitPane.getUI()).hasBeenDragged())
850 			// return;
851 			//
852 			int pos = requestSplitPane.getDividerLocation();
853 			if( pos >= 600 )
854 				return;
855 			if( requestSplitPane.getMaximumDividerLocation() > 700 )
856 				requestSplitPane.setDividerLocation( 600 );
857 			else
858 				requestSplitPane.setDividerLocation( 0.8 );
859 		}
860 
861 		public void focusLost( FocusEvent e )
862 		{
863 		}
864 	}
865 
866 	protected final class ResultAreaFocusListener implements FocusListener
867 	{
868 		@SuppressWarnings( "unused" )
869 		private final ModelItemXmlEditor<?, ?> responseEditor;
870 
871 		public ResultAreaFocusListener( ModelItemXmlEditor<?, ?> editor )
872 		{
873 			this.responseEditor = editor;
874 		}
875 
876 		public void focusGained( FocusEvent e )
877 		{
878 			responseHasFocus = true;
879 
880 			// statusBar.setTarget(sourceEditor.getInputArea());
881 			if( !splitButton.isEnabled() )
882 			{
883 				requestTabs.setSelectedIndex( 1 );
884 				return;
885 			}
886 
887 			if( getModelItem().getSettings().getBoolean( UISettings.NO_RESIZE_REQUEST_EDITOR ) )
888 				return;
889 
890 			// dont resize if split has been dragged or result is empty
891 			if( requestSplitPane.getUI() instanceof SoapUISplitPaneUI
892 					&& ( ( SoapUISplitPaneUI )requestSplitPane.getUI() ).hasBeenDragged()
893 					|| amfRequestTestStep.getAMFRequest().getResponse() == null )
894 				return;
895 
896 			int pos = requestSplitPane.getDividerLocation();
897 			int maximumDividerLocation = requestSplitPane.getMaximumDividerLocation();
898 			if( pos + 600 < maximumDividerLocation )
899 				return;
900 
901 			if( maximumDividerLocation > 700 )
902 				requestSplitPane.setDividerLocation( maximumDividerLocation - 600 );
903 			else
904 				requestSplitPane.setDividerLocation( 0.2 );
905 		}
906 
907 		public void focusLost( FocusEvent e )
908 		{
909 		}
910 	}
911 
912 	private final class ChangeToTabsAction extends AbstractAction
913 	{
914 		public ChangeToTabsAction()
915 		{
916 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/toggle_tabs.gif" ) );
917 			putValue( Action.SHORT_DESCRIPTION, "Toggles to tab-based layout" );
918 		}
919 
920 		public void actionPerformed( ActionEvent e )
921 		{
922 			if( splitButton.isEnabled() )
923 			{
924 				splitButton.setEnabled( false );
925 				removeContent( requestSplitPane );
926 				setContent( requestTabPanel );
927 				requestTabs.addTab( "Request", requestEditor );
928 
929 				if( responseEditor != null )
930 					requestTabs.addTab( "Response", responseEditor );
931 
932 				if( responseHasFocus )
933 				{
934 					requestTabs.setSelectedIndex( 1 );
935 					requestEditor.requestFocus();
936 				}
937 				requestTabs.repaint();
938 			}
939 			else
940 			{
941 				int selectedIndex = requestTabs.getSelectedIndex();
942 
943 				splitButton.setEnabled( true );
944 				removeContent( requestTabPanel );
945 				setContent( requestSplitPane );
946 				requestSplitPane.setTopComponent( requestEditor );
947 				if( responseEditor != null )
948 					requestSplitPane.setBottomComponent( responseEditor );
949 				requestSplitPane.setDividerLocation( 0.5 );
950 
951 				if( selectedIndex == 0 || responseEditor == null )
952 					requestEditor.requestFocus();
953 				else
954 					responseEditor.requestFocus();
955 				requestSplitPane.repaint();
956 			}
957 
958 			revalidate();
959 		}
960 	}
961 
962 	public void setContent( JComponent content )
963 	{
964 		inspectorPanel.setContentComponent( content );
965 	}
966 
967 	public void removeContent( JComponent content )
968 	{
969 		inspectorPanel.setContentComponent( null );
970 	}
971 
972 	private class CancelAction extends AbstractAction
973 	{
974 		public CancelAction()
975 		{
976 			super();
977 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/cancel_request.gif" ) );
978 			putValue( Action.SHORT_DESCRIPTION, "Aborts ongoing request" );
979 			putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "alt X" ) );
980 		}
981 
982 		public void actionPerformed( ActionEvent e )
983 		{
984 			onCancel();
985 		}
986 	}
987 
988 	protected void onCancel()
989 	{
990 		if( submit == null )
991 			return;
992 
993 		cancelButton.setEnabled( false );
994 		submit.cancel();
995 		setEnabled( true );
996 		submit = null;
997 	}
998 
999 	public void setEnabled( boolean enabled )
1000 	{
1001 		if( responseEditor != null )
1002 			responseEditor.setEnabled( enabled );
1003 
1004 		submitButton.setEnabled( enabled );
1005 		addAssertionButton.setEnabled( enabled );
1006 		propertiesTableComponent.setEnabled( enabled );
1007 		groovyEditor.setEnabled( enabled );
1008 		endpointField.setEnabled( enabled );
1009 		amfCallField.setEnabled( enabled );
1010 
1011 		statusBar.setIndeterminate( !enabled );
1012 	}
1013 
1014 	public void afterSubmit( Submit submit, SubmitContext context )
1015 	{
1016 		if( submit.getRequest() != amfRequestTestStep.getAMFRequest() )
1017 			return;
1018 
1019 		Status status = submit.getStatus();
1020 		AMFResponse response = ( AMFResponse )submit.getResponse();
1021 		if( status == Status.FINISHED )
1022 		{
1023 			amfRequestTestStep.setResponse( response, context );
1024 		}
1025 
1026 		cancelButton.setEnabled( false );
1027 		setEnabled( true );
1028 
1029 		String message = null;
1030 		String infoMessage = null;
1031 		String requestName = amfRequestTestStep.getName();
1032 
1033 		if( status == Status.CANCELED )
1034 		{
1035 			message = "CANCELED";
1036 			infoMessage = "[" + requestName + "] - CANCELED";
1037 		}
1038 		else
1039 		{
1040 			if( status == Status.ERROR || response == null )
1041 			{
1042 				message = "Error getting response; " + submit.getError();
1043 				infoMessage = "Error getting response for [" + requestName + "]; " + submit.getError();
1044 			}
1045 			else
1046 			{
1047 				message = "response time: " + response.getTimeTaken() + "ms (" + response.getContentLength() + " bytes)";
1048 				infoMessage = "Got response for [" + requestName + "] in " + response.getTimeTaken() + "ms ("
1049 						+ response.getContentLength() + " bytes)";
1050 
1051 				if( !splitButton.isEnabled() )
1052 					requestTabs.setSelectedIndex( 1 );
1053 
1054 				responseEditor.requestFocus();
1055 			}
1056 		}
1057 
1058 		logMessages( message, infoMessage );
1059 
1060 		if( getModelItem().getSettings().getBoolean( UISettings.AUTO_VALIDATE_RESPONSE ) )
1061 			responseEditor.getSourceEditor().validate();
1062 
1063 		AMFRequestTestStepDesktopPanel.this.submit = null;
1064 
1065 		updateStatusIcon();
1066 	}
1067 
1068 	protected void logMessages( String message, String infoMessage )
1069 	{
1070 		log.info( infoMessage );
1071 		statusBar.setInfo( message );
1072 	}
1073 
1074 	public boolean beforeSubmit( Submit submit, SubmitContext context )
1075 	{
1076 		if( submit.getRequest() != amfRequestTestStep.getAMFRequest() )
1077 			return true;
1078 
1079 		setEnabled( false );
1080 		cancelButton.setEnabled( AMFRequestTestStepDesktopPanel.this.submit != null );
1081 		return true;
1082 	}
1083 
1084 	public void propertyChange( PropertyChangeEvent evt )
1085 	{
1086 		super.propertyChange( evt );
1087 		if( evt.getPropertyName().equals( "script" ) && !updating )
1088 		{
1089 			updating = true;
1090 			groovyEditor.getEditArea().setText( ( String )evt.getNewValue() );
1091 			updating = false;
1092 		}
1093 		if( evt.getPropertyName().equals( AMFRequestTestStep.STATUS_PROPERTY ) )
1094 			updateStatusIcon();
1095 	}
1096 
1097 	private final class InternalAssertionsListener implements AssertionsListener
1098 	{
1099 		public void assertionAdded( TestAssertion assertion )
1100 		{
1101 			assertionInspector.setTitle( "Assertions (" + getModelItem().getAssertionCount() + ")" );
1102 		}
1103 
1104 		public void assertionRemoved( TestAssertion assertion )
1105 		{
1106 			assertionInspector.setTitle( "Assertions (" + getModelItem().getAssertionCount() + ")" );
1107 		}
1108 
1109 		public void assertionMoved( TestAssertion assertion, int ix, int offset )
1110 		{
1111 			assertionInspector.setTitle( "Assertions (" + getModelItem().getAssertionCount() + ")" );
1112 		}
1113 	}
1114 
1115 	private void updateStatusIcon()
1116 	{
1117 		AssertionStatus status = amfRequestTestStep.getAssertionStatus();
1118 		switch( status )
1119 		{
1120 		case FAILED :
1121 		{
1122 			assertionInspector.setIcon( UISupport.createImageIcon( "/failed_assertion.gif" ) );
1123 			inspectorPanel.activate( assertionInspector );
1124 			break;
1125 		}
1126 		case UNKNOWN :
1127 		{
1128 			assertionInspector.setIcon( UISupport.createImageIcon( "/unknown_assertion.gif" ) );
1129 			break;
1130 		}
1131 		case VALID :
1132 		{
1133 			assertionInspector.setIcon( UISupport.createImageIcon( "/valid_assertion.gif" ) );
1134 			inspectorPanel.deactivate();
1135 			break;
1136 		}
1137 		}
1138 	}
1139 
1140 }