package com.yiqiniu.easytrans.executor; import java.io.Serializable; import java.util.concurrent.Callable; import java.util.concurrent.Future; 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.compensable.CompensatedContent; import com.yiqiniu.easytrans.log.vo.compensable.PreCompensableCallContent; import com.yiqiniu.easytrans.protocol.BusinessIdentifer; import com.yiqiniu.easytrans.protocol.EasyTransRequest; import com.yiqiniu.easytrans.protocol.cps.CompensableMethod; import com.yiqiniu.easytrans.util.ReflectUtil; @RelativeInterface(CompensableMethod.class) public class CompensableMethodExecutor 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 COMPENSABLE_BUSINESS_METHOD_NAME = "doCompensableBusiness"; private static final String COMPENSATION_METHOD_NAME = "compensation"; @Override public <P extends EasyTransRequest<R,E>,E extends EasyTransExecutor,R extends Serializable> Future<R> execute(final P params) { final LogProcessContext logProcessContext = transSynchronizer.getLogProcessContext(); Callable<R> callable = new Callable<R>() { @Override public R call() throws Exception { BusinessIdentifer businessIdentifer = ReflectUtil.getBusinessIdentifer(params.getClass()); return (R) rpcClient.call(businessIdentifer.appId(), businessIdentifer.busCode(), COMPENSABLE_BUSINESS_METHOD_NAME, params,logProcessContext); } }; PreCompensableCallContent content = new PreCompensableCallContent(); content.setParams(params); return transSynchronizer.executeMethod(callable, content); } @Override public boolean logProcess(LogProcessContext ctx, Content currentContent) { if(currentContent instanceof PreCompensableCallContent){ PreCompensableCallContent preCallContent = (PreCompensableCallContent) currentContent; //register DemiLogEvent ctx.getDemiLogManager().registerSemiLogEventListener(preCallContent, this); } return true; } @Override public boolean onMatch(LogProcessContext logCtx, Content leftContent, Content rightContent) { return true;// do nothing } @Override public boolean onDismatch(LogProcessContext logCtx, Content leftContent) { PreCompensableCallContent preCpsContent = (PreCompensableCallContent) leftContent; EasyTransRequest<?,?> params = preCpsContent.getParams(); 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 //do nothing return true; }else{ //roll back //execute compensation and then write Log rpcClient.callWithNoReturn(businessIdentifer.appId(), businessIdentifer.busCode(), COMPENSATION_METHOD_NAME, preCpsContent.getParams(),logCtx); CompensatedContent compensatedContent = new CompensatedContent(); compensatedContent.setLeftDemiConentId(leftContent.getcId()); LOG.info("Compensable method executed:" + businessIdentifer); return true; } } }