/* * 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.rest; import com.eviware.soapui.config.AttachmentConfig; import com.eviware.soapui.config.RestRequestConfig; import com.eviware.soapui.config.StringToStringMapConfig; import com.eviware.soapui.impl.rest.RestRepresentation.Type; import com.eviware.soapui.impl.rest.support.RestParamProperty; import com.eviware.soapui.impl.rest.support.RestParamsPropertyHolder; import com.eviware.soapui.impl.rest.support.RestRequestParamsPropertyHolder; import com.eviware.soapui.impl.rest.support.handlers.JsonMediaTypeHandler; import com.eviware.soapui.impl.support.AbstractHttpRequest; import com.eviware.soapui.impl.wsdl.HttpAttachmentPart; import com.eviware.soapui.impl.wsdl.WsdlSubmit; import com.eviware.soapui.impl.wsdl.submit.RequestTransportRegistry; import com.eviware.soapui.impl.wsdl.submit.transports.http.HttpResponse; import com.eviware.soapui.impl.wsdl.submit.transports.jms.JMSHeader; import com.eviware.soapui.impl.wsdl.support.PathUtils; import com.eviware.soapui.impl.wsdl.support.jms.header.JMSHeaderConfig; import com.eviware.soapui.impl.wsdl.support.jms.property.JMSPropertiesConfig; import com.eviware.soapui.model.ModelItem; import com.eviware.soapui.model.iface.MessagePart; import com.eviware.soapui.model.iface.MessagePart.ContentPart; import com.eviware.soapui.model.iface.SubmitContext; import com.eviware.soapui.model.propertyexpansion.PropertyExpander; import com.eviware.soapui.model.propertyexpansion.PropertyExpansion; import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils; import com.eviware.soapui.model.propertyexpansion.PropertyExpansionsResult; import com.eviware.soapui.model.testsuite.TestProperty; import com.eviware.soapui.model.testsuite.TestPropertyListener; import com.eviware.soapui.support.StringUtils; import com.eviware.soapui.support.UISupport; import com.eviware.soapui.support.types.StringList; import com.eviware.soapui.support.types.StringToStringMap; import com.eviware.soapui.support.types.StringToStringsMap; import org.apache.xmlbeans.SchemaGlobalElement; import org.apache.xmlbeans.SchemaType; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlString; import javax.xml.namespace.QName; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Request implementation holding a SOAP request * * @author Ole.Matzura */ public class RestRequest extends AbstractHttpRequest<RestRequestConfig> implements RestRequestInterface { static final String ACCEPT_HEADER_NAME = "Accept"; private RestMethod method; private RestRequestParamsPropertyHolder params; private ParamUpdater paramUpdater; private JMSHeaderConfig jmsHeaderConfig; private JMSPropertiesConfig jmsPropertyConfig; public RestRequest(RestMethod method, RestRequestConfig requestConfig, boolean forLoadTest) { super(requestConfig, method.getOperation(), "/rest_request_step.png", forLoadTest); this.method = method; if (requestConfig.getParameters() == null) { requestConfig.addNewParameters(); } StringToStringMap paramValues = StringToStringMap.fromXml(requestConfig.getParameters()); params = new RestRequestParamsPropertyHolder(method.getOverlayParams(), this, paramValues); paramUpdater = new ParamUpdater(paramValues); params.addTestPropertyListener(paramUpdater); method.addPropertyChangeListener(this); if (requestConfig.getMediaType() == null) { String defaultMediaType = getRestMethod().getDefaultRequestMediaType(); getConfig().setMediaType(defaultMediaType); } cleanUpAcceptEncoding(); } public ModelItem getParent() { return getRestMethod(); } public RestMethod getRestMethod() { return method; } protected RequestIconAnimator<?> initIconAnimator() { return new RequestIconAnimator<AbstractHttpRequest<?>>(this, "/rest_request.gif", "/exec_rest_request.gif", 4); } public MessagePart[] getRequestParts() { List<MessagePart> result = new ArrayList<MessagePart>(); for (int c = 0; c < getPropertyCount(); c++) { result.add(new ParameterMessagePart(getPropertyAt(c))); } if (getMethod() == HttpMethod.POST || getMethod() == HttpMethod.PUT || getMethod() == HttpMethod.PATCH) { result.add(new RestContentPart()); } return result.toArray(new MessagePart[result.size()]); } public RestRepresentation[] getRepresentations() { return getRepresentations(null, null); } public RestRepresentation[] getRepresentations(RestRepresentation.Type type) { return getRepresentations(type, null); } public RestRepresentation[] getRepresentations(RestRepresentation.Type type, String mediaType) { return getRestMethod().getRepresentations(type, mediaType); } public MessagePart[] getResponseParts() { return new MessagePart[0]; } public HttpMethod getMethod() { return getRestMethod().getMethod(); } public String getAccept() { String accept = getConfig().getAccept(); return accept == null ? "" : accept; } public void setAccept(String acceptEncoding) { String old = getAccept(); getConfig().setAccept(acceptEncoding); notifyPropertyChanged("accept", old, acceptEncoding); } public void setMediaType(String mediaType) { String old = getMediaType(); getConfig().setMediaType(mediaType); notifyPropertyChanged(MEDIA_TYPE, old, mediaType); } public String getMediaType() { return getConfig().getMediaType(); } public void setMethod(HttpMethod method) { getRestMethod().setMethod(method); } public WsdlSubmit<RestRequest> submit(SubmitContext submitContext, boolean async) throws SubmitException { String endpoint = PropertyExpander.expandProperties(submitContext, getEndpoint()); if (StringUtils.isNullOrEmpty(endpoint)) { try { endpoint = new URL(getPath()).toString(); } catch (MalformedURLException ignore) { } } if (StringUtils.isNullOrEmpty(endpoint)) { UISupport.showErrorMessage("Missing endpoint for request [" + getName() + "]"); return null; } try { WsdlSubmit<RestRequest> submitter = new WsdlSubmit<RestRequest>(this, getSubmitListeners(), RequestTransportRegistry.getTransport(endpoint, submitContext)); submitter.submitRequest(submitContext, async); addPropertyChangeListener(AbstractHttpRequest.RESPONSE_PROPERTY, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getNewValue() != null) { setOriginalUriInConfig((HttpResponse) evt.getNewValue()); } } }); return submitter; } catch (Exception e) { throw new SubmitException(e.toString()); } } public PropertyExpansion[] getPropertyExpansions() { PropertyExpansionsResult result = new PropertyExpansionsResult(this, this); result.addAll(super.getPropertyExpansions()); result.addAll(getRestMethod().getPropertyExpansions()); result.addAll(params.getPropertyExpansions()); addJMSHeaderExpansions(result, getJMSHeaderConfig(), this); return result.toArray(); } public void addJMSHeaderExpansions(PropertyExpansionsResult result, JMSHeaderConfig jmsHeaderConfig, ModelItem modelItem) { result.addAll(PropertyExpansionUtils.extractPropertyExpansions(modelItem, jmsHeaderConfig, JMSHeader.JMSCORRELATIONID)); result.addAll(PropertyExpansionUtils .extractPropertyExpansions(modelItem, jmsHeaderConfig, JMSHeader.JMSREPLYTO)); result.addAll(PropertyExpansionUtils.extractPropertyExpansions(modelItem, jmsHeaderConfig, JMSHeader.JMSTYPE)); result.addAll(PropertyExpansionUtils.extractPropertyExpansions(modelItem, jmsHeaderConfig, JMSHeader.JMSPRIORITY)); result.addAll(PropertyExpansionUtils .extractPropertyExpansions(modelItem, jmsHeaderConfig, JMSHeader.TIMETOLIVE)); result.addAll(PropertyExpansionUtils.extractPropertyExpansions(modelItem, jmsHeaderConfig, JMSHeader.DURABLE_SUBSCRIPTION_NAME)); result.addAll(PropertyExpansionUtils.extractPropertyExpansions(modelItem, jmsHeaderConfig, JMSHeader.CLIENT_ID)); result.addAll(PropertyExpansionUtils.extractPropertyExpansions(modelItem, jmsHeaderConfig, JMSHeader.SEND_AS_BYTESMESSAGE)); result.addAll(PropertyExpansionUtils.extractPropertyExpansions(modelItem, jmsHeaderConfig, JMSHeader.SOAP_ACTION_ADD)); } public TestProperty addProperty(String name) { return params.addProperty(name); } public void moveProperty(String propertyName, int targetIndex) { params.moveProperty(propertyName, targetIndex); } public TestProperty removeProperty(String propertyName) { return params.removeProperty(propertyName); } public boolean renameProperty(String name, String newName) { return params.renameProperty(name, newName); } public void addTestPropertyListener(TestPropertyListener listener) { params.addTestPropertyListener(listener); } public ModelItem getModelItem() { return this; } @Override public RestResource getOperation() { return method.getOperation(); } public Map<String, TestProperty> getProperties() { return params.getProperties(); } public RestParamProperty getProperty(String name) { return params.getProperty(name); } public RestParamProperty getPropertyAt(int index) { return params.getPropertyAt(index); } public int getPropertyCount() { return params.getPropertyCount(); } public String[] getPropertyNames() { return params.getPropertyNames(); } public String getPropertyValue(String name) { return params.getPropertyValue(name); } public boolean hasProperty(String name) { return params.hasProperty(name); } public void removeTestPropertyListener(TestPropertyListener listener) { params.removeTestPropertyListener(listener); } public void setPropertyValue(String name, String value) { params.setPropertyValue(name, value); } public void resetPropertyValues() { params.clear(); for (String name : params.getPropertyNames()) { params.getProperty(name).setValue(params.getProperty(name).getDefaultValue()); } } public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals("path")) { notifyPropertyChanged("path", null, getPath()); } else if (evt.getPropertyName().equals("method")) { notifyPropertyChanged("method", evt.getOldValue(), evt.getNewValue()); } } public String[] getResponseMediaTypes() { StringList result = new StringList(); for (RestRepresentation representation : getRepresentations(Type.RESPONSE, null)) { if (!result.contains(representation.getMediaType())) { result.add(representation.getMediaType()); } } return result.toStringArray(); } public boolean isPostQueryString() { return hasRequestBody() && getConfig().getPostQueryString(); } public void setPostQueryString(boolean b) { boolean old = isPostQueryString(); getConfig().setPostQueryString(b); notifyPropertyChanged("postQueryString", old, b); if (!("multipart/form-data".equals(getMediaType()) || "multipart/mixed".equals(getMediaType()))) { setMediaType(b ? "application/x-www-form-urlencoded" : getMediaType()); } } public final static class ParameterMessagePart extends MessagePart.ParameterPart { private String name; public ParameterMessagePart(TestProperty propertyAt) { this.name = propertyAt.getName(); } @Override public SchemaType getSchemaType() { return XmlString.type; } @Override public SchemaGlobalElement getPartElement() { return null; } @Override public QName getPartElementName() { return new QName(getName()); } public String getDescription() { return null; } public String getName() { return name; } } public String getPropertiesLabel() { return "Request Params"; } public RestParamsPropertyHolder getParams() { return params; } public HttpAttachmentPart getAttachmentPart(String partName) { return null; } public HttpAttachmentPart[] getDefinedAttachmentParts() { return new HttpAttachmentPart[0]; } public class RestContentPart extends ContentPart implements MessagePart { @Override public SchemaGlobalElement getPartElement() { return null; } @Override public QName getPartElementName() { return null; } @Override public SchemaType getSchemaType() { return null; } public String getDescription() { return null; } public String getName() { return null; } public String getMediaType() { return getConfig().getMediaType(); } } public boolean hasRequestBody() { return getRestMethod().hasRequestBody(); } public RestResource getResource() { return getOperation(); } public String getPath() { if (!StringUtils.isNullOrEmpty(getConfig().getFullPath()) || getResource() == null) { return getConfig().getFullPath(); } else { return getResource().getFullPath(); } } public void setPath(String fullPath) { String old = getPath(); if (getResource() != null && getResource().getFullPath().equals(fullPath)) { getConfig().unsetFullPath(); } else { getConfig().setFullPath(fullPath); } notifyPropertyChanged("path", old, fullPath); } public String getResponseContentAsXml() { HttpResponse response = getResponse(); if (response == null) { return null; } return response.getContentAsXml(); } @Override public void release() { super.release(); if (method != null) { method.removePropertyChangeListener(this); } params.removeTestPropertyListener(paramUpdater); params.release(); } public void updateConfig(RestRequestConfig request) { setConfig(request); updateParams(); List<AttachmentConfig> attachmentConfigs = getConfig().getAttachmentList(); for (int i = 0; i < attachmentConfigs.size(); i++) { AttachmentConfig config = attachmentConfigs.get(i); getAttachmentsList().get(i).updateConfig(config); } if (jmsHeaderConfig != null) { jmsHeaderConfig.setJMSHeaderConfConfig(request.getJmsConfig()); } if (jmsPropertyConfig != null) { jmsPropertyConfig.setJmsPropertyConfConfig(request.getJmsPropertyConfig()); } } protected void updateParams() { StringToStringMap paramValues = StringToStringMap.fromXml(getConfig().getParameters()); params.reset(getRestMethod().getOverlayParams(), paramValues); paramUpdater.setValues(paramValues); } public boolean hasEndpoint() { return super.hasEndpoint() || PathUtils.isHttpPath(getPath()); } private class ParamUpdater implements TestPropertyListener { private StringToStringMap values; public ParamUpdater(StringToStringMap paramValues) { values = paramValues; } public void setValues(StringToStringMap paramValues) { values = paramValues; } private void sync() { try { RestRequestConfig requestConfig = getConfig(); requestConfig.setParameters(StringToStringMapConfig.Factory.parse(values.toXml())); } catch (XmlException e) { e.printStackTrace(); } } public void propertyAdded(String name) { sync(); } public void propertyMoved(String name, int oldIndex, int newIndex) { } public void propertyRemoved(String name) { sync(); } public void propertyRenamed(String oldName, String newName) { sync(); } public void propertyValueChanged(String name, String oldValue, String newValue) { sync(); } } public List<TestProperty> getPropertyList() { return params.getPropertyList(); } protected void setRestMethod(RestMethod restMethod) { if (this.method != null) { this.method.removePropertyChangeListener(this); } this.method = restMethod; if (method != null) { method.addPropertyChangeListener(this); } updateParams(); } public JMSHeaderConfig getJMSHeaderConfig() { if (jmsHeaderConfig == null) { if (!getConfig().isSetJmsConfig()) { getConfig().addNewJmsConfig(); } jmsHeaderConfig = new JMSHeaderConfig(getConfig().getJmsConfig(), this); } return jmsHeaderConfig; } public JMSPropertiesConfig getJMSPropertiesConfig() { if (jmsPropertyConfig == null) { if (!getConfig().isSetJmsPropertyConfig()) { getConfig().addNewJmsPropertyConfig(); } jmsPropertyConfig = new JMSPropertiesConfig(getConfig().getJmsPropertyConfig(), this); } return jmsPropertyConfig; } @Override public String getMultiValueDelimiter() { return getConfig().getMultiValueDelimiter(); } public void setMultiValueDelimiter(String delimiter) { String old = getMultiValueDelimiter(); getConfig().setMultiValueDelimiter(delimiter); notifyPropertyChanged("multiValueDelimiter", old, delimiter); } /* Helper methods */ private void setOriginalUriInConfig(HttpResponse response) { if (getConfig().getOriginalUri() == null && response.getURL() != null) { getConfig().setOriginalUri(JsonMediaTypeHandler.makeNamespaceUriFrom(response.getURL())); } } private void cleanUpAcceptEncoding() { if (StringUtils.hasContent(getAccept())) { StringToStringsMap requestHeaders = getRequestHeaders(); requestHeaders.add(ACCEPT_HEADER_NAME, getAccept()); setRequestHeaders(requestHeaders); setAccept(null); } } }