/*
* 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.submit.transports.jms;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.rest.RestRequest;
import com.eviware.soapui.impl.support.AbstractHttpRequest;
import com.eviware.soapui.impl.wsdl.WsdlOperation;
import com.eviware.soapui.impl.wsdl.WsdlProject;
import com.eviware.soapui.impl.wsdl.WsdlRequest;
import com.eviware.soapui.impl.wsdl.submit.RequestFilter;
import com.eviware.soapui.impl.wsdl.submit.RequestTransport;
import com.eviware.soapui.impl.wsdl.submit.RequestTransportRegistry.CannotResolveJmsTypeException;
import com.eviware.soapui.impl.wsdl.submit.RequestTransportRegistry.MissingTransportException;
import com.eviware.soapui.impl.wsdl.submit.transports.http.BaseHttpRequestTransport;
import com.eviware.soapui.impl.wsdl.submit.transports.jms.util.HermesUtils;
import com.eviware.soapui.impl.wsdl.submit.transports.jms.util.JMSUtils;
import com.eviware.soapui.impl.wsdl.support.RequestFileAttachment;
import com.eviware.soapui.impl.wsdl.support.jms.header.JMSHeaderConfig;
import com.eviware.soapui.impl.wsdl.teststeps.HttpTestRequest;
import com.eviware.soapui.model.iface.Attachment;
import com.eviware.soapui.model.iface.Request;
import com.eviware.soapui.model.iface.Response;
import com.eviware.soapui.model.iface.SubmitContext;
import com.eviware.soapui.model.propertyexpansion.PropertyExpander;
import com.eviware.soapui.model.support.ModelSupport;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.xml.XmlUtils;
import hermes.Hermes;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang.NotImplementedException;
import javax.jms.BytesMessage;
import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicSubscriber;
import javax.naming.NamingException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
public class HermesJmsRequestTransport implements RequestTransport {
public static final String IS_JMS_MESSAGE_RECEIVED = "JMS_MESSAGE_RECEIVE";
public static final String JMS_MESSAGE_SEND = "JMS_MESSAGE_SEND";
public static final String JMS_RESPONSE = "JMS_RESPONSE";
public static final String JMS_ERROR = "JMS_ERROR";
public static final String JMS_RECEIVE_TIMEOUT = "JMS_RECEIVE_TIMEOUT";
protected String username;
protected String password;
protected JMSEndpoint jmsEndpoint;
protected String durableSubscriptionName;
protected String clientID;
protected String messageSelector;
protected boolean sendAsBytesMessage;
protected boolean addSoapAction;
protected Hermes hermes;
protected static List<RequestFilter> filters = new ArrayList<RequestFilter>();
public Response sendRequest(SubmitContext submitContext, Request request) throws Exception {
long timeStarted = Calendar.getInstance().getTimeInMillis();
submitContext.setProperty(JMS_RECEIVE_TIMEOUT, getTimeout(submitContext, request));
return resolveType(submitContext, request).execute(submitContext, request, timeStarted);
}
protected void init(SubmitContext submitContext, Request request) throws NamingException {
this.jmsEndpoint = new JMSEndpoint(request, submitContext);
this.hermes = getHermes(jmsEndpoint.getSessionName(), request);
this.username = submitContext.expand(request.getUsername());
this.password = submitContext.expand(request.getPassword());
JMSHeaderConfig jmsConfig = ((AbstractHttpRequest<?>) request).getJMSHeaderConfig();
this.durableSubscriptionName = submitContext.expand(jmsConfig.getDurableSubscriptionName());
this.clientID = submitContext.expand(jmsConfig.getClientID());
this.messageSelector = jmsConfig.getMessageSelector();// expand latter
// just before use
this.sendAsBytesMessage = jmsConfig.getSendAsBytesMessage();
this.addSoapAction = jmsConfig.getSoapActionAdd();
submitContext.setProperty(HermesJmsRequestTransport.IS_JMS_MESSAGE_RECEIVED, false);
}
protected Response execute(SubmitContext submitContext, Request request, long timeStarted) throws Exception {
throw new NotImplementedException();
}
private HermesJmsRequestTransport resolveType(SubmitContext submitContext, Request request)
throws CannotResolveJmsTypeException, MissingTransportException {
String endpoint = PropertyExpander.expandProperties(submitContext, request.getEndpoint());
int ix = endpoint.indexOf("://");
if (ix == -1) {
throw new MissingTransportException("Missing protocol in endpoint [" + endpoint + "]");
}
String[] params = JMSEndpoint.extractEndpointParameters(request, submitContext);
// resolve sending class
if (params.length == 2) {
String destinationName = PropertyExpander.expandProperties(submitContext, params[1]);
if (destinationName.startsWith(JMSEndpoint.QUEUE_ENDPOINT_PREFIX)) {
return new HermesJmsRequestSendTransport();
} else if (destinationName.startsWith(JMSEndpoint.TOPIC_ENDPOINT_PREFIX)) {
return new HermesJmsRequestPublishTransport();
} else {
cannotResolve();
}
}
// resolve receiving class
else if (params.length == 3 && PropertyExpander.expandProperties(submitContext, params[1]).equals("-")) {
String destinationName = PropertyExpander.expandProperties(submitContext, params[2]);
if (destinationName.startsWith(JMSEndpoint.QUEUE_ENDPOINT_PREFIX)) {
return new HermesJmsRequestReceiveTransport();
} else if (destinationName.startsWith(JMSEndpoint.TOPIC_ENDPOINT_PREFIX)) {
return new HermesJmsRequestSubscribeTransport();
} else {
cannotResolve();
}
}
// resolve send-receive class
else if (params.length == 3) {
String destinationSendName = PropertyExpander.expandProperties(submitContext, params[1]);
String destinationReceiveName = PropertyExpander.expandProperties(submitContext, params[2]);
if (destinationSendName.startsWith(JMSEndpoint.QUEUE_ENDPOINT_PREFIX)
&& destinationReceiveName.startsWith(JMSEndpoint.QUEUE_ENDPOINT_PREFIX)) {
return new HermesJmsRequestSendReceiveTransport();
} else if (destinationSendName.startsWith(JMSEndpoint.QUEUE_ENDPOINT_PREFIX)
&& destinationReceiveName.startsWith(JMSEndpoint.TOPIC_ENDPOINT_PREFIX)) {
return new HermesJmsRequestSendSubscribeTransport();
} else if (destinationSendName.startsWith(JMSEndpoint.TOPIC_ENDPOINT_PREFIX)
&& destinationReceiveName.startsWith(JMSEndpoint.TOPIC_ENDPOINT_PREFIX)) {
return new HermesJmsRequestPublishSubscribeTransport();
} else if (destinationSendName.startsWith(JMSEndpoint.TOPIC_ENDPOINT_PREFIX)
&& destinationReceiveName.startsWith(JMSEndpoint.QUEUE_ENDPOINT_PREFIX)) {
return new HermesJmsRequestPublishReceiveTransport();
} else {
cannotResolve();
}
} else {
cannotResolve();
}
return null;
}
private static void cannotResolve() throws CannotResolveJmsTypeException {
throw new CannotResolveJmsTypeException(
"\nBad jms alias! \nFor JMS please use this endpont pattern:\nfor sending 'jms://sessionName::queue_myqueuename' \nfor receive 'jms://sessionName::-::queue_myqueuename'\nfor send-receive 'jms://sessionName::queue_myqueuename1::queue_myqueuename2'");
}
protected Hermes getHermes(String sessionName, Request request) throws NamingException {
WsdlProject project = (WsdlProject) ModelSupport.getModelItemProject(request);
return HermesUtils.getHermes(project, sessionName);
}
protected long getTimeout(SubmitContext submitContext, Request request) {
String timeout = PropertyExpander.expandProperties(submitContext, request.getTimeout());
long to = 0;
try {
to = Long.parseLong(timeout);
} catch (Exception e) {
}
return to;
}
protected JMSHeader createJMSHeader(SubmitContext submitContext, Request request, Hermes hermes, Message message,
Destination replyToDestination) {
JMSHeader jmsHeader = new JMSHeader();
jmsHeader.setMessageHeaders(message, request, hermes, submitContext);
JMSHeader.setMessageProperties(message, request, hermes, submitContext);
try {
if (message.getJMSReplyTo() == null) {
message.setJMSReplyTo(replyToDestination);
}
if (addSoapAction) {
message.setStringProperty(JMSHeader.SOAPJMS_SOAP_ACTION, request.getOperation().getName());
if (request.getOperation() instanceof WsdlOperation) {
message.setStringProperty(JMSHeader.SOAP_ACTION,
((WsdlOperation) request.getOperation()).getAction());
} else {
message.setStringProperty(JMSHeader.SOAP_ACTION, request.getOperation().getName());
}
}
} catch (JMSException e) {
SoapUI.logError(e);
}
return jmsHeader;
}
protected void closeSessionAndConnection(Connection connection, Session session) throws JMSException {
if (session != null) {
session.close();
}
if (connection != null) {
connection.close();
}
}
protected Response errorResponse(SubmitContext submitContext, Request request, long timeStarted, JMSException jmse) {
JMSResponse response;
SoapUI.logError(jmse);
submitContext.setProperty(JMS_ERROR, jmse);
response = new JMSResponse("", null, null, request, timeStarted);
submitContext.setProperty(JMS_RESPONSE, response);
return response;
}
protected Message messageSend(SubmitContext submitContext, Request request, Session session, Hermes hermes,
Queue queueSend, Destination replyToDestination) throws JMSException {
MessageProducer messageProducer = session.createProducer(queueSend);
Message messageSend = createMessage(submitContext, request, session);
return send(submitContext, request, hermes, messageProducer, messageSend, replyToDestination);
}
protected Message messagePublish(SubmitContext submitContext, Request request, Session topicSession, Hermes hermes,
Topic topicPublish, Destination replyToDestination) throws JMSException {
MessageProducer topicPublisher = topicSession.createProducer(topicPublish);
Message messagePublish = createMessage(submitContext, request, topicSession);
return send(submitContext, request, hermes, topicPublisher, messagePublish, replyToDestination);
}
private Message send(SubmitContext submitContext, Request request, Hermes hermes, MessageProducer messageProducer,
Message message, Destination replyToDestination) throws JMSException {
JMSHeader jmsHeader = createJMSHeader(submitContext, request, hermes, message, replyToDestination);
messageProducer.send(message, message.getJMSDeliveryMode(), message.getJMSPriority(), jmsHeader.getTimeTolive());
submitContext.setProperty(JMS_MESSAGE_SEND, message);
return message;
}
protected Response makeResponse(SubmitContext submitContext, Request request, long timeStarted,
Message messageSend, MessageConsumer messageConsumer) throws JMSException {
long timeout = getTimeout(submitContext, request);
Message messageReceive = messageConsumer.receive(timeout);
if (messageReceive != null) {
JMSResponse response = resolveMessage(request, timeStarted, messageSend, messageReceive);
submitContext.setProperty(IS_JMS_MESSAGE_RECEIVED, true);
submitContext.setProperty(JMS_RESPONSE, response);
return response;
} else {
return new JMSResponse("", null, null, request, timeStarted);
}
}
private JMSResponse resolveMessage(Request request, long timeStarted, Message messageSend, Message messageReceive)
throws JMSException {
if (messageReceive instanceof TextMessage) {
TextMessage textMessageReceive = (TextMessage) messageReceive;
return new JMSResponse(textMessageReceive.getText(), messageSend, textMessageReceive, request, timeStarted);
} else if (messageReceive instanceof MapMessage) {
MapMessage mapMessageReceive = (MapMessage) messageReceive;
return new JMSResponse(JMSUtils.extractMapMessagePayloadToXML(mapMessageReceive), messageSend,
mapMessageReceive, request, timeStarted);
} else if (messageReceive instanceof BytesMessage) {
BytesMessage bytesMessageReceive = (BytesMessage) messageReceive;
String bytesMessageAsString = new String(JMSUtils.extractByteArrayFromMessage(bytesMessageReceive));
// if message seems to be XML make xml response
if (XmlUtils.seemsToBeXml(bytesMessageAsString)) {
return new JMSResponse(bytesMessageAsString, messageSend, bytesMessageReceive, request, timeStarted);
} else {
JMSResponse jmsResponse = new JMSResponse("", messageSend, bytesMessageReceive, request, timeStarted);
addAttachment(request, bytesMessageReceive, jmsResponse);
return jmsResponse;
}
}
return null;
}
protected Response makeEmptyResponse(SubmitContext submitContext, Request request, long timeStarted,
Message messageSend) {
JMSResponse response = new JMSResponse("", messageSend, null, request, timeStarted);
submitContext.setProperty(JMS_RESPONSE, response);
return response;
}
private Message createMessage(SubmitContext submitContext, Request request, Session session) throws JMSException {
if (request instanceof WsdlRequest || request instanceof HttpTestRequest || request instanceof RestRequest) {
if (hasAttachment(request)) {
if (isTextAttachment(request) && !sendAsBytesMessage) {
return createTextMessageFromAttachment(submitContext, request, session);
} else {
return createBytesMessage(request, session);
}
} else {
String requestContent = applyFilters(submitContext, request);
if (sendAsBytesMessage) {
return createBytesMessageFromText(submitContext, requestContent, session);
} else {
return createTextMessage(submitContext, requestContent, session);
}
}
}
return null;
}
private String applyFilters(SubmitContext submitContext, Request request) {
submitContext.setProperty(BaseHttpRequestTransport.REQUEST_CONTENT, request.getRequestContent());
submitContext.setProperty(WSDL_REQUEST, request);
for (RequestFilter filter : filters) {
filter.filterRequest(submitContext, request);
}
String requestContent = (String) submitContext.getProperty(BaseHttpRequestTransport.REQUEST_CONTENT);
return requestContent;
}
private Message createBytesMessageFromText(SubmitContext submitContext, String requestContent, Session session)
throws JMSException {
BytesMessage bytesMessage = session.createBytesMessage();
bytesMessage.writeBytes(requestContent.getBytes());
return bytesMessage;
}
private Message createTextMessageFromAttachment(SubmitContext submitContext, Request request, Session session) {
try {
String content = convertStreamToString(request.getAttachments()[0].getInputStream());
TextMessage textMessageSend = session.createTextMessage();
String messageBody = PropertyExpander.expandProperties(submitContext, content);
textMessageSend.setText(messageBody);
return textMessageSend;
} catch (Exception e) {
SoapUI.logError(e);
}
return null;
}
private String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
private boolean hasAttachment(Request request) {
if (request.getAttachments().length > 0) {
return true;
}
return false;
}
private Message createTextMessage(SubmitContext submitContext, String requestContent, Session session)
throws JMSException {
TextMessage textMessageSend = session.createTextMessage();
textMessageSend.setText(requestContent);
return textMessageSend;
}
private boolean isTextAttachment(Request request) {
if (request.getAttachments().length > 0
&& (request.getAttachments()[0].getContentType().contains("/text")
|| request.getAttachments()[0].getContentType().contains("/xml") || request.getAttachments()[0]
.getContentType().contains("text/plain"))) {
return true;
}
return false;
}
private Message createBytesMessage(Request request, Session session) {
try {
InputStream in = request.getAttachments()[0].getInputStream();
int buff = -1;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((buff = in.read()) != -1) {
baos.write(buff);
}
BytesMessage bytesMessage = session.createBytesMessage();
bytesMessage.writeBytes(baos.toByteArray());
return bytesMessage;
} catch (Exception e) {
SoapUI.logError(e);
}
return null;
}
private void addAttachment(Request request, BytesMessage bytesMessageReceive, JMSResponse jmsResponse)
throws JMSException {
try {
byte[] buff = new byte[1];
File temp = File.createTempFile("bytesmessage", ".tmp");
OutputStream out = new FileOutputStream(temp);
bytesMessageReceive.reset();
while (bytesMessageReceive.readBytes(buff) != -1) {
out.write(buff);
}
out.close();
Attachment[] attachments = new Attachment[]{new RequestFileAttachment(temp, false,
(AbstractHttpRequest<?>) request)};
jmsResponse.setAttachments(attachments);
} catch (IOException e) {
SoapUI.logError(e);
}
}
protected TopicSubscriber createDurableSubscription(SubmitContext submitContext, Session topicSession,
JMSConnectionHolder jmsConnectionHolder) throws JMSException, NamingException {
Topic topicSubscribe = jmsConnectionHolder.getTopic(jmsConnectionHolder.getJmsEndpoint().getReceive());
// create durable subscriber
TopicSubscriber topicDurableSubsriber = topicSession.createDurableSubscriber(topicSubscribe,
StringUtils.hasContent(durableSubscriptionName) ? durableSubscriptionName : "durableSubscription"
+ jmsConnectionHolder.getJmsEndpoint().getReceive(), submitContext.expand(messageSelector), false);
return topicDurableSubsriber;
}
@SuppressWarnings("serial")
public static class UnresolvedJMSEndpointException extends Exception {
public UnresolvedJMSEndpointException(String msg) {
super(msg);
}
}
public void abortRequest(SubmitContext submitContext) {
}
public void addRequestFilter(RequestFilter filter) {
filters.add(filter);
}
public void removeRequestFilter(RequestFilter filter) {
filters.remove(filter);
}
@Override
public void insertRequestFilter(RequestFilter filter, RequestFilter refFilter) {
int ix = filters.indexOf( refFilter );
if( ix == -1 )
filters.add( filter );
else
filters.add( ix, filter );
}
}