View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2009 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.mockoperation;
14  
15  import java.awt.BorderLayout;
16  import java.awt.Dimension;
17  import java.awt.event.ActionEvent;
18  import java.awt.event.FocusAdapter;
19  import java.awt.event.FocusEvent;
20  import java.awt.event.FocusListener;
21  import java.beans.PropertyChangeEvent;
22  import java.beans.PropertyChangeListener;
23  
24  import javax.swing.AbstractAction;
25  import javax.swing.Action;
26  import javax.swing.BorderFactory;
27  import javax.swing.Box;
28  import javax.swing.JButton;
29  import javax.swing.JComponent;
30  import javax.swing.JPanel;
31  import javax.swing.JPopupMenu;
32  import javax.swing.JSeparator;
33  import javax.swing.JSplitPane;
34  import javax.swing.JTabbedPane;
35  import javax.swing.JToggleButton;
36  import javax.swing.JToolBar;
37  
38  import com.eviware.soapui.SoapUI;
39  import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
40  import com.eviware.soapui.impl.support.components.ModelItemXmlEditor;
41  import com.eviware.soapui.impl.support.components.RequestMessageXmlEditor;
42  import com.eviware.soapui.impl.support.components.ResponseMessageXmlEditor;
43  import com.eviware.soapui.impl.wsdl.actions.mockresponse.OpenRequestForMockResponseAction;
44  import com.eviware.soapui.impl.wsdl.mock.WsdlMockRequest;
45  import com.eviware.soapui.impl.wsdl.mock.WsdlMockResponse;
46  import com.eviware.soapui.impl.wsdl.mock.WsdlMockResult;
47  import com.eviware.soapui.impl.wsdl.panels.mockoperation.actions.CreateEmptyMockResponseAction;
48  import com.eviware.soapui.impl.wsdl.panels.mockoperation.actions.CreateFaultMockResponseAction;
49  import com.eviware.soapui.impl.wsdl.panels.mockoperation.actions.RecreateMockResponseAction;
50  import com.eviware.soapui.impl.wsdl.panels.mockoperation.actions.WSIValidateResponseAction;
51  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
52  import com.eviware.soapui.model.ModelItem;
53  import com.eviware.soapui.model.mock.MockRunner;
54  import com.eviware.soapui.settings.UISettings;
55  import com.eviware.soapui.support.UISupport;
56  import com.eviware.soapui.support.action.swing.SwingActionDelegate;
57  import com.eviware.soapui.support.actions.ChangeSplitPaneOrientationAction;
58  import com.eviware.soapui.support.components.JEditorStatusBarWithProgress;
59  import com.eviware.soapui.support.components.JXToolBar;
60  import com.eviware.soapui.support.editor.views.xml.source.XmlSourceEditorView;
61  import com.eviware.soapui.support.editor.xml.XmlDocument;
62  import com.eviware.soapui.support.swing.SoapUISplitPaneUI;
63  import com.eviware.soapui.support.xml.JXEditTextArea;
64  import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
65  
66  /***
67   * Abstract base DesktopPanel for WsdlMockResponses
68   * 
69   * @author Ole.Matzura
70   */
71  
72  public class AbstractWsdlMockResponseDesktopPanel<T extends ModelItem, T2 extends WsdlMockResponse> extends
73  		ModelItemDesktopPanel<T>
74  {
75  	// private final static Log log =
76  	// Logger.getLogger(WsdlMockOperationDesktopPanel.class);
77  	private JEditorStatusBarWithProgress statusBar;
78  	private JButton splitButton;
79  	private MockRunner mockRunner;
80  	private JButton recreateButton;
81  	private JButton createEmptyButton;
82  	private JSplitPane requestSplitPane;
83  	private MoveFocusAction moveFocusAction;
84  	private ClosePanelAction closePanelAction = new ClosePanelAction();
85  
86  	private ModelItemXmlEditor<?, ?> requestEditor;
87  	private ModelItemXmlEditor<?, ?> responseEditor;
88  
89  	public AbstractAction wsiValidateAction;
90  
91  	private JTabbedPane requestTabs;
92  	private JPanel requestTabPanel;
93  	private JToggleButton tabsButton;
94  
95  	public boolean responseHasFocus;
96  
97  	private InternalPropertyChangeListener propertyChangeListener = new InternalPropertyChangeListener();
98  	private JButton createFaultButton;
99  	private T2 mockResponse;
100 	private JButton openRequestButton;
101 
102 	public AbstractWsdlMockResponseDesktopPanel( T modelItem )
103 	{
104 		super( modelItem );
105 	}
106 
107 	protected void init( T2 mockResponse )
108 	{
109 		this.mockResponse = mockResponse;
110 
111 		add( buildContent(), BorderLayout.CENTER );
112 		add( buildToolbar(), BorderLayout.NORTH );
113 		add( buildStatusLabel(), BorderLayout.SOUTH );
114 
115 		setPreferredSize( new Dimension( 600, 500 ) );
116 
117 		mockResponse.addPropertyChangeListener( propertyChangeListener );
118 
119 		addFocusListener( new FocusAdapter()
120 		{
121 
122 			@Override
123 			public void focusGained( FocusEvent e )
124 			{
125 				if( requestTabs.getSelectedIndex() == 1 || responseHasFocus )
126 					responseEditor.requestFocus();
127 				else
128 					requestEditor.requestFocus();
129 			}
130 		} );
131 
132 		try
133 		{
134 			// required to avoid deadlock in UI when opening attachments inspector
135 			if( mockResponse.getAttachmentCount() > 0 )
136 			{
137 				mockResponse.getOperation().getInterface().getDefinitionContext().loadIfNecessary();
138 			}
139 		}
140 		catch( Exception e )
141 		{
142 			e.printStackTrace();
143 		}
144 	}
145 
146 	protected WsdlMockResponse getMockResponse()
147 	{
148 		return mockResponse;
149 	}
150 
151 	public final ModelItemXmlEditor<?, ?> getRequestEditor()
152 	{
153 		return requestEditor;
154 	}
155 
156 	public final ModelItemXmlEditor<?, ?> getResponseEditor()
157 	{
158 		return responseEditor;
159 	}
160 
161 	public MockRunner getSubmit()
162 	{
163 		return mockRunner;
164 	}
165 
166 	protected JComponent buildStatusLabel()
167 	{
168 		statusBar = new JEditorStatusBarWithProgress();
169 		statusBar.setBorder( BorderFactory.createEmptyBorder( 1, 0, 0, 0 ) );
170 
171 		return statusBar;
172 	}
173 
174 	public JEditorStatusBarWithProgress getStatusBar()
175 	{
176 		return statusBar;
177 	}
178 
179 	protected JComponent buildContent()
180 	{
181 		requestSplitPane = UISupport.createHorizontalSplit();
182 		requestSplitPane.setResizeWeight( 0.5 );
183 		requestSplitPane.setBorder( null );
184 
185 		splitButton = createActionButton( new ChangeSplitPaneOrientationAction( requestSplitPane ), true );
186 
187 		tabsButton = new JToggleButton( new ChangeToTabsAction() );
188 		tabsButton.setPreferredSize( UISupport.TOOLBAR_BUTTON_DIMENSION );
189 
190 		openRequestButton = createActionButton( SwingActionDelegate.createDelegate(
191 				OpenRequestForMockResponseAction.SOAPUI_ACTION_ID, mockResponse, null, "/open_request.gif" ), true );
192 
193 		// TODO Ericsson: This was removed and replaced with "true" below.
194 		boolean bidirectional = mockResponse.getMockOperation().getOperation().isBidirectional();
195 
196 		recreateButton = createActionButton( new RecreateMockResponseAction( mockResponse ), bidirectional );
197 		createEmptyButton = createActionButton( new CreateEmptyMockResponseAction( mockResponse ), bidirectional );
198 		createFaultButton = createActionButton( new CreateFaultMockResponseAction( mockResponse ), bidirectional );
199 
200 		moveFocusAction = new MoveFocusAction();
201 		wsiValidateAction = // new WSIValidateResponseAction( mockResponse );
202 		SwingActionDelegate.createDelegate( new WSIValidateResponseAction(), mockResponse, "alt W" );
203 
204 		requestEditor = buildRequestEditor();
205 		responseEditor = buildResponseEditor();
206 
207 		requestTabs = new JTabbedPane();
208 		requestTabPanel = UISupport.createTabPanel( requestTabs, true );
209 
210 		JComponent component = null;
211 
212 		if( mockResponse.getSettings().getBoolean( UISettings.START_WITH_REQUEST_TABS ) )
213 		{
214 			requestTabs.addTab( "Last Request", requestEditor );
215 			requestTabs.addTab( "Mock Response", responseEditor );
216 			splitButton.setEnabled( false );
217 			tabsButton.setSelected( true );
218 			component = requestTabPanel;
219 
220 			requestTabs.setSelectedIndex( 1 );
221 		}
222 		else
223 		{
224 			requestSplitPane.setTopComponent( requestEditor );
225 			requestSplitPane.setBottomComponent( responseEditor );
226 			requestSplitPane.setDividerLocation( 0.5 );
227 			component = requestSplitPane;
228 		}
229 
230 		return component;
231 	}
232 
233 	protected ModelItemXmlEditor<?, ?> buildResponseEditor()
234 	{
235 		return new WsdlMockResponseMessageEditor( new MockResponseXmlDocument( mockResponse ) );
236 	}
237 
238 	protected ModelItemXmlEditor<?, ?> buildRequestEditor()
239 	{
240 		return new WsdlMockRequestMessageEditor( new MockRequestXmlDocument( mockResponse ) );
241 	}
242 
243 	protected JComponent buildToolbar()
244 	{
245 		JXToolBar toolbar = UISupport.createToolbar();
246 
247 		toolbar.add( openRequestButton );
248 		toolbar.addUnrelatedGap();
249 		toolbar.add( recreateButton );
250 		toolbar.add( createEmptyButton );
251 		toolbar.add( createFaultButton );
252 
253 		createToolbar( toolbar );
254 
255 		toolbar.add( Box.createHorizontalGlue() );
256 		toolbar.add( tabsButton );
257 		toolbar.add( splitButton );
258 		toolbar.add( UISupport.createToolbarButton( new ShowOnlineHelpAction( getHelpUrl() ) ) );
259 
260 		return toolbar;
261 	}
262 
263 	protected void createToolbar( JXToolBar toolbar )
264 	{
265 	}
266 
267 	protected String getHelpUrl()
268 	{
269 		return HelpUrls.REQUESTEDITOR_HELP_URL;
270 	}
271 
272 	protected void insertButtons( JToolBar toolbar )
273 	{
274 	}
275 
276 	public void setEnabled( boolean enabled )
277 	{
278 		requestEditor.getSourceEditor().setEditable( enabled );
279 		responseEditor.getSourceEditor().setEditable( enabled );
280 		recreateButton.setEnabled( enabled );
281 		createEmptyButton.setEnabled( enabled );
282 		statusBar.setIndeterminate( !enabled );
283 	}
284 
285 	private final class InternalPropertyChangeListener implements PropertyChangeListener
286 	{
287 		public void propertyChange( PropertyChangeEvent evt )
288 		{
289 			if( evt.getPropertyName().equals( WsdlMockResponse.MOCKRESULT_PROPERTY ) )
290 			{
291 				WsdlMockResult mockResult = mockResponse.getMockResult();
292 				WsdlMockRequest mockRequest = mockResult == null ? null : mockResult.getMockRequest();
293 				requestEditor.getDocument().setXml( mockRequest == null ? "" : mockRequest.getRequestContent() );
294 
295 				boolean bidirectional = mockResponse.getMockOperation().getOperation().isBidirectional();
296 				wsiValidateAction.setEnabled( bidirectional ); // TODO Ericsson: Had
297 																				// "true" here. Why?
298 			}
299 		}
300 	}
301 
302 	public class WsdlMockRequestMessageEditor extends RequestMessageXmlEditor<WsdlMockResponse, XmlDocument>
303 	{
304 		public WsdlMockRequestMessageEditor( XmlDocument document )
305 		{
306 			super( document, mockResponse );
307 		}
308 
309 		protected XmlSourceEditorView<?> buildSourceEditor()
310 		{
311 			XmlSourceEditorView<?> editor = getSourceEditor();
312 			JXEditTextArea inputArea = editor.getInputArea();
313 
314 			inputArea.addFocusListener( new InputAreaFocusListener() );
315 
316 			inputArea.getInputHandler().addKeyBinding( "AC+TAB", moveFocusAction );
317 			inputArea.getInputHandler().addKeyBinding( "F5", recreateButton.getAction() );
318 			inputArea.getInputHandler().addKeyBinding( "C+F4", closePanelAction );
319 
320 			return editor;
321 		}
322 	}
323 
324 	public class WsdlMockResponseMessageEditor extends ResponseMessageXmlEditor<WsdlMockResponse, XmlDocument>
325 	{
326 		public WsdlMockResponseMessageEditor( XmlDocument document )
327 		{
328 			super( document, mockResponse );
329 
330 			XmlSourceEditorView<?> editor = getSourceEditor();
331 
332 			if( getModelItem().getMockOperation().isBidirectional() )
333 			{
334 				JXEditTextArea inputArea = editor.getInputArea();
335 				inputArea.addFocusListener( new ResultAreaFocusListener() );
336 
337 				inputArea.getInputHandler().addKeyBinding( "AC+TAB", moveFocusAction );
338 				inputArea.getInputHandler().addKeyBinding( "C+F4", closePanelAction );
339 
340 				// TODO Ericsson: This if test was changed and moved up. Ok?
341 				// if( !getModelItem().getMockOperation().isOneWay())
342 				// {
343 				JPopupMenu inputPopup = editor.getEditorPopup();
344 				inputPopup.insert( new JSeparator(), 2 );
345 				inputPopup.insert( wsiValidateAction, 3 );
346 			}
347 		}
348 	}
349 
350 	protected final class InputAreaFocusListener implements FocusListener
351 	{
352 		public void focusGained( FocusEvent e )
353 		{
354 			responseHasFocus = false;
355 
356 			statusBar.setTarget( requestEditor.getSourceEditor().getInputArea() );
357 			if( !splitButton.isEnabled() )
358 			{
359 				requestTabs.setSelectedIndex( 0 );
360 				return;
361 			}
362 
363 			if( getModelItem().getSettings().getBoolean( UISettings.NO_RESIZE_REQUEST_EDITOR ) )
364 				return;
365 
366 			// dont resize if split has been dragged
367 			if( ( ( SoapUISplitPaneUI )requestSplitPane.getUI() ).hasBeenDragged() )
368 				return;
369 
370 			int pos = requestSplitPane.getDividerLocation();
371 			if( pos >= 600 )
372 				return;
373 			if( requestSplitPane.getMaximumDividerLocation() > 700 )
374 				requestSplitPane.setDividerLocation( 600 );
375 			else
376 				requestSplitPane.setDividerLocation( 0.8 );
377 		}
378 
379 		public void focusLost( FocusEvent e )
380 		{
381 		}
382 	}
383 
384 	protected final class ResultAreaFocusListener implements FocusListener
385 	{
386 		public void focusGained( FocusEvent e )
387 		{
388 			responseHasFocus = true;
389 
390 			statusBar.setTarget( responseEditor.getSourceEditor().getInputArea() );
391 			if( !splitButton.isEnabled() )
392 			{
393 				requestTabs.setSelectedIndex( 1 );
394 				return;
395 			}
396 
397 			if( getModelItem().getSettings().getBoolean( UISettings.NO_RESIZE_REQUEST_EDITOR ) )
398 				return;
399 
400 			// dont resize if split has been dragged or result is empty
401 			if( ( ( SoapUISplitPaneUI )requestSplitPane.getUI() ).hasBeenDragged() )
402 				return;
403 
404 			int pos = requestSplitPane.getDividerLocation();
405 			int maximumDividerLocation = requestSplitPane.getMaximumDividerLocation();
406 			if( pos + 600 < maximumDividerLocation )
407 				return;
408 
409 			if( maximumDividerLocation > 700 )
410 				requestSplitPane.setDividerLocation( maximumDividerLocation - 600 );
411 			else
412 				requestSplitPane.setDividerLocation( 0.2 );
413 		}
414 
415 		public void focusLost( FocusEvent e )
416 		{
417 		}
418 	}
419 
420 	private class ClosePanelAction extends AbstractAction
421 	{
422 		public void actionPerformed( ActionEvent e )
423 		{
424 			SoapUI.getDesktop().closeDesktopPanel( getModelItem() );
425 		}
426 	}
427 
428 	private class MoveFocusAction extends AbstractAction
429 	{
430 		public void actionPerformed( ActionEvent e )
431 		{
432 			if( requestEditor.hasFocus() )
433 			{
434 				responseEditor.requestFocus();
435 			}
436 			else
437 			{
438 				requestEditor.requestFocus();
439 			}
440 		}
441 	}
442 
443 	public boolean dependsOn( ModelItem modelItem )
444 	{
445 		return modelItem == getModelItem() || modelItem == mockResponse.getMockOperation()
446 				|| modelItem == mockResponse.getMockOperation().getMockService()
447 				|| modelItem == mockResponse.getMockOperation().getMockService().getProject();
448 	}
449 
450 	private final class ChangeToTabsAction extends AbstractAction
451 	{
452 		public ChangeToTabsAction()
453 		{
454 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/toggle_tabs.gif" ) );
455 			putValue( Action.SHORT_DESCRIPTION, "Toggles to tab-based layout" );
456 		}
457 
458 		public void actionPerformed( ActionEvent e )
459 		{
460 			if( splitButton.isEnabled() )
461 			{
462 				splitButton.setEnabled( false );
463 				removeContent( requestSplitPane );
464 				setContent( requestTabPanel );
465 				requestTabs.addTab( "Last Request", requestEditor );
466 				requestTabs.addTab( "Mock Response", responseEditor );
467 			}
468 			else
469 			{
470 				int selectedIndex = requestTabs.getSelectedIndex();
471 
472 				splitButton.setEnabled( true );
473 				removeContent( requestTabPanel );
474 				setContent( requestSplitPane );
475 				requestSplitPane.setTopComponent( requestEditor );
476 				requestSplitPane.setBottomComponent( responseEditor );
477 				requestSplitPane.setDividerLocation( 0.5 );
478 
479 				if( selectedIndex == 0 )
480 					requestEditor.requestFocus();
481 				else
482 					responseEditor.requestFocus();
483 			}
484 
485 			revalidate();
486 		}
487 	}
488 
489 	public void setContent( JComponent content )
490 	{
491 		add( content, BorderLayout.CENTER );
492 	}
493 
494 	public void removeContent( JComponent content )
495 	{
496 		remove( content );
497 	}
498 
499 	public boolean onClose( boolean canCancel )
500 	{
501 		mockResponse.removePropertyChangeListener( propertyChangeListener );
502 
503 		requestEditor.release();
504 		responseEditor.release();
505 
506 		responseEditor.getParent().remove( responseEditor );
507 		responseEditor = null;
508 		requestEditor.getParent().remove( requestEditor );
509 		requestEditor = null;
510 
511 		return release();
512 	}
513 }