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