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.mock;
014:
015: import java.awt.BorderLayout;
016: import java.awt.Color;
017: import java.awt.Component;
018: import java.awt.Dimension;
019: import java.awt.event.ActionEvent;
020: import java.awt.event.ActionListener;
021: import java.beans.PropertyChangeEvent;
022: import java.beans.PropertyChangeListener;
023: import java.text.SimpleDateFormat;
024: import java.util.ArrayList;
025: import java.util.Date;
026: import java.util.LinkedList;
027: import java.util.List;
028:
029: import javax.swing.AbstractAction;
030: import javax.swing.AbstractListModel;
031: import javax.swing.Action;
032: import javax.swing.BorderFactory;
033: import javax.swing.JButton;
034: import javax.swing.JCheckBox;
035: import javax.swing.JLabel;
036: import javax.swing.JList;
037: import javax.swing.JPanel;
038: import javax.swing.JProgressBar;
039: import javax.swing.JScrollPane;
040: import javax.swing.JSplitPane;
041: import javax.swing.JTextField;
042: import javax.swing.ListCellRenderer;
043: import javax.swing.ListModel;
044: import javax.swing.text.Document;
045:
046: import com.eviware.soapui.SoapUI;
047: import com.eviware.soapui.impl.wsdl.actions.support.ShowOnlineHelpAction;
048: import com.eviware.soapui.impl.wsdl.mock.WsdlMockOperation;
049: import com.eviware.soapui.impl.wsdl.mock.WsdlMockRunner;
050: import com.eviware.soapui.impl.wsdl.mock.WsdlMockService;
051: import com.eviware.soapui.impl.wsdl.support.HelpUrls;
052: import com.eviware.soapui.model.ModelItem;
053: import com.eviware.soapui.model.mock.MockOperation;
054: import com.eviware.soapui.model.mock.MockResponse;
055: import com.eviware.soapui.model.mock.MockResult;
056: import com.eviware.soapui.model.mock.MockServiceListener;
057: import com.eviware.soapui.model.support.MockRunListenerAdapter;
058: import com.eviware.soapui.support.DocumentListenerAdapter;
059: import com.eviware.soapui.support.UISupport;
060: import com.eviware.soapui.support.action.swing.ActionList;
061: import com.eviware.soapui.support.components.JXToolBar;
062: import com.eviware.soapui.support.swing.ListMouseListener;
063: import com.eviware.soapui.support.swing.ModelItemListMouseListener;
064: import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
065:
066: /**
067: * DesktopPanel for WsdlMockServices
068: *
069: * @author ole.matzura
070: */
071:
072: public class WsdlMockServiceDesktopPanel extends
073: ModelItemDesktopPanel<WsdlMockService> {
074: private static final String LOG_TITLE = "Message Log";
075: private JButton runButton;
076: private WsdlMockRunner mockRunner;
077: private JButton stopButton;
078: private JProgressBar progressBar;
079: private LogListModel logListModel;
080: private JList testLogList;
081: private JCheckBox enableLogCheckBox;
082: private JScrollPane logScrollPane;
083: private JList operationList;
084: private InternalMockRunListener mockRunListener;
085: // private JButton optionsButton;
086: private JTextField pathTextField;
087: private JTextField portTextField;
088:
089: public WsdlMockServiceDesktopPanel(WsdlMockService mockService) {
090: super (mockService);
091: buildUI();
092:
093: setPreferredSize(new Dimension(400, 500));
094:
095: mockRunListener = new InternalMockRunListener();
096: mockService.addMockRunListener(mockRunListener);
097: }
098:
099: public boolean onClose(boolean canCancel) {
100: if (mockRunner != null && canCancel) {
101: if (!UISupport.confirm("Close and stop MockService",
102: "Close MockService")) {
103: return false;
104: }
105: }
106:
107: if (mockRunner != null) {
108: mockRunner.stop();
109: mockRunner.release();
110: }
111:
112: getModelItem().removeMockRunListener(mockRunListener);
113: ((OperationListModel) operationList.getModel()).release();
114:
115: logListModel.clear();
116:
117: return release();
118: }
119:
120: public boolean dependsOn(ModelItem modelItem) {
121: return modelItem == getModelItem()
122: || modelItem == getModelItem().getProject();
123: }
124:
125: private void buildUI() {
126: add(buildToolbar(), BorderLayout.NORTH);
127:
128: JSplitPane splitPane = UISupport.createVerticalSplit();
129: splitPane.setTopComponent(buildOperationList());
130: splitPane.setBottomComponent(buildLog());
131: splitPane.setDividerLocation(0.7);
132: splitPane.setDividerLocation(250);
133:
134: add(splitPane, BorderLayout.CENTER);
135: add(new JLabel("--"), BorderLayout.PAGE_END);
136: }
137:
138: public boolean logIsEnabled() {
139: return enableLogCheckBox.isSelected();
140: }
141:
142: private Component buildOperationList() {
143: operationList = new JList(new OperationListModel());
144: operationList
145: .addMouseListener(new ModelItemListMouseListener());
146: operationList.setCellRenderer(new OperationListCellRenderer());
147:
148: JScrollPane scrollPane = new JScrollPane(operationList);
149: UISupport.addTitledBorder(scrollPane, "Operations");
150: return scrollPane;
151: }
152:
153: private Component buildLog() {
154: JPanel panel = new JPanel(new BorderLayout());
155: JXToolBar builder = UISupport.createToolbar();
156:
157: enableLogCheckBox = new JCheckBox(" ", true);
158: enableLogCheckBox.addActionListener(new ActionListener() {
159:
160: public void actionPerformed(ActionEvent arg0) {
161: testLogList.setEnabled(enableLogCheckBox.isSelected());
162:
163: // border needs to be repainted..
164: logScrollPane.repaint();
165: }
166: });
167:
168: builder.addFixed(enableLogCheckBox);
169: builder.addRelatedGap();
170: builder.addFixed(new JLabel("Enable"));
171: builder.addRelatedGap();
172: builder.addFixed(new JButton(new ClearLogAction()));
173: builder.addRelatedGap();
174: builder.addFixed(new JButton(new SetLogOptionsAction()));
175:
176: builder.addGlue();
177: builder.setBorder(BorderFactory.createEmptyBorder(2, 3, 3, 3));
178:
179: panel.add(builder, BorderLayout.NORTH);
180:
181: logListModel = new LogListModel();
182: testLogList = new JList(logListModel);
183: testLogList.setCellRenderer(new LogCellRenderer());
184: testLogList.setPrototypeCellValue("Testing 123");
185: testLogList.setFixedCellWidth(-1);
186: testLogList.addMouseListener(new LogListMouseListener());
187: testLogList.setBorder(BorderFactory
188: .createLineBorder(Color.GRAY));
189:
190: logScrollPane = new JScrollPane(testLogList);
191: logScrollPane.setBorder(null);
192: UISupport.addTitledBorder(logScrollPane, LOG_TITLE);
193:
194: panel.add(logScrollPane, BorderLayout.CENTER);
195:
196: return panel;
197: }
198:
199: private Component buildToolbar() {
200: JXToolBar toolbar = UISupport.createToolbar();
201:
202: runButton = createActionButton(new RunMockServiceAction(), true);
203: stopButton = createActionButton(new StopMockServiceAction(),
204: false);
205: // optionsButton = createActionButton( new MockServiceOptionsAction( getModelItem() ), true );
206:
207: toolbar.addFixed(runButton);
208: toolbar.addFixed(stopButton);
209: toolbar.addUnrelatedGap();
210:
211: pathTextField = new JTextField(10);
212: pathTextField
213: .setToolTipText("The URL path to listen on for this service");
214: pathTextField.setText(getModelItem().getPath());
215: pathTextField.setCaretPosition(0);
216: pathTextField.getDocument().addDocumentListener(
217: new DocumentListenerAdapter() {
218:
219: @Override
220: public void update(Document document) {
221: getModelItem().setPath(pathTextField.getText());
222: }
223: });
224:
225: toolbar.addLabeledFixed("Path:", pathTextField);
226: toolbar.addUnrelatedGap();
227:
228: portTextField = new JTextField(5);
229: portTextField
230: .setToolTipText("The local port to listen on for this service");
231: portTextField.setText(String.valueOf(getModelItem().getPort()));
232: portTextField.getDocument().addDocumentListener(
233: new DocumentListenerAdapter() {
234:
235: @Override
236: public void update(Document document) {
237: try {
238: getModelItem().setPort(
239: Integer.parseInt(portTextField
240: .getText()));
241: } catch (Exception e) {
242: }
243: }
244: });
245:
246: toolbar.addLabeledFixed("Port:", portTextField);
247:
248: toolbar.addGlue();
249: progressBar = new JProgressBar();
250: JPanel progressBarPanel = UISupport.createProgressBarPanel(
251: progressBar, 2, false);
252: progressBarPanel.setPreferredSize(new Dimension(60, 20));
253:
254: toolbar.addFixed(progressBarPanel);
255: toolbar.addRelatedGap();
256:
257: // toolbar.addFixed( optionsButton );
258: toolbar.addFixed(createActionButton(new ShowOnlineHelpAction(
259: HelpUrls.MOCKSERVICE_HELP_URL), true));
260:
261: return toolbar;
262: }
263:
264: public void startMockService() {
265: if (mockRunner != null
266: || SoapUI.getMockEngine()
267: .hasRunningMock(getModelItem())) {
268: UISupport
269: .showErrorMessage("MockService is already running");
270: } else {
271: try {
272: mockRunner = getModelItem().start();
273: mockRunner.setMaxResults(logListModel.getMaxSize());
274: } catch (Exception e) {
275: UISupport.showErrorMessage(e);
276: return;
277: }
278: }
279:
280: progressBar.setIndeterminate(true);
281:
282: runButton.setEnabled(false);
283: stopButton.setEnabled(true);
284: pathTextField.setEnabled(false);
285: portTextField.setEnabled(false);
286: }
287:
288: private final class InternalMockRunListener extends
289: MockRunListenerAdapter {
290: public void onMockResult(MockResult result) {
291: if (logIsEnabled()) {
292: logListModel.addElement(result);
293: }
294: }
295: }
296:
297: public class OperationListModel extends AbstractListModel implements
298: ListModel, MockServiceListener, PropertyChangeListener {
299: private List<WsdlMockOperation> operations = new ArrayList<WsdlMockOperation>();
300:
301: public OperationListModel() {
302: for (int c = 0; c < getModelItem().getMockOperationCount(); c++) {
303: WsdlMockOperation mockOperation = (WsdlMockOperation) getModelItem()
304: .getMockOperationAt(c);
305: mockOperation.addPropertyChangeListener(this );
306:
307: operations.add(mockOperation);
308: }
309:
310: getModelItem().addMockServiceListener(this );
311: }
312:
313: public Object getElementAt(int arg0) {
314: return operations.get(arg0);
315: }
316:
317: public int getSize() {
318: return operations.size();
319: }
320:
321: public void mockOperationAdded(MockOperation operation) {
322: operations.add((WsdlMockOperation) operation);
323: operation.addPropertyChangeListener(this );
324: fireIntervalAdded(this , operations.size() - 1, operations
325: .size() - 1);
326: }
327:
328: public void mockOperationRemoved(MockOperation operation) {
329: int ix = operations.indexOf(operation);
330: operations.remove(ix);
331: operation.removePropertyChangeListener(this );
332: fireIntervalRemoved(this , ix, ix);
333: }
334:
335: public void mockResponseAdded(MockResponse request) {
336: }
337:
338: public void mockResponseRemoved(MockResponse request) {
339: }
340:
341: public void propertyChange(PropertyChangeEvent arg0) {
342: if (arg0.getPropertyName().equals(
343: WsdlMockOperation.NAME_PROPERTY)) {
344: int ix = operations.indexOf(arg0.getSource());
345: fireContentsChanged(this , ix, ix);
346: }
347: }
348:
349: public void release() {
350: for (WsdlMockOperation operation : operations) {
351: operation.removePropertyChangeListener(this );
352: }
353:
354: getModelItem().removeMockServiceListener(this );
355: }
356: }
357:
358: private final static class OperationListCellRenderer extends JLabel
359: implements ListCellRenderer {
360: public Component getListCellRendererComponent(JList list,
361: Object value, int index, boolean isSelected,
362: boolean cellHasFocus) {
363: MockOperation testStep = (MockOperation) value;
364: setText(testStep.getName());
365: setIcon(testStep.getIcon());
366:
367: if (isSelected) {
368: setBackground(list.getSelectionBackground());
369: setForeground(list.getSelectionForeground());
370: } else {
371: setBackground(list.getBackground());
372: setForeground(list.getForeground());
373: }
374:
375: setEnabled(list.isEnabled());
376: setFont(list.getFont());
377: setOpaque(true);
378: setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
379:
380: return this ;
381: }
382: }
383:
384: public class RunMockServiceAction extends AbstractAction {
385: public RunMockServiceAction() {
386: putValue(Action.SMALL_ICON, UISupport
387: .createImageIcon("/submit_request.gif"));
388: putValue(Action.SHORT_DESCRIPTION,
389: "Starts this MockService on the specified port and endpoint");
390: putValue(Action.ACCELERATOR_KEY, UISupport
391: .getKeyStroke("alt ENTER"));
392: }
393:
394: public void actionPerformed(ActionEvent arg0) {
395: startMockService();
396: }
397: }
398:
399: public class StopMockServiceAction extends AbstractAction {
400: public StopMockServiceAction() {
401: putValue(Action.SMALL_ICON, UISupport
402: .createImageIcon("/cancel_request.gif"));
403: putValue(Action.SHORT_DESCRIPTION,
404: "Stops this MockService on the specified port and endpoint");
405: }
406:
407: public void actionPerformed(ActionEvent arg0) {
408: if (mockRunner == null) {
409: UISupport
410: .showErrorMessage("MockService is not running");
411: } else {
412: mockRunner.stop();
413: mockRunner.release();
414: mockRunner = null;
415: }
416:
417: progressBar.setIndeterminate(false);
418:
419: runButton.setEnabled(true);
420: stopButton.setEnabled(false);
421: pathTextField.setEnabled(true);
422: portTextField.setEnabled(true);
423: }
424: }
425:
426: private static final class LogCellRenderer extends JLabel implements
427: ListCellRenderer {
428: private SimpleDateFormat dateFormat = new SimpleDateFormat(
429: "yyyy-MM-dd HH:mm:ss.SSS");
430:
431: public LogCellRenderer() {
432: setOpaque(true);
433: setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
434: }
435:
436: public Component getListCellRendererComponent(JList list,
437: Object value, int index, boolean isSelected,
438: boolean cellHasFocus) {
439: if (value instanceof String) {
440: setText(value.toString());
441: } else if (value instanceof MockResult) {
442: MockResult result = (MockResult) value;
443: String msg = dateFormat.format(new Date(result
444: .getTimestamp()));
445: MockResponse mockResponse = result.getMockResponse();
446:
447: if (mockResponse == null) {
448: msg += ": [dispatch error; missing response]";
449: } else {
450: msg += ": ["
451: + mockResponse.getMockOperation().getName();
452: msg += "] " + result.getTimeTaken() + "ms";
453: }
454:
455: setText(msg);
456: }
457:
458: if (isSelected) {
459: setBackground(list.getSelectionBackground());
460: setForeground(list.getSelectionForeground());
461: } else {
462: setBackground(list.getBackground());
463: setForeground(list.getForeground());
464: }
465:
466: setEnabled(list.isEnabled());
467:
468: return this ;
469: }
470: }
471:
472: private class LogListModel extends AbstractListModel {
473: private List<MockResult> elements = new LinkedList<MockResult>();
474: private long maxSize = 100;
475:
476: public synchronized void addElement(MockResult result) {
477: elements.add(result);
478: fireIntervalAdded(this , elements.size() - 1, elements
479: .size() - 1);
480:
481: while (elements.size() > maxSize) {
482: removeElementAt(0);
483: }
484: }
485:
486: public Object getElementAt(int index) {
487: return elements.get(index);
488: }
489:
490: public synchronized void removeElementAt(int index) {
491: elements.remove(index);
492: fireIntervalRemoved(this , index, index);
493: }
494:
495: public synchronized void clear() {
496: int sz = elements.size();
497: if (sz > 0) {
498: elements.clear();
499: fireIntervalRemoved(this , 0, sz - 1);
500: }
501: }
502:
503: public int getSize() {
504: return elements.size();
505: }
506:
507: public long getMaxSize() {
508: return maxSize;
509: }
510:
511: public synchronized void setMaxSize(long l) {
512: this .maxSize = l;
513:
514: while (elements.size() > maxSize) {
515: removeElementAt(0);
516: }
517: }
518: }
519:
520: private class SetLogOptionsAction extends AbstractAction {
521: public SetLogOptionsAction() {
522: putValue(Action.SMALL_ICON, UISupport
523: .createImageIcon("/options.gif"));
524: putValue(Action.SHORT_DESCRIPTION,
525: "Sets MockService Log Options");
526: }
527:
528: public void actionPerformed(ActionEvent e) {
529: String s = UISupport.prompt(
530: "Enter maximum number of rows for MockService Log",
531: "Log Options", String.valueOf(logListModel
532: .getMaxSize()));
533: if (s != null) {
534: try {
535: logListModel.setMaxSize(Long.parseLong(s));
536: if (mockRunner != null)
537: mockRunner.setMaxResults(logListModel
538: .getMaxSize());
539: } catch (NumberFormatException e1) {
540: }
541: }
542: }
543: }
544:
545: private class ClearLogAction extends AbstractAction {
546: public ClearLogAction() {
547: putValue(Action.SMALL_ICON, UISupport
548: .createImageIcon("/clear_loadtest.gif"));
549: putValue(Action.SHORT_DESCRIPTION,
550: "Clears the MockService Log");
551: }
552:
553: public void actionPerformed(ActionEvent e) {
554: logListModel.clear();
555: if (mockRunner != null)
556: mockRunner.clearResults();
557: }
558: }
559:
560: /**
561: * Mouse Listener for triggering default action and showing popup for log list items
562: *
563: * @author Ole.Matzura
564: */
565:
566: private final class LogListMouseListener extends ListMouseListener {
567: @Override
568: protected ActionList getActionsForRow(JList list, int row) {
569: MockResult result = (MockResult) logListModel
570: .getElementAt(row);
571: return result == null ? null : result.getActions();
572: }
573: }
574: }
|