org.wso2.carbon.transport.jms.factory.PooledJMSConnectionFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.transport.jms.factory.PooledJMSConnectionFactory.java

Source

/*
*  Copyright (c) 2017, 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.transport.jms.factory;

import org.apache.commons.pool2.KeyedPooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wso2.carbon.transport.jms.exception.JMSConnectorException;
import org.wso2.carbon.transport.jms.utils.JMSConstants;

import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.QueueConnection;
import javax.jms.Session;
import javax.jms.TopicConnection;

/**
 * JMS Connection Factory which pools connections for better performance.
 */
public class PooledJMSConnectionFactory extends JMSConnectionFactory
        implements KeyedPooledObjectFactory<PooledConnectionKey, Connection> {

    private static final Logger log = LoggerFactory.getLogger(PooledJMSConnectionFactory.class);

    private GenericKeyedObjectPool<PooledConnectionKey, Connection> keyedObjectPool = new GenericKeyedObjectPool<>(
            this);

    private ConcurrentHashMap<Connection, PooledConnectionKey> connectionKeyMap = new ConcurrentHashMap<>();

    public PooledJMSConnectionFactory(Properties properties) throws JMSConnectorException {
        super(properties);

        Object maxConcurrentConnections = properties.get(JMSConstants.MAX_CONNECTIONS);

        if (maxConcurrentConnections != null) {
            keyedObjectPool.setMaxTotal(Integer.parseInt((String) maxConcurrentConnections));
        }

    }

    @Override
    public Connection createConnection() throws JMSException {
        PooledConnectionKey key = new PooledConnectionKey(null, null);
        Connection connection;
        try {
            connection = keyedObjectPool.borrowObject(key);

            if (!validateObject(key, new DefaultPooledObject<>(connection))) {
                keyedObjectPool.invalidateObject(key, connection);
                throw new JMSException("Could not create a valid connection");
            }

            return connection;
        } catch (Exception e) {
            throw new JMSException("Error occurred creating connection : " + e.getMessage());
        }
    }

    @Override
    public Connection createConnection(String userName, String password) throws JMSException {
        PooledConnectionKey key = new PooledConnectionKey(userName, password);
        try {
            return keyedObjectPool.borrowObject(key);
        } catch (Exception e) {
            throw new JMSException("Error occurred creating connection : " + e.getMessage());
        }
    }

    @Override
    public QueueConnection createQueueConnection() throws JMSException {
        return (QueueConnection) createConnection();
    }

    @Override
    public QueueConnection createQueueConnection(String userName, String password) throws JMSException {
        return (QueueConnection) createConnection(userName, password);
    }

    @Override
    public TopicConnection createTopicConnection() throws JMSException {
        return (TopicConnection) createConnection();
    }

    @Override
    public TopicConnection createTopicConnection(String userName, String password) throws JMSException {
        return (TopicConnection) createConnection(userName, password);
    }

    @Override
    public void closeConnection(Connection connection) throws JMSConnectorException {
        PooledConnectionKey key = connectionKeyMap.get(connection);

        if (key != null) {
            try {
                keyedObjectPool.returnObject(key, connection);
            } catch (Exception e) {
                throw new JMSConnectorException("Failed to return the connection back to the pool", e);
            }
        }
    }

    // PooledObjectFactory implementations

    /**
     * This is invoked when a new connection object has to be made.
     *
     * @param key The connection key
     * @return Wrapped connection object
     * @throws Exception Any exception thrown when creating a JMS connection will be thrown
     */
    @Override
    public PooledObject<Connection> makeObject(PooledConnectionKey key) throws Exception {
        Connection connection;

        String username = key.getUsername();
        String password = key.getPassword();

        if (username == null && password == null) {
            connection = super.createConnection();
        } else {

            connection = super.createConnection(key.getUsername(), key.getPassword());
        }

        connectionKeyMap.put(connection, key);

        return new DefaultPooledObject<>(connection);
    }

    /**
     * This is called when an connection object is invalidated.
     *
     * @param key                    The connection key
     * @param pooledConnectionObject The invalidated wrapped connection object.
     * @throws Exception Any exception thrown when closing a JMS connection will be thrown
     */
    @Override
    public void destroyObject(PooledConnectionKey key, PooledObject<Connection> pooledConnectionObject)
            throws Exception {
        Connection connection = pooledConnectionObject.getObject();

        connectionKeyMap.remove(connection);
        connection.close();
    }

    /**
     * Validates a connection object and verifies it can be used further.
     *
     * @param key                    The connection key
     * @param pooledConnectionObject The wrapped connection object
     * @return True if the object is valid
     */
    @Override
    public boolean validateObject(PooledConnectionKey key, PooledObject<Connection> pooledConnectionObject) {

        boolean valid = false;

        try {
            Session session = pooledConnectionObject.getObject().createSession(false, Session.AUTO_ACKNOWLEDGE);

            session.close();

            valid = true;
        } catch (JMSException e) {
            log.warn("Connection with key " + key.hashCode() + " is not valid anymore");
        }

        return valid;
    }

    /**
     * Activates a suspended connection.
     *
     * @param key                    The connection key
     * @param pooledConnectionObject Wrapped suspended connection object.
     * @throws Exception Any exception thrown when starting a JMS connection will be thrown
     */
    @Override
    public void activateObject(PooledConnectionKey key, PooledObject<Connection> pooledConnectionObject)
            throws Exception {
        pooledConnectionObject.getObject().start();
    }

    /**
     * Suspend a connection.
     *
     * @param key                    The connection key
     * @param pooledConnectionObject The wrapped connection object that needs to be suspended.
     * @throws Exception Any exception thrown when stopping a JMS connection will be thrown
     */
    @Override
    public void passivateObject(PooledConnectionKey key, PooledObject<Connection> pooledConnectionObject)
            throws Exception {
        pooledConnectionObject.getObject().stop();
    }

}