/** * 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.feign; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.bytesoft.bytejta.supports.rpc.TransactionRequestImpl; import org.bytesoft.bytejta.supports.wire.RemoteCoordinator; import org.bytesoft.bytetcc.CompensableTransactionImpl; import org.bytesoft.bytetcc.supports.springcloud.SpringCloudBeanRegistry; import org.bytesoft.bytetcc.supports.springcloud.ribbon.CompensableRibbonInterceptor; import org.bytesoft.compensable.CompensableBeanFactory; import org.bytesoft.compensable.CompensableManager; import org.bytesoft.compensable.TransactionContext; import org.bytesoft.transaction.archive.XAResourceArchive; import org.bytesoft.transaction.supports.resource.XAResourceDescriptor; import org.bytesoft.transaction.supports.rpc.TransactionInterceptor; import com.netflix.loadbalancer.Server; import feign.InvocationHandlerFactory.MethodHandler; import feign.Target; public class CompensableFeignHandler implements InvocationHandler { private Target<?> target; private Map<Method, MethodHandler> handlers; public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } else { final SpringCloudBeanRegistry beanRegistry = SpringCloudBeanRegistry.getInstance(); CompensableBeanFactory beanFactory = beanRegistry.getBeanFactory(); CompensableManager compensableManager = beanFactory.getCompensableManager(); final TransactionInterceptor transactionInterceptor = beanFactory.getTransactionInterceptor(); CompensableTransactionImpl compensable = // (CompensableTransactionImpl) compensableManager.getCompensableTransactionQuietly(); if (compensable == null) { return this.handlers.get(method).invoke(args); } final TransactionContext transactionContext = compensable.getTransactionContext(); if (transactionContext.isCompensable() == false) { return this.handlers.get(method).invoke(args); } final List<XAResourceArchive> participantList = compensable.getParticipantArchiveList(); beanRegistry.setRibbonInterceptor(new CompensableRibbonInterceptor() { public Server beforeCompletion(List<Server> servers) { for (int i = 0; servers != null && participantList != null && i < servers.size(); i++) { Server server = servers.get(i); String instanceId = server.getMetaInfo().getInstanceId(); for (int j = 0; participantList != null && j < participantList.size(); j++) { XAResourceArchive archive = participantList.get(j); XAResourceDescriptor descriptor = archive.getDescriptor(); String identifier = descriptor.getIdentifier(); if (StringUtils.equals(instanceId, identifier)) { return server; } } } return null; } public void afterCompletion(Server server) { beanRegistry.removeRibbonInterceptor(); TransactionRequestImpl request = new TransactionRequestImpl(); request.setTransactionContext(transactionContext); String identifier = server.getMetaInfo().getInstanceId(); RemoteCoordinator coordinator = beanRegistry.getConsumeCoordinator(identifier); request.setTargetTransactionCoordinator(coordinator); transactionInterceptor.beforeSendRequest(request); } }); return this.handlers.get(method).invoke(args); } } public Target<?> getTarget() { return target; } public void setTarget(Target<?> target) { this.target = target; } public Map<Method, MethodHandler> getHandlers() { return handlers; } public void setHandlers(Map<Method, MethodHandler> handlers) { this.handlers = handlers; } }