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 	@SuppressWarnings( "unchecked" )
180 	protected JComponent buildContent()
181 	{
182 		requestSplitPane = UISupport.createHorizontalSplit();
183 		requestSplitPane.setResizeWeight( 0.5 );
184 		requestSplitPane.setBorder( null );
185 
186 		splitButton = createActionButton( new ChangeSplitPaneOrientationAction( requestSplitPane ), true );
187 
188 		tabsButton = new JToggleButton( new ChangeToTabsAction() );
189 		tabsButton.setPreferredSize( UISupport.TOOLBAR_BUTTON_DIMENSION );
190 
191 		openRequestButton = createActionButton( SwingActionDelegate.createDelegate(
192 				OpenRequestForMockResponseAction.SOAPUI_ACTION_ID, mockResponse, null, "/open_request.gif" ), true );
193 
194 		// TODO Ericsson: This was removed and replaced with "true" below.
195 		boolean bidirectional = mockResponse.getMockOperation().getOperation().isBidirectional();
196 
197 		recreateButton = createActionButton( new RecreateMockResponseAction( mockResponse ), bidirectional );
198 		createEmptyButton = createActionButton( new CreateEmptyMockResponseAction( mockResponse ), bidirectional );
199 		createFaultButton = createActionButton( new CreateFaultMockResponseAction( mockResponse ), bidirectional );
200 
201 		moveFocusAction = new MoveFocusAction();
202 		wsiValidateAction = // new WSIValidateResponseAction( mockResponse );
203 		SwingActionDelegate.createDelegate( new WSIValidateResponseAction(), mockResponse, "alt W" );
204 
205 		requestEditor = buildRequestEditor();
206 		responseEditor = buildResponseEditor();
207 
208 		requestTabs = new JTabbedPane();
209 		requestTabPanel = UISupport.createTabPanel( requestTabs, true );
210 
211 		JComponent component = null;
212 
213 		if( mockResponse.getSettings().getBoolean( UISettings.START_WITH_REQUEST_TABS ) )
214 		{
215 			requestTabs.addTab( "Last Request", requestEditor );
216 			requestTabs.addTab( "Mock Response", responseEditor );
217 			splitButton.setEnabled( false );
218 			tabsButton.setSelected( true );
219 			component = requestTabPanel;
220 
221 			requestTabs.setSelectedIndex( 1 );
222 		}
223 		else
224 		{
225 			requestSplitPane.setTopComponent( requestEditor );
226 			requestSplitPane.setBottomComponent( responseEditor );
227 			requestSplitPane.setDividerLocation( 0.5 );
228 			component = requestSplitPane;
229 		}
230 
231 		return component;
232 	}
233 
234 	protected ModelItemXmlEditor<?, ?> buildResponseEditor()
235 	{
236 		return new WsdlMockResponseMessageEditor( new MockResponseXmlDocument( mockResponse ) );
237 	}
238 
239 	protected ModelItemXmlEditor<?, ?> buildRequestEditor()
240 	{
241 		return new WsdlMockRequestMessageEditor( new MockRequestXmlDocument( mockResponse ) );
242 	}
243 
244 	protected JComponent buildToolbar()
245 	{
246 		JXToolBar toolbar = UISupport.createToolbar();
247 
248 		toolbar.add( openRequestButton );
249 		toolbar.addUnrelatedGap();
250 		toolbar.add( recreateButton );
251 		toolbar.add( createEmptyButton );
252 		toolbar.add( createFaultButton );
253 
254 		createToolbar( toolbar );
255 
256 		toolbar.add( Box.createHorizontalGlue() );
257 		toolbar.add( tabsButton );
258 		toolbar.add( splitButton );
259 		toolbar.add( UISupport.createToolbarButton( new ShowOnlineHelpAction( getHelpUrl() ) ) );
260 
261 		return toolbar;
262 	}
263 
264 	protected void createToolbar( JXToolBar toolbar )
265 	{
266 	}
267 
268 	protected String getHelpUrl()
269 	{
270 		return HelpUrls.REQUESTEDITOR_HELP_URL;
271 	}
272 
273 	protected void insertButtons( JToolBar toolbar )
274 	{
275 	}
276 
277 	public void setEnabled( boolean enabled )
278 	{
279 		requestEditor.getSourceEditor().setEditable( enabled );
280 		responseEditor.getSourceEditor().setEditable( enabled );
281 		recreateButton.setEnabled( enabled );
282 		createEmptyButton.setEnabled( enabled );
283 		statusBar.setIndeterminate( !enabled );
284 	}
285 
286 	private final class InternalPropertyChangeListener implements PropertyChangeListener
287 	{
288 		public void propertyChange( PropertyChangeEvent evt )
289 		{
290 			if( evt.getPropertyName().equals( WsdlMockResponse.MOCKRESULT_PROPERTY ) )
291 			{
292 				WsdlMockResult mockResult = mockResponse.getMockResult();
293 				WsdlMockRequest mockRequest = mockResult == null ? null : mockResult.getMockRequest();
294 				requestEditor.getDocument().setXml( mockRequest == null ? "" : mockRequest.getRequestContent() );
295 
296 				boolean bidirectional = mockResponse.getMockOperation().getOperation().isBidirectional();
297 				wsiValidateAction.setEnabled( bidirectional ); // TODO Ericsson: Had
298 																				// "true" here. Why?
299 			}
300 		}
301 	}
302 
303 	public class WsdlMockRequestMessageEditor extends RequestMessageXmlEditor<WsdlMockResponse, XmlDocument>
304 	{
305 		public WsdlMockRequestMessageEditor( XmlDocument document )
306 		{
307 			super( document, mockResponse );
308 		}
309 
310 		protected XmlSourceEditorView buildSourceEditor()
311 		{
312 			XmlSourceEditorView editor = getSourceEditor();
313 			JXEditTextArea inputArea = editor.getInputArea();
314 
315 			inputArea.addFocusListener( new InputAreaFocusListener() );
316 
317 			inputArea.getInputHandler().addKeyBinding( "AC+TAB", moveFocusAction );
318 			inputArea.getInputHandler().addKeyBinding( "F5", recreateButton.getAction() );
319 			inputArea.getInputHandler().addKeyBinding( "C+F4", closePanelAction );
320 
321 			return editor;
322 		}
323 	}
324 
325 	public class WsdlMockResponseMessageEditor extends ResponseMessageXmlEditor<WsdlMockResponse, XmlDocument>
326 	{
327 		public WsdlMockResponseMessageEditor( XmlDocument document )
328 		{
329 			super( document, mockResponse );
330 
331 			XmlSourceEditorView editor = getSourceEditor();
332 
333 			if( getModelItem().getMockOperation().isBidirectional() )
334 			{
335 				JXEditTextArea inputArea = editor.getInputArea();
336 				inputArea.addFocusListener( new ResultAreaFocusListener() );
337 
338 				inputArea.getInputHandler().addKeyBinding( "AC+TAB", moveFocusAction );
339 				inputArea.getInputHandler().addKeyBinding( "C+F4", closePanelAction );
340 
341 				// TODO Ericsson: This if test was changed and moved up. Ok?
342 				// if( !getModelItem().getMockOperation().isOneWay())
343 				// {
344 				JPopupMenu inputPopup = editor.getEditorPopup();
345 				inputPopup.insert( new JSeparator(), 2 );
346 				inputPopup.insert( wsiValidateAction, 3 );
347 			}
348 		}
349 	}
350 
351 	protected final class InputAreaFocusListener implements FocusListener
352 	{
353 		public void focusGained( FocusEvent e )
354 		{
355 			responseHasFocus = false;
356 
357 			statusBar.setTarget( requestEditor.getSourceEditor().getInputArea() );
358 			if( !splitButton.isEnabled() )
359 			{
360 				requestTabs.setSelectedIndex( 0 );
361 				return;
362 			}
363 
364 			if( getModelItem().getSettings().getBoolean( UISettings.NO_RESIZE_REQUEST_EDITOR ) )
365 				return;
366 
367 			// dont resize if split has been dragged
368 			if( ( ( SoapUISplitPaneUI )requestSplitPane.getUI() ).hasBeenDragged() )
369 				return;
370 
371 			int pos = requestSplitPane.getDividerLocation();
372 			if( pos >= 600 )
373 				return;
374 			if( requestSplitPane.getMaximumDividerLocation() > 700 )
375 				requestSplitPane.setDividerLocation( 600 );
376 			else
377 				requestSplitPane.setDividerLocation( 0.8 );
378 		}
379 
380 		public void focusLost( FocusEvent e )
381 		{
382 		}
383 	}
384 
385 	protected final class ResultAreaFocusListener implements FocusListener
386 	{
387 		public void focusGained( FocusEvent e )
388 		{
389 			responseHasFocus = true;
390 
391 			statusBar.setTarget( responseEditor.getSourceEditor().getInputArea() );
392 			if( !splitButton.isEnabled() )
393 			{
394 				requestTabs.setSelectedIndex( 1 );
395 				return;
396 			}
397 
398 			if( getModelItem().getSettings().getBoolean( UISettings.NO_RESIZE_REQUEST_EDITOR ) )
399 				return;
400 
401 			// dont resize if split has been dragged or result is empty
402 			if( ( ( SoapUISplitPaneUI )requestSplitPane.getUI() ).hasBeenDragged() )
403 				return;
404 
405 			int pos = requestSplitPane.getDividerLocation();
406 			int maximumDividerLocation = requestSplitPane.getMaximumDividerLocation();
407 			if( pos + 600 < maximumDividerLocation )
408 				return;
409 
410 			if( maximumDividerLocation > 700 )
411 				requestSplitPane.setDividerLocation( maximumDividerLocation - 600 );
412 			else
413 				requestSplitPane.setDividerLocation( 0.2 );
414 		}
415 
416 		public void focusLost( FocusEvent e )
417 		{
418 		}
419 	}
420 
421 	private class ClosePanelAction extends AbstractAction
422 	{
423 		public void actionPerformed( ActionEvent e )
424 		{
425 			SoapUI.getDesktop().closeDesktopPanel( getModelItem() );
426 		}
427 	}
428 
429 	private class MoveFocusAction extends AbstractAction
430 	{
431 		public void actionPerformed( ActionEvent e )
432 		{
433 			if( requestEditor.hasFocus() )
434 			{
435 				responseEditor.requestFocus();
436 			}
437 			else
438 			{
439 				requestEditor.requestFocus();
440 			}
441 		}
442 	}
443 
444 	public boolean dependsOn( ModelItem modelItem )
445 	{
446 		return modelItem == getModelItem() || modelItem == mockResponse.getMockOperation()
447 				|| modelItem == mockResponse.getMockOperation().getMockService()
448 				|| modelItem == mockResponse.getMockOperation().getMockService().getProject();
449 	}
450 
451 	private final class ChangeToTabsAction extends AbstractAction
452 	{
453 		public ChangeToTabsAction()
454 		{
455 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/toggle_tabs.gif" ) );
456 			putValue( Action.SHORT_DESCRIPTION, "Toggles to tab-based layout" );
457 		}
458 
459 		public void actionPerformed( ActionEvent e )
460 		{
461 			if( splitButton.isEnabled() )
462 			{
463 				splitButton.setEnabled( false );
464 				removeContent( requestSplitPane );
465 				setContent( requestTabPanel );
466 				requestTabs.addTab( "Last Request", requestEditor );
467 				requestTabs.addTab( "Mock Response", responseEditor );
468 			}
469 			else
470 			{
471 				int selectedIndex = requestTabs.getSelectedIndex();
472 
473 				splitButton.setEnabled( true );
474 				removeContent( requestTabPanel );
475 				setContent( requestSplitPane );
476 				requestSplitPane.setTopComponent( requestEditor );
477 				requestSplitPane.setBottomComponent( responseEditor );
478 				requestSplitPane.setDividerLocation( 0.5 );
479 
480 				if( selectedIndex == 0 )
481 					requestEditor.requestFocus();
482 				else
483 					responseEditor.requestFocus();
484 			}
485 
486 			revalidate();
487 		}
488 	}
489 
490 	public void setContent( JComponent content )
491 	{
492 		add( content, BorderLayout.CENTER );
493 	}
494 
495 	public void removeContent( JComponent content )
496 	{
497 		remove( content );
498 	}
499 
500 	public boolean onClose( boolean canCancel )
501 	{
502 		mockResponse.removePropertyChangeListener( propertyChangeListener );
503 
504 		requestEditor.release();
505 		responseEditor.release();
506 
507 		responseEditor.getParent().remove( responseEditor );
508 		responseEditor = null;
509 		requestEditor.getParent().remove( requestEditor );
510 		requestEditor = null;
511 
512 		return release();
513 	}
514 }