/* * 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 javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.QueueSender; import javax.jms.QueueSession; import javax.jms.Session; import javax.jms.Topic; import javax.jms.TopicPublisher; import javax.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<JmsPoolMessageProducer> cachedProducers; private final ProducerLRUCache<JmsPoolTopicPublisher> cachedPublishers; private final ProducerLRUCache<JmsPoolQueueSender> 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) 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. if (isUseAnonymousProducer() || producer.isAnonymousProducer()) { return; } else if (producer.getRefCount().decrementAndGet() <= 0) { producer.getDelegate().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); } } 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); } } 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); } } 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<E> extends LRUCache<Destination, E> { private static final long serialVersionUID = -1; public ProducerLRUCache(int maximumCacheSize) { super(maximumCacheSize); } @Override protected void onCacheEviction(Map.Entry<Destination, E> eldest) { JmsPoolMessageProducer producer = (JmsPoolMessageProducer) eldest.getValue(); try { producer.close(); } catch (JMSException jmsEx) {} } } }