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

org.messaginghub.pooled.jms.pool.PooledSessionHolder Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF 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.messaginghub.pooled.jms.pool;

import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import jakarta.jms.Destination;
import jakarta.jms.IllegalStateException;
import jakarta.jms.JMSException;
import jakarta.jms.MessageProducer;
import jakarta.jms.Queue;
import jakarta.jms.QueueSender;
import jakarta.jms.QueueSession;
import jakarta.jms.Session;
import jakarta.jms.Topic;
import jakarta.jms.TopicPublisher;
import jakarta.jms.TopicSession;

import org.messaginghub.pooled.jms.JmsPoolMessageProducer;
import org.messaginghub.pooled.jms.JmsPoolQueueSender;
import org.messaginghub.pooled.jms.JmsPoolSession;
import org.messaginghub.pooled.jms.JmsPoolTopicPublisher;
import org.messaginghub.pooled.jms.util.LRUCache;

/**
 * Used to store a pooled session instance and any resources that can
 * be left open and carried along with the pooled instance such as the
 * anonymous producer used for all MessageProducer instances created
 * from this pooled session when enabled.
 */
public final class PooledSessionHolder {

    private final PooledConnection connection;
    private final Session session;

    private final boolean useAnonymousProducer;
    private final int explicitProducerCacheSize;

    private volatile MessageProducer anonymousProducer;
    private volatile TopicPublisher anonymousPublisher;
    private volatile QueueSender anonymousSender;

    private final ProducerLRUCache cachedProducers;
    private final ProducerLRUCache cachedPublishers;
    private final ProducerLRUCache cachedSenders;

    public PooledSessionHolder(PooledConnection connection, Session session, boolean useAnonymousProducer, int namedProducerCacheSize) {
        this.connection = connection;
        this.session = session;
        this.useAnonymousProducer = useAnonymousProducer;
        this.explicitProducerCacheSize = namedProducerCacheSize;

        if (!useAnonymousProducer && namedProducerCacheSize > 0) {
            cachedProducers = new ProducerLRUCache<>(namedProducerCacheSize);
            cachedPublishers = new ProducerLRUCache<>(namedProducerCacheSize);
            cachedSenders = new ProducerLRUCache<>(namedProducerCacheSize);
        } else {
            cachedProducers = null;
            cachedPublishers = null;
            cachedSenders = null;
        }
    }

    public void close() throws JMSException {
        try {
            session.close();
        } finally {
            anonymousProducer = null;
            anonymousPublisher = null;
            anonymousSender = null;

            if (cachedProducers != null) {
                cachedProducers.clear();
            }
            if (cachedPublishers != null) {
                cachedPublishers.clear();
            }
            if (cachedSenders != null) {
                cachedSenders.clear();
            }
        }
    }

    public Session getSession() {
        return session;
    }

    public void onJmsPoolProducerClosed(JmsPoolMessageProducer producer, boolean force) throws JMSException {
        synchronized (this) {

            // We cache anonymous producers regardless of the useAnonymousProducer
            // setting so in either of those cases the pooled producer is not closed
            // unless the wrapper indicates a forced closure is being requested.
            if (!force) {
                try {
                    producer.getDelegate().getDestination();

                    if (isUseAnonymousProducer() || producer.isAnonymousProducer()) {
                        return;
                    } else if (producer.getRefCount().decrementAndGet() > 0) {
                        return;
                    }
                } catch (IllegalStateException jmsISE) {
                    // Delegated producer appears to be closed so remove it from pooling.
                    producer.getRefCount().decrementAndGet();
                    force = true;
                } catch (Exception ambiguous) {
                    // Not clear that the resource is closed so we don't assume it is.
                    return;
                }
            }

            final MessageProducer delegate = producer.getDelegate();

            // Ensure that the anonymous reference are cleared of a closed producer resource or the
            // cache is updated if enabled to remove the closed named producer.
            if (delegate == anonymousProducer) {
                anonymousProducer = null;
            } else if (delegate == anonymousPublisher) {
                anonymousPublisher = null;
            } else if (delegate == anonymousSender) {
                anonymousSender = null;
            }

            if (!producer.isAnonymousProducer()) {
                if (cachedProducers != null) {
                    cachedProducers.remove(producer.getDelegateDestination());
                }
                if (cachedPublishers != null) {
                    cachedPublishers.remove(producer.getDelegateDestination());
                }
                if (cachedSenders != null) {
                    cachedSenders.remove(producer.getDelegateDestination());
                }
            }

            delegate.close();
        }
    }

    public JmsPoolMessageProducer getOrCreateProducer(JmsPoolSession jmsPoolSession, Destination destination) throws JMSException {
        MessageProducer delegate = null;
        AtomicInteger refCount = null;

        synchronized (this) {
            if (isUseAnonymousProducer() || destination == null) {
                delegate = anonymousProducer;
                if (delegate == null) {
                    delegate = anonymousProducer = session.createProducer(null);
                    refCount = new AtomicInteger(0);
                }
            } else if (explicitProducerCacheSize > 0) {
                JmsPoolMessageProducer cached = cachedProducers.get(destination);
                if (cached == null) {
                    delegate = session.createProducer(destination);
                    refCount = new AtomicInteger(1);
                    cached = new JmsPoolMessageProducer(jmsPoolSession, delegate, destination, refCount);

                    cachedProducers.put(destination, cached);
                } else {
                    delegate = cached.getDelegate();
                    refCount = cached.getRefCount();
                }

                refCount.incrementAndGet();
            } else {
                delegate = session.createProducer(destination);
                refCount = new AtomicInteger(1);
            }
        }

        return new JmsPoolMessageProducer(jmsPoolSession, delegate, destination, refCount);
    }

    public JmsPoolTopicPublisher getOrCreatePublisher(JmsPoolSession jmsPoolSession, Topic topic) throws JMSException {
        TopicPublisher delegate = null;
        AtomicInteger refCount = null;

        synchronized (this) {
            if (isUseAnonymousProducer() || topic == null) {
                delegate = anonymousPublisher;
                if (delegate == null) {
                    delegate = anonymousPublisher = ((TopicSession) session).createPublisher(null);
                    refCount = new AtomicInteger(0);
                }
            } else if (explicitProducerCacheSize > 0) {
                JmsPoolTopicPublisher cached = cachedPublishers.get(topic);
                if (cached == null) {
                    delegate = ((TopicSession) session).createPublisher(topic);
                    refCount = new AtomicInteger(1);
                    cached = new JmsPoolTopicPublisher(jmsPoolSession, delegate, topic, refCount);

                    cachedPublishers.put(topic, cached);
                } else {
                    delegate = (TopicPublisher) cached.getDelegate();
                    refCount = cached.getRefCount();
                }

                refCount.incrementAndGet();
            } else {
                delegate = ((TopicSession) session).createPublisher(topic);
                refCount = new AtomicInteger(1);
            }
        }

        return new JmsPoolTopicPublisher(jmsPoolSession, delegate, topic, refCount);
    }

    public JmsPoolQueueSender getOrCreateSender(JmsPoolSession jmsPoolSession, Queue queue) throws JMSException {
        QueueSender delegate = null;
        AtomicInteger refCount = null;

        synchronized (this) {
            if (isUseAnonymousProducer() || queue == null) {
                delegate = anonymousSender;
                if (delegate == null) {
                    delegate = anonymousSender = ((QueueSession) session).createSender(null);
                    refCount = new AtomicInteger(0);
                }
            } else if (explicitProducerCacheSize > 0) {
                JmsPoolQueueSender cached = cachedSenders.get(queue);
                if (cached == null) {
                    delegate = ((QueueSession) session).createSender(queue);
                    refCount = new AtomicInteger(1);
                    cached = new JmsPoolQueueSender(jmsPoolSession, delegate, queue, refCount);

                    cachedSenders.put(queue, cached);
                } else {
                    delegate = (QueueSender) cached.getDelegate();
                    refCount = cached.getRefCount();
                }

                refCount.incrementAndGet();
            } else {
                delegate = ((QueueSession) session).createSender(queue);
                refCount = new AtomicInteger(1);
            }
        }

        return new JmsPoolQueueSender(jmsPoolSession, delegate, queue, refCount);
    }

    public PooledConnection getConnection() {
        return connection;
    }

    public boolean isUseAnonymousProducer() {
        return useAnonymousProducer;
    }

    @Override
    public String toString() {
        return session.toString();
    }

    private static class ProducerLRUCache extends LRUCache {

        private static final long serialVersionUID = -1;

        public ProducerLRUCache(int maximumCacheSize) {
            super(maximumCacheSize);
        }

        @Override
        protected void onCacheEviction(Map.Entry eldest) {
             JmsPoolMessageProducer producer = (JmsPoolMessageProducer) eldest.getValue();
             try {
                 producer.close();
             } catch (JMSException jmsEx) {}
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy