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