package com.uas.platform.b2b.data.support;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;

import com.alibaba.druid.pool.DruidDataSource;
import com.uas.platform.b2b.core.util.ContextUtils;

public class DSUtils {

	/**
	 * 校验连接
	 * 
	 * <pre>
	 * 如果连接不存在，会先创建
	 * </pre>
	 * 
	 * @param jdbcTemplate
	 * @return
	 */
	public static boolean isConnectable(JdbcTemplate jdbcTemplate, DS ds) {
		if (!ContextUtils.getApplicationContext().containsBean(ds.getId())) {
			createDataSource(ds);
		}
		return testConnection(jdbcTemplate, ds);
	}

	/**
	 * 创建bean
	 * 
	 * @param beanName
	 */
	private static void createDataSource(DS ds) {
		ConfigurableApplicationContext context = (ConfigurableApplicationContext) ContextUtils.getApplicationContext();
		DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();
		BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(DruidDataSource.class);
		bdb.getBeanDefinition().setAttribute("id", ds.getId());
		// bdb.getBeanDefinition().setAttribute("destroy-method", "close");
		bdb.addPropertyValue("driverClassName", ds.getDriverClassName());
		bdb.addPropertyValue("url", ds.getUrl());
		bdb.addPropertyValue("username", ds.getUsername());
		bdb.addPropertyValue("password", ds.getPassword());
		bdb.addPropertyValue("initialSize", 1);
		bdb.addPropertyValue("maxActive", 20);
		bdb.addPropertyValue("maxWait", 5000);
		bdb.addPropertyValue("poolPreparedStatements", true);
		bdb.addPropertyValue("defaultAutoCommit", true);
		bdb.addPropertyValue("removeAbandoned", true);
		bdb.addPropertyValue("testWhileIdle", true);
		bdb.addPropertyValue("validationQuery", "select 1 from dual");
		bdb.addPropertyValue("timeBetweenEvictionRunsMillis", 300000);
		bdb.addPropertyValue("minEvictableIdleTimeMillis", 60000);
		beanFactory.registerBeanDefinition(ds.getId(), bdb.getBeanDefinition());
	}

	/**
	 * 测试连接，未防止数据库连接登录超时 <b> oracle不支持loginTimeOut </b>
	 * 
	 * @param jdbcTemplate
	 * @return
	 */
	private static boolean testConnection(final JdbcTemplate jdbcTemplate, final DS ds) {
		boolean isValid = false;
		String currSrc = SpObserver.getSp();
		ExecutorService executor = Executors.newSingleThreadExecutor();
		FutureTask<Boolean> future = new FutureTask<Boolean>(new Callable<Boolean>() {
			@Override
            public Boolean call() {
				SpObserver.putSp(ds.getId());
				jdbcTemplate.execute("select 1 from dual");
				return true;
			}
		});
		executor.execute(future);
		try {
			isValid = future.get(6000, TimeUnit.MILLISECONDS);
		} catch (Exception e) {
			future.cancel(true);
		} finally {
			executor.shutdown();
			SpObserver.putSp(currSrc);
		}
		return isValid;
	}

}
