Java tutorial
/* * Copyright (c) 2005-2014, 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 org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.inbound.endpoint.protocol.jms.factory.CachedJMSConnectionFactory; import java.util.Date; import java.util.Properties; import javax.jms.Connection; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.Session; import javax.jms.TextMessage; public class JMSPollingConsumer { private static final Log logger = LogFactory.getLog(JMSPollingConsumer.class.getName()); private CachedJMSConnectionFactory jmsConnectionFactory; private JMSInjectHandler injectHandler; private long scanInterval; private Long lastRanTime; private String strUserName; private String strPassword; private Integer iReceiveTimeout; private String replyDestinationName; private String name; private Properties jmsProperties; private boolean isConnected; private Long reconnectDuration; private long retryDuration; private int retryIteration; private double reconnectionProgressionFactor; private long maxReconnectDuration; private Connection connection = null; private Session session = null; private Destination destination = null; private MessageConsumer messageConsumer = null; private Destination replyDestination = null; public JMSPollingConsumer(Properties jmsProperties, long scanInterval, String name) { this.jmsConnectionFactory = new CachedJMSConnectionFactory(jmsProperties); strUserName = jmsProperties.getProperty(JMSConstants.PARAM_JMS_USERNAME); strPassword = jmsProperties.getProperty(JMSConstants.PARAM_JMS_PASSWORD); this.name = name; this.retryIteration = 0; this.reconnectionProgressionFactor = 2.0; this.maxReconnectDuration = 60000; this.retryDuration = 1000; String strReceiveTimeout = jmsProperties.getProperty(JMSConstants.RECEIVER_TIMEOUT); if (strReceiveTimeout != null) { try { iReceiveTimeout = Integer.parseInt(strReceiveTimeout.trim()); } catch (NumberFormatException e) { logger.warn("Invalid value for transport.jms.ReceiveTimeout : " + strReceiveTimeout); iReceiveTimeout = null; } } String strReconnectDuration = jmsProperties.getProperty(JMSConstants.JMS_RETRY_DURATION); if (strReconnectDuration != null) { try { this.reconnectDuration = Long.parseLong(strReconnectDuration.trim()); } catch (NumberFormatException e) { logger.warn("Invalid value for transport.jms.retry.duration : " + strReconnectDuration); this.reconnectDuration = null; } } this.replyDestinationName = jmsProperties.getProperty(JMSConstants.PARAM_REPLY_DESTINATION); this.scanInterval = scanInterval; this.lastRanTime = null; this.jmsProperties = jmsProperties; } /** * * Register a handler to implement injection of the retrieved message * * @param injectHandler */ public void registerHandler(JMSInjectHandler injectHandler) { this.injectHandler = injectHandler; } /** * This will be called by the task scheduler. If a cycle execution takes * more than the schedule interval, tasks will call this method ignoring the * interval. Timestamp based check is done to avoid that. */ public void execute() { try { logger.debug("Executing : JMS Inbound EP : "); // Check if the cycles are running in correct interval and start // scan long currentTime = (new Date()).getTime(); if (lastRanTime == null || ((lastRanTime + (scanInterval)) <= currentTime)) { lastRanTime = currentTime; poll(); } else if (logger.isDebugEnabled()) { logger.debug("Skip cycle since concurrent rate is higher than the scan interval : JMS Inbound EP "); } if (logger.isDebugEnabled()) { logger.debug("End : JMS Inbound EP : "); } } catch (Exception e) { logger.error("Error while retrieving or injecting JMS message. " + e.getMessage(), e); } } /** * Create connection with broker and retrieve the messages. Then inject * according to the registered handler */ public Message poll() { logger.debug("Polling JMS messages."); try { connection = jmsConnectionFactory.getConnection(strUserName, strPassword); if (connection == null) { logger.warn("Inbound JMS endpoint unable to get a connection."); isConnected = false; return null; } if (retryIteration != 0) { logger.info("Reconnection attempt: " + retryIteration + " for the JMS Inbound: " + name + " was successful!"); this.retryIteration = 0; this.retryDuration = 1; } isConnected = true; session = jmsConnectionFactory.getSession(connection); //Fixing ESBJAVA-4446 //Closing the connection if we cannot get a session. //Then in the next poll iteration it will create a new connection //instead of using cached connection if (session == null) { logger.warn("Inbound JMS endpoint unable to get a session."); jmsConnectionFactory.closeConnection(); return null; } destination = jmsConnectionFactory.getDestination(session); if (replyDestinationName != null && !replyDestinationName.trim().equals("")) { if (logger.isDebugEnabled()) { logger.debug( "Using the reply destination as " + replyDestinationName + " in inbound endpoint."); } replyDestination = jmsConnectionFactory.createDestination(session, replyDestinationName); } messageConsumer = jmsConnectionFactory.getMessageConsumer(session, destination); Message msg = receiveMessage(messageConsumer); if (msg == null) { logger.debug("Inbound JMS Endpoint. No JMS message received."); return null; } while (msg != null) { if (!JMSUtils.inferJMSMessageType(msg).equals(TextMessage.class.getName())) { logger.error("JMS " + "Inbound transport support JMS TextMessage type only. Found message type " + JMSUtils.inferJMSMessageType(msg)); return null; } if (injectHandler != null) { boolean commitOrAck = true; // Set the reply destination and connection if (replyDestination != null) { injectHandler.setReplyDestination(replyDestination); } injectHandler.setConnection(connection); commitOrAck = injectHandler.invoke(msg, name); // if client acknowledgement is selected, and processing // requested ACK if (jmsConnectionFactory.getSessionAckMode() == Session.CLIENT_ACKNOWLEDGE) { if (commitOrAck) { try { msg.acknowledge(); if (logger.isDebugEnabled()) { logger.debug("Message : " + msg.getJMSMessageID() + " acknowledged"); } } catch (JMSException e) { logger.error("Error acknowledging message : " + msg.getJMSMessageID(), e); } } else { // Need to create a new consumer and session since // we need to rollback the message if (messageConsumer != null) { jmsConnectionFactory.closeConsumer(messageConsumer); } if (session != null) { jmsConnectionFactory.closeSession(session); } session = jmsConnectionFactory.getSession(connection); messageConsumer = jmsConnectionFactory.getMessageConsumer(session, destination); } } // if session was transacted, commit it or rollback if (jmsConnectionFactory.isTransactedSession()) { try { if (session.getTransacted()) { if (commitOrAck) { session.commit(); if (logger.isDebugEnabled()) { logger.debug( "Session for message : " + msg.getJMSMessageID() + " committed"); } } else { session.rollback(); if (logger.isDebugEnabled()) { logger.debug( "Session for message : " + msg.getJMSMessageID() + " rolled back"); } } } } catch (JMSException e) { logger.error("Error " + (commitOrAck ? "committing" : "rolling back") + " local session txn for message : " + msg.getJMSMessageID(), e); } } } else { return msg; } msg = receiveMessage(messageConsumer); } } catch (JMSException e) { logger.error("Error while receiving JMS message. " + e.getMessage(), e); } catch (Exception e) { logger.error("Error while receiving JMS message. " + e.getMessage(), e); } finally { if (!isConnected) { if (reconnectDuration != null) { retryDuration = reconnectDuration; logger.error("Reconnection attempt : " + (retryIteration++) + " for JMS Inbound : " + name + " failed. Next retry in " + (retryDuration / 1000) + " seconds. (Fixed Interval)"); } else { retryDuration = (long) (retryDuration * reconnectionProgressionFactor); if (retryDuration > maxReconnectDuration) { retryDuration = maxReconnectDuration; logger.info("InitialReconnectDuration reached to MaxReconnectDuration."); } logger.error("Reconnection attempt : " + (retryIteration++) + " for JMS Inbound : " + name + " failed. Next retry in " + (retryDuration / 1000) + " seconds"); } try { Thread.sleep(retryDuration); } catch (InterruptedException ignore) { } } if (messageConsumer != null) { jmsConnectionFactory.closeConsumer(messageConsumer); } if (session != null) { jmsConnectionFactory.closeSession(session); } if (connection != null) { jmsConnectionFactory.closeConnection(connection); } } return null; } public void destroy() { if (messageConsumer != null) { jmsConnectionFactory.closeConsumer(messageConsumer, true); } if (session != null) { jmsConnectionFactory.closeSession(session, true); } if (connection != null) { jmsConnectionFactory.closeConnection(connection, true); } } private Message receiveMessage(MessageConsumer messageConsumer) throws JMSException { Message msg = null; if (iReceiveTimeout == null) { msg = messageConsumer.receive(1); } else if (iReceiveTimeout > 0) { msg = messageConsumer.receive(iReceiveTimeout); } else { msg = messageConsumer.receive(); } return msg; } protected Properties getInboundProperites() { return jmsProperties; } }