package vnet.sms.common.wme.jmsbridge; import static org.apache.commons.lang.Validate.isTrue; import static org.apache.commons.lang.Validate.notNull; import java.io.Serializable; import javax.jms.JMSException; import javax.jms.ObjectMessage; import javax.jms.Session; import org.springframework.jms.JmsException; import org.springframework.jms.support.JmsUtils; import org.springframework.jms.support.converter.MessageConversionException; import org.springframework.jms.support.converter.MessageConverter; import vnet.sms.common.messages.GsmPdu; import vnet.sms.common.messages.Headers; import vnet.sms.common.messages.Sms; import vnet.sms.common.wme.MessageEventType; import vnet.sms.common.wme.WindowedMessageEvent; import vnet.sms.common.wme.acknowledge.SendSmsAckContainer; import vnet.sms.common.wme.acknowledge.SendSmsNackContainer; import vnet.sms.common.wme.send.SendSmsContainer; /** * @author obergner * */ public class WindowedMessageEventToJmsMessageConverter implements MessageConverter { @Override public final javax.jms.Message toMessage(final Object object, final Session session) throws JMSException, MessageConversionException { if (!WindowedMessageEvent.class.isInstance(object)) { throw new IllegalArgumentException("Can only convert instances of " + WindowedMessageEvent.class.getName() + ". Got: " + object); } final WindowedMessageEvent<? extends Serializable, ? extends GsmPdu> windowedMessageEvent = (WindowedMessageEvent<? extends Serializable, ? extends GsmPdu>) object; final ObjectMessage converted = session .createObjectMessage(windowedMessageEvent.getMessage()); converted.setJMSMessageID("urn:message:id:" + windowedMessageEvent.getMessage().getId().toString()); converted.setObjectProperty(Headers.MESSAGE_REFERENCE, windowedMessageEvent.getMessageReference()); converted.setStringProperty(Headers.EVENT_TYPE, windowedMessageEvent .getMessageType().toString()); converted.setIntProperty(Headers.RECEIVING_CHANNEL_ID, windowedMessageEvent.getChannel().getId()); converted.setLongProperty(Headers.RECEIVE_TIMESTAMP, windowedMessageEvent.getMessage().getCreationTimestamp()); converted .setStringProperty(Headers.SENDER_SOCKET_ADDRESS, windowedMessageEvent.getChannel().getRemoteAddress() .toString()); converted.setStringProperty(Headers.RECEIVER_SOCKET_ADDRESS, windowedMessageEvent.getChannel().getLocalAddress().toString()); return converted; } @Override public final Object fromMessage(final javax.jms.Message message) throws JMSException, MessageConversionException { validateReceivedMessage(message); final ObjectMessage objectMessage = ObjectMessage.class.cast(message); final MessageEventType eventType = MessageEventType .valueOf(objectMessage.getStringProperty(Headers.EVENT_TYPE)); final Object converted; switch (eventType) { case SEND_SMS_ACK: final Sms ackedSms = Sms.class.cast(objectMessage.getObject()); final Serializable messageReference = Serializable.class .cast(objectMessage .getObjectProperty(Headers.MESSAGE_REFERENCE)); final int receivingChannelId = objectMessage .getIntProperty(Headers.RECEIVING_CHANNEL_ID); converted = new SendSmsAckContainer<Serializable>(messageReference, receivingChannelId, ackedSms); break; case SEND_SMS_NACK: final Sms nackedSms = Sms.class.cast(objectMessage.getObject()); final Serializable messageRef = Serializable.class .cast(objectMessage .getObjectProperty(Headers.MESSAGE_REFERENCE)); final int receivChannelId = objectMessage .getIntProperty(Headers.RECEIVING_CHANNEL_ID); final int errorKey = objectMessage .getIntProperty(Headers.ERROR_KEY); final String errorDescription = objectMessage .getStringProperty(Headers.ERROR_DESCRIPTION); converted = new SendSmsNackContainer<Serializable>(errorKey, errorDescription, messageRef, receivChannelId, nackedSms); break; case SEND_SMS: final Sms sms = Sms.class.cast(objectMessage.getObject()); converted = new SendSmsContainer(sms); break; default: throw new IllegalArgumentException("Unsupported message type: " + eventType); } return converted; } private void validateReceivedMessage(final javax.jms.Message message) throws IllegalArgumentException, JmsException { try { if (!ObjectMessage.class.isInstance(message)) { throw new IllegalArgumentException( "Can only convert JMS messages of type " + ObjectMessage.class.getName() + ". Got: " + message); } final ObjectMessage objectMessage = ObjectMessage.class .cast(message); final Serializable messagePayload = objectMessage.getObject(); notNull(messagePayload, "No body/payload has been set on message " + objectMessage); notNull(objectMessage.getStringProperty(Headers.EVENT_TYPE), "No header '" + Headers.EVENT_TYPE + "' has been set on message " + objectMessage); final MessageEventType eventType = MessageEventType .valueOf(objectMessage .getStringProperty(Headers.EVENT_TYPE)); switch (eventType) { case SEND_SMS: validateSendSms(objectMessage, messagePayload); break; case SEND_SMS_ACK: validateReceivedSmsAcked(objectMessage, messagePayload); break; case SEND_SMS_NACK: validateReceivedSmsNacked(objectMessage, messagePayload); break; default: throw new IllegalArgumentException( "Unsupported message event type: " + eventType); } } catch (final JMSException e) { throw JmsUtils.convertJmsAccessException(e); } } private void validateSendSms(final ObjectMessage jmsMessage, final Serializable messagePayload) { isTrue(Sms.class.isInstance(messagePayload), "GsmPdu '" + jmsMessage + "' is of type " + MessageEventType.SEND_SMS + ", yet it does not contain an SMS but rather " + messagePayload); } private void validateReceivedSmsAcked(final ObjectMessage jmsMessage, final Serializable messagePayload) throws JMSException { isTrue(Sms.class.isInstance(messagePayload), "GsmPdu '" + jmsMessage + "' is of type " + MessageEventType.SEND_SMS_ACK + ", yet it does not contain an SMS but rather " + messagePayload); isTrue(jmsMessage.getObjectProperty(Headers.RECEIVING_CHANNEL_ID) != null, "No header '" + Headers.RECEIVING_CHANNEL_ID + "' has been set on message " + jmsMessage + ". Cannot determine reply channel."); notNull(jmsMessage.getObjectProperty(Headers.MESSAGE_REFERENCE), "No message reference has been set on message " + jmsMessage + ". Cannot determine acked SMS."); } private void validateReceivedSmsNacked(final ObjectMessage jmsMessage, final Serializable messagePayload) throws JMSException { isTrue(Sms.class.isInstance(messagePayload), "GsmPdu '" + jmsMessage + "' is of type " + MessageEventType.SEND_SMS_NACK + ", yet it does not contain an SMS but rather " + messagePayload); isTrue(jmsMessage.getObjectProperty(Headers.RECEIVING_CHANNEL_ID) != null, "No header '" + Headers.RECEIVING_CHANNEL_ID + "' has been set on message " + jmsMessage + ". Cannot determine reply channel."); notNull(jmsMessage.getObjectProperty(Headers.MESSAGE_REFERENCE), "No message reference has been set on message " + jmsMessage + ". Cannot determine nacked SMS."); isTrue(jmsMessage.getObjectProperty(Headers.ERROR_KEY) != null, "No header '" + Headers.ERROR_KEY + "' has been set on message " + jmsMessage + ". This SMS has been nacked, and yet no error key has been provided."); notNull(jmsMessage.getObjectProperty(Headers.ERROR_DESCRIPTION), "No header '" + Headers.ERROR_DESCRIPTION + "' has been set on message " + jmsMessage + ". This SMS has been nacked, and yet no error description has been provided."); } }