/*
* 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);
}
}
}