/*
* soapUI, copyright (C) 2004-2011 eviware.com
*
* soapUI is free software; you can redistribute it and/or modify it under the
* terms of version 2.1 of the GNU Lesser General Public License as published by
* the Free Software Foundation.
*
* soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details at gnu.org.
*/
package com.eviware.soapui.impl.wsdl.submit.transports.jms;
import hermes.Hermes;
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;
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 org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang.NotImplementedException;
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.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;
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() );
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 );
}
}