/*
* SoapUI, Copyright (C) 2004-2016 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/
package com.eviware.soapui.impl.wsdl.mock.dispatch;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.config.MockOperationQueryMatchDispatchConfig;
import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
import com.eviware.soapui.impl.wsdl.mock.DispatchException;
import com.eviware.soapui.impl.wsdl.mock.WsdlMockOperation;
import com.eviware.soapui.impl.wsdl.mock.WsdlMockResponse;
import com.eviware.soapui.impl.wsdl.mock.WsdlMockRunContext;
import com.eviware.soapui.impl.wsdl.support.HelpUrls;
import com.eviware.soapui.model.mock.MockOperation;
import com.eviware.soapui.model.mock.MockRequest;
import com.eviware.soapui.model.mock.MockResponse;
import com.eviware.soapui.model.mock.MockResult;
import com.eviware.soapui.model.propertyexpansion.PropertyExpander;
import com.eviware.soapui.support.AbstractPropertyChangeNotifier;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.components.JXToolBar;
import com.eviware.soapui.support.components.SimpleBindingForm;
import com.eviware.soapui.support.xml.XmlUtils;
import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
import com.jgoodies.binding.PresentationModel;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import javax.swing.AbstractAction;
import javax.swing.AbstractListModel;
import javax.swing.Action;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class QueryMatchMockOperationDispatcher extends AbstractMockOperationDispatcher implements
PropertyChangeListener {
private MockOperationQueryMatchDispatchConfig conf;
private List<Query> queries = new ArrayList<Query>();
private PresentationModel<Query> queryDetailFormPresentationModel;
private QueryItemListModel queryItemListModel;
private JList itemList;
private JButton deleteButton;
private JButton copyButton;
private JButton renameButton;
private SimpleBindingForm detailForm;
private JButton runButton;
private JButton declareNsButton = new JButton(new DeclareNamespacesAction());
private JButton extractFromCurrentButton = new JButton(new ExtractFromCurrentAction());
public QueryMatchMockOperationDispatcher(MockOperation mockOperation) {
super(mockOperation);
try {
conf = MockOperationQueryMatchDispatchConfig.Factory.parse(((WsdlMockOperation) mockOperation).getConfig().getDispatchConfig().xmlText());
for (MockOperationQueryMatchDispatchConfig.Query query : conf.getQueryList()) {
queries.add(new Query(query));
}
} catch (XmlException e) {
e.printStackTrace();
}
mockOperation.addPropertyChangeListener("mockResponses", this);
}
@Override
public void release() {
getMockOperation().removePropertyChangeListener("mockResponses", this);
super.release();
}
@Override
public JComponent getEditorComponent() {
JSplitPane splitPane = UISupport.createHorizontalSplit(buildQueryListComponent(), buildQueryDetailComponent());
splitPane.setDividerLocation(300);
setEnabled();
return splitPane;
}
@Override
public boolean hasDefaultResponse() {
return true;
}
protected Component buildQueryListComponent() {
JPanel panel = new JPanel(new BorderLayout());
queryItemListModel = new QueryItemListModel();
itemList = new JList(queryItemListModel);
itemList.setCellRenderer(new QueryItemListCellRenderer());
itemList.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
queryDetailFormPresentationModel.setBean((Query) itemList.getSelectedValue());
setEnabled();
}
});
panel.add(buildItemsToolbar(), BorderLayout.NORTH);
panel.add(new JScrollPane(itemList), BorderLayout.CENTER);
return panel;
}
protected void setEnabled() {
QueryMatchMockOperationDispatcher.Query bean = queryDetailFormPresentationModel.getBean();
detailForm.setEnabled(bean != null);
renameButton.setEnabled(bean != null);
deleteButton.setEnabled(bean != null);
copyButton.setEnabled(bean != null);
extractFromCurrentButton.setEnabled(bean != null);
copyButton.setEnabled(bean != null);
declareNsButton.setEnabled(bean != null);
runButton.setEnabled(getQueryCount() > 0);
}
private JXToolBar buildItemsToolbar() {
JXToolBar toolbar = UISupport.createSmallToolbar();
runButton = UISupport.createToolbarButton(new RunAction());
toolbar.addFixed(runButton);
toolbar.addSeparator();
toolbar.addFixed(UISupport.createToolbarButton(new AddAction()));
deleteButton = UISupport.createToolbarButton(new DeleteAction());
deleteButton.setEnabled(false);
toolbar.addFixed(deleteButton);
toolbar.addSeparator();
copyButton = UISupport.createToolbarButton(new CopyAction());
copyButton.setEnabled(false);
toolbar.addFixed(copyButton);
renameButton = UISupport.createToolbarButton(new RenameAction());
renameButton.setEnabled(false);
toolbar.addFixed(renameButton);
toolbar.addSeparator();
return toolbar;
}
protected Component buildQueryDetailComponent() {
queryDetailFormPresentationModel = new PresentationModel<Query>(null);
detailForm = new SimpleBindingForm(queryDetailFormPresentationModel);
detailForm.setDefaultTextAreaRows(5);
detailForm.setDefaultTextAreaColumns(50);
detailForm.append(buildQueryToolbar());
detailForm.appendTextArea("query", "XPath", "The XPath to query in the request");
detailForm.appendTextArea("match", "Expected Value", "The value to match");
JComboBox comboBox = detailForm.appendComboBox("response", "Dispatch to", new MockResponsesComboBoxModel(),
"The MockResponse to dispatch to");
UISupport.setFixedSize(comboBox, 150, 20);
detailForm.appendCheckBox("disabled", "Disabled", "Disables this Query");
return new JScrollPane(detailForm.getPanel());
}
protected JXToolBar buildQueryToolbar() {
JXToolBar toolBar = UISupport.createSmallToolbar();
addQueryToolbarActions(toolBar);
toolBar.addGlue();
toolBar.addFixed(ModelItemDesktopPanel.createActionButton(new ShowOnlineHelpAction(
HelpUrls.MOCKOPERATION_QUERYMATCHDISPATCH_HELP_URL), true));
return toolBar;
}
protected void addQueryToolbarActions(JXToolBar toolBar) {
toolBar.addFixed(declareNsButton);
toolBar.addFixed(extractFromCurrentButton);
}
public WsdlMockResponse selectMockResponse(MockRequest request, MockResult result)
throws DispatchException {
Map<String, XmlCursor> cursorCache = new HashMap<String, XmlCursor>();
try {
XmlObject xmlObject = request.getRequestXmlObject();
for (Query query : getQueries()) {
if (query.isDisabled()) {
continue;
}
String path = PropertyExpander.expandProperties(request.getContext(), query.getQuery());
if (StringUtils.hasContent(path)) {
XmlCursor cursor = cursorCache.get(path);
if (cursor == null && !cursorCache.containsKey(path)) {
cursor = xmlObject.newCursor();
cursor.selectPath(path);
if (!cursor.toNextSelection()) {
cursor.dispose();
cursor = null;
}
}
if (cursor != null) {
String value = PropertyExpander.expandProperties(request.getContext(), query.getMatch());
if (value.equals(XmlUtils.getValueForMatch(cursor))) {
WsdlMockRunContext requestContext = (WsdlMockRunContext) request.getRequestContext();
requestContext.put("usedQueryMatch", query.getName());
WsdlMockResponse resp = null;
for (MockResponse mockResponse : this.getMockOperation().getMockResponses()) {
if (query.getResponse().equals(mockResponse.getName())) {
resp = (WsdlMockResponse) mockResponse;
}
}
// return getMockOperation().getMockResponseByName(
// query.getResponse() );
if (resp != null) {
return resp;
}
return ((WsdlMockOperation) getMockOperation()).getMockResponseByName(query.getResponse());
}
}
cursorCache.put(path, cursor);
}
}
return null;
} catch (Throwable e) {
throw new DispatchException(e);
} finally {
for (XmlCursor cursor : cursorCache.values()) {
if (cursor != null) {
cursor.dispose();
}
}
}
}
public Query addQuery(String name) {
Query query = new Query(conf.addNewQuery());
query.setName(name);
queries.add(query);
getPropertyChangeSupport().firePropertyChange("queries", null, query);
if (queryItemListModel != null) {
queryItemListModel.fireAdded();
}
return query;
}
public void deleteQuery(Query query) {
int ix = queries.indexOf(query);
queries.remove(ix);
getPropertyChangeSupport().firePropertyChange("queries", query, null);
if (queryItemListModel != null) {
queryItemListModel.fireRemoved(ix);
}
conf.removeQuery(ix);
saveConfig();
}
public Query[] getQueries() {
return queries.toArray(new Query[queries.size()]);
}
public int getQueryCount() {
return queries.size();
}
public Query getQueryByName(String name) {
for (Query q : queries) {
if (q.getName().equals(name)) {
return q;
}
}
return null;
}
public Query getQueryAt(int index) {
return queries.get(index);
}
public void propertyChange(PropertyChangeEvent evt) {
if (queryItemListModel != null) {
queryItemListModel.refresh();
}
}
public static class Factory implements MockOperationDispatchFactory {
public MockOperationDispatcher build(MockOperation mockOperation) {
return new QueryMatchMockOperationDispatcher(mockOperation);
}
}
public class Query extends AbstractPropertyChangeNotifier {
private MockOperationQueryMatchDispatchConfig.Query config;
protected Query(MockOperationQueryMatchDispatchConfig.Query config) {
this.config = config;
}
public String getName() {
return config.getName();
}
public void setName(String s) {
String old = config.getName();
config.setName(s);
saveConfig();
firePropertyChange("name", old, s);
}
public boolean isDisabled() {
return config.getDisabled();
}
public void setDisabled(boolean disabled) {
boolean old = config.getDisabled();
if (old == disabled) {
return;
}
config.setDisabled(disabled);
saveConfig();
firePropertyChange("disabled", old, disabled);
queryItemListModel.refresh();
}
public String getQuery() {
return config.getQuery();
}
public void setQuery(String s) {
String old = config.getQuery();
config.setQuery(s);
saveConfig();
firePropertyChange("query", old, s);
}
public String getMatch() {
return config.getMatch();
}
public void setMatch(String s) {
String old = config.getMatch();
config.setMatch(s);
saveConfig();
firePropertyChange("match", old, s);
}
public String getResponse() {
return config.getResponse();
}
public void setResponse(String s) {
String old = config.getResponse();
config.setResponse(s);
saveConfig();
firePropertyChange("response", old, s);
}
}
private void saveConfig() {
((WsdlMockOperation) getMockOperation()).getConfig().getDispatchConfig().set(conf);
}
private class QueryItemListModel extends AbstractListModel {
public int getSize() {
return getQueryCount();
}
public Object getElementAt(int index) {
return getQueryAt(index);
}
public void refresh() {
fireContentsChanged(this, 0, getQueryCount());
}
public void fireAdded() {
fireIntervalAdded(this, getQueryCount(), getQueryCount());
}
public void fireRemoved(int index) {
fireIntervalRemoved(this, index, index);
}
}
private class MockResponsesComboBoxModel extends AbstractListModel implements ComboBoxModel {
public int getSize() {
return getMockOperation().getMockResponseCount();
}
public Object getElementAt(int index) {
return getMockOperation().getMockResponseAt(index).getName();
}
public void setSelectedItem(Object anItem) {
Query query = getSelectedQuery();
if (query != null) {
query.setResponse(String.valueOf(anItem));
}
}
public Object getSelectedItem() {
Query query = getSelectedQuery();
return query != null ? query.getResponse() : null;
}
}
protected Query getSelectedQuery() {
return queryDetailFormPresentationModel == null ? null : queryDetailFormPresentationModel.getBean();
}
private final class AddAction extends AbstractAction {
public AddAction() {
putValue(Action.SHORT_DESCRIPTION, "Adds a new Match");
putValue(Action.SMALL_ICON, UISupport.createImageIcon("/add.png"));
}
public void actionPerformed(ActionEvent e) {
String name = UISupport.prompt("Specify name for Match", "Add Query Match", "");
if (name == null || name.trim().length() == 0) {
return;
}
addQuery(name);
}
}
private final class CopyAction extends AbstractAction {
public CopyAction() {
putValue(Action.SHORT_DESCRIPTION, "Copies the selected Match");
putValue(Action.SMALL_ICON, UISupport.createImageIcon("/clone.png"));
}
public void actionPerformed(ActionEvent e) {
QueryMatchMockOperationDispatcher.Query selectedQuery = getSelectedQuery();
if (selectedQuery == null) {
return;
}
String name = UISupport.prompt("Specify name for copied Query", "Copy Query", selectedQuery.getName());
if (name == null || name.trim().length() == 0) {
return;
}
QueryMatchMockOperationDispatcher.Query query = addQuery(name);
query.setMatch(selectedQuery.getMatch());
query.setQuery(selectedQuery.getQuery());
query.setResponse(selectedQuery.getResponse());
itemList.setSelectedIndex(getQueryCount() - 1);
}
}
private final class DeleteAction extends AbstractAction {
public DeleteAction() {
putValue(Action.SMALL_ICON, UISupport.createImageIcon("/delete.png"));
putValue(Action.SHORT_DESCRIPTION, "Deletes the selected Property Transfer");
}
public void actionPerformed(ActionEvent e) {
QueryMatchMockOperationDispatcher.Query selectedQuery = getSelectedQuery();
if (selectedQuery == null) {
return;
}
if (UISupport.confirm("Delete selected Query", "Delete Query")) {
deleteQuery(selectedQuery);
if (getQueryCount() > 0) {
itemList.setSelectedIndex(0);
}
}
}
}
private final class RenameAction extends AbstractAction {
public RenameAction() {
putValue(Action.SMALL_ICON, UISupport.createImageIcon("/rename.gif"));
putValue(Action.SHORT_DESCRIPTION, "Renames the selected Property Transfer");
}
public void actionPerformed(ActionEvent e) {
QueryMatchMockOperationDispatcher.Query selectedQuery = getSelectedQuery();
if (selectedQuery == null) {
return;
}
String newName = UISupport.prompt("Specify new name for Query", "Rename Query", selectedQuery.getName());
if (newName != null && !selectedQuery.getName().equals(newName)) {
selectedQuery.setName(newName);
queryItemListModel.refresh();
}
}
}
private final class DeclareNamespacesAction extends AbstractAction {
public DeclareNamespacesAction() {
putValue(Action.SMALL_ICON, UISupport.createImageIcon("/declareNs.gif"));
putValue(Action.SHORT_DESCRIPTION, "Declare request namespaces in current query");
}
public void actionPerformed(ActionEvent e) {
QueryMatchMockOperationDispatcher.Query selectedQuery = getSelectedQuery();
if (selectedQuery == null) {
return;
}
try {
MockResult lastResult = getMockOperation().getLastMockResult();
String content = null;
if (lastResult == null) {
if (!UISupport.confirm("Missing last result, declare from default request instead?",
"Declare Namespaces")) {
return;
}
content = getMockOperation().getOperation().createRequest(true);
} else {
content = lastResult.getMockRequest().getRequestContent();
}
String path = selectedQuery.getQuery();
if (path == null) {
path = "";
}
selectedQuery.setQuery(XmlUtils.declareXPathNamespaces(content) + path);
} catch (Exception e1) {
UISupport.showErrorMessage(e1);
}
}
}
private final class RunAction extends AbstractAction {
public RunAction() {
putValue(Action.SMALL_ICON, UISupport.createImageIcon("/run.png"));
putValue(Action.SHORT_DESCRIPTION, "Runs Queries on last request");
}
public void actionPerformed(ActionEvent e) {
MockResult result = getMockOperation().getLastMockResult();
if (result != null) {
try {
UISupport.showInfoMessage("Selected ["
+ selectMockResponse(result.getMockRequest(), result).getName() + "]");
} catch (DispatchException e1) {
UISupport.showErrorMessage(e1);
}
} else {
UISupport.showErrorMessage("Missing request to query");
}
}
}
private final class ExtractFromCurrentAction extends AbstractAction {
public ExtractFromCurrentAction() {
super("Extract");
putValue(Action.SHORT_DESCRIPTION, "Extracts the current value into the Value field");
}
public void actionPerformed(ActionEvent e) {
QueryMatchMockOperationDispatcher.Query selectedQuery = getSelectedQuery();
if (selectedQuery == null) {
return;
}
MockResult result = getMockOperation().getLastMockResult();
String content;
if (result != null && StringUtils.hasContent(result.getMockRequest().getRequestContent())) {
content = result.getMockRequest().getRequestContent();
} else {
if (!UISupport.confirm("Missing last result, extract from default request instead?", "Extract Match")) {
return;
}
content = getMockOperation().getOperation().createRequest(true);
}
XmlCursor cursor = null;
try {
// XmlObject xmlObject = XmlObject.Factory.parse( content );
XmlObject xmlObject = XmlUtils.createXmlObject(content);
cursor = xmlObject.newCursor();
cursor.selectPath(selectedQuery.getQuery());
if (!cursor.toNextSelection()) {
UISupport.showErrorMessage("Missing match in request");
} else {
selectedQuery.setMatch(XmlUtils.getValueForMatch(cursor));
}
} catch (Throwable e1) {
SoapUI.logError(e1);
} finally {
if (cursor != null) {
cursor.dispose();
}
}
}
}
private class QueryItemListCellRenderer extends DefaultListCellRenderer {
private Color defaultForeground;
private QueryItemListCellRenderer() {
this.defaultForeground = getForeground();
}
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
boolean cellHasFocus) {
JLabel component = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
Query query = (Query) value;
component.setText(query.getName());
component.setForeground(((Query) value).isDisabled() ? Color.GRAY : defaultForeground);
return component;
}
}
}