1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.impl.support.panels;
14
15 import com.eviware.soapui.SoapUI;
16 import com.eviware.soapui.impl.support.AbstractHttpRequest;
17 import com.eviware.soapui.impl.support.EndpointsComboBoxModel;
18 import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
19 import com.eviware.soapui.impl.support.components.ModelItemXmlEditor;
20 import com.eviware.soapui.impl.support.components.RequestMessageXmlEditor;
21 import com.eviware.soapui.impl.support.components.ResponseMessageXmlEditor;
22 import com.eviware.soapui.impl.wsdl.submit.transports.http.HttpResponse;
23 import com.eviware.soapui.model.ModelItem;
24 import com.eviware.soapui.model.iface.Request.SubmitException;
25 import com.eviware.soapui.model.iface.Submit;
26 import com.eviware.soapui.model.iface.Submit.Status;
27 import com.eviware.soapui.model.iface.SubmitContext;
28 import com.eviware.soapui.model.iface.SubmitListener;
29 import com.eviware.soapui.settings.UISettings;
30 import com.eviware.soapui.support.UISupport;
31 import com.eviware.soapui.support.actions.ChangeSplitPaneOrientationAction;
32 import com.eviware.soapui.support.components.JEditorStatusBarWithProgress;
33 import com.eviware.soapui.support.components.JXToolBar;
34 import com.eviware.soapui.support.editor.views.xml.source.XmlSourceEditorView;
35 import com.eviware.soapui.support.editor.xml.XmlDocument;
36 import com.eviware.soapui.support.swing.SoapUISplitPaneUI;
37 import com.eviware.soapui.support.xml.JXEditTextArea;
38 import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
39 import org.apache.log4j.Logger;
40
41 import javax.swing.*;
42 import javax.swing.event.ChangeEvent;
43 import javax.swing.event.ChangeListener;
44 import java.awt.*;
45 import java.awt.event.*;
46 import java.beans.PropertyChangeEvent;
47
48 /***
49 * Abstract DesktopPanel for HttpRequests
50 *
51 * @author Ole.Matzura
52 */
53
54 public abstract class AbstractHttpRequestDesktopPanel<T extends ModelItem, T2 extends AbstractHttpRequest<?>> extends
55 ModelItemDesktopPanel<T> implements SubmitListener
56 {
57 private final static Logger log = Logger.getLogger( AbstractHttpRequestDesktopPanel.class );
58
59 private JComponent endpointComponent;
60 private JButton submitButton;
61 private JButton cancelButton;
62 private EndpointsComboBoxModel endpointsModel;
63 private JEditorStatusBarWithProgress statusBar;
64 private JButton splitButton;
65 private Submit submit;
66 private JSplitPane requestSplitPane;
67 private MoveFocusAction moveFocusAction;
68 private ClosePanelAction closePanelAction = new ClosePanelAction();
69 private T2 request;
70
71 private ModelItemXmlEditor<?, ?> requestEditor;
72 private ModelItemXmlEditor<?, ?> responseEditor;
73
74 private JTabbedPane requestTabs;
75 private JPanel requestTabPanel;
76 private JToggleButton tabsButton;
77
78 private boolean responseHasFocus;
79 private SubmitAction submitAction;
80 private boolean hasClosed;
81
82 public AbstractHttpRequestDesktopPanel( T modelItem, T2 request )
83 {
84 super( modelItem );
85
86 this.request = request;
87
88 init( request );
89 }
90
91 protected void init( T2 request )
92 {
93 this.endpointsModel = new EndpointsComboBoxModel( request );
94
95 request.addSubmitListener( this );
96 request.addPropertyChangeListener( this );
97
98 add( buildContent(), BorderLayout.CENTER );
99 add( buildToolbar(), BorderLayout.NORTH );
100 add( buildStatusLabel(), BorderLayout.SOUTH );
101
102 setPreferredSize( new Dimension( 600, 500 ) );
103
104 addFocusListener( new FocusAdapter()
105 {
106
107 @Override
108 public void focusGained( FocusEvent e )
109 {
110 if( requestTabs.getSelectedIndex() == 1 || responseHasFocus )
111 responseEditor.requestFocusInWindow();
112 else
113 requestEditor.requestFocusInWindow();
114 }
115 } );
116 }
117
118 public final T2 getRequest()
119 {
120 return request;
121 }
122
123 public final ModelItemXmlEditor<?, ?> getRequestEditor()
124 {
125 return requestEditor;
126 }
127
128 public final ModelItemXmlEditor<?, ?> getResponseEditor()
129 {
130 return responseEditor;
131 }
132
133 public Submit getSubmit()
134 {
135 return submit;
136 }
137
138 protected JComponent buildStatusLabel()
139 {
140 statusBar = new JEditorStatusBarWithProgress();
141 statusBar.setBorder( BorderFactory.createEmptyBorder( 1, 0, 0, 0 ) );
142
143 return statusBar;
144 }
145
146 public JEditorStatusBarWithProgress getStatusBar()
147 {
148 return statusBar;
149 }
150
151 protected JComponent buildContent()
152 {
153 requestSplitPane = UISupport.createHorizontalSplit();
154 requestSplitPane.setResizeWeight( 0.5 );
155 requestSplitPane.setBorder( null );
156
157 submitAction = new SubmitAction();
158 submitButton = createActionButton( submitAction, true );
159 submitButton.setEnabled( request.getEndpoint() != null && request.getEndpoint().trim().length() > 0 );
160
161 cancelButton = createActionButton( new CancelAction(), false );
162 splitButton = createActionButton( new ChangeSplitPaneOrientationAction( requestSplitPane ), true );
163
164 tabsButton = new JToggleButton( new ChangeToTabsAction() );
165 tabsButton.setPreferredSize( UISupport.TOOLBAR_BUTTON_DIMENSION );
166
167 moveFocusAction = new MoveFocusAction();
168
169 requestEditor = buildRequestEditor();
170 responseEditor = buildResponseEditor();
171
172 requestTabs = new JTabbedPane();
173 requestTabs.addChangeListener( new ChangeListener()
174 {
175
176 public void stateChanged( ChangeEvent e )
177 {
178 SwingUtilities.invokeLater( new Runnable()
179 {
180
181 public void run()
182 {
183 int ix = requestTabs.getSelectedIndex();
184 if( ix == 0 )
185 requestEditor.requestFocus();
186 else if( ix == 1 && responseEditor != null )
187 responseEditor.requestFocus();
188 }
189 } );
190 }
191 } );
192
193 requestTabPanel = UISupport.createTabPanel( requestTabs, true );
194
195 if( request.getSettings().getBoolean( UISettings.START_WITH_REQUEST_TABS ) )
196 {
197 requestTabs.addTab( "Request", requestEditor );
198 if( responseEditor != null )
199 requestTabs.addTab( "Response", responseEditor );
200 splitButton.setEnabled( false );
201 tabsButton.setSelected( true );
202
203 return requestTabPanel;
204 }
205 else
206 {
207 requestSplitPane.setTopComponent( requestEditor );
208 requestSplitPane.setBottomComponent( responseEditor );
209 requestSplitPane.setDividerLocation( 0.5 );
210 return requestSplitPane;
211 }
212 }
213
214 public SubmitAction getSubmitAction()
215 {
216 return submitAction;
217 }
218
219 protected abstract ModelItemXmlEditor<?, ?> buildResponseEditor();
220
221 protected abstract ModelItemXmlEditor<?, ?> buildRequestEditor();
222
223 protected JComponent buildToolbar()
224 {
225 endpointComponent = buildEndpointComponent();
226
227 JXToolBar toolbar = UISupport.createToolbar();
228 toolbar.add( submitButton );
229
230 insertButtons( toolbar );
231
232 toolbar.add( cancelButton );
233
234 if( endpointComponent != null )
235 {
236 toolbar.addSeparator();
237 toolbar.add( endpointComponent );
238 }
239
240 toolbar.add( Box.createHorizontalGlue() );
241 toolbar.add( tabsButton );
242 toolbar.add( splitButton );
243 toolbar.add( UISupport.createToolbarButton( new ShowOnlineHelpAction( getHelpUrl() ) ) );
244
245 return toolbar;
246 }
247
248 protected JComponent buildEndpointComponent()
249 {
250 final JComboBox endpointCombo = new JComboBox( endpointsModel );
251 endpointCombo.setToolTipText( endpointsModel.getSelectedItem().toString() );
252
253 endpointCombo.addItemListener( new ItemListener()
254 {
255 public void itemStateChanged( ItemEvent e )
256 {
257 Object item = endpointCombo.getSelectedItem();
258 if( item == null )
259 {
260 endpointCombo.setToolTipText( "- no endpoint set for request -" );
261 }
262 else
263 {
264 String selectedItem = item.toString();
265 endpointCombo.setToolTipText( selectedItem );
266 }
267 }
268 } );
269
270 return endpointCombo;
271 }
272
273 public void propertyChange( PropertyChangeEvent evt )
274 {
275 if( evt.getPropertyName().equals( AbstractHttpRequest.ENDPOINT_PROPERTY ) )
276 {
277 submitButton.setEnabled( submit == null && request.getEndpoint() != null
278 && request.getEndpoint().trim().length() > 0 );
279 }
280
281 super.propertyChange( evt );
282 }
283
284 public JButton getSubmitButton()
285 {
286 return submitButton;
287 }
288
289 protected abstract String getHelpUrl();
290
291 protected abstract void insertButtons( JXToolBar toolbar );
292
293 public void setEnabled( boolean enabled )
294 {
295 if( endpointComponent != null )
296 endpointComponent.setEnabled( enabled );
297
298 requestEditor.setEditable( enabled );
299 if( responseEditor != null )
300 responseEditor.setEditable( enabled );
301
302 submitButton.setEnabled( enabled && request.hasEndpoint() );
303
304 statusBar.setIndeterminate( !enabled );
305 }
306
307 public abstract class AbstractHttpRequestMessageEditor<T3 extends XmlDocument> extends RequestMessageXmlEditor<T2, T3>
308 {
309 private InputAreaFocusListener inputAreaFocusListener;
310 private JXEditTextArea inputArea;
311
312 public AbstractHttpRequestMessageEditor( T3 document )
313 {
314 super( document, request );
315
316 XmlSourceEditorView editor = getSourceEditor();
317 if( editor != null )
318 {
319 inputArea = editor.getInputArea();
320 inputArea.getInputHandler().addKeyBinding( "A+ENTER", submitButton.getAction() );
321 inputArea.getInputHandler().addKeyBinding( "A+X", cancelButton.getAction() );
322 inputArea.getInputHandler().addKeyBinding( "AC+TAB", moveFocusAction );
323 inputArea.getInputHandler().addKeyBinding( "C+F4", closePanelAction );
324
325 inputAreaFocusListener = new InputAreaFocusListener( editor );
326 inputArea.addFocusListener( inputAreaFocusListener );
327 }
328 }
329
330 @Override
331 public void release()
332 {
333 super.release();
334 if( inputArea != null )
335 inputArea.removeFocusListener( inputAreaFocusListener );
336 }
337 }
338
339 public abstract class AbstractHttpResponseMessageEditor<T3 extends XmlDocument> extends ResponseMessageXmlEditor<T2, T3>
340 {
341 private JXEditTextArea inputArea;
342 private ResultAreaFocusListener resultAreaFocusListener;
343
344 public AbstractHttpResponseMessageEditor( T3 document )
345 {
346 super( document, request );
347
348 XmlSourceEditorView editor = getSourceEditor();
349
350 inputArea = editor.getInputArea();
351 if( inputArea != null )
352 {
353 resultAreaFocusListener = new ResultAreaFocusListener( editor );
354 inputArea.addFocusListener( resultAreaFocusListener );
355
356 inputArea.getInputHandler().addKeyBinding( "A+ENTER", submitButton.getAction() );
357 inputArea.getInputHandler().addKeyBinding( "A+X", cancelButton.getAction() );
358 inputArea.getInputHandler().addKeyBinding( "AC+TAB", moveFocusAction );
359 inputArea.getInputHandler().addKeyBinding( "C+F4", closePanelAction );
360 }
361 }
362
363 @Override
364 public void release()
365 {
366 super.release();
367
368 if( inputArea != null )
369 inputArea.removeFocusListener( resultAreaFocusListener );
370 }
371 }
372
373 protected final class InputAreaFocusListener implements FocusListener
374 {
375 private final XmlSourceEditorView sourceEditor;
376
377 public InputAreaFocusListener( XmlSourceEditorView editor )
378 {
379 this.sourceEditor = editor;
380 }
381
382 public void focusGained( FocusEvent e )
383 {
384 responseHasFocus = false;
385
386 statusBar.setTarget( sourceEditor.getInputArea() );
387 if( !splitButton.isEnabled() )
388 {
389 requestTabs.setSelectedIndex( 0 );
390 return;
391 }
392
393 if( getModelItem().getSettings().getBoolean( UISettings.NO_RESIZE_REQUEST_EDITOR ) )
394 return;
395
396
397 if( ( (SoapUISplitPaneUI) requestSplitPane.getUI() ).hasBeenDragged() )
398 return;
399
400 int pos = requestSplitPane.getDividerLocation();
401 if( pos >= 600 )
402 return;
403 if( requestSplitPane.getMaximumDividerLocation() > 700 )
404 requestSplitPane.setDividerLocation( 600 );
405 else
406 requestSplitPane.setDividerLocation( 0.8 );
407 }
408
409 public void focusLost( FocusEvent e )
410 {
411 }
412 }
413
414 protected final class ResultAreaFocusListener implements FocusListener
415 {
416 private final XmlSourceEditorView sourceEditor;
417
418 public ResultAreaFocusListener( XmlSourceEditorView editor )
419 {
420 this.sourceEditor = editor;
421 }
422
423 public void focusGained( FocusEvent e )
424 {
425 responseHasFocus = true;
426
427 statusBar.setTarget( sourceEditor.getInputArea() );
428 if( !splitButton.isEnabled() )
429 {
430 requestTabs.setSelectedIndex( 1 );
431 return;
432 }
433
434 if( request.getSettings().getBoolean( UISettings.NO_RESIZE_REQUEST_EDITOR ) )
435 return;
436
437
438 if( ( (SoapUISplitPaneUI) requestSplitPane.getUI() ).hasBeenDragged() || request.getResponse() == null )
439 return;
440
441 int pos = requestSplitPane.getDividerLocation();
442 int maximumDividerLocation = requestSplitPane.getMaximumDividerLocation();
443 if( pos + 600 < maximumDividerLocation )
444 return;
445
446 if( maximumDividerLocation > 700 )
447 requestSplitPane.setDividerLocation( maximumDividerLocation - 600 );
448 else
449 requestSplitPane.setDividerLocation( 0.2 );
450 }
451
452 public void focusLost( FocusEvent e )
453 {
454 }
455 }
456
457 public class SubmitAction extends AbstractAction
458 {
459 public SubmitAction()
460 {
461 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/submit_request.gif" ) );
462 putValue( Action.SHORT_DESCRIPTION, "Submit request to specified endpoint URL" );
463 putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "alt ENTER" ) );
464 }
465
466 public void actionPerformed( ActionEvent e )
467 {
468 onSubmit();
469 }
470 }
471
472 protected abstract Submit doSubmit() throws SubmitException;
473
474 private class CancelAction extends AbstractAction
475 {
476 public CancelAction()
477 {
478 super();
479 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/cancel_request.gif" ) );
480 putValue( Action.SHORT_DESCRIPTION, "Aborts ongoing request" );
481 putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "alt X" ) );
482 }
483
484 public void actionPerformed( ActionEvent e )
485 {
486 onCancel();
487 }
488 }
489
490 private class ClosePanelAction extends AbstractAction
491 {
492 public void actionPerformed( ActionEvent e )
493 {
494 SoapUI.getDesktop().closeDesktopPanel( getModelItem() );
495 }
496 }
497
498 private class MoveFocusAction extends AbstractAction
499 {
500 public void actionPerformed( ActionEvent e )
501 {
502 if( requestEditor.hasFocus() )
503 {
504 responseEditor.requestFocus();
505 }
506 else
507 {
508 requestEditor.requestFocus();
509 }
510 }
511 }
512
513 public boolean beforeSubmit( Submit submit, SubmitContext context )
514 {
515 if( submit.getRequest() != request )
516 return true;
517
518 if( getModelItem().getSettings().getBoolean( UISettings.AUTO_VALIDATE_REQUEST ) )
519 {
520 boolean result = requestEditor.saveDocument( true );
521 if( !result && getModelItem().getSettings().getBoolean( UISettings.ABORT_ON_INVALID_REQUEST ) )
522 {
523 statusBar.setInfo( "Cancelled request due to invalid content" );
524 return false;
525 }
526 }
527 else
528 {
529 requestEditor.saveDocument( false );
530 }
531
532 setEnabled( false );
533 cancelButton.setEnabled( AbstractHttpRequestDesktopPanel.this.submit != null );
534 return true;
535 }
536
537 public void afterSubmit( Submit submit, SubmitContext context )
538 {
539 if( submit.getRequest() != request )
540 return;
541
542 Status status = submit.getStatus();
543 HttpResponse response = (HttpResponse) submit.getResponse();
544 if( status != Status.CANCELED )
545 {
546 request.setResponse( response, context );
547 }
548
549 if( hasClosed )
550 {
551 request.removeSubmitListener(this);
552 return;
553 }
554
555 cancelButton.setEnabled( false );
556 setEnabled( true );
557
558 String message = null;
559 String infoMessage = null;
560 String requestName = request.getOperation() == null ? request.getName() :
561 request.getOperation().getInterface().getName() + "." + request.getOperation().getName()
562 + ":" + request.getName();
563
564 if( status == Status.CANCELED )
565 {
566 message = "CANCELED";
567 infoMessage = "[" + requestName + "] - CANCELED";
568 }
569 else
570 {
571 if( status == Status.ERROR || response == null )
572 {
573 message = "Error getting response; " + submit.getError();
574 infoMessage = "Error getting response for [" + requestName + "]; " + submit.getError();
575 }
576 else
577 {
578 message = "response time: " + response.getTimeTaken() + "ms (" + response.getContentLength() + " bytes)";
579 infoMessage = "Got response for [" + requestName + "] in " + response.getTimeTaken() + "ms ("
580 + response.getContentLength() + " bytes)";
581
582 if( !splitButton.isEnabled() )
583 requestTabs.setSelectedIndex( 1 );
584
585 responseEditor.requestFocus();
586 }
587 }
588
589 logMessages( message, infoMessage );
590
591 if( getModelItem().getSettings().getBoolean( UISettings.AUTO_VALIDATE_RESPONSE ) )
592 responseEditor.getSourceEditor().validate();
593
594 AbstractHttpRequestDesktopPanel.this.submit = null;
595 }
596
597 protected void logMessages( String message, String infoMessage )
598 {
599 log.info( infoMessage );
600 statusBar.setInfo( message );
601 }
602
603 public boolean onClose( boolean canCancel )
604 {
605 if( canCancel )
606 {
607 if( submit != null && submit.getStatus() == Submit.Status.RUNNING )
608 {
609 Boolean retVal = UISupport.confirmOrCancel( "Cancel request before closing?", "Closing window" );
610 if( retVal == null )
611 return false;
612
613 if( retVal.booleanValue() && submit.getStatus() == Submit.Status.RUNNING )
614 {
615 submit.cancel();
616 }
617
618 hasClosed = true;
619 }
620 else
621 {
622 request.removeSubmitListener( this );
623 }
624 }
625 else if( submit != null && submit.getStatus() == Submit.Status.RUNNING )
626 {
627 submit.cancel();
628 hasClosed = true;
629 }
630 else
631 {
632 request.removeSubmitListener( this );
633 }
634
635 request.removePropertyChangeListener( this );
636 requestEditor.saveDocument( false );
637
638 if( responseEditor != null )
639 responseEditor.getParent().remove( responseEditor );
640
641 requestEditor.getParent().remove( requestEditor );
642 requestSplitPane.removeAll();
643
644 return release();
645 }
646
647 @Override
648 protected boolean release()
649 {
650 endpointsModel.release();
651 requestEditor.release();
652
653 if( responseEditor != null )
654 responseEditor.release();
655
656 return super.release();
657 }
658
659 public boolean dependsOn( ModelItem modelItem )
660 {
661 return request.dependsOn( modelItem );
662 }
663
664 private final class ChangeToTabsAction extends AbstractAction
665 {
666 public ChangeToTabsAction()
667 {
668 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/toggle_tabs.gif" ) );
669 putValue( Action.SHORT_DESCRIPTION, "Toggles to tab-based layout" );
670 }
671
672 public void actionPerformed( ActionEvent e )
673 {
674 if( splitButton.isEnabled() )
675 {
676 splitButton.setEnabled( false );
677 removeContent( requestSplitPane );
678 setContent( requestTabPanel );
679 requestTabs.addTab( "Request", requestEditor );
680
681 if( responseEditor != null )
682 requestTabs.addTab( "Response", responseEditor );
683
684 if( responseHasFocus )
685 {
686 requestTabs.setSelectedIndex( 1 );
687 requestEditor.requestFocus();
688 }
689 }
690 else
691 {
692 int selectedIndex = requestTabs.getSelectedIndex();
693
694 splitButton.setEnabled( true );
695 removeContent( requestTabPanel );
696 setContent( requestSplitPane );
697 requestSplitPane.setTopComponent( requestEditor );
698 if( responseEditor != null )
699 requestSplitPane.setBottomComponent( responseEditor );
700 requestSplitPane.setDividerLocation( 0.5 );
701
702 if( selectedIndex == 0 || responseEditor == null )
703 requestEditor.requestFocus();
704 else
705 responseEditor.requestFocus();
706 }
707
708 revalidate();
709 }
710 }
711
712 public void setContent( JComponent content )
713 {
714 add( content, BorderLayout.CENTER );
715 }
716
717 public void removeContent( JComponent content )
718 {
719 remove( content );
720 }
721
722 protected void onSubmit()
723 {
724 if( submit != null && submit.getStatus() == Submit.Status.RUNNING )
725 {
726 if( UISupport.confirm( "Cancel current request?", "Submit Request" ) )
727 {
728 submit.cancel();
729 }
730 else
731 return;
732 }
733
734 try
735 {
736 submit = doSubmit();
737 }
738 catch( SubmitException e1 )
739 {
740 SoapUI.logError( e1 );
741 }
742 }
743
744 protected void onCancel()
745 {
746 if( submit == null )
747 return;
748
749 cancelButton.setEnabled( false );
750 submit.cancel();
751 setEnabled( true );
752 submit = null;
753 }
754
755 public boolean isHasClosed()
756 {
757 return hasClosed;
758 }
759 }