1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.impl.wsdl.panels.request;
14
15 import java.awt.BorderLayout;
16 import java.awt.Component;
17 import java.awt.Dimension;
18 import java.awt.Toolkit;
19 import java.awt.event.ActionEvent;
20 import java.awt.event.FocusEvent;
21 import java.awt.event.FocusListener;
22 import java.awt.event.ItemEvent;
23 import java.awt.event.ItemListener;
24 import java.awt.event.KeyEvent;
25 import java.awt.event.MouseAdapter;
26 import java.awt.event.MouseEvent;
27 import java.beans.PropertyChangeEvent;
28 import java.beans.PropertyChangeListener;
29
30 import javax.swing.AbstractAction;
31 import javax.swing.Action;
32 import javax.swing.BorderFactory;
33 import javax.swing.DefaultListModel;
34 import javax.swing.JButton;
35 import javax.swing.JComboBox;
36 import javax.swing.JComponent;
37 import javax.swing.JLabel;
38 import javax.swing.JList;
39 import javax.swing.JOptionPane;
40 import javax.swing.JPanel;
41 import javax.swing.JPopupMenu;
42 import javax.swing.JScrollPane;
43 import javax.swing.JSplitPane;
44 import javax.swing.KeyStroke;
45 import javax.swing.event.DocumentEvent;
46 import javax.swing.event.DocumentListener;
47
48 import org.apache.commons.logging.Log;
49 import org.apache.commons.logging.LogFactory;
50
51 import com.eviware.soapui.SoapUI;
52 import com.eviware.soapui.impl.wsdl.WsdlRequest;
53 import com.eviware.soapui.impl.wsdl.actions.request.AddToTestCaseAction;
54 import com.eviware.soapui.impl.wsdl.actions.request.CloneRequestAction;
55 import com.eviware.soapui.impl.wsdl.actions.request.CreateEmptyRequestAction;
56 import com.eviware.soapui.impl.wsdl.actions.request.RecreateRequestAction;
57 import com.eviware.soapui.impl.wsdl.panels.request.actions.ValidateRequestXmlAction;
58 import com.eviware.soapui.impl.wsdl.panels.request.actions.ValidateResponseXmlAction;
59 import com.eviware.soapui.impl.wsdl.panels.request.support.EndpointsComboBoxModel;
60 import com.eviware.soapui.impl.wsdl.teststeps.assertions.AssertionError;
61 import com.eviware.soapui.model.DesktopPanel;
62 import com.eviware.soapui.model.ModelItem;
63 import com.eviware.soapui.model.iface.Submit;
64 import com.eviware.soapui.model.iface.SubmitListener;
65 import com.eviware.soapui.model.iface.Submit.Status;
66 import com.eviware.soapui.support.JXmlTextArea;
67 import com.eviware.soapui.support.SoapUISplitPaneUI;
68 import com.eviware.soapui.support.UISupport;
69 import com.eviware.soapui.support.actions.ChangeSplitPaneOrientationAction;
70 import com.eviware.soapui.support.actions.FormatXmlAction;
71 import com.eviware.soapui.support.actions.SaveXmlTextAreaAction;
72 import com.jgoodies.forms.builder.ButtonBarBuilder;
73
74 /***
75 * DesktopPanel for WsdlRequests
76 *
77 * @author Ole.Matzura
78 */
79
80 public class WsdlRequestDesktopPanel extends JPanel implements DesktopPanel
81 {
82 private final static Log log = LogFactory.getLog( WsdlRequestDesktopPanel.class );
83
84 private JXmlTextArea resultArea;
85 private JXmlTextArea inputArea;
86 private JComboBox endpointCombo;
87 private JButton submitButton;
88 private JButton cancelButton;
89 private JComboBox encodingCombo;
90 private WsdlRequest request;
91 private EndpointsComboBoxModel endpointsModel;
92 private JLabel statusLabel;
93 private InternalPropertyChangeListener internalPropertyChangeListener;
94 private JButton splitButton;
95 private Submit submit;
96 private JButton recreateButton;
97 private JButton cloneButton;
98 private JButton createEmptyButton;
99 private JButton addToTestCaseButton;
100 private InternalSubmitListener internalSubmitListener;
101 private JSplitPane requestSplitPane;
102 private MoveFocusAction moveFocusAction;
103
104 public WsdlRequestDesktopPanel( WsdlRequest request )
105 {
106 super( new BorderLayout() );
107 this.request = (WsdlRequest) request;
108 this.endpointsModel = new EndpointsComboBoxModel( request );
109
110 internalSubmitListener = new InternalSubmitListener();
111 internalPropertyChangeListener = new InternalPropertyChangeListener();
112
113 request.addSubmitListener( internalSubmitListener );
114 request.addPropertyChangeListener( internalPropertyChangeListener );
115 request.getOperation().getInterface().addPropertyChangeListener( internalPropertyChangeListener );
116
117 add( buildUI(), BorderLayout.CENTER );
118 add( buildSearchBar(), BorderLayout.NORTH );
119 statusLabel = new JLabel("- no response -");
120 add( statusLabel, BorderLayout.SOUTH );
121
122 setPreferredSize( new Dimension( 600, 500 ));
123 }
124
125 private JComponent buildUI()
126 {
127 requestSplitPane = UISupport.createHorizontalSplit();
128 submitButton = createActionButton( new SubmitAction(), true );
129 cancelButton = createActionButton( new CancelAction(), false );
130 splitButton = createActionButton( new ChangeSplitPaneOrientationAction( requestSplitPane ), true );
131 recreateButton = createActionButton( new RecreateRequestAction(request), true );
132 cloneButton = createActionButton( new CloneRequestAction( request ), true );
133 createEmptyButton = createActionButton( new CreateEmptyRequestAction(request), true );
134 addToTestCaseButton = createActionButton( new AddToTestCaseAction( request ), true );
135
136 submitButton.setEnabled( request.getEndpoint() != null && request.getEndpoint().trim().length() > 0 );
137
138 moveFocusAction = new MoveFocusAction();
139
140 requestSplitPane.setTopComponent( buildInputUI() );
141 requestSplitPane.setBottomComponent( buildOutputUI() );
142 requestSplitPane.setDividerLocation( 0.5 );
143 requestSplitPane.setResizeWeight( 0.5 );
144 requestSplitPane.setBorder( null );
145
146 return requestSplitPane;
147 }
148
149 private JButton createActionButton( Action action, boolean enabled )
150 {
151 JButton button = new JButton( action );
152 action.putValue( Action.NAME, null );
153 button.setPreferredSize( new Dimension(24, 24 ));
154 button.setEnabled( enabled );
155 return button;
156 }
157
158 private Component buildOutputUI()
159 {
160 resultArea = new JXmlTextArea();
161 resultArea.setMinimumSize( new Dimension( 50, 50 ));
162 resultArea.setToolTipText( "Response Area" );
163 if( request.getResponseContent() != null )
164 {
165 resultArea.setText( request.getResponseContent() );
166 resultArea.setCaretPosition( 0 );
167 }
168 resultArea.addFocusListener( new ResultAreaFocusListener() );
169
170 DefaultListModel listModel = new DefaultListModel();
171 JList list = new JList( listModel );
172 list.setToolTipText( "Response Validation Errors" );
173 list.addMouseListener( new ValidationListMouseAdapter( list, resultArea ));
174
175 JScrollPane scrollPane = new JScrollPane( list );
176 scrollPane.setVisible( false );
177
178 JSplitPane resultAreaSplit = UISupport.createVerticalSplit();
179 JPopupMenu popup = new JPopupMenu();
180
181 popup = new JPopupMenu();
182 ValidateResponseXmlAction validateResponseXmlAction = new ValidateResponseXmlAction( request, scrollPane, listModel, resultAreaSplit, resultArea );
183 popup.add( validateResponseXmlAction );
184 FormatXmlAction formatXmlAction = new FormatXmlAction(resultArea);
185 popup.add( formatXmlAction);
186 popup.addSeparator();
187 popup.add( resultArea.getUndoAction() );
188 popup.add( resultArea.getRedoAction() );
189 popup.add( resultArea.getCopyAction() );
190 popup.add( resultArea.getCutAction() );
191 popup.add( resultArea.getPasteAction() );
192 popup.addSeparator();
193 popup.add( resultArea.getFindAndReplaceAction() );
194 popup.addSeparator();
195 SaveXmlTextAreaAction saveXmlTextAreaAction = new SaveXmlTextAreaAction(resultArea, "Save Response");
196 popup.add( saveXmlTextAreaAction);
197
198 resultArea.setRightClickPopup( popup );
199
200 resultArea.getInputHandler().addKeyBinding( "A+ENTER", submitButton.getAction() );
201 resultArea.getInputHandler().addKeyBinding( "A+X", cancelButton.getAction() );
202 resultArea.getInputHandler().addKeyBinding( "A+V", validateResponseXmlAction );
203 resultArea.getInputHandler().addKeyBinding( "A+F", formatXmlAction );
204 resultArea.getInputHandler().addKeyBinding( "A+S", saveXmlTextAreaAction );
205 resultArea.getInputHandler().addKeyBinding( "S+TAB", moveFocusAction );
206
207 resultAreaSplit.setTopComponent( resultArea );
208 resultAreaSplit.setBottomComponent( scrollPane);
209 resultAreaSplit.setDividerLocation( 1.0 );
210
211 return resultAreaSplit;
212 }
213
214 private Component buildInputUI()
215 {
216 inputArea = new JXmlTextArea();
217 inputArea.setMinimumSize( new Dimension( 50, 50 ));
218 inputArea.setToolTipText( "Request Area" );
219 inputArea.setText( request.getRequestContent() );
220 inputArea.setCaretPosition( 0 );
221 inputArea.setDiscardEditsOnSet( false );
222 inputArea.addFocusListener( new InputAreaFocusListener());
223
224 DefaultListModel listModel = new DefaultListModel();
225 JList list = new JList( listModel );
226 list.setToolTipText( "Request Validation Errors" );
227 list.addMouseListener( new ValidationListMouseAdapter( list, inputArea ));
228 JScrollPane scrollPane = new JScrollPane( list );
229 scrollPane.setVisible( false );
230
231 JSplitPane inputAreaSplit = UISupport.createVerticalSplit();
232
233 JPopupMenu inputPopup = new JPopupMenu();
234 ValidateRequestXmlAction validateRequestXmlAction = new ValidateRequestXmlAction( request, scrollPane, listModel, inputAreaSplit, inputArea );
235 inputPopup.add( validateRequestXmlAction);
236 FormatXmlAction formatXmlAction = new FormatXmlAction(inputArea);
237 inputPopup.add( formatXmlAction);
238 inputPopup.addSeparator();
239 inputPopup.add( inputArea.getUndoAction() );
240 inputPopup.add( inputArea.getRedoAction() );
241 inputPopup.add( inputArea.getCopyAction() );
242 inputPopup.add( inputArea.getCutAction() );
243 inputPopup.add( inputArea.getPasteAction() );
244 inputPopup.addSeparator();
245 inputPopup.add( inputArea.getFindAndReplaceAction() );
246 inputPopup.addSeparator();
247 SaveXmlTextAreaAction saveXmlTextAreaAction = new SaveXmlTextAreaAction(inputArea, "Save Request");
248 inputPopup.add( saveXmlTextAreaAction);
249 inputArea.setRightClickPopup( inputPopup );
250
251 inputArea.getDocument().addDocumentListener( new DocumentListener() {
252
253 public void insertUpdate(DocumentEvent e)
254 {
255 request.setRequest( inputArea.getText() );
256 }
257
258 public void removeUpdate(DocumentEvent e)
259 {
260 request.setRequest( inputArea.getText() );
261 }
262
263 public void changedUpdate(DocumentEvent e)
264 {
265 }} );
266
267 inputArea.getInputHandler().addKeyBinding( "A+ENTER", submitButton.getAction() );
268 inputArea.getInputHandler().addKeyBinding( "A+X", cancelButton.getAction() );
269 inputArea.getInputHandler().addKeyBinding( "A+V", validateRequestXmlAction );
270 inputArea.getInputHandler().addKeyBinding( "A+F", formatXmlAction );
271 inputArea.getInputHandler().addKeyBinding( "A+S", saveXmlTextAreaAction );
272 inputArea.getInputHandler().addKeyBinding( "S+TAB", moveFocusAction );
273
274 inputAreaSplit.setTopComponent( inputArea );
275 inputAreaSplit.setBottomComponent( scrollPane);
276 inputAreaSplit.setDividerLocation( 1.0 );
277
278 return inputAreaSplit;
279 }
280
281 private JPanel buildSearchBar()
282 {
283 endpointCombo = new JComboBox( endpointsModel);
284 endpointCombo.setToolTipText( endpointsModel.getSelectedItem().toString() );
285 endpointCombo.setPreferredSize( new Dimension( 300, 20 ));
286
287 endpointCombo.addItemListener( new ItemListener() {
288
289 public void itemStateChanged(ItemEvent e)
290 {
291 Object item = endpointCombo.getSelectedItem();
292 if( item == null )
293 {
294 endpointCombo.setToolTipText( "- no endpoint set for request -" );
295 }
296 else
297 {
298 String selectedItem = item.toString();
299 endpointCombo.setToolTipText( selectedItem );
300 }
301
302 submitButton.setEnabled( submit == null && request.getEndpoint() != null && request.getEndpoint().trim().length() > 0 );
303 }});
304
305 encodingCombo = new JComboBox();
306 encodingCombo.setEditable( true );
307 encodingCombo.addItem( "UTF-8" );
308 encodingCombo.addItem( "iso-8859-1" );
309 encodingCombo.setSelectedItem( request.getEncoding() );
310 encodingCombo.setToolTipText( "Sets the encoding to use for the request" );
311
312 encodingCombo.addItemListener( new ItemListener() {
313
314 public void itemStateChanged(ItemEvent e)
315 {
316 request.setEncoding( encodingCombo.getSelectedItem().toString() );
317 }});
318
319 ButtonBarBuilder builder = new ButtonBarBuilder();
320
321 builder.addFixed( submitButton );
322 builder.addRelatedGap();
323 builder.addFixed( addToTestCaseButton );
324 builder.addRelatedGap();
325 builder.addFixed( recreateButton );
326 builder.addRelatedGap();
327 builder.addFixed( createEmptyButton );
328 builder.addRelatedGap();
329 builder.addFixed( cloneButton );
330 builder.addRelatedGap();
331 builder.addFixed( cancelButton );
332 builder.addRelatedGap();
333 builder.addFixed( endpointCombo );
334 builder.addRelatedGap();
335 builder.addFixed( encodingCombo );
336 builder.addRelatedGap();
337 builder.addFixed( splitButton );
338 builder.setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) );
339 return builder.getPanel();
340 }
341
342 public void setEnabled( boolean enabled )
343 {
344 endpointCombo.setEnabled( enabled );
345 inputArea.setEditable( enabled );
346 resultArea.setEditable( enabled );
347 submitButton.setEnabled( enabled && request.getEndpoint() != null && request.getEndpoint().trim().length() > 0 );
348 addToTestCaseButton.setEnabled( enabled );
349 recreateButton.setEnabled( enabled );
350 createEmptyButton.setEnabled( enabled );
351 cloneButton.setEnabled( enabled );
352 encodingCombo.setEnabled( enabled );
353 }
354
355 private final class ValidationListMouseAdapter extends MouseAdapter
356 {
357 private final JList list;
358 private final JXmlTextArea textArea;
359
360 public ValidationListMouseAdapter(JList list, JXmlTextArea textArea)
361 {
362 this.list = list;
363 this.textArea = textArea;
364 }
365
366 public void mouseClicked(MouseEvent e)
367 {
368 if( e.getClickCount() < 2 ) return;
369
370 int ix = list.getSelectedIndex();
371 if( ix == -1 ) return;
372
373 Object obj = list.getModel().getElementAt( ix );
374 if( obj instanceof AssertionError )
375 {
376 AssertionError error = (AssertionError) obj;
377 if( error.getLineNumber() >= 0 )
378 {
379 textArea.setCaretPosition( textArea.getLineStartOffset( error.getLineNumber()-1 ) );
380 textArea.requestFocus();
381 }
382 else Toolkit.getDefaultToolkit().beep();
383 }
384 else Toolkit.getDefaultToolkit().beep();
385 }
386 }
387
388 private final class InputAreaFocusListener implements FocusListener
389 {
390 public void focusGained(FocusEvent e)
391 {
392
393 if( ((SoapUISplitPaneUI)requestSplitPane.getUI()).hasBeenDragged() ) return;
394
395 int pos = requestSplitPane.getDividerLocation();
396 if( pos >= 600 ) return;
397 if( requestSplitPane.getMaximumDividerLocation() > 700 )
398 requestSplitPane.setDividerLocation( 600 );
399 else
400 requestSplitPane.setDividerLocation( 0.8 );
401 }
402
403 public void focusLost(FocusEvent e)
404 {
405 }
406 }
407
408 private final class ResultAreaFocusListener implements FocusListener
409 {
410 public void focusGained(FocusEvent e)
411 {
412
413 if( ((SoapUISplitPaneUI)requestSplitPane.getUI()).hasBeenDragged() || resultArea.getText().trim().length() == 0 )
414 return;
415
416 int pos = requestSplitPane.getDividerLocation();
417 int maximumDividerLocation = requestSplitPane.getMaximumDividerLocation();
418 if( pos + 600 < maximumDividerLocation ) return;
419
420 if( maximumDividerLocation > 700 )
421 requestSplitPane.setDividerLocation( maximumDividerLocation-600 );
422 else
423 requestSplitPane.setDividerLocation( 0.2 );
424 }
425
426 public void focusLost(FocusEvent e)
427 {
428 }
429 }
430
431 public class SubmitAction extends AbstractAction
432 {
433 public SubmitAction()
434 {
435 putValue( Action.SMALL_ICON, SoapUI.createImageIcon( "/submit_request.gif"));
436 putValue( Action.SHORT_DESCRIPTION, "Submit request to specified endpoint URL" );
437 putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, KeyEvent.ALT_MASK ));
438 }
439
440 public void actionPerformed( ActionEvent e )
441 {
442 if( submit != null && submit.getStatus() == Submit.Status.RUNNING )
443 {
444 if( UISupport.confirm( "Cancel current request?", "Submit Request" ))
445 {
446 submit.cancel();
447 }
448 else return;
449 }
450
451 submit = request.submit();
452 }
453 }
454
455 private class CancelAction extends AbstractAction
456 {
457 public CancelAction()
458 {
459 super();
460 putValue( Action.SMALL_ICON, SoapUI.createImageIcon( "/cancel_request.gif"));
461 putValue( Action.SHORT_DESCRIPTION, "Aborts ongoing request" );
462 putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke( KeyEvent.VK_X, KeyEvent.ALT_MASK ));
463 }
464
465 public void actionPerformed( ActionEvent e )
466 {
467 if( submit == null ) return;
468
469 cancelButton.setEnabled( false );
470 WsdlRequestDesktopPanel.this.setEnabled( true );
471 submit.cancel();
472 }
473 }
474
475 private class MoveFocusAction extends AbstractAction
476 {
477 public void actionPerformed(ActionEvent e)
478 {
479 if( inputArea.hasFocus() )
480 resultArea.requestFocus();
481 else
482 inputArea.requestFocus();
483 }
484 }
485
486 private class InternalSubmitListener implements SubmitListener
487 {
488 private InternalSubmitListener()
489 {
490 }
491
492 public boolean beforeSubmit(Submit submit)
493 {
494 if( submit.getRequest() != request ) return true;
495
496 setEnabled( false );
497 cancelButton.setEnabled( true );
498 return true;
499 }
500
501 public void afterSubmit(Submit submit)
502 {
503 if( submit.getRequest() != request ) return;
504
505 Status status = submit.getStatus();
506 if( status != Status.CANCELED )
507 {
508 cancelButton.setEnabled( false );
509 setEnabled( true );
510
511 request.setResponse( submit.getResponse( false ).getContentAsString() );
512 }
513
514 String message = null;
515 String infoMessage = null;
516 String requestName = request.getOperation().getInterface().getName() + "." +
517 request.getOperation().getName() + ":" + request.getName();
518
519 if( status == Status.CANCELED )
520 {
521 message = "CANCELED";
522 infoMessage = "[" + requestName + "] - CANCELED";
523 }
524 else
525 {
526 if( status == Status.ERROR )
527 {
528 message = "Error getting response; " + submit.getError().getMessage();
529 infoMessage = "Error getting response for [" + requestName + "]; " + submit.getError().getMessage();
530 }
531 else
532 {
533 message = "response time: " + submit.getTimeTaken() + "ms (" +
534 submit.getResponse( false ).getContentLength() + " bytes)";
535 infoMessage = "Got response for [" + requestName + "] in " + submit.getTimeTaken() + "ms (" +
536 submit.getResponse( false ).getContentLength() + " bytes)";
537
538 resultArea.requestFocus();
539 }
540 }
541
542 log.info( infoMessage );
543 statusLabel.setText( message );
544
545 WsdlRequestDesktopPanel.this.submit = null;
546 }
547 }
548
549 private class InternalPropertyChangeListener implements PropertyChangeListener
550 {
551 public void propertyChange(PropertyChangeEvent evt)
552 {
553 String propertyName = evt.getPropertyName();
554 if( propertyName.equals( WsdlRequest.RESPONSE_PROPERTY ))
555 {
556 resultArea.setText( request.getResponseContent() );
557 resultArea.setCaretPosition( 0 );
558 }
559 else if( propertyName.equals( WsdlRequest.ENCODING_PROPERTY ))
560 {
561 encodingCombo.setSelectedItem( request.getEncoding() );
562 }
563 else if( propertyName.equals( WsdlRequest.REQUEST_PROPERTY ))
564 {
565 String requestContent = request.getRequestContent();
566 if( !requestContent.equals( inputArea.getText()))
567 inputArea.setText( requestContent );
568 }
569 }
570 }
571
572 public ModelItem getModelItem()
573 {
574 return request;
575 }
576
577 public boolean onClose()
578 {
579 if( submit != null && submit.getStatus() == Submit.Status.RUNNING )
580 {
581 int retVal = JOptionPane.showConfirmDialog( SoapUI.getInstance().getFrame(),
582 "Cancel request before closing?", "Closing window", JOptionPane.YES_NO_CANCEL_OPTION );
583 if( retVal == JOptionPane.CANCEL_OPTION ) return false;
584
585 if( retVal == JOptionPane.YES_OPTION && submit.getStatus() == Submit.Status.RUNNING )
586 submit.cancel();
587 }
588
589 request.removeSubmitListener( internalSubmitListener );
590 request.removePropertyChangeListener( internalPropertyChangeListener );
591 request.getOperation().getInterface().removePropertyChangeListener( internalPropertyChangeListener );
592
593 endpointsModel.release();
594
595 return true;
596 }
597
598 public JComponent getComponent()
599 {
600 return this;
601 }
602 }