/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.infrastructure.core.service;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.apache.tomcat.jdbc.pool.PoolConfiguration;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import org.mifosplatform.infrastructure.core.domain.MifosPlatformTenant;
import org.mifosplatform.infrastructure.core.domain.MifosPlatformTenantConnection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
/**
* Implementation that returns a new or existing tomcat 7 jdbc connection pool
* datasource based on the tenant details stored in a {@link ThreadLocal}
* variable for this request.
*
* {@link ThreadLocalContextUtil} is used to retrieve the
* {@link MifosPlatformTenant} for the request.
*/
@Service
public class TomcatJdbcDataSourcePerTenantService implements RoutingDataSourceService {
private final Map<Long, DataSource> tenantToDataSourceMap = new HashMap<>(1);
private final DataSource tenantDataSource;
@Autowired
public TomcatJdbcDataSourcePerTenantService(final @Qualifier("tenantDataSourceJndi") DataSource tenantDataSource) {
this.tenantDataSource = tenantDataSource;
}
@Override
public DataSource retrieveDataSource() {
// default to tenant database datasource
DataSource tenantDataSource = this.tenantDataSource;
final MifosPlatformTenant tenant = ThreadLocalContextUtil.getTenant();
if (tenant != null) {
final MifosPlatformTenantConnection tenantConnection = tenant.getConnection();
synchronized (this.tenantToDataSourceMap) {
// if tenantConnection information available switch to
// appropriate
// datasource
// for that tenant.
if (this.tenantToDataSourceMap.containsKey(tenantConnection.getConnectionId())) {
tenantDataSource = this.tenantToDataSourceMap.get(tenantConnection.getConnectionId());
} else {
tenantDataSource = createNewDataSourceFor(tenantConnection);
this.tenantToDataSourceMap.put(tenantConnection.getConnectionId(), tenantDataSource);
}
}
}
return tenantDataSource;
}
// creates the data source oltp and report databases
private DataSource createNewDataSourceFor(final MifosPlatformTenantConnection tenantConnectionObj) {
// see
// http://www.tomcatexpert.com/blog/2010/04/01/configuring-jdbc-pool-high-concurrency
// see also org.mifosplatform.DataSourceProperties.setMifosDefaults()
final String jdbcUrl = tenantConnectionObj.databaseURL();
final PoolConfiguration poolConfiguration = new PoolProperties();
poolConfiguration.setDriverClassName("com.mysql.jdbc.Driver");
poolConfiguration.setName(tenantConnectionObj.getSchemaName() + "_pool");
poolConfiguration.setUrl(jdbcUrl);
poolConfiguration.setUsername(tenantConnectionObj.getSchemaUsername());
poolConfiguration.setPassword(tenantConnectionObj.getSchemaPassword());
poolConfiguration.setInitialSize(tenantConnectionObj.getInitialSize());
poolConfiguration.setTestOnBorrow(tenantConnectionObj.isTestOnBorrow());
poolConfiguration.setValidationQuery("SELECT 1");
poolConfiguration.setValidationInterval(tenantConnectionObj.getValidationInterval());
poolConfiguration.setRemoveAbandoned(tenantConnectionObj.isRemoveAbandoned());
poolConfiguration.setRemoveAbandonedTimeout(tenantConnectionObj.getRemoveAbandonedTimeout());
poolConfiguration.setLogAbandoned(tenantConnectionObj.isLogAbandoned());
poolConfiguration.setAbandonWhenPercentageFull(tenantConnectionObj.getAbandonWhenPercentageFull());
/**
* Vishwas- Do we need to enable the below properties and add
* ResetAbandonedTimer for long running batch Jobs?
**/
// poolConfiguration.setMaxActive(tenant.getMaxActive());
// poolConfiguration.setMinIdle(tenant.getMinIdle());
// poolConfiguration.setMaxIdle(tenant.getMaxIdle());
// poolConfiguration.setSuspectTimeout(tenant.getSuspectTimeout());
// poolConfiguration.setTimeBetweenEvictionRunsMillis(tenant.getTimeBetweenEvictionRunsMillis());
// poolConfiguration.setMinEvictableIdleTimeMillis(tenant.getMinEvictableIdleTimeMillis());
poolConfiguration.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"
+ "org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport");
return new org.apache.tomcat.jdbc.pool.DataSource(poolConfiguration);
}
}