/*
* JBoss, Home of Professional Open Source.
* Copyright 2016, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.extension.messaging.activemq.deployment.injection;
import static org.wildfly.extension.messaging.activemq.logging.MessagingLogger.ROOT_LOGGER;
import java.io.Serializable;
import java.util.UUID;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.inject.Inject;
import javax.jms.ConnectionFactory;
import javax.jms.JMSConnectionFactory;
import javax.jms.JMSContext;
import javax.jms.JMSPasswordCredential;
import javax.jms.JMSSessionMode;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.transaction.Status;
import javax.transaction.TransactionSynchronizationRegistry;
/**
* @author <a href="http://jmesnil.net/">Jeff Mesnil</a> (c) 2016 Red Hat inc.
*/
class InjectedJMSContext extends JMSContextWrapper implements Serializable {
private static final String TRANSACTION_SYNCHRONIZATION_REGISTRY_LOOKUP = "java:comp/TransactionSynchronizationRegistry";
// Metadata to create the actual JMSContext.
private final JMSInfo info;
// JMSContext bean with the @RequestedScope
private final RequestedJMSContext requestedJMSContext;
// Identifier of the injected JMSContext
private final String id;
// JMSContext bean with the @TransactionScoped scope.
// An indirect reference is used as the instance is only valide when the transaction scope is active.
private transient Instance<TransactedJMSContext> transactedJMSContext;
// Cached reference to the connectionFactory used to create the actual JMSContext.
// It is cached to avoid repeated JNDI lookups.
private transient ConnectionFactory connectionFactory;
// Cached reference to the transaction sync registry to determine if a transaction is active
private transient TransactionSynchronizationRegistry transactionSynchronizationRegistry;
@Inject
InjectedJMSContext(InjectionPoint ip, RequestedJMSContext requestedJMSContext, Instance<TransactedJMSContext> transactedJMSContext) {
this.id = UUID.randomUUID().toString();
this.requestedJMSContext = requestedJMSContext;
this.transactedJMSContext = transactedJMSContext;
JMSConnectionFactory connectionFactory = ip.getAnnotated().getAnnotation(JMSConnectionFactory.class);
JMSPasswordCredential credential = ip.getAnnotated().getAnnotation(JMSPasswordCredential.class);
JMSSessionMode sessionMode = ip.getAnnotated().getAnnotation(JMSSessionMode.class);
this.info = new JMSInfo(connectionFactory, credential, sessionMode);
}
/**
* Return the actual JMSContext used by this injection.
*
* The use of the correct AbstractJMSContext (one with the @RequestScoped, the other
* with the @TransactionScoped) is determined by the presence on an active transaction.
*/
@Override
JMSContext getDelegate() {
boolean inTx = isInTransaction();
AbstractJMSContext jmsContext = inTx ? transactedJMSContext.get() : requestedJMSContext;
ROOT_LOGGER.debugf("using %s to create the injected JMSContext", jmsContext, id);
ConnectionFactory connectionFactory = getConnectionFactory();
return jmsContext.getContext(id, info, connectionFactory);
}
/**
* check whether there is an active transaction.
*/
private boolean isInTransaction() {
TransactionSynchronizationRegistry tsr = getTransactionSynchronizationRegistry();
boolean inTx = tsr.getTransactionStatus() == Status.STATUS_ACTIVE;
return inTx;
}
/**
* lookup the transactionSynchronizationRegistry and cache it.
*/
private TransactionSynchronizationRegistry getTransactionSynchronizationRegistry() {
TransactionSynchronizationRegistry cachedTSR = transactionSynchronizationRegistry;
if (cachedTSR == null) {
cachedTSR = (TransactionSynchronizationRegistry) lookup(TRANSACTION_SYNCHRONIZATION_REGISTRY_LOOKUP);
transactionSynchronizationRegistry = cachedTSR;
}
return cachedTSR;
}
/**
* lookup the connectionFactory and cache it.
*/
private ConnectionFactory getConnectionFactory() {
ConnectionFactory cachedCF = connectionFactory;
if (cachedCF == null) {
cachedCF = (ConnectionFactory)lookup(info.getConnectionFactoryLookup());
connectionFactory = cachedCF;
}
return cachedCF;
}
private Object lookup(String name) {
Context ctx = null;
try {
ctx = new InitialContext();
return ctx.lookup(name);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (ctx != null) {
try {
ctx.close();
} catch (NamingException e) {
}
}
}
}
}