001/*
002 * Copyright 2012-2017 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.boot.jta.bitronix;
018
019import java.util.Properties;
020
021import javax.jms.JMSException;
022import javax.jms.XAConnection;
023import javax.jms.XAConnectionFactory;
024import javax.jms.XAJMSContext;
025
026import bitronix.tm.resource.common.ResourceBean;
027import bitronix.tm.resource.common.XAStatefulHolder;
028import bitronix.tm.resource.jms.PoolingConnectionFactory;
029
030import org.springframework.beans.factory.BeanNameAware;
031import org.springframework.beans.factory.DisposableBean;
032import org.springframework.beans.factory.InitializingBean;
033import org.springframework.boot.context.properties.ConfigurationProperties;
034import org.springframework.util.StringUtils;
035
036/**
037 * Spring friendly version of {@link PoolingConnectionFactory}. Provides sensible defaults
038 * and also supports direct wrapping of a {@link XAConnectionFactory} instance.
039 *
040 * @author Phillip Webb
041 * @author Josh Long
042 * @author Andy Wilkinson
043 * @since 1.2.0
044 */
045@SuppressWarnings("serial")
046@ConfigurationProperties(prefix = "spring.jta.bitronix.connectionfactory")
047public class PoolingConnectionFactoryBean extends PoolingConnectionFactory
048                implements BeanNameAware, InitializingBean, DisposableBean {
049
050        private static final ThreadLocal<PoolingConnectionFactoryBean> source = new ThreadLocal<>();
051
052        private String beanName;
053
054        private XAConnectionFactory connectionFactory;
055
056        public PoolingConnectionFactoryBean() {
057                setMaxPoolSize(10);
058                setTestConnections(true);
059                setAutomaticEnlistingEnabled(true);
060                setAllowLocalTransactions(true);
061        }
062
063        @Override
064        public synchronized void init() {
065                source.set(this);
066                try {
067                        super.init();
068                }
069                finally {
070                        source.remove();
071                }
072        }
073
074        @Override
075        public void setBeanName(String name) {
076                this.beanName = name;
077        }
078
079        @Override
080        public void afterPropertiesSet() throws Exception {
081                if (!StringUtils.hasLength(getUniqueName())) {
082                        setUniqueName(this.beanName);
083                }
084                init();
085        }
086
087        @Override
088        public void destroy() throws Exception {
089                close();
090        }
091
092        /**
093         * Set the {@link XAConnectionFactory} directly, instead of calling
094         * {@link #setClassName(String)}.
095         * @param connectionFactory the connection factory to use
096         */
097        public void setConnectionFactory(XAConnectionFactory connectionFactory) {
098                this.connectionFactory = connectionFactory;
099                setClassName(DirectXAConnectionFactory.class.getName());
100                setDriverProperties(new Properties());
101        }
102
103        protected final XAConnectionFactory getConnectionFactory() {
104                return this.connectionFactory;
105        }
106
107        @Override
108        public XAStatefulHolder createPooledConnection(Object xaFactory, ResourceBean bean)
109                        throws Exception {
110                if (xaFactory instanceof DirectXAConnectionFactory) {
111                        xaFactory = ((DirectXAConnectionFactory) xaFactory).getConnectionFactory();
112                }
113                return super.createPooledConnection(xaFactory, bean);
114        }
115
116        /**
117         * A {@link XAConnectionFactory} implementation that delegates to the
118         * {@link ThreadLocal} {@link PoolingConnectionFactoryBean}.
119         *
120         * @see PoolingConnectionFactoryBean#setConnectionFactory(XAConnectionFactory)
121         */
122        public static class DirectXAConnectionFactory implements XAConnectionFactory {
123
124                private final XAConnectionFactory connectionFactory;
125
126                public DirectXAConnectionFactory() {
127                        this.connectionFactory = source.get().connectionFactory;
128                }
129
130                @Override
131                public XAConnection createXAConnection() throws JMSException {
132                        return this.connectionFactory.createXAConnection();
133                }
134
135                @Override
136                public XAConnection createXAConnection(String userName, String password)
137                                throws JMSException {
138                        return this.connectionFactory.createXAConnection(userName, password);
139                }
140
141                public XAConnectionFactory getConnectionFactory() {
142                        return this.connectionFactory;
143                }
144
145                @Override
146                public XAJMSContext createXAContext() {
147                        return this.connectionFactory.createXAContext();
148                }
149
150                @Override
151                public XAJMSContext createXAContext(String username, String password) {
152                        return this.connectionFactory.createXAContext(username, password);
153                }
154
155        }
156
157}