package com.easyooo.framework.support.transaction;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;

import com.easyooo.framework.sharding.transaction.ChainedTransactionManager;

/**
 * <p>
 *  系统事务管理器,这里只是对事务资源的一种扩充,而多数据源的事务依赖父类来完成
 * </p>
 * <p>
 * 该类在数据库事务之后,将额外保证其它任何资源的事务一致性(这仅仅是一种理论上的事务一致性,一阶段事务)
 * 这部分资源包括只要实现了TransactionResource 接口的都将支持一阶段事务
 * </p>
 * 
 * @see TransactionResource
 * @see ChainedTransactionManager
 *
 * @author Killer
 */
public class BusinessResourceTransactionManager extends ChainedTransactionManager{
	
	Logger logger = LoggerFactory.getLogger(getClass());

	@Override
	public TransactionStatus getTransaction(TransactionDefinition definition)
			throws TransactionException {
		TransactionStatus status = super.getTransaction(definition);
		try {
			TransactionResourceManager.initSynchronization();
			triggerBegin(status);
		} catch (Throwable e) {
			throw new CannotCreateTransactionException(
					"Unable to open the transaction", e);
		}
		return status;
	}
	
	@Override
	public void commit(TransactionStatus status) throws TransactionException {
		try{
			super.commit(status);
			triggerCommit(status);
		}catch(TransactionException te){
			triggerRollback(status);
			throw te;
		}finally{
			// finally将保证cleanup被调用
			cleanup();
		}
	}

	@Override
	public void rollback(TransactionStatus status) throws TransactionException {
		try{
			TransactionException rollbackException = null;
			try{
				super.rollback(status);
			}catch(TransactionException te){
				rollbackException = te;
			}
			
			// 保证触发资源回滚
			triggerRollback(status);
			
			if(rollbackException != null){
				throw rollbackException; 
			}
		}finally{
			cleanup();
		}
	}
	
	/**
	 * 触发事务开始方法 
	 */
	protected void triggerBegin(TransactionStatus status)throws Throwable{
		Map<Object, TransactionResource> trs = TransactionResourceManager.getResourceMap();
		for (TransactionResource tr : trs.values()) {
			tr.begin();
		}
	}
	
	/**
	 * 触发资源提交,使得每一个资源实例都触发提交,
	 * 如果一旦出现异常,简单的记录日志,并继续下一资源的提交任务
	 * 
	 * @param status
	 */
	protected void triggerCommit(TransactionStatus status){
		Map<Object, TransactionResource> trs = TransactionResourceManager.getResourceMap();
		List<Throwable> commitException = new ArrayList<>();
		List<TransactionResource> res = new ArrayList<>();
		for (TransactionResource tr : trs.values()) {
			try {
				tr.commit();
			} catch (Throwable e) {
				commitException.add(e);
				res.add(tr);
				logger.error("Resource commit error.", e);
			}
		}
		
		if(commitException.size() > 0){
			logger.info("The transaction resource commit failure. total " + res.size());
		}
	}
	
	/**
	 * 触发资源回滚,使得每一个资源实例都触发回滚
	 * @param status
	 */
	protected void triggerRollback(TransactionStatus status){
		Map<Object, TransactionResource> trs = TransactionResourceManager.getResourceMap();
		List<Throwable> rollbackException = new ArrayList<>();
		List<TransactionResource> res = new ArrayList<>();
		for (TransactionResource tr : trs.values()) {
			try {
				tr.rollback();
			} catch (Throwable e) {
				rollbackException.add(e);
				res.add(tr);
				logger.error("Resource rollback error.", e);
			}
		}
		
		if(rollbackException.size() > 0){
			logger.info("The transaction resource rollback failure. total " + res.size());
		}
	}
	
	/**
	 * 事务资源的清理任务
	 * 清理线程变量
	 */
	protected void cleanup(){
		TransactionResourceManager.clear();
		
		if(logger.isDebugEnabled()){
			logger.debug("Transaction Resources has clean up.");
		}
	}
	
}