org.messaginghub.pooled.jms.pool.PooledSessionHolder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pooled-jms Show documentation
Show all versions of pooled-jms Show documentation
Generic JMS Pooled Connection library
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) {}
}
}
}