org.activiti.DeprecateMultiTenantProcessEngineConfiguration.java Source code

Java tutorial

Introduction

Here is the source code for org.activiti.DeprecateMultiTenantProcessEngineConfiguration.java

Source

/* Licensed 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 org.activiti;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.sql.DataSource;

import org.activiti.engine.ActivitiException;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.db.DbSqlSessionFactory;
import org.activiti.engine.impl.interceptor.CommandInterceptor;
import org.activiti.engine.impl.persistence.StrongUuidGenerator;
import org.activiti.engine.impl.util.IoUtil;
import org.activiti.impl.db.ExecuteSchemaOperationCommand;
import org.activiti.tenant.TenantInfoHolder;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Joram Barrez
 */
public class DeprecateMultiTenantProcessEngineConfiguration extends ProcessEngineConfigurationImpl {

    private static final Logger logger = LoggerFactory
            .getLogger(DeprecateMultiTenantProcessEngineConfiguration.class);

    protected TenantInfoHolder tenantInfoHolder;

    protected String multiTenantDatabaseSchemaUpdate;

    protected List<MultiTenantDataSourceConfiguration> dataSourceConfigurations;

    protected MultiTenantDbSqlSessionFactory multiTenantDbSqlSessionFactory;

    protected Map<String, DataSource> datasources = new HashMap<String, DataSource>();

    public DeprecateMultiTenantProcessEngineConfiguration() {
        // Using the UUID generator, as otherwise the ids are pulled from a global pool of ids, backed by
        // a database table. Which is impossible with a mult-database-schema setup.
        this.idGenerator = new StrongUuidGenerator();

        // TODO: what about the job executor?
        this.setAsyncExecutorActivate(false);
        this.setAsyncExecutorEnabled(false);
        this.setJobExecutorActivate(false);

    }

    @Override
    protected CommandInterceptor createTransactionInterceptor() {
        return null;
    }

    @Override
    protected void initDataSource() {
        // Getting the datasources from the config
        for (MultiTenantDataSourceConfiguration dataSourceConfig : dataSourceConfigurations) {
            datasources.put(dataSourceConfig.getTenantId(), dataSourceConfig.getDataSource());
        }
    }

    @Override
    protected DbSqlSessionFactory createDbSqlSessionFactory() {
        multiTenantDbSqlSessionFactory = new MultiTenantDbSqlSessionFactory(tenantInfoHolder);
        for (MultiTenantDataSourceConfiguration dataSourceConfig : dataSourceConfigurations) {
            multiTenantDbSqlSessionFactory.addDatabaseType(dataSourceConfig.getTenantId(),
                    dataSourceConfig.getDatabaseType());
        }
        return multiTenantDbSqlSessionFactory;
    }

    @Override
    protected void initSqlSessionFactory() {

        MultiTenantSqlSessionFactory multiTenantSqlSessionFactory = new MultiTenantSqlSessionFactory(
                tenantInfoHolder);
        this.sqlSessionFactory = multiTenantSqlSessionFactory;

        for (String tenantId : tenantInfoHolder.getAllTenants()) {
            initSqlSessionFactoryForTenant(multiTenantSqlSessionFactory, tenantId);
        }
    }

    protected void initSqlSessionFactoryForTenant(MultiTenantSqlSessionFactory multiTenantSqlSessionFactory,
            String tenantId) {
        logger.info("Initializing sql session factory for tenant " + tenantId);

        // This could be optimized by a hack: http://www.jorambarrez.be/blog/2014/08/22/seriously-reducing-memory/
        // For each database type, the Mybatis configuration could be cached and reused.
        // But not applied it, as it's a quite dirty bit of hacking with relfection.

        InputStream inputStream = null;
        try {
            inputStream = getMyBatisXmlConfigurationStream();
            DataSource dataSource = datasources.get(tenantId);

            MultiTenantDataSourceConfiguration dataSourceConfiguration = null;
            for (MultiTenantDataSourceConfiguration d : dataSourceConfigurations) {
                if (d.getTenantId().equals(tenantId)) {
                    dataSourceConfiguration = d;
                    break;
                }
            }

            String databaseType = dataSourceConfiguration.getDatabaseType();

            Environment environment = new Environment("default", transactionFactory, dataSource);
            Reader reader = new InputStreamReader(inputStream);
            Properties properties = new Properties();
            properties.put("prefix", databaseTablePrefix);
            if (databaseType != null) {
                properties.put("limitBefore",
                        DbSqlSessionFactory.databaseSpecificLimitBeforeStatements.get(databaseType));
                properties.put("limitAfter",
                        DbSqlSessionFactory.databaseSpecificLimitAfterStatements.get(databaseType));
                properties.put("limitBetween",
                        DbSqlSessionFactory.databaseSpecificLimitBetweenStatements.get(databaseType));
                properties.put("limitOuterJoinBetween",
                        DbSqlSessionFactory.databaseOuterJoinLimitBetweenStatements.get(databaseType));
                properties.put("orderBy", DbSqlSessionFactory.databaseSpecificOrderByStatements.get(databaseType));
                properties.put("limitBeforeNativeQuery", ObjectUtils.toString(
                        DbSqlSessionFactory.databaseSpecificLimitBeforeNativeQueryStatements.get(databaseType)));
            }

            Configuration configuration = initMybatisConfiguration(environment, reader, properties);
            multiTenantSqlSessionFactory.addConfig(tenantId, configuration);

        } catch (Exception e) {
            throw new ActivitiException("Error while building ibatis SqlSessionFactory: " + e.getMessage(), e);
        } finally {
            IoUtil.closeSilently(inputStream);
        }
    }

    @Override
    public ProcessEngine buildProcessEngine() {

        // Disable schema creation/validation by setting it to null.
        // We'll do it manually, see buildProcessEngine() method (hence why it's copied first)
        this.multiTenantDatabaseSchemaUpdate = this.databaseSchemaUpdate;
        this.databaseSchemaUpdate = null;

        ProcessEngine processEngine = super.buildProcessEngine();

        for (String tenantId : tenantInfoHolder.getAllTenants()) {
            createTenantSchema(tenantId);
        }
        tenantInfoHolder.clearCurrentTenantId();

        return processEngine;
    }

    protected void createTenantSchema(String tenantId) {
        logger.info("creating/validating database schema for tenant " + tenantId);
        tenantInfoHolder.setCurrentTenantId(tenantId);
        getCommandExecutor().execute(getSchemaCommandConfig(),
                new ExecuteSchemaOperationCommand(multiTenantDatabaseSchemaUpdate));
    }

    public void addMultiTenantDataSourceConfiguration(MultiTenantDataSourceConfiguration dataSourceConfiguration) {

        String tenantId = dataSourceConfiguration.getTenantId();

        // Add datasource
        dataSourceConfigurations.add(dataSourceConfiguration);
        datasources.put(tenantId, dataSourceConfiguration.getDataSource());

        // Create session factory for tenant
        initSqlSessionFactoryForTenant((MultiTenantSqlSessionFactory) sqlSessionFactory, tenantId);

        // Register with db sql session factory
        multiTenantDbSqlSessionFactory.addDatabaseType(tenantId, dataSourceConfiguration.getDatabaseType());

        // Init schema
        createTenantSchema(tenantId);
    }

    // Getters and Setters ////////////////////////////////////////////////////////////////////////

    public List<MultiTenantDataSourceConfiguration> getDataSourceConfigurations() {
        return dataSourceConfigurations;
    }

    public TenantInfoHolder getTenantInfoHolder() {
        return tenantInfoHolder;
    }

    public void setTenantInfoHolder(TenantInfoHolder tenantInfoHolder) {
        this.tenantInfoHolder = tenantInfoHolder;
    }

    public void setDataSourceConfigurations(List<MultiTenantDataSourceConfiguration> dataSourceConfigurations) {
        this.dataSourceConfigurations = dataSourceConfigurations;
    }

}