/** * Copyright 2014-2016 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.spring; import java.lang.reflect.Method; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.lang3.StringUtils; import org.bytesoft.bytetcc.supports.CompensableInvocationImpl; import org.bytesoft.bytetcc.supports.CompensableSynchronization; import org.bytesoft.bytetcc.supports.spring.aware.CompensableBeanNameAware; import org.bytesoft.compensable.Compensable; import org.bytesoft.compensable.CompensableBeanFactory; import org.bytesoft.compensable.CompensableCancel; import org.bytesoft.compensable.CompensableConfirm; import org.bytesoft.compensable.CompensableInvocation; import org.bytesoft.compensable.CompensableInvocationRegistry; import org.bytesoft.compensable.CompensableManager; import org.bytesoft.compensable.CompensableTransaction; import org.bytesoft.compensable.TransactionContext; import org.bytesoft.compensable.aware.CompensableBeanFactoryAware; import org.bytesoft.transaction.Transaction; import org.bytesoft.transaction.TransactionManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; public class CompensableMethodInterceptor implements MethodInterceptor, CompensableSynchronization, ApplicationContextAware, CompensableBeanFactoryAware { static final Logger logger = LoggerFactory.getLogger(CompensableMethodInterceptor.class); private CompensableBeanFactory beanFactory; private ApplicationContext applicationContext; public void afterBegin(Transaction transaction, boolean createFlag) { CompensableManager compensableManager = this.beanFactory.getCompensableManager(); CompensableInvocationRegistry registry = CompensableInvocationRegistry.getInstance(); CompensableInvocation invocation = registry.getCurrent(); CompensableTransaction compensable = compensableManager.getCompensableTransactionQuietly(); TransactionContext transactionContext = compensable.getTransactionContext(); if (transactionContext.isCompensating()) { return; } compensable.registerCompensable(invocation); } public Object invoke(MethodInvocation mi) throws Throwable { CompensableManager compensableManager = this.beanFactory.getCompensableManager(); CompensableTransaction compensable = compensableManager.getCompensableTransactionQuietly(); if (compensable != null && compensable.getTransactionContext() != null && compensable.getTransactionContext().isCompensating()) { return mi.proceed(); } String identifier = null; Object bean = mi.getThis(); if (CompensableBeanNameAware.class.isInstance(bean)) { CompensableBeanNameAware config = (CompensableBeanNameAware) bean; identifier = config.getBeanName(); if (StringUtils.isBlank(identifier)) { logger.error("BeanId(class= {}) should not be null!", bean.getClass().getName()); throw new IllegalStateException( String.format("BeanId(class= %s) should not be null!", bean.getClass().getName())); } } else { String[] beanNameArray = this.applicationContext.getBeanNamesForType(bean.getClass()); if (beanNameArray.length == 1) { identifier = beanNameArray[0]; } else { logger.error("Class {} does not implement interface {}, and there are multiple bean definitions!", bean.getClass().getName(), CompensableBeanNameAware.class.getName()); throw new IllegalStateException( String.format("Class %s does not implement interface %s, and there are multiple bean definitions!", bean.getClass().getName(), CompensableBeanNameAware.class.getName())); } } return this.execute(identifier, mi); } public Object execute(String identifier, MethodInvocation mi) throws Throwable { Transactional transactional = mi.getMethod().getAnnotation(Transactional.class); CompensableInvocationRegistry registry = CompensableInvocationRegistry.getInstance(); Compensable annotation = mi.getMethod().getDeclaringClass().getAnnotation(Compensable.class); TransactionManager transactionManager = this.beanFactory.getTransactionManager(); CompensableManager compensableManager = this.beanFactory.getCompensableManager(); boolean desociateRequired = false; try { CompensableInvocationImpl invocation = new CompensableInvocationImpl(); Method method = mi.getMethod(); invocation.setArgs(mi.getArguments()); invocation.setIdentifier(identifier); invocation.setSimplified(annotation.simplified()); Class<?> interfaceClass = annotation.interfaceClass(); String methodName = method.getName(); Class<?>[] parameterTypes = method.getParameterTypes(); if (annotation.simplified()) { invocation.setMethod(method); // class-method Class<?> currentClazz = mi.getThis().getClass(); Method[] methodArray = currentClazz.getDeclaredMethods(); boolean confirmFlag = false; boolean cancelFlag = false; for (int i = 0; (confirmFlag == false || cancelFlag == false) && i < methodArray.length; i++) { Method element = methodArray[i]; if (element.getAnnotation(CompensableConfirm.class) != null) { confirmFlag = true; invocation.setConfirmableKey(identifier); } if (element.getAnnotation(CompensableCancel.class) != null) { cancelFlag = true; invocation.setCancellableKey(identifier); } } } else { invocation.setMethod(interfaceClass.getMethod(methodName, parameterTypes)); invocation.setConfirmableKey(annotation.confirmableKey()); invocation.setCancellableKey(annotation.cancellableKey()); } Transaction transaction = transactionManager.getTransactionQuietly(); CompensableTransaction compensable = compensableManager.getCompensableTransactionQuietly(); Transaction existingTxn = (compensable == null) ? null : compensable.getTransaction(); if (transaction == null && existingTxn != null) { transaction = existingTxn; transactionManager.associateThread(existingTxn); desociateRequired = true; } if (transactional != null && compensable != null && transaction != null) { Propagation propagation = transactional == null ? null : transactional.propagation(); if (propagation == null) { compensable.registerCompensable(invocation); } else if (Propagation.REQUIRED.equals(propagation)) { compensable.registerCompensable(invocation); } else if (Propagation.MANDATORY.equals(propagation)) { compensable.registerCompensable(invocation); } else if (Propagation.SUPPORTS.equals(propagation)) { compensable.registerCompensable(invocation); } } registry.register(invocation); return mi.proceed(); } finally { registry.unegister(); if (desociateRequired) { transactionManager.desociateThread(); } // end-if (associated) } } public void setBeanFactory(CompensableBeanFactory tbf) { this.beanFactory = tbf; } public CompensableBeanFactory getBeanFactory() { return beanFactory; } public ApplicationContext getApplicationContext() { return applicationContext; } public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; } }