All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apertereports.backbone.jms.ARJmsFacade Maven / Gradle / Ivy

package org.apertereports.backbone.jms;

import java.util.HashMap;
import java.util.Map;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Session;
import org.apertereports.backbone.jms.listener.GenerateReportQueueMessageListener;
import org.apertereports.backbone.jms.listener.ProcessReportQueueMessageListener;
import org.apertereports.common.ARConstants;
import org.apertereports.common.ARConstants.ErrorCode;
import org.apertereports.common.exception.ARException;
import org.apertereports.model.ReportOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Facade for JMS used in Aperte Reports. Handles message listeners
 * registration, message pushing and signals JMS availability. Supports JMS
 * usage outside a J2EE container.
 *
 * @author Zbigniew Malinowski
 * @author Tomasz Serafin, BlueSoft Sp. z o.o.
 */
public final class ARJmsFacade {

    private static final Logger logger = LoggerFactory.getLogger("ar.backbone.jms");
    /**
     * If JMS is initialized.
     */
    private static boolean initialized = false;
    private static final Map queueToListenerMap = new HashMap();
    private static JmsContext mainCtx;

    static {
        queueToListenerMap.put(ARConstants.JNDI_JMS_GENERATE_REPORT_QUEUE_ID,
                GenerateReportQueueMessageListener.getInstance());
        queueToListenerMap.put(ARConstants.JNDI_JMS_PROCESS_REPORT_QUEUE_ID,
                ProcessReportQueueMessageListener.getInstance());
    }

    private ARJmsFacade() {
    }

    /**
     * If not initialized, subscribes configured listeners to proper queues and
     * initialize.
     *
     * @return true if the facade has been initialized, false otherwise
     * @throws Exception
     */
    private static synchronized boolean init() {
        if (initialized) {
            return true;
        }

        logger.info("Initializing JMS context");
        try {
            mainCtx = JmsContext.getNewContext();
            for (String queueName : queueToListenerMap.keySet()) {
                MessageListener listener = queueToListenerMap.get(queueName);
                try {
                    MessageConsumer consumer = mainCtx.getSession().createConsumer(
                            (Destination) JndiContext.lookup(queueName));
                    consumer.setMessageListener(listener);
                } catch (Exception e) {
                    logger.error("Cannot find queue in JNDI: " + queueName, e);
                }
            }

            mainCtx.getConnection().start();
            initialized = true;
        } catch (Exception e) {
            logger.error("Cannot initialize JMS context", e);
            if (mainCtx != null) {
                mainCtx.close();
            }
            return false;
        }
        return initialized;
    }

    /**
     * Sends message to JMS in order to generate report from the given report
     * order
     *
     * @param ro Report order as a base for report to generate
     * @throws ARException When there is a problem to send message to JMS
     */
    public static synchronized void sendToGenerateReport(ReportOrder ro) throws ARException {
        sendReportOrderId(ro, ARConstants.JNDI_JMS_GENERATE_REPORT_QUEUE_ID);
    }

    /**
     * Sends message to JMS in order to process generated report from the given
     * report order
     *
     * @param ro Report order as a base for generated report
     * @throws ARException When there is a problem to send message to JMS
     */
    public static synchronized void sendToProcessReport(ReportOrder ro) throws ARException {
        sendReportOrderId(ro, ARConstants.JNDI_JMS_PROCESS_REPORT_QUEUE_ID);
    }

    /**
     * Adds message to queue. Messages contains only report order id.
     *
     * @param orderId id of the order to be stored
     * @param queueName configuration key of queue which message will be sent to
     */
    private static synchronized void sendReportOrderId(ReportOrder ro, String queueName) throws ARException {
        logger.info("Sending report order id: " + ro.getId() + " to " + queueName);

        Long id = ro.getId();
        if (id == null) {
            logger.warn("id == null, discarding...");
            return;
        }

        if (!init()) {
            throw new ARException(ErrorCode.JMS_UNAVAILABLE);
        }

        JmsContext ctx = null;
        try {
            ctx = JmsContext.getNewContext();

            MessageProducer producer = ctx.getSession().createProducer((Destination) JndiContext
                    .lookup(queueName));

            Message reportOrderMessage = ctx.getSession().createMessage();
            reportOrderMessage.setLongProperty(ARConstants.JMS_PROPERTY_REPORT_ORDER_ID, id.intValue());
            producer.send(reportOrderMessage);
        } catch (Exception e) {
            logger.error("Error while sending report order id", e);
            throw new ARException(ErrorCode.JMS_UNAVAILABLE, e);
        } finally {
            if (ctx != null) {
                ctx.close();
            }
        }
    }

    /**
     * Checks if JMS ConnectionFactory is registered with JNDI, and if can
     * create connection and session.
     *
     * @return
     */
    public static synchronized boolean isJmsAvailable() {
        JmsContext ctx;
        try {
            ctx = JmsContext.getNewContext();
        } catch (Exception e) {
            return false;
        }
        ctx.close();
        return true;
    }

    private static class JmsContext {

        private Connection connection = null;
        private Session session = null;

        /**
         * Initializes JMS connection and session. When there is a problem to
         * init the context, an exception is thrown - in such case there is no
         * need to use {@link #close()} method 

After using properly * initalized context, it should be closed by calling {@link #close()} * method * * @throws Exception */ public static JmsContext getNewContext() throws Exception { JmsContext ctx = new JmsContext(); try { ConnectionFactory connectionFactory = (ConnectionFactory) JndiContext .lookup(ARConstants.JNDI_JMS_CONNECTION_FACTORY_ID); ctx.connection = connectionFactory.createConnection(); ctx.session = ctx.connection.createSession(false, Session.AUTO_ACKNOWLEDGE); } catch (Exception e) { logger.warn("Cannot initialize JMS context", e); ctx.close(); throw e; } return ctx; } /** * Closes connection and session objects */ public void close() { if (connection != null) { try { connection.close(); } catch (JMSException ex) { logger.error("while closing connection", ex); } connection = null; } if (session != null) { try { session.close(); } catch (JMSException ex) { logger.error("while closing session", ex); } session = null; } } /** * Returns session object. The session shouldn't be closed externally * * @return Session object. It can be null when context hasn't been * initialized properly */ public Session getSession() { return session; } /** * Returns connection object. The connection shouldn't be closed * externally * * @return Connection object. It can be null when context hasn't been * initialized properly */ public Connection getConnection() { return connection; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy