net.firejack.platform.model.config.hibernate.HibernateFactoryBean.java Source code

Java tutorial

Introduction

Here is the source code for net.firejack.platform.model.config.hibernate.HibernateFactoryBean.java

Source

/*
 * 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 net.firejack.platform.model.config.hibernate;

import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.atomikos.jdbc.AtomikosSQLException;
import net.firejack.platform.core.model.BaseEntityModel;
import net.firejack.platform.core.model.registry.DatabaseName;
import net.firejack.platform.core.store.HibernateSupport;
import net.firejack.platform.core.utils.ConfigContainer;
import net.firejack.platform.core.utils.StringUtils;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.log4j.Logger;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Environment;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.support.lob.DefaultLobHandler;
import org.springframework.jdbc.support.lob.OracleLobHandler;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;
import org.springframework.transaction.jta.JtaTransactionManager;

import java.util.*;

public class HibernateFactoryBean implements ApplicationContextAware, InitializingBean {
    private static final Logger logger = Logger.getLogger(HibernateFactoryBean.class);

    public static final String HIBERNATE_MANAGER = "hibernateManager";
    public static final String HIBERNATE_TARGET = "hibernateTarget";
    public static final String HIBERNATE_DEFAULT_PREFIX = "default";
    public static final String HIBERNATE_TEMPLATE_PREFIX = "template";
    public static final String XA = "XA";
    public static final String HIBERNATE_DATA_SOURCE_SUFFIX = "DataSource";
    public static final String HIBERNATE_PROPERTIES_SUFFIX = "HibernateProperties";
    public static final String HIBERNATE_SESSION_FACTORY_SUFFIX = "SessionFactory";
    public static final String HIBERNATE_TRANSACTION_MANAGER_SUFFIX = "TransactionManager";

    public static final String TRANSACTION_STRATEGY = "com.atomikos.icatch.jta.hibernate3.AtomikosJTATransactionFactory";
    public static final String TRANSACTION_MANAGER_STRATEGY = "com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup";

    private Map<String, BeanDefinition> registers = new HashMap<String, BeanDefinition>();
    private Map<Class, String> targets = new HashMap<Class, String>();
    private Map<String, Database> databases = new HashMap<String, Database>();
    private Map<String, Database> xaDatabases = new HashMap<String, Database>();
    private List<DisposableBean> disposableBeans = new ArrayList<DisposableBean>();
    private ConfigurableApplicationContext context;
    private ClassPathXmlApplicationContext defaultHibernate;

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        this.context = (ConfigurableApplicationContext) context;
        defaultHibernate = new ClassPathXmlApplicationContext("hibernate-default.xml");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        context.getBeanFactory().registerSingleton(HIBERNATE_MANAGER, registers);
        context.getBeanFactory().registerSingleton(HIBERNATE_TARGET, targets);

        findDatabase();

        buildHibernateTransactionManager();
        buildXAHibernateTransactionManager();
        defaultHibernate.destroy();
    }

    private void findDatabase() {
        List<String> xaDomains = new ArrayList<String>();

        String xa = ConfigContainer.get("xa");
        if (StringUtils.isNotBlank(xa)) {
            Collections.addAll(xaDomains, xa.split(";"));
        }

        Properties properties = ConfigContainer.getProperties();

        for (Map.Entry<Object, Object> entry : properties.entrySet()) {
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            String[] strings = key.split("\\.");
            if (strings.length == 3 && strings[0].equals("db")) {
                Database database = databases.get(strings[1]);
                if (database == null) {
                    database = new Database();
                    databases.put(strings[1], database);
                }
                if (strings[2].equals("type")) {
                    database.setType(DatabaseName.valueOf(value));
                } else if (strings[2].equals("domains")) {
                    List<String> domains = Arrays.asList(value.split(";"));
                    database.setDomains(domains);
                    for (String domain : domains) {
                        if (domain.split("\\.").length == 3)
                            database.setRoot(true);
                    }
                } else if (strings[2].equals("url")) {
                    database.setUrl(value);
                } else if (strings[2].equals("username")) {
                    database.setUsername(value);
                } else if (strings[2].equals("password")) {
                    database.setPassword(value);
                }
            }
        }

        Map<String, HibernateSupport> stories = context.getBeansOfType(HibernateSupport.class);

        for (Database database : databases.values()) {
            if (database.isRoot())
                database.setStores(stories.values());
            for (Iterator<Map.Entry<String, HibernateSupport>> iterator = stories.entrySet().iterator(); iterator
                    .hasNext();) {
                Map.Entry<String, HibernateSupport> supportEntry = iterator.next();
                HibernateSupport support = supportEntry.getValue();
                if (database.addStore(support)) {
                    iterator.remove();
                }
            }
        }

        if (xaDomains.size() > 1) {
            for (Iterator<Map.Entry<String, Database>> iterator = databases.entrySet().iterator(); iterator
                    .hasNext();) {
                Map.Entry<String, Database> entry = iterator.next();
                List<String> domains = new ArrayList<String>(entry.getValue().getDomains());

                for (Iterator<String> stringIterator = domains.iterator(); stringIterator.hasNext();) {
                    if (xaDomains.contains(stringIterator.next())) {
                        xaDatabases.put(entry.getKey(), entry.getValue());
                        stringIterator.remove();
                    }
                }

                if (domains.isEmpty())
                    iterator.remove();
            }
        }
    }

    private void buildHibernateTransactionManager() {
        for (Map.Entry<String, Database> entry : databases.entrySet()) {
            String name = entry.getKey();
            Database database = entry.getValue();

            BasicDataSource dataSource = null;
            try {
                dataSource = context.getBean(name + HIBERNATE_DATA_SOURCE_SUFFIX, BasicDataSource.class);
            } catch (BeansException e) {
                logger.info("Manual Hibernate DataSource: " + name + HIBERNATE_DATA_SOURCE_SUFFIX
                        + " not found use default");
            }

            if (dataSource == null) {
                dataSource = defaultHibernate.getBean(HIBERNATE_DEFAULT_PREFIX + HIBERNATE_DATA_SOURCE_SUFFIX,
                        BasicDataSource.class);
                dataSource.setDriverClassName(database.type.getDriver());
                dataSource.setUrl(database.getUrl());
                dataSource.setUsername(database.getUsername());
                dataSource.setPassword(database.getPassword());
                dataSource.setValidationQuery(database.getType().getValidate());

                context.getBeanFactory().registerSingleton(name + HIBERNATE_DATA_SOURCE_SUFFIX, dataSource);
            }

            Properties properties = null;
            try {
                properties = context.getBean(name + HIBERNATE_PROPERTIES_SUFFIX, Properties.class);
            } catch (BeansException e) {
                logger.info("Manual Hibernate properties: " + name + HIBERNATE_PROPERTIES_SUFFIX
                        + " not found use default");
            }

            if (properties == null) {
                properties = defaultHibernate.getBean(HIBERNATE_DEFAULT_PREFIX + HIBERNATE_PROPERTIES_SUFFIX,
                        Properties.class);
                properties.put(Environment.DIALECT, database.getType().getDialect());

                context.getBeanFactory().registerSingleton(name + HIBERNATE_PROPERTIES_SUFFIX, properties);
            }

            SessionFactory sessionFactory = null;
            try {
                sessionFactory = context.getBean(name + HIBERNATE_SESSION_FACTORY_SUFFIX, SessionFactory.class);
            } catch (BeansException e) {
                logger.info("Manual Hibernate Session Factory: " + name + HIBERNATE_SESSION_FACTORY_SUFFIX
                        + " not found use default");
            }

            if (sessionFactory == null) {
                try {
                    AnnotationSessionFactoryBean annotationSessionFactoryBean = new AnnotationSessionFactoryBean();
                    annotationSessionFactoryBean.setAnnotatedClasses(new Class[] { BaseEntityModel.class });
                    annotationSessionFactoryBean.setDataSource(dataSource);
                    annotationSessionFactoryBean.setHibernateProperties(properties);
                    annotationSessionFactoryBean.setPackagesToScan(database.getScanPackages());
                    annotationSessionFactoryBean.setNamingStrategy(new OpenFlameNamingStrategy(database.getType()));

                    if (database.getType() == DatabaseName.MySQL || database.getType() == DatabaseName.MSSQL) {
                        annotationSessionFactoryBean.setLobHandler(new DefaultLobHandler());
                    } else if (database.getType() == DatabaseName.Oracle) {
                        annotationSessionFactoryBean.setLobHandler(new OracleLobHandler());
                    }

                    disposableBeans.add(annotationSessionFactoryBean);
                    annotationSessionFactoryBean.afterPropertiesSet();
                    sessionFactory = annotationSessionFactoryBean.getObject();
                } catch (Exception e) {
                    logger.error(e, e);
                }
            }

            HibernateTemplate template = new HibernateTemplate();
            template.setSessionFactory(sessionFactory);

            context.getBeanFactory().registerSingleton(name + HIBERNATE_TEMPLATE_PREFIX, template);
            database.setHibernateSupport(template);
            logger.info("Initialize Hibernate support for stories: " + database);

            String beanName = name + HIBERNATE_TRANSACTION_MANAGER_SUFFIX;

            ConstructorArgumentValues values = new ConstructorArgumentValues();
            values.addGenericArgumentValue(sessionFactory);

            RootBeanDefinition definition = new RootBeanDefinition(HibernateTransactionManager.class);
            definition.setConstructorArgumentValues(values);
            registers.put(beanName, definition);

            Collection<HibernateSupport> stores = database.getStores();
            for (HibernateSupport store : stores) {
                targets.put(((Advised) store).getTargetClass(), beanName);
            }
        }
    }

    private void buildXAHibernateTransactionManager() {
        if (xaDatabases.size() == 0)
            return;

        String beanName = XA + HIBERNATE_TRANSACTION_MANAGER_SUFFIX;

        for (Map.Entry<String, Database> entry : xaDatabases.entrySet()) {
            String name = entry.getKey();
            Database database = entry.getValue();

            AtomikosDataSourceBean dataSource = null;
            try {
                dataSource = context.getBean(name + HIBERNATE_DATA_SOURCE_SUFFIX, AtomikosDataSourceBean.class);
            } catch (BeansException e) {
                logger.info("Manual XA Hibernate DataSource: " + name + HIBERNATE_DATA_SOURCE_SUFFIX
                        + " not found use default");
            }

            if (dataSource == null) {
                try {
                    dataSource = defaultHibernate.getBean(
                            HIBERNATE_DEFAULT_PREFIX + XA + HIBERNATE_DATA_SOURCE_SUFFIX,
                            AtomikosDataSourceBean.class);
                    dataSource.setUniqueResourceName(name);
                    dataSource.setXaDataSourceClassName(database.getType().getXads());
                    dataSource.setTestQuery(database.getType().getValidate());
                    Properties xaProperties = new Properties();
                    xaProperties.put("URL", database.getUrl());
                    xaProperties.put("user", database.getUsername());
                    xaProperties.put("password", database.getPassword());
                    if (database.getType() == DatabaseName.MySQL) {
                        xaProperties.put("pinGlobalTxToPhysicalConnection", true);
                    }
                    dataSource.setXaProperties(xaProperties);
                    dataSource.init();

                    context.getBeanFactory().registerSingleton(name + HIBERNATE_DATA_SOURCE_SUFFIX, dataSource);
                } catch (AtomikosSQLException e) {
                    logger.error(e, e);
                }
            }

            Properties properties = null;
            try {
                properties = context.getBean(name + HIBERNATE_PROPERTIES_SUFFIX, Properties.class);
            } catch (BeansException e) {
                logger.info("Manual XA Hibernate properties: " + name + HIBERNATE_PROPERTIES_SUFFIX
                        + " not found use default");
            }

            if (properties == null) {
                properties = defaultHibernate.getBean(HIBERNATE_DEFAULT_PREFIX + HIBERNATE_PROPERTIES_SUFFIX,
                        Properties.class);
                properties.put(Environment.DIALECT, database.getType().getDialect());
                properties.put(Environment.TRANSACTION_STRATEGY, TRANSACTION_STRATEGY);
                properties.put(Environment.TRANSACTION_MANAGER_STRATEGY, TRANSACTION_MANAGER_STRATEGY);

                context.getBeanFactory().registerSingleton(name + HIBERNATE_PROPERTIES_SUFFIX, properties);
            }

            SessionFactory sessionFactory = null;
            try {
                sessionFactory = context.getBean(name + HIBERNATE_SESSION_FACTORY_SUFFIX, SessionFactory.class);
            } catch (BeansException e) {
                logger.info("Manual XA Hibernate Session Factory: " + name + HIBERNATE_SESSION_FACTORY_SUFFIX
                        + " not found use default");
            }

            if (sessionFactory == null) {
                try {
                    AnnotationSessionFactoryBean annotationSessionFactoryBean = new AnnotationSessionFactoryBean();
                    annotationSessionFactoryBean.setAnnotatedClasses(new Class[] { BaseEntityModel.class });
                    annotationSessionFactoryBean.setDataSource(dataSource);
                    annotationSessionFactoryBean.setHibernateProperties(properties);
                    annotationSessionFactoryBean.setPackagesToScan(database.getScanPackages());
                    annotationSessionFactoryBean.setNamingStrategy(new OpenFlameNamingStrategy(database.getType()));

                    if (database.getType() == DatabaseName.MySQL || database.getType() == DatabaseName.MSSQL) {
                        annotationSessionFactoryBean.setLobHandler(new DefaultLobHandler());
                    } else if (database.getType() == DatabaseName.Oracle) {
                        annotationSessionFactoryBean.setLobHandler(new OracleLobHandler());
                    }

                    disposableBeans.add(annotationSessionFactoryBean);
                    annotationSessionFactoryBean.afterPropertiesSet();
                    sessionFactory = annotationSessionFactoryBean.getObject();
                } catch (Exception e) {
                    logger.error(e, e);
                }

                Collection<HibernateSupport> stores = database.getStores();
                for (HibernateSupport store : stores) {
                    targets.put(((Advised) store).getTargetClass(), beanName);
                }
            }

            HibernateTemplate template = new HibernateTemplate();
            template.setSessionFactory(sessionFactory);

            context.getBeanFactory().registerSingleton(HIBERNATE_TEMPLATE_PREFIX + name, template);
            database.setHibernateSupport(template);
            logger.info("Initialize Hibernate :" + HIBERNATE_TEMPLATE_PREFIX + name + " for stories:" + database);
        }

        ConstructorArgumentValues values = new ConstructorArgumentValues();
        values.addGenericArgumentValue(new UserTransactionImp());
        values.addGenericArgumentValue(new UserTransactionManager());

        RootBeanDefinition definition = new RootBeanDefinition(JtaTransactionManager.class);
        definition.setConstructorArgumentValues(values);
        registers.put(beanName, definition);
    }

    public void destroy() {
        for (String name : databases.keySet()) {
            try {
                BasicDataSource dataSource = context.getBean(name + HIBERNATE_DATA_SOURCE_SUFFIX,
                        BasicDataSource.class);
                dataSource.close();
            } catch (Exception e) {
                logger.error(e);
            }
        }

        for (String name : xaDatabases.keySet()) {
            try {
                AtomikosDataSourceBean dataSource = context.getBean(name + HIBERNATE_DATA_SOURCE_SUFFIX,
                        AtomikosDataSourceBean.class);
                dataSource.close();
            } catch (Exception e) {
                logger.error(e);
            }
        }

        for (DisposableBean bean : disposableBeans) {
            try {
                bean.destroy();
            } catch (Exception e) {
                logger.error(e);
            }
        }
    }

    private class Database {
        private DatabaseName type;
        private boolean root;
        private List<String> domains;
        private String url;
        private String username;
        private String password;
        private Collection<HibernateSupport> stores = new ArrayList<HibernateSupport>();

        public DatabaseName getType() {
            return type;
        }

        public void setType(DatabaseName type) {
            this.type = type;
        }

        private boolean isRoot() {
            return root;
        }

        private void setRoot(boolean root) {
            this.root = root;
        }

        public List<String> getDomains() {
            return domains;
        }

        public void setDomains(List<String> domains) {
            this.domains = domains;
        }

        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public Collection<HibernateSupport> getStores() {
            return stores;
        }

        public void setStores(Collection<HibernateSupport> stores) {
            this.stores = stores;
        }

        public boolean addStore(HibernateSupport store) {
            if (isRoot())
                return false;
            String name = store.getClass().getPackage().getName().replaceAll("(.*?\\.)[\\w\\-]+$", "$1");
            for (String domain : domains) {
                if (name.startsWith(domain + ".")) {
                    return this.stores.add(store);
                }
            }
            return false;
        }

        public String[] getScanPackages() {
            String[] strings = new String[stores.size()];
            int index = 0;
            for (HibernateSupport store : stores) {
                strings[index++] = store.getClass().getPackage().getName().replaceAll("(.*?)\\.[\\w\\-]+$", "$1");
            }
            return strings;
        }

        public void setHibernateSupport(HibernateTemplate template) {
            for (HibernateSupport store : stores) {
                store.setTemplate(template);
            }
        }

        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder();
            for (HibernateSupport store : stores) {
                sb.append(store.getClass().getSimpleName()).append(" ");
            }
            return sb.toString();
        }
    }
}