/** * Copyright 2014-2017 yangming.liu<bytefox@126.com>. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, see <http://www.gnu.org/licenses/>. */ package org.bytesoft.bytetcc.supports.springcloud.web; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.bytesoft.bytejta.supports.rpc.TransactionRequestImpl; import org.bytesoft.bytejta.supports.rpc.TransactionResponseImpl; import org.bytesoft.bytetcc.supports.springcloud.SpringCloudBeanRegistry; import org.bytesoft.bytetcc.supports.springcloud.controller.CompensableCoordinatorController; import org.bytesoft.common.utils.ByteUtils; import org.bytesoft.common.utils.CommonUtils; import org.bytesoft.compensable.Compensable; import org.bytesoft.compensable.CompensableBeanFactory; import org.bytesoft.compensable.CompensableManager; import org.bytesoft.compensable.CompensableTransaction; import org.bytesoft.compensable.TransactionContext; import org.bytesoft.compensable.aware.CompensableEndpointAware; import org.bytesoft.transaction.supports.rpc.TransactionInterceptor; import org.springframework.beans.BeansException; import org.springframework.boot.autoconfigure.web.ErrorController; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public class CompensableHandlerInterceptor implements HandlerInterceptor, CompensableEndpointAware, ApplicationContextAware { static final String HEADER_TRANCACTION_KEY = "org.bytesoft.bytetcc.transaction"; static final String HEADER_PROPAGATION_KEY = "org.bytesoft.bytetcc.propagation"; private String identifier; private ApplicationContext applicationContext; public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HandlerMethod hm = (HandlerMethod) handler; Class<?> clazz = hm.getBeanType(); if (CompensableCoordinatorController.class.equals(clazz)) { return true; } else if (ErrorController.class.isInstance(hm.getBean())) { return true; } String transactionStr = request.getHeader(HEADER_TRANCACTION_KEY); if (StringUtils.isBlank(transactionStr)) { return true; } String propagationStr = request.getHeader(HEADER_PROPAGATION_KEY); String transactionText = StringUtils.trimToNull(transactionStr); String propagationText = StringUtils.trimToNull(propagationStr); Compensable annotation = clazz.getAnnotation(Compensable.class); if (annotation == null) { return true; } SpringCloudBeanRegistry beanRegistry = SpringCloudBeanRegistry.getInstance(); CompensableBeanFactory beanFactory = beanRegistry.getBeanFactory(); TransactionInterceptor transactionInterceptor = beanFactory.getTransactionInterceptor(); byte[] byteArray = transactionText == null ? new byte[0] : ByteUtils.stringToByteArray(transactionText); TransactionContext transactionContext = null; if (byteArray != null && byteArray.length > 0) { transactionContext = (TransactionContext) CommonUtils.deserializeObject(byteArray); } TransactionRequestImpl req = new TransactionRequestImpl(); req.setTransactionContext(transactionContext); req.setTargetTransactionCoordinator(beanRegistry.getConsumeCoordinator(propagationText)); transactionInterceptor.afterReceiveRequest(req); return true; } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { HandlerMethod hm = (HandlerMethod) handler; Class<?> clazz = hm.getBeanType(); if (CompensableCoordinatorController.class.equals(clazz)) { return; } else if (ErrorController.class.isInstance(hm.getBean())) { return; } String transactionStr = request.getHeader(HEADER_TRANCACTION_KEY); if (StringUtils.isBlank(transactionStr)) { return; } Compensable annotation = clazz.getAnnotation(Compensable.class); if (annotation == null) { return; } SpringCloudBeanRegistry beanRegistry = SpringCloudBeanRegistry.getInstance(); CompensableBeanFactory beanFactory = beanRegistry.getBeanFactory(); CompensableManager compensableManager = beanFactory.getCompensableManager(); TransactionInterceptor transactionInterceptor = beanFactory.getTransactionInterceptor(); CompensableTransaction compensable = compensableManager.getCompensableTransactionQuietly(); TransactionContext transactionContext = compensable.getTransactionContext(); byte[] byteArray = CommonUtils.serializeObject(transactionContext); String compensableStr = ByteUtils.byteArrayToString(byteArray); response.addHeader(HEADER_TRANCACTION_KEY, compensableStr); response.addHeader(HEADER_PROPAGATION_KEY, this.identifier); TransactionResponseImpl resp = new TransactionResponseImpl(); resp.setTransactionContext(transactionContext); resp.setSourceTransactionCoordinator(beanRegistry.getConsumeCoordinator(null)); transactionInterceptor.beforeSendResponse(resp); } public void setEndpoint(String identifier) { this.identifier = identifier; } public ApplicationContext getApplicationContext() { return applicationContext; } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }