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 javax.transaction.TransactionManager;
020
021import org.springframework.beans.BeansException;
022import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
023import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
024import org.springframework.core.Ordered;
025
026/**
027 * {@link BeanFactoryPostProcessor} to automatically register the recommended
028 * {@link ConfigurableListableBeanFactory#registerDependentBean(String, String)
029 * dependencies} for correct Bitronix shutdown ordering. With Bitronix it appears that
030 * ConnectionFactory and DataSource beans must be shutdown before the
031 * {@link TransactionManager}.
032 *
033 * @author Phillip Webb
034 * @since 1.2.0
035 */
036public class BitronixDependentBeanFactoryPostProcessor
037                implements BeanFactoryPostProcessor, Ordered {
038
039        private static final String[] NO_BEANS = {};
040
041        private int order = Ordered.LOWEST_PRECEDENCE;
042
043        @Override
044        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
045                        throws BeansException {
046                String[] transactionManagers = beanFactory
047                                .getBeanNamesForType(TransactionManager.class, true, false);
048                for (String transactionManager : transactionManagers) {
049                        addTransactionManagerDependencies(beanFactory, transactionManager);
050                }
051        }
052
053        private void addTransactionManagerDependencies(
054                        ConfigurableListableBeanFactory beanFactory, String transactionManager) {
055                for (String dependentBeanName : getBeanNamesForType(beanFactory,
056                                "javax.jms.ConnectionFactory")) {
057                        beanFactory.registerDependentBean(transactionManager, dependentBeanName);
058                }
059                for (String dependentBeanName : getBeanNamesForType(beanFactory,
060                                "javax.sql.DataSource")) {
061                        beanFactory.registerDependentBean(transactionManager, dependentBeanName);
062                }
063        }
064
065        private String[] getBeanNamesForType(ConfigurableListableBeanFactory beanFactory,
066                        String type) {
067                try {
068                        return beanFactory.getBeanNamesForType(Class.forName(type), true, false);
069                }
070                catch (ClassNotFoundException | NoClassDefFoundError ex) {
071                        // Ignore
072                }
073                return NO_BEANS;
074        }
075
076        @Override
077        public int getOrder() {
078                return this.order;
079        }
080
081        public void setOrder(int order) {
082                this.order = order;
083        }
084
085}