/** Copyright 2008, 2009 Mark Hooijkaas This file is part of the RelayConnector framework. The RelayConnector framework is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The RelayConnector framework 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 General Public License for more details. You should have received a copy of the GNU General Public License along with the RelayConnector framework. If not, see <http://www.gnu.org/licenses/>. */ package org.kisst.gft.action; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import org.kisst.gft.GftContainer; import org.kisst.gft.filetransfer.PollerTask; import org.kisst.gft.poller.PollerJob; import org.kisst.gft.task.Task; import org.kisst.jms.JmsSystem; import org.kisst.jms.JmsUtil; import org.kisst.props4j.Props; import org.kisst.util.TemplateUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class is a base class for sending messages transactionally, specifically from the PollerJob, using a FoundFileTask. * The Pollerjob/FoundFileTask will use the following sequence: * 1. call prepareTransaction * 2. move the found file to a in-progress directory (this is what the pollerjob does) * 3. call the regular Action.execute * 4. call the commitTransaction or rollbackTransaction depending if an error occurred or not * * Typically one wants to override the prepareTransaction, to already send a message, but not commit this, to detect if * message can be sent correctly. * In this case the execute could be overridden to do nothing. * The default implementation of execute is to do all steps, but with a safeguard that if transaction is already running, * or message is already sent it will not start over again. * */ public abstract class SendTransactedMessageAction implements PollerJob.Action, Transaction { private static final String VAR_JMS_SESSION = "_jms_session"; private static final String VAR_MESSAGE_SENT = "_message_sent"; private final static Logger logger = LoggerFactory.getLogger(SendTransactedMessageAction.class); private final JmsSystem qmgr; private final String queueName; public SendTransactedMessageAction(GftContainer gft, Props props) { String queueSystemName = TemplateUtil.processTemplate(props.getString("queueSystem", "main"), gft.getContext()); this.qmgr = gft.getQueueSystem(queueSystemName); this.queueName = props.getString("queue", gft.getMainQueue()); if (queueName == null) throw new RuntimeException("No queue defined for action " + props.getLocalName()); } abstract String getMessageContent(Task task); @Override public boolean safeToRetry() { return false; } private Session getSession(Task task) { return (Session) task.getVar(VAR_JMS_SESSION); } @Override public void prepareTransaction(Task task) { try { Session session = qmgr.getConnection().createSession(true, Session.SESSION_TRANSACTED); task.setVar(VAR_JMS_SESSION, session); } catch (JMSException e) { throw JmsUtil.wrapJMSException(e); } } @Override public void execute(Task task) { PollerTask fftask=(PollerTask) task; boolean succesfull=false; try { if (getSession(fftask)==null) prepareTransaction(fftask); // the session is not yet prepared sendMessage(fftask); succesfull=true; } finally { if (succesfull) commitTransaction(fftask); else rollbackTransaction(fftask); } } @Override public void commitTransaction(Task task) { try { Session sess=getSession(task); if (sess!=null) { sess.commit(); closeSession(task); } } catch (JMSException e) { throw JmsUtil.wrapJMSException(e); } } @Override public void rollbackTransaction(Task task) { try { Session sess=getSession(task); if (sess!=null) { sess.rollback(); closeSession(task); } } catch (JMSException e) { throw JmsUtil.wrapJMSException(e); } } private void closeSession(Task task) { Session session = getSession(task); try { if (session != null) { session.close(); task.setVar(VAR_JMS_SESSION, null); } } catch (JMSException e) { throw JmsUtil.wrapJMSException(e); } } public void sendMessage(Task task) { if ("true".equals(task.getVar(VAR_MESSAGE_SENT))) return; Session session = getSession(task); try { Destination destination = session.createQueue(queueName + qmgr.sendParams); MessageProducer producer = session.createProducer(destination); String content=getMessageContent(task); logger.info("Sending message to queue {}", queueName); TextMessage message = session.createTextMessage(); message.setText(content); producer.send(message); task.setVar(VAR_MESSAGE_SENT, "true"); logger.info("verzonden bericht \n {}", content); } catch (JMSException e) { throw JmsUtil.wrapJMSException(e); } } }