org.wso2.carbon.bpmn.extensions.jms.JMSConnectionFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.bpmn.extensions.jms.JMSConnectionFactory.java

Source

/*
 * Copyright 2005-2015 WSO2, Inc. (http://wso2.com)
 *
 * Licensed 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.bpmn.extensions.jms;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by dilini on 12/10/15.
 */
public class JMSConnectionFactory {
    private static final Log log = LogFactory.getLog(JMSConnectionFactory.class);

    /** the list of parameters from activiti.xml definition*/
    private Hashtable<String, String> parameters = new Hashtable<>();

    /** InitialContext reference*/
    private Context context = null;

    /** The JMS ConnectionFactory to create connection objects*/
    private ConnectionFactory connectionFactory = null;

    /** The shared JMS Connection for the JMS connection factory*/
    private Connection sharedConnection = null;

    private Session sharedSession = null;

    /** The shared JMS MessageProducer for the JMS connection factory*/
    private MessageProducer sharedProducer = null;

    /** The shared JMS Destination for the JMS connection factory*/
    private Destination sharedDestination = null;

    private int cacheLevel = JMSConstants.CACHE_CONNECTION;

    private int lastReturnedConnectionIndex = 0;

    private Map<Integer, Connection> sharedConnectionMap = new ConcurrentHashMap<>();

    private int maxSharedConnectionCount = 10;

    //    private HashMap<Integer, Integer> connectionCount;

    JMSUtils utils = new JMSUtils();

    /**
     *
     * @param parameters
     */
    public JMSConnectionFactory(Hashtable<String, String> parameters) {
        this.parameters = parameters;
        //        this.connectionCount = new HashMap<>();

        //set the cacheLevel according to the value given by the user.
        digestCacheLevel();

        try {

            //creates the connectionFactory object and the sharedDestination if any is given by the user.
            context = new InitialContext(parameters);

            if (JMSConstants.DESTINATION_TYPE_QUEUE
                    .equalsIgnoreCase(parameters.get(JMSConstants.PARAM_DESTINATION_TYPE))) {
                connectionFactory = utils.lookup(context, QueueConnectionFactory.class,
                        parameters.get(JMSConstants.PARAM_CONNECTION_FACTORY_JNDI_NAME));
            } else {
                connectionFactory = utils.lookup(context, TopicConnectionFactory.class,
                        parameters.get(JMSConstants.PARAM_CONNECTION_FACTORY_JNDI_NAME));
            }

            if (parameters.get(JMSConstants.PARAM_DESTINATION) != null) {
                sharedDestination = utils.lookup(context, Destination.class,
                        parameters.get(JMSConstants.PARAM_DESTINATION));
            }

            log.info("JMS ConnectionFactory initialized for: "
                    + parameters.get(JMSConstants.PARAM_CONNECTION_FACTORY_JNDI_NAME));
        } catch (NamingException e) {
            String errorMsg = "Cannot acquire JNDI context, JMS Connection factory : "
                    + parameters.get(JMSConstants.PARAM_CONNECTION_FACTORY_JNDI_NAME) + " or default destination : "
                    + parameters.get(JMSConstants.PARAM_DESTINATION) + " using : " + parameters;
            log.error(errorMsg, e);
        }
    }

    /**
     * set the cacheLevel according to the value given by the user.
     */
    private void digestCacheLevel() {
        String value = parameters.get(JMSConstants.PARAM_CACHE_LEVEL);

        if ("none".equalsIgnoreCase(value)) {
            this.cacheLevel = JMSConstants.CACHE_NONE;
        } else if ("connection".equalsIgnoreCase(value)) {
            this.cacheLevel = JMSConstants.CACHE_CONNECTION;
        } else if ("session".equalsIgnoreCase(value)) {
            this.cacheLevel = JMSConstants.CACHE_SESSION;
        } else if ("producer".equalsIgnoreCase(value)) {
            this.cacheLevel = JMSConstants.CACHE_PRODUCER;
        } else if ("consumer".equalsIgnoreCase(value)) {
            this.cacheLevel = JMSConstants.CACHE_CONSUMER;
        } else if (value != null) {
            String errorMsg = "Invalid cache level: " + value + " for JMS Connection Factory";
            log.error(errorMsg);
        }
    }

    /**
     *
     */
    public synchronized void stop() {
        if (sharedConnection != null) {
            try {
                sharedConnection.close();
            } catch (JMSException e) {
                log.warn("Error while shutting down the connection factory", e);
            }
        }

        if (context != null) {
            try {
                context.close();
            } catch (NamingException e) {
                log.warn("Error while closing the InitialContext", e);
            }
        }
    }

    /**
     *
     * @return
     */
    public Hashtable<String, String> getParameters() {
        return parameters;
    }

    /**
     *
     * @return
     */
    public Context getContext() {
        return context;
    }

    /**
     *
     * @return
     */
    public Destination getSharedDestination() {
        return sharedDestination;
    }

    //    private void incrementConnectionCounter(int connectionIndex){
    //        if(connectionCount.get(connectionIndex) != null)
    //            connectionCount.put(connectionIndex, connectionCount.get(connectionIndex) + 1);
    //        else
    //            connectionCount.put(connectionIndex, 1);
    //    }
    /**
     *
     * @return the shared connection object
     */
    private synchronized Connection getSharedConnection() {

        Connection connection = sharedConnectionMap.get(lastReturnedConnectionIndex);

        //int connectionIndex = lastReturnedConnectionIndex;
        if (connection == null) {
            connection = createConnection();
            try {
                connection.start();
            } catch (JMSException e) {
                log.error(e.getMessage(), e);
            }

            if (connection != null) {
            }

            //            incrementConnectionCounter(lastReturnedConnectionIndex);
            sharedConnectionMap.put(lastReturnedConnectionIndex, connection);
        }
        //        else{
        //            incrementConnectionCounter(lastReturnedConnectionIndex);
        //        }
        lastReturnedConnectionIndex++;
        if (lastReturnedConnectionIndex >= maxSharedConnectionCount) {
            lastReturnedConnectionIndex = 0;
        }

        return connection;
    }

    //    public HashMap<Integer, Integer> getConnectionCount(){
    //        return connectionCount;
    //    }

    //    public int getLastReturnedConnectionIndex(){
    //        return lastReturnedConnectionIndex;
    //    }

    //    public Connection getConnection(int lastReturnedConnectionIndex){
    //        return sharedConnectionMap.get(lastReturnedConnectionIndex);
    //    }

    //    public void decrementCounter(int connectionIndex){
    //        connectionCount.put(connectionIndex, connectionCount.get(connectionIndex) - 1);
    //    }

    /**
     *
     * @return the shared session
     */
    private synchronized Session getSharedSession(int connectionIndex) {

        if (sharedSession == null) {
            sharedSession = createSession(sharedConnectionMap.get(connectionIndex));
            if (log.isDebugEnabled()) {
                log.debug("Creating a shared session from JMS Connection");
            }
        }
        return sharedSession;
    }

    /**
     *
     * @param destinationName
     * @param destinationType
     * @return the destination object given the destination name and type by the user.
     */
    public Destination getDestination(String destinationName, String destinationType) {
        try {
            return utils.lookupDestination(context, destinationName, destinationType);
        } catch (NamingException e) {
            log.error("Error looking up the JMS destination with name " + destinationName + " of type "
                    + destinationType, e);
        }

        return null;
    }

    /**
     *
     * @return whether the destination type is queue or topic based on the parameters given by the user.
     */
    public Boolean isQueue() {
        if (parameters.get(JMSConstants.PARAM_DESTINATION_TYPE) == null) {
            return false;
        } else {
            if (JMSConstants.DESTINATION_TYPE_QUEUE
                    .equalsIgnoreCase(parameters.get(JMSConstants.PARAM_DESTINATION_TYPE))) {
                return true;
            } else if (JMSConstants.DESTINATION_TYPE_TOPIC
                    .equalsIgnoreCase(parameters.get(JMSConstants.PARAM_DESTINATION_TYPE))) {
                return false;
            } else {
                String invalidDestTypeErrorMsg = "Invalid " + JMSConstants.PARAM_DESTINATION_TYPE + ": "
                        + parameters.get(JMSConstants.PARAM_DESTINATION_TYPE);
                log.error(invalidDestTypeErrorMsg);
                return null;
            }
        }
    }

    /**
     * create a connection object and
     * @return it
     */
    private Connection createConnection() {
        Connection connection = null;
        try {
            connection = JMSUtils.createConnection(connectionFactory, parameters.get(JMSConstants.PARAM_USERNAME),
                    parameters.get(JMSConstants.PARAM_PASSWORD), isQueue());
            if (log.isDebugEnabled()) {
                log.debug("New JMS Connection was created from the JMS ConnectionFactory");
            }
        } catch (JMSException e) {
            log.error("Error creating a connection from the JMS Connection Factory using properties: " + parameters,
                    e);
        }
        return connection;
    }

    /**
     *
     * @param connection
     * @return
     * create a session object and return it.
     */
    private Session createSession(Connection connection) {
        Session session = null;
        try {
            //session is always not transacted
            session = JMSUtils.createSession(connection, false, Session.AUTO_ACKNOWLEDGE, isQueue());
            if (log.isDebugEnabled()) {
                log.debug("New JMS Session was created from the JMS Connection");
            }
        } catch (JMSException e) {
            log.error("Error creating a session from the JMS Connection using properties: " + parameters, e);
        }
        return session;
    }

    /**
     *
     * @return a connection object
     */
    public Connection getConnection() {
        if (cacheLevel > JMSConstants.CACHE_NONE) {
            return getSharedConnection();
        } else {
            return createConnection();
        }
    }

    /**
     *
     * @param connection
     * @return a session object
     */
    public Session getSession(Connection connection) {
        if (cacheLevel > JMSConstants.CACHE_CONNECTION) {
            return getSharedSession(lastReturnedConnectionIndex - 1);
        } else {
            if (connection == null) {
                return createSession(getConnection());
            } else {
                return createSession(connection);
            }
        }
    }

    /**
     * Get a new MessageProducer or shared MessageProducer from this JMS CF
     * @param connection the Connection to be used
     * @param session the Session to be used
     * @param destination the Destination to bind MessageProducer to
     * @return new or shared MessageProducer from this JMS CF
     */
    public MessageProducer getMessageProducer(Connection connection, Session session, Destination destination) {
        if (cacheLevel > JMSConstants.CACHE_SESSION) {
            return getSharedProducer(destination);
        } else {
            return createProducer((session == null ? getSession(connection) : session), destination);
        }
    }

    /**
     * Get a shared MessageProducer from this JMS CF
     * @return shared MessageProducer from this JMS CF
     */
    private synchronized MessageProducer getSharedProducer(Destination destination) {
        if (sharedProducer == null) {

            if (sharedDestination != null) {
                sharedProducer = createProducer(getSharedSession(lastReturnedConnectionIndex - 1),
                        sharedDestination);

            } else {
                sharedProducer = createProducer(getSharedSession(lastReturnedConnectionIndex - 1), destination);
                sharedDestination = destination;
            }
            if (log.isDebugEnabled()) {
                log.debug("Created shared JMS MessageConsumer for JMS CF : ");
            }
        }
        return sharedProducer;
    }

    /**
     * Create a new MessageProducer
     * @param session Session to be used
     * @param destination Destination to be used
     * @return a new MessageProducer
     */
    private MessageProducer createProducer(Session session, Destination destination) {
        try {
            if (log.isDebugEnabled()) {
                log.debug("Creating a new JMS MessageProducer from JMS CF");
            }

            return JMSUtils.createProducer(session, destination, isQueue());

        } catch (JMSException e) {
            log.error("Error creating JMS producer from JMS CF : ", e);
        }
        return null;
    }

    /**
     * Cache level applicable for this JMS CF
     * @return applicable cache level
     */
    public int getCacheLevel() {
        return cacheLevel;
    }
}