001: /*
002: * soapUI, copyright (C) 2004-2007 eviware.com
003: *
004: * soapUI is free software; you can redistribute it and/or modify it under the
005: * terms of version 2.1 of the GNU Lesser General Public License as published by
006: * the Free Software Foundation.
007: *
008: * soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
009: * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
010: * See the GNU Lesser General Public License for more details at gnu.org.
011: */
012:
013: package com.eviware.soapui.impl.wsdl.panels.mockoperation;
014:
015: import java.awt.BorderLayout;
016: import java.awt.Component;
017: import java.awt.Dimension;
018: import java.awt.event.ActionEvent;
019: import java.awt.event.ItemEvent;
020: import java.awt.event.ItemListener;
021: import java.beans.PropertyChangeEvent;
022: import java.beans.PropertyChangeListener;
023: import java.util.ArrayList;
024: import java.util.List;
025:
026: import javax.swing.AbstractAction;
027: import javax.swing.AbstractListModel;
028: import javax.swing.Action;
029: import javax.swing.BorderFactory;
030: import javax.swing.DefaultComboBoxModel;
031: import javax.swing.JComboBox;
032: import javax.swing.JLabel;
033: import javax.swing.JList;
034: import javax.swing.JPanel;
035: import javax.swing.JScrollPane;
036: import javax.swing.JSplitPane;
037: import javax.swing.ListCellRenderer;
038: import javax.swing.ListModel;
039:
040: import org.apache.xmlbeans.XmlObject;
041:
042: import com.eviware.soapui.SoapUI;
043: import com.eviware.soapui.config.DispatchStyleConfig;
044: import com.eviware.soapui.impl.wsdl.WsdlInterface;
045: import com.eviware.soapui.impl.wsdl.WsdlOperation;
046: import com.eviware.soapui.impl.wsdl.actions.mockoperation.NewMockResponseAction;
047: import com.eviware.soapui.impl.wsdl.actions.mockoperation.OpenRequestForMockOperationAction;
048: import com.eviware.soapui.impl.wsdl.actions.support.ShowOnlineHelpAction;
049: import com.eviware.soapui.impl.wsdl.mock.WsdlMockOperation;
050: import com.eviware.soapui.impl.wsdl.mock.WsdlMockRequest;
051: import com.eviware.soapui.impl.wsdl.mock.WsdlMockResponse;
052: import com.eviware.soapui.impl.wsdl.mock.WsdlMockResult;
053: import com.eviware.soapui.impl.wsdl.panels.teststeps.support.GroovyEditor;
054: import com.eviware.soapui.impl.wsdl.panels.teststeps.support.GroovyEditorModel;
055: import com.eviware.soapui.impl.wsdl.support.HelpUrls;
056: import com.eviware.soapui.model.ModelItem;
057: import com.eviware.soapui.model.iface.Interface;
058: import com.eviware.soapui.model.iface.Operation;
059: import com.eviware.soapui.model.mock.MockOperation;
060: import com.eviware.soapui.model.mock.MockResponse;
061: import com.eviware.soapui.model.mock.MockServiceListener;
062: import com.eviware.soapui.model.settings.Settings;
063: import com.eviware.soapui.model.support.InterfaceListenerAdapter;
064: import com.eviware.soapui.model.support.ProjectListenerAdapter;
065: import com.eviware.soapui.model.util.ModelItemNames;
066: import com.eviware.soapui.support.UISupport;
067: import com.eviware.soapui.support.action.swing.SwingActionDelegate;
068: import com.eviware.soapui.support.components.JXToolBar;
069: import com.eviware.soapui.support.swing.ExtendedComboBoxModel;
070: import com.eviware.soapui.support.swing.ModelItemListMouseListener;
071: import com.eviware.soapui.support.types.StringList;
072: import com.eviware.soapui.support.xml.XmlUtils;
073: import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
074: import com.jgoodies.forms.builder.ButtonBarBuilder;
075:
076: /**
077: * DesktopPanel for WsdlGroovyTestSteps
078: *
079: * @author Ole.Matzura
080: */
081:
082: public class WsdlMockOperationDesktopPanel extends
083: ModelItemDesktopPanel<WsdlMockOperation> {
084: private JList responseList;
085: private JComboBox interfaceCombo;
086: private JComboBox operationCombo;
087: private JComboBox dispatchCombo;
088: private JPanel dispatchPanel;
089: private InternalInterfaceListener interfaceListener = new InternalInterfaceListener();
090: private InternalProjectListener projectListener = new InternalProjectListener();
091: private WsdlInterface currentInterface;
092: private JPanel groovyEditorPanel;
093: private JPanel xpathEditorPanel;
094: private JComboBox defaultResponseCombo;
095: private JSplitPane splitPane;
096: private ResponseListModel responseListModel;
097: private GroovyEditor xpathEditor;
098: private GroovyEditor groovyEditor;
099:
100: public WsdlMockOperationDesktopPanel(WsdlMockOperation mockOperation) {
101: super (mockOperation);
102:
103: buildUI();
104: setPreferredSize(new Dimension(600, 440));
105:
106: mockOperation.getMockService().getProject().addProjectListener(
107: projectListener);
108:
109: WsdlOperation operation = getModelItem().getOperation();
110: if (operation != null) {
111: currentInterface = operation.getInterface();
112: currentInterface.addInterfaceListener(interfaceListener);
113: }
114: }
115:
116: private void buildUI() {
117: add(buildToolbar(), BorderLayout.NORTH);
118:
119: splitPane = UISupport.createVerticalSplit();
120: splitPane.setTopComponent(buildResponseList());
121: splitPane.setBottomComponent(buildDispatchEditor());
122: splitPane.setDividerLocation(0.5);
123: splitPane.setDividerLocation(150);
124:
125: add(splitPane, BorderLayout.CENTER);
126: }
127:
128: private Component buildResponseList() {
129: responseListModel = new ResponseListModel();
130: responseList = new JList(responseListModel);
131: responseList.addMouseListener(new ModelItemListMouseListener());
132: responseList.setCellRenderer(new ResponseListCellRenderer());
133:
134: JScrollPane scrollPane = new JScrollPane(responseList);
135: UISupport.addTitledBorder(scrollPane, "Reponses");
136: return scrollPane;
137: }
138:
139: private Component buildDispatchEditor() {
140: buildGroovyEditor();
141: buildXPathEditor();
142:
143: dispatchPanel = new JPanel(new BorderLayout());
144: dispatchPanel.setOpaque(true);
145: ButtonBarBuilder builder = new ButtonBarBuilder();
146: builder.addFixed(new JLabel("Dispatch: "));
147: builder.addRelatedGap();
148: dispatchCombo = new JComboBox(new Object[] { "Sequence",
149: "Random", "XPath", "Script" });
150:
151: dispatchCombo.addItemListener(new ItemListener() {
152:
153: public void itemStateChanged(ItemEvent e) {
154: if (dispatchPanel.getComponentCount() > 1)
155: dispatchPanel.remove(1);
156:
157: String item = (String) dispatchCombo.getSelectedItem();
158: if (item.equalsIgnoreCase("Script")) {
159: getModelItem().setDispatchStyle(
160: DispatchStyleConfig.SCRIPT);
161: dispatchPanel.add(groovyEditorPanel);
162: groovyEditor.getEditArea().setText(
163: getModelItem().getDispatchPath());
164: defaultResponseCombo.setEnabled(true);
165: } else if (item.equalsIgnoreCase("XPath")) {
166: getModelItem().setDispatchStyle(
167: DispatchStyleConfig.XPATH);
168: dispatchPanel.add(xpathEditorPanel);
169: xpathEditor.getEditArea().setText(
170: getModelItem().getDispatchPath());
171: defaultResponseCombo.setEnabled(true);
172: } else if (item.equalsIgnoreCase("Sequence")) {
173: getModelItem().setDispatchStyle(
174: DispatchStyleConfig.SEQUENCE);
175: defaultResponseCombo.setEnabled(false);
176: } else if (item.equalsIgnoreCase("Random")) {
177: getModelItem().setDispatchStyle(
178: DispatchStyleConfig.RANDOM);
179: defaultResponseCombo.setEnabled(false);
180: }
181:
182: dispatchPanel.revalidate();
183: dispatchPanel.repaint();
184:
185: }
186: });
187:
188: builder.addFixed(dispatchCombo);
189:
190: builder.addUnrelatedGap();
191: builder.addFixed(new JLabel("Default Response: "));
192: builder.addRelatedGap();
193:
194: ModelItemNames<MockResponse> names = new ModelItemNames<MockResponse>(
195: getModelItem().getMockResponses());
196: defaultResponseCombo = new JComboBox(new ExtendedComboBoxModel(
197: names.getNames()));
198: defaultResponseCombo.setPreferredSize(new Dimension(150, 20));
199: defaultResponseCombo.addItemListener(new ItemListener() {
200:
201: public void itemStateChanged(ItemEvent e) {
202: Object selectedItem = defaultResponseCombo
203: .getSelectedItem();
204: getModelItem()
205: .setDefaultResponse((String) selectedItem);
206: }
207: });
208:
209: builder.addFixed(defaultResponseCombo);
210: builder.setBorder(BorderFactory.createEmptyBorder(2, 3, 3, 3));
211:
212: dispatchPanel.add(builder.getPanel(), BorderLayout.NORTH);
213:
214: // init data
215: defaultResponseCombo.setSelectedItem(getModelItem()
216: .getDefaultResponse());
217: DispatchStyleConfig.Enum dispatchStyle = getModelItem()
218: .getDispatchStyle();
219: if (dispatchStyle.equals(DispatchStyleConfig.SEQUENCE)) {
220: dispatchCombo.setSelectedItem("Sequence");
221: defaultResponseCombo.setEnabled(false);
222: } else if (dispatchStyle.equals(DispatchStyleConfig.RANDOM)) {
223: dispatchCombo.setSelectedItem("Random");
224: defaultResponseCombo.setEnabled(false);
225: } else if (dispatchStyle.equals(DispatchStyleConfig.SCRIPT)) {
226: dispatchCombo.setSelectedItem("Script");
227: } else if (dispatchStyle.equals(DispatchStyleConfig.XPATH)) {
228: dispatchCombo.setSelectedItem("XPath");
229: }
230:
231: return dispatchPanel;
232: }
233:
234: private void buildXPathEditor() {
235: xpathEditorPanel = new JPanel(new BorderLayout());
236: DispatchXPathGroovyEditorModel editorModel = new DispatchXPathGroovyEditorModel();
237: xpathEditor = new GroovyEditor(editorModel);
238: xpathEditorPanel.add(new JScrollPane(xpathEditor),
239: BorderLayout.CENTER);
240: xpathEditorPanel.add(buildXPathEditorToolbar(editorModel),
241: BorderLayout.PAGE_START);
242: }
243:
244: public GroovyEditor getXPathEditor() {
245: return xpathEditor;
246: }
247:
248: protected JXToolBar buildXPathEditorToolbar(
249: DispatchXPathGroovyEditorModel editorModel) {
250: JXToolBar toolbar = UISupport.createToolbar();
251: toolbar.addSpace(3);
252: toolbar.addFixed(UISupport.createToolbarButton(editorModel
253: .getRunAction()));
254: toolbar.addGlue();
255: toolbar.addFixed(createActionButton(new ShowOnlineHelpAction(
256: HelpUrls.MOCKOPERATION_XPATHDISPATCH_HELP_URL), true));
257: return toolbar;
258: }
259:
260: private void buildGroovyEditor() {
261: groovyEditorPanel = new JPanel(new BorderLayout());
262: DispatchScriptGroovyEditorModel editorModel = new DispatchScriptGroovyEditorModel();
263: groovyEditor = new GroovyEditor(editorModel);
264: groovyEditorPanel.add(new JScrollPane(groovyEditor),
265: BorderLayout.CENTER);
266: groovyEditorPanel.add(buildGroovyEditorToolbar(editorModel),
267: BorderLayout.PAGE_START);
268: }
269:
270: protected JXToolBar buildGroovyEditorToolbar(
271: DispatchScriptGroovyEditorModel editorModel) {
272: JXToolBar toolbar = UISupport.createToolbar();
273: toolbar.addSpace(3);
274: toolbar.addFixed(UISupport.createToolbarButton(editorModel
275: .getRunAction()));
276: toolbar.addGlue();
277:
278: JLabel label = new JLabel(
279: "<html>Script is invoked with <code>log</code>, <code>context</code>, "
280: + "<code>requestContext</code>, <code>mockRequest</code> and <code>mockOperation</code> variables</html>");
281: label.setToolTipText(label.getText());
282: label.setMaximumSize(label.getPreferredSize());
283:
284: toolbar.add(label);
285: toolbar.addFixed(createActionButton(new ShowOnlineHelpAction(
286: HelpUrls.MOCKOPERATION_SCRIPTDISPATCH_HELP_URL), true));
287: return toolbar;
288: }
289:
290: private Component buildToolbar() {
291: JXToolBar toolbar = UISupport.createToolbar();
292: toolbar.addSpace(3);
293:
294: toolbar.addFixed(UISupport
295: .createToolbarButton(SwingActionDelegate
296: .createDelegate(
297: NewMockResponseAction.SOAPUI_ACTION_ID,
298: getModelItem(), null,
299: "/addToMockService.gif")));
300: toolbar
301: .addFixed(UISupport
302: .createToolbarButton(SwingActionDelegate
303: .createDelegate(
304: OpenRequestForMockOperationAction.SOAPUI_ACTION_ID,
305: getModelItem(), null,
306: "/open_request.gif")));
307: toolbar.addUnrelatedGap();
308:
309: ModelItemNames<Interface> names = new ModelItemNames<Interface>(
310: getModelItem().getMockService().getProject()
311: .getInterfaces());
312: interfaceCombo = new JComboBox(names.getNames());
313: interfaceCombo.setSelectedIndex(-1);
314: interfaceCombo.addItemListener(new InterfaceComboListener());
315:
316: toolbar.addLabeledFixed("Interface", interfaceCombo);
317: toolbar.addUnrelatedGap();
318: operationCombo = new JComboBox(new ExtendedComboBoxModel());
319: operationCombo.setPreferredSize(new Dimension(150, 20));
320: operationCombo.addItemListener(new OperationComboListener());
321:
322: toolbar.addLabeledFixed("Operation", operationCombo);
323:
324: WsdlOperation operation = getModelItem().getOperation();
325: interfaceCombo.setSelectedItem(operation == null ? null
326: : operation.getInterface().getName());
327: operationCombo.setSelectedItem(operation == null ? null
328: : operation.getName());
329:
330: toolbar.addGlue();
331: toolbar.addFixed(createActionButton(new ShowOnlineHelpAction(
332: HelpUrls.MOCKOPERATION_HELP_URL), true));
333:
334: return toolbar;
335: }
336:
337: public boolean onClose(boolean canCancel) {
338: if (currentInterface != null)
339: currentInterface.removeInterfaceListener(interfaceListener);
340:
341: getModelItem().getMockService().getProject()
342: .removeProjectListener(projectListener);
343: responseListModel.release();
344:
345: groovyEditor.release();
346: xpathEditor.release();
347:
348: return release();
349: }
350:
351: public boolean dependsOn(ModelItem modelItem) {
352: return modelItem == getModelItem()
353: || modelItem == getModelItem().getMockService()
354: || modelItem == getModelItem().getMockService()
355: .getProject();
356: }
357:
358: private final class OperationComboListener implements ItemListener {
359: public void itemStateChanged(ItemEvent e) {
360: WsdlInterface iface = getModelItem()
361: .getMockService()
362: .getProject()
363: .getInterfaceByName(
364: interfaceCombo.getSelectedItem().toString());
365: WsdlOperation operation = iface
366: .getOperationByName(operationCombo
367: .getSelectedItem().toString());
368: getModelItem().setOperation(operation);
369: }
370: }
371:
372: private final class InterfaceComboListener implements ItemListener {
373: public void itemStateChanged(ItemEvent e) {
374: if (currentInterface != null) {
375: currentInterface
376: .removeInterfaceListener(interfaceListener);
377: }
378:
379: Object selectedItem = interfaceCombo.getSelectedItem();
380: if (selectedItem == null) {
381: operationCombo.setModel(new DefaultComboBoxModel());
382: currentInterface = null;
383: } else {
384: currentInterface = getModelItem().getMockService()
385: .getProject().getInterfaceByName(
386: selectedItem.toString());
387: ModelItemNames<Operation> names = new ModelItemNames<Operation>(
388: currentInterface.getOperations());
389: operationCombo.setModel(new DefaultComboBoxModel(names
390: .getNames()));
391:
392: currentInterface
393: .addInterfaceListener(interfaceListener);
394: }
395: }
396: }
397:
398: private final class InternalProjectListener extends
399: ProjectListenerAdapter {
400: @Override
401: public void interfaceAdded(Interface iface) {
402: interfaceCombo.addItem(iface.getName());
403: }
404:
405: @Override
406: public void interfaceRemoved(Interface iface) {
407: if (interfaceCombo.getSelectedItem()
408: .equals(iface.getName())) {
409: getModelItem().setOperation(null);
410: }
411: }
412: }
413:
414: private final class InternalInterfaceListener extends
415: InterfaceListenerAdapter {
416: @Override
417: public void operationAdded(Operation operation) {
418: operationCombo.addItem(operation.getName());
419: }
420:
421: @Override
422: public void operationRemoved(Operation operation) {
423: Object selectedItem = operationCombo.getSelectedItem();
424: operationCombo.removeItem(operation.getName());
425:
426: if (selectedItem.equals(operation.getName())) {
427: getModelItem().setOperation(null);
428: interfaceCombo.setSelectedIndex(-1);
429: }
430: }
431:
432: @Override
433: public void operationUpdated(Operation operation) {
434: ExtendedComboBoxModel model = ((ExtendedComboBoxModel) operationCombo
435: .getModel());
436: int ix = model.getIndexOf(operation.getName());
437: if (ix != -1) {
438: model.setElementAt(operation.getName(), ix);
439: }
440: }
441: }
442:
443: public class DispatchScriptGroovyEditorModel implements
444: GroovyEditorModel {
445: private RunScriptAction runScriptAction = new RunScriptAction();
446:
447: public String[] getKeywords() {
448: return new String[] { "mockRequest", "context",
449: "requestContext", "log", "mockOperation" };
450: }
451:
452: public Action getRunAction() {
453: return runScriptAction;
454: }
455:
456: public String getScript() {
457: return getModelItem().getDispatchPath();
458: }
459:
460: public Settings getSettings() {
461: return getModelItem().getSettings();
462: }
463:
464: public void setScript(String text) {
465: getModelItem().setDispatchPath(text);
466: }
467: }
468:
469: public class DispatchXPathGroovyEditorModel implements
470: GroovyEditorModel {
471: private RunXPathAction runXPathAction = new RunXPathAction();
472:
473: public String[] getKeywords() {
474: return new String[] { "define", "namespace" };
475: }
476:
477: public Action getRunAction() {
478: return runXPathAction;
479: }
480:
481: public String getScript() {
482: return getModelItem().getDispatchPath();
483: }
484:
485: public Settings getSettings() {
486: return getModelItem().getSettings();
487: }
488:
489: public void setScript(String text) {
490: getModelItem().setDispatchPath(text);
491: }
492: }
493:
494: public class ResponseListModel extends AbstractListModel implements
495: ListModel, MockServiceListener, PropertyChangeListener {
496: private List<WsdlMockResponse> responses = new ArrayList<WsdlMockResponse>();
497:
498: public ResponseListModel() {
499: for (int c = 0; c < getModelItem().getMockResponseCount(); c++) {
500: WsdlMockResponse mockResponse = (WsdlMockResponse) getModelItem()
501: .getMockResponseAt(c);
502: mockResponse.addPropertyChangeListener(this );
503:
504: responses.add(mockResponse);
505: }
506:
507: getModelItem().getMockService()
508: .addMockServiceListener(this );
509: }
510:
511: public Object getElementAt(int arg0) {
512: return responses.get(arg0);
513: }
514:
515: public int getSize() {
516: return responses.size();
517: }
518:
519: public void mockOperationAdded(MockOperation operation) {
520:
521: }
522:
523: public void mockOperationRemoved(MockOperation operation) {
524:
525: }
526:
527: public void mockResponseAdded(MockResponse response) {
528: if (response.getMockOperation() != getModelItem())
529: return;
530:
531: responses.add((WsdlMockResponse) response);
532: response.addPropertyChangeListener(this );
533: fireIntervalAdded(this , responses.size() - 1, responses
534: .size() - 1);
535:
536: defaultResponseCombo.addItem(response.getName());
537: }
538:
539: public void mockResponseRemoved(MockResponse response) {
540: if (response.getMockOperation() != getModelItem())
541: return;
542:
543: int ix = responses.indexOf(response);
544: responses.remove(ix);
545: response.removePropertyChangeListener(this );
546: fireIntervalRemoved(this , ix, ix);
547:
548: defaultResponseCombo.removeItem(response.getName());
549: }
550:
551: public void propertyChange(PropertyChangeEvent arg0) {
552: if (arg0.getPropertyName().equals(
553: WsdlMockOperation.NAME_PROPERTY)) {
554: int ix = responses.indexOf(arg0.getSource());
555: fireContentsChanged(this , ix, ix);
556:
557: ExtendedComboBoxModel model = (ExtendedComboBoxModel) defaultResponseCombo
558: .getModel();
559: model.setElementAt(arg0.getNewValue(), ix);
560:
561: if (model.getSelectedItem().equals(arg0.getOldValue()))
562: model.setSelectedItem(arg0.getNewValue());
563: }
564: }
565:
566: public void release() {
567: for (WsdlMockResponse operation : responses) {
568: operation.removePropertyChangeListener(this );
569: }
570:
571: getModelItem().getMockService().removeMockServiceListener(
572: this );
573: }
574: }
575:
576: private final static class ResponseListCellRenderer extends JLabel
577: implements ListCellRenderer {
578: public Component getListCellRendererComponent(JList list,
579: Object value, int index, boolean isSelected,
580: boolean cellHasFocus) {
581: MockResponse testStep = (MockResponse) value;
582: setText(testStep.getName());
583: setIcon(testStep.getIcon());
584:
585: if (isSelected) {
586: setBackground(list.getSelectionBackground());
587: setForeground(list.getSelectionForeground());
588: } else {
589: setBackground(list.getBackground());
590: setForeground(list.getForeground());
591: }
592:
593: setEnabled(list.isEnabled());
594: setFont(list.getFont());
595: setOpaque(true);
596: setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
597:
598: return this ;
599: }
600: }
601:
602: private class RunScriptAction extends AbstractAction {
603: public RunScriptAction() {
604: putValue(Action.SMALL_ICON, UISupport
605: .createImageIcon("/run_groovy_script.gif"));
606: putValue(Action.SHORT_DESCRIPTION,
607: "Runs this script using a mockRequest and context");
608: }
609:
610: public void actionPerformed(ActionEvent e) {
611: WsdlMockResult lastMockResult = getModelItem()
612: .getLastMockResult();
613: WsdlMockRequest mockRequest = lastMockResult == null ? null
614: : lastMockResult.getMockRequest();
615:
616: try {
617: Object retVal = getModelItem().evaluateDispatchScript(
618: mockRequest);
619: UISupport.showInfoMessage("Script returned [" + retVal
620: + "]");
621: } catch (Exception e1) {
622: UISupport.showErrorMessage(e1);
623: }
624: }
625: }
626:
627: private class RunXPathAction extends AbstractAction {
628: public RunXPathAction() {
629: putValue(Action.SMALL_ICON, UISupport
630: .createImageIcon("/run_groovy_script.gif"));
631: putValue(Action.SHORT_DESCRIPTION,
632: "Evaluates this xpath expression against the latest request");
633: }
634:
635: public void actionPerformed(ActionEvent e) {
636: WsdlMockResult lastMockResult = getModelItem()
637: .getLastMockResult();
638: if (lastMockResult == null) {
639: UISupport
640: .showErrorMessage("Missing last request to select from");
641: return;
642: }
643:
644: try {
645: XmlObject[] retVal = getModelItem()
646: .evaluateDispatchXPath(
647: lastMockResult.getMockRequest());
648: StringList list = new StringList();
649: for (XmlObject xmlObject : retVal) {
650: list.add(XmlUtils.getNodeValue(xmlObject
651: .getDomNode()));
652: }
653:
654: UISupport.showInfoMessage("XPath returned "
655: + list.toString());
656: } catch (Exception e1) {
657: SoapUI.logError(e1);
658: }
659: }
660: }
661: }
|