/* * Copyright (c) 2005-2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.wso2.carbon.inbound.endpoint.protocol.jms; import java.io.IOException; import java.io.OutputStream; import java.io.StringWriter; import java.nio.charset.UnsupportedCharsetException; import javax.activation.DataHandler; 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.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.OMNode; import org.apache.axiom.om.OMOutputFormat; import org.apache.axiom.om.OMText; import org.apache.axis2.AxisFault; import org.apache.axis2.transport.MessageFormatter; import org.apache.axis2.transport.base.BaseConstants; import org.apache.axis2.transport.base.BaseUtils; import org.apache.axis2.transport.http.HTTPConstants; import org.apache.axis2.util.MessageProcessorSelector; import org.apache.commons.io.output.WriterOutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.synapse.MessageContext; import org.apache.synapse.core.axis2.Axis2MessageContext; import org.apache.synapse.inbound.InboundResponseSender; import org.wso2.carbon.inbound.endpoint.protocol.jms.factory.CachedJMSConnectionFactory; public class JMSReplySender implements InboundResponseSender { private static final Log log = LogFactory.getLog(JMSReplySender.class.getName()); private Destination replyTo; private CachedJMSConnectionFactory cachedJMSConnectionFactory; private String strUserName; private String strPassword; public JMSReplySender(Destination replyTo, CachedJMSConnectionFactory cachedJMSConnectionFactory, String strUserName, String strPassword) { this.replyTo = replyTo; this.strUserName = strUserName; this.strPassword = strPassword; this.cachedJMSConnectionFactory = cachedJMSConnectionFactory; } /** * Send the reply back to the response queue/topic * */ public void sendBack(MessageContext synCtx) { log.debug("Begin sending reply to the destination queue."); MessageProducer producer = null; Session session = null; try { Connection connection = cachedJMSConnectionFactory.getConnection(strUserName, strPassword); session = cachedJMSConnectionFactory.getSession(connection); producer = cachedJMSConnectionFactory.createProducer(session, replyTo, true); Message message = createJMSMessage(synCtx, session, null); producer.send(message); } catch (JMSException e) { log.error("Error sending JMS response", e); } catch (Exception e) { log.error("Error sending JMS response", e); } finally { try { producer.close(); } catch (Exception e) { log.debug("ERROR: Unable to close the producer"); } try { session.close(); } catch (Exception e) { log.debug("ERROR: Unable to close the session"); } } } /** * Create a JMS Message from the given MessageContext and using the given * session * * @param msgContext * the MessageContext * @param session * the JMS session * @param contentTypeProperty * the message property to be used to store the content type * @return a JMS message from the context and session * @throws JMSException * on exception * @throws AxisFault * on exception */ private Message createJMSMessage(MessageContext synCtx, Session session, String contentTypeProperty) throws JMSException { Message message = null; org.apache.axis2.context.MessageContext msgContext = ((Axis2MessageContext) synCtx).getAxis2MessageContext(); String msgType = getProperty(msgContext, JMSConstants.JMS_MESSAGE_TYPE); String jmsPayloadType = guessMessageType(msgContext); if (jmsPayloadType == null) { OMOutputFormat format = BaseUtils.getOMOutputFormat(msgContext); MessageFormatter messageFormatter = null; try { messageFormatter = MessageProcessorSelector.getMessageFormatter(msgContext); } catch (AxisFault axisFault) { throw new JMSException("Unable to get the message formatter to use"); } String contentType = messageFormatter.getContentType(msgContext, format, msgContext.getSoapAction()); boolean useBytesMessage = msgType != null && JMSConstants.JMS_BYTE_MESSAGE.equals(msgType) || contentType.indexOf(HTTPConstants.HEADER_ACCEPT_MULTIPART_RELATED) > -1; OutputStream out; StringWriter sw; if (useBytesMessage) { BytesMessage bytesMsg = session.createBytesMessage(); sw = null; out = new BytesMessageOutputStream(bytesMsg); message = bytesMsg; } else { sw = new StringWriter(); try { out = new WriterOutputStream(sw, format.getCharSetEncoding()); } catch (UnsupportedCharsetException ex) { log.error("Unsupported encoding " + format.getCharSetEncoding(), ex); throw new JMSException("Unsupported encoding " + format.getCharSetEncoding()); } } try { messageFormatter.writeTo(msgContext, format, out, true); out.close(); } catch (IOException e) { log.error("IO Error while creating BytesMessage", e); throw new JMSException("IO Error while creating BytesMessage"); } if (!useBytesMessage) { TextMessage txtMsg = session.createTextMessage(); txtMsg.setText(sw.toString()); message = txtMsg; } if (contentTypeProperty != null) { message.setStringProperty(contentTypeProperty, contentType); } } else if (JMSConstants.JMS_BYTE_MESSAGE.equals(jmsPayloadType)) { message = session.createBytesMessage(); BytesMessage bytesMsg = (BytesMessage) message; OMElement wrapper = msgContext.getEnvelope() .getBody() .getFirstChildWithName(BaseConstants.DEFAULT_BINARY_WRAPPER); OMNode omNode = wrapper.getFirstOMChild(); if (omNode != null && omNode instanceof OMText) { Object dh = ((OMText) omNode).getDataHandler(); if (dh != null && dh instanceof DataHandler) { try { ((DataHandler) dh).writeTo(new BytesMessageOutputStream(bytesMsg)); } catch (IOException e) { log.error("Error serializing binary content of element : " + BaseConstants.DEFAULT_BINARY_WRAPPER, e); throw new JMSException("Error serializing binary content of element : " + BaseConstants.DEFAULT_BINARY_WRAPPER); } } } } else if (JMSConstants.JMS_TEXT_MESSAGE.equals(jmsPayloadType)) { message = session.createTextMessage(); TextMessage txtMsg = (TextMessage) message; txtMsg.setText(msgContext.getEnvelope().getBody() .getFirstChildWithName(BaseConstants.DEFAULT_TEXT_WRAPPER) .getText()); } else if (JMSConstants.JMS_MAP_MESSAGE.equalsIgnoreCase(jmsPayloadType)) { message = session.createMapMessage(); JMSUtils.convertXMLtoJMSMap(msgContext.getEnvelope() .getBody() .getFirstChildWithName(JMSConstants.JMS_MAP_QNAME), (MapMessage) message); } // set the JMS correlation ID if specified String correlationId = (String) synCtx.getProperty(JMSConstants.JMS_COORELATION_ID); if (correlationId != null) { message.setJMSCorrelationID(correlationId); } if (msgContext.isServerSide()) { // set SOAP Action as a property on the JMS message setProperty(message, msgContext, BaseConstants.SOAPACTION); } else { String action = msgContext.getOptions().getAction(); if (action != null) { message.setStringProperty(BaseConstants.SOAPACTION, action); } } JMSUtils.setTransportHeaders(msgContext, message); return message; } private void setProperty(Message message, org.apache.axis2.context.MessageContext msgCtx, String key) { String value = getProperty(msgCtx, key); if (value != null) { try { message.setStringProperty(key, value); } catch (JMSException e) { log.warn("Couldn't set message property : " + key + " = " + value, e); } } } private String getProperty(org.apache.axis2.context.MessageContext mc, String key) { return (String) mc.getProperty(key); } /** * * check the first element of the SOAP body, do we have content wrapped * using the * default wrapper elements for binary * (BaseConstants.DEFAULT_BINARY_WRAPPER) or * text (BaseConstants.DEFAULT_TEXT_WRAPPER) ? If so, do not create SOAP * messages * for JMS but just get the payload in its native format * Guess the message type to use for JMS looking at the message contexts' * envelope * * @param msgContext * the message context * @return JMSConstants.JMS_BYTE_MESSAGE or JMSConstants.JMS_TEXT_MESSAGE or * null */ private String guessMessageType(org.apache.axis2.context.MessageContext msgContext) { OMElement firstChild = msgContext.getEnvelope().getBody().getFirstElement(); if (firstChild != null) { if (BaseConstants.DEFAULT_BINARY_WRAPPER.equals(firstChild.getQName())) { return JMSConstants.JMS_BYTE_MESSAGE; } else if (BaseConstants.DEFAULT_TEXT_WRAPPER.equals(firstChild.getQName())) { return JMSConstants.JMS_TEXT_MESSAGE; } else if (JMSConstants.JMS_MAP_QNAME.equals(firstChild.getQName())) { return JMSConstants.JMS_MAP_MESSAGE; } } return null; } }