001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.jms.pool; 018 019import java.io.Serializable; 020import java.util.Hashtable; 021 022import javax.jms.Connection; 023import javax.jms.JMSException; 024import javax.jms.XAConnectionFactory; 025import javax.naming.Binding; 026import javax.naming.Context; 027import javax.naming.InitialContext; 028import javax.naming.Name; 029import javax.naming.NamingEnumeration; 030import javax.naming.spi.ObjectFactory; 031import javax.transaction.TransactionManager; 032 033import org.slf4j.Logger; 034import org.slf4j.LoggerFactory; 035 036/** 037 * A pooled connection factory that automatically enlists sessions in the 038 * current active XA transaction if any. 039 */ 040public class XaPooledConnectionFactory extends PooledConnectionFactory implements ObjectFactory, Serializable { 041 042 private static final transient Logger LOG = LoggerFactory.getLogger(XaPooledConnectionFactory.class); 043 private static final long serialVersionUID = -6545688026350913005L; 044 045 private TransactionManager transactionManager; 046 private boolean tmFromJndi = false; 047 private String tmJndiName = "java:/TransactionManager"; 048 049 public TransactionManager getTransactionManager() { 050 if (transactionManager == null && tmFromJndi) { 051 try { 052 transactionManager = (TransactionManager) new InitialContext().lookup(getTmJndiName()); 053 } catch (Throwable ignored) { 054 if (LOG.isTraceEnabled()) { 055 LOG.trace("exception on tmFromJndi: " + getTmJndiName(), ignored); 056 } 057 } 058 } 059 return transactionManager; 060 } 061 062 public void setTransactionManager(TransactionManager transactionManager) { 063 this.transactionManager = transactionManager; 064 } 065 066 @Override 067 public void setConnectionFactory(Object toUse) { 068 if (toUse instanceof XAConnectionFactory) { 069 connectionFactory = toUse; 070 } else { 071 throw new IllegalArgumentException("connectionFactory should implement javax.xml.XAConnectionFactory"); 072 } 073 } 074 075 @Override 076 protected Connection createConnection(ConnectionKey key) throws JMSException { 077 if (connectionFactory instanceof XAConnectionFactory) { 078 if (key.getUserName() == null && key.getPassword() == null) { 079 return ((XAConnectionFactory) connectionFactory).createXAConnection(); 080 } else { 081 return ((XAConnectionFactory) connectionFactory).createXAConnection(key.getUserName(), key.getPassword()); 082 } 083 } else { 084 throw new IllegalStateException("connectionFactory should implement javax.jms.XAConnectionFactory"); 085 } 086 } 087 088 @Override 089 protected ConnectionPool createConnectionPool(Connection connection) { 090 return new XaConnectionPool(connection, getTransactionManager()); 091 } 092 093 @Override 094 public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception { 095 setTmFromJndi(true); 096 configFromJndiConf(obj); 097 if (environment != null) { 098 IntrospectionSupport.setProperties(this, environment); 099 } 100 return this; 101 } 102 103 private void configFromJndiConf(Object rootContextName) { 104 if (rootContextName instanceof String) { 105 String name = (String) rootContextName; 106 name = name.substring(0, name.lastIndexOf('/')) + "/conf" + name.substring(name.lastIndexOf('/')); 107 try { 108 InitialContext ctx = new InitialContext(); 109 NamingEnumeration<Binding> bindings = ctx.listBindings(name); 110 111 while (bindings.hasMore()) { 112 Binding bd = bindings.next(); 113 IntrospectionSupport.setProperty(this, bd.getName(), bd.getObject()); 114 } 115 116 } catch (Exception ignored) { 117 if (LOG.isTraceEnabled()) { 118 LOG.trace("exception on config from jndi: " + name, ignored); 119 } 120 } 121 } 122 } 123 124 public String getTmJndiName() { 125 return tmJndiName; 126 } 127 128 public void setTmJndiName(String tmJndiName) { 129 this.tmJndiName = tmJndiName; 130 } 131 132 public boolean isTmFromJndi() { 133 return tmFromJndi; 134 } 135 136 /** 137 * Allow transaction manager resolution from JNDI (ee deployment) 138 * 139 * @param tmFromJndi 140 */ 141 public void setTmFromJndi(boolean tmFromJndi) { 142 this.tmFromJndi = tmFromJndi; 143 } 144}