package com.yiqiniu.easytrans.executor; import java.io.Serializable; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import javax.annotation.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.yiqiniu.easytrans.EasyTransSynchronizer; import com.yiqiniu.easytrans.LogProcessor; import com.yiqiniu.easytrans.RemoteServiceCaller; import com.yiqiniu.easytrans.config.EasyTransConifg; import com.yiqiniu.easytrans.context.LogProcessContext; import com.yiqiniu.easytrans.context.event.DemiLogEventHandler; import com.yiqiniu.easytrans.log.vo.Content; import com.yiqiniu.easytrans.log.vo.aft.AfterTransCallRegisterContent; import com.yiqiniu.easytrans.log.vo.aft.AfterTransCalledContent; import com.yiqiniu.easytrans.protocol.BusinessIdentifer; import com.yiqiniu.easytrans.protocol.EasyTransRequest; import com.yiqiniu.easytrans.protocol.aft.AfterMasterTransMethod; import com.yiqiniu.easytrans.util.FutureAdapter; import com.yiqiniu.easytrans.util.ReflectUtil; @RelativeInterface(AfterMasterTransMethod.class) public class AfterTransMethodExecutor implements EasyTransExecutor,LogProcessor,DemiLogEventHandler { @Resource private EasyTransSynchronizer transSynchronizer; @Resource private RemoteServiceCaller rpcClient; @Resource private EasyTransConifg config; private Logger LOG = LoggerFactory.getLogger(this.getClass()); private static final String AFTER_TRANS_METHOD_NAME = "afterTransaction"; private static final String AFTER_TRANS_METHOD_FUTURE_PREFIX = "ATMF"; @Override public <P extends EasyTransRequest<R,E>,E extends EasyTransExecutor,R extends Serializable> Future<R> execute(final P params) { final AfterTransCallRegisterContent content = new AfterTransCallRegisterContent(); content.setParams(params); transSynchronizer.registerLog(content); LogProcessContext logProcessContext = transSynchronizer.getLogProcessContext(); FutureProxy<R> future = new FutureProxy<R>(logProcessContext); Object orign = logProcessContext.getExtendResourceMap().put(getFutureKey(content), future); if(orign != null){ throw new RuntimeException("Unkown Exception:" + AFTER_TRANS_METHOD_FUTURE_PREFIX + content.getcId()); } return future; } @Override public boolean logProcess(LogProcessContext ctx, Content currentContent) { if(currentContent instanceof AfterTransCallRegisterContent){ AfterTransCallRegisterContent afterTransCallContent = (AfterTransCallRegisterContent) currentContent; //register DemiLogEvent ctx.getDemiLogManager().registerSemiLogEventListener(afterTransCallContent, this); } return true; } @Override public boolean onMatch(LogProcessContext logCtx, Content leftContent, Content rightContent) { return true;// do nothig } @Override public boolean onDismatch(final LogProcessContext logCtx, Content leftContent) { final AfterTransCallRegisterContent afterTransCallContent = (AfterTransCallRegisterContent) leftContent; final EasyTransRequest<?,?> params = afterTransCallContent.getParams(); final BusinessIdentifer businessIdentifer = ReflectUtil.getBusinessIdentifer(params.getClass()); if(logCtx.getFinalMasterTransStatus() == null){ LOG.info("final trans status unknown,process later." + logCtx.getLogCollection()); return false; }else if(logCtx.getFinalMasterTransStatus()){ //commit //execute the register method FutureTask<Object> futureTask = new FutureTask<Object>(new Callable<Object>() { @Override public Object call() throws Exception { return rpcClient.call(businessIdentifer.appId(), businessIdentifer.busCode(), AFTER_TRANS_METHOD_NAME, afterTransCallContent.getParams(),logCtx); } }); futureTask.run();//get result in this thread try { futureTask.get(); FutureProxy<?> object = (FutureProxy<?>) logCtx.getExtendResourceMap().get(getFutureKey(afterTransCallContent)); if(object != null){ object.setResult(futureTask); } } catch (InterruptedException | ExecutionException e) { LOG.error("After transaction method execute ERROR",e); return false;//try later } AfterTransCalledContent compensatedContent = new AfterTransCalledContent(); compensatedContent.setLeftDemiConentId(leftContent.getcId()); LOG.info("After transaction method executed:" + businessIdentifer); return true; }else{ //roll back //do nothing return true; } } private String getFutureKey( final AfterTransCallRegisterContent afterTransCallContent) { return AFTER_TRANS_METHOD_FUTURE_PREFIX + afterTransCallContent.getcId(); } private class FutureProxy<R> extends FutureAdapter<R> { private LogProcessContext logContext; public FutureProxy(LogProcessContext logContext){ this.logContext = logContext; } private volatile Future<R> result; @SuppressWarnings("unchecked") public void setResult(Future<Object> result) { this.result = (Future<R>) result; } @Override public R get() throws InterruptedException, ExecutionException { Boolean finalMasterTransStatus = logContext.getFinalMasterTransStatus(); if(finalMasterTransStatus == null || !finalMasterTransStatus){ throw new RuntimeException("please get the result after the transaction commited"); } if(result == null){ throw new RuntimeException("Unknow Error!"); } return result.get(); } }; }