killbill-aplcache

payment: Fixes #780

9/20/2017 8:34:12 PM

Details

diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPaymentWithControl.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPaymentWithControl.java
index 7879aad..60bdf05 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPaymentWithControl.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPaymentWithControl.java
@@ -271,6 +271,12 @@ public class TestPaymentWithControl extends TestIntegrationBase {
                 public UUID getAdjustedPaymentMethodId() {
                     return adjustedPaymentMethodId;
                 }
+
+                @Override
+                public String getAdjustedPluginName() {
+                    return null;
+                }
+
                 @Override
                 public Iterable<PluginProperty> getAdjustedPluginProperties() {
                     return null;
diff --git a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
index e114d2e..8c55462 100644
--- a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
@@ -991,6 +991,17 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
     }
 
     @Override
+    public UUID addPaymentMethodWithPaymentControl(final Account account, final String paymentMethodExternalKey, final String pluginName, final boolean setDefault, final PaymentMethodPlugin paymentMethodInfo, final Iterable<PluginProperty> properties, final PaymentOptions paymentOptions, final CallContext context) throws PaymentApiException {
+        final List<String> paymentControlPluginNames = toPaymentControlPluginNames(paymentOptions, context);
+        if (paymentControlPluginNames.isEmpty()) {
+            return addPaymentMethod(account, paymentMethodExternalKey, pluginName, setDefault, paymentMethodInfo, properties, context);
+        }
+
+        return paymentMethodProcessor.addPaymentMethodWithControl(paymentMethodExternalKey, pluginName, account, setDefault, paymentMethodInfo, properties,
+                                                                  paymentControlPluginNames, context, internalCallContextFactory.createInternalCallContext(account.getId(), context));
+    }
+
+    @Override
     public List<PaymentMethod> getAccountPaymentMethods(final UUID accountId, final boolean includedInactive, final boolean withPluginInfo, final Iterable<PluginProperty> properties, final TenantContext context)
             throws PaymentApiException {
         return paymentMethodProcessor.getPaymentMethods(includedInactive, withPluginInfo, properties, context, internalCallContextFactory.createInternalTenantContext(accountId, context));
diff --git a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentGatewayApi.java b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentGatewayApi.java
index 26bce39..55cddc7 100644
--- a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentGatewayApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentGatewayApi.java
@@ -147,6 +147,7 @@ public class DefaultPaymentGatewayApi extends DefaultApiBase implements PaymentG
                                                                                                                        null,
                                                                                                                        null,
                                                                                                                        null,
+                                                                                                                       null,
                                                                                                                        PaymentApiType.HPP,
                                                                                                                        null,
                                                                                                                        HPPType.BUILD_FORM_DESCRIPTOR,
@@ -174,6 +175,7 @@ public class DefaultPaymentGatewayApi extends DefaultApiBase implements PaymentG
                                                                                                          null,
                                                                                                          null,
                                                                                                          null,
+                                                                                                         null,
                                                                                                          PaymentApiType.HPP,
                                                                                                          null,
                                                                                                          HPPType.BUILD_FORM_DESCRIPTOR,
@@ -194,6 +196,7 @@ public class DefaultPaymentGatewayApi extends DefaultApiBase implements PaymentG
                                                                                                          null,
                                                                                                          null,
                                                                                                          null,
+                                                                                                         null,
                                                                                                          PaymentApiType.HPP,
                                                                                                          null,
                                                                                                          HPPType.BUILD_FORM_DESCRIPTOR,
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java
index c30581d..b37085c 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java
@@ -23,6 +23,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
+import java.util.concurrent.Callable;
 import java.util.concurrent.TimeUnit;
 
 import javax.annotation.Nullable;
@@ -33,12 +34,17 @@ import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.control.plugin.api.PaymentApiType;
+import org.killbill.billing.control.plugin.api.PaymentControlApiException;
+import org.killbill.billing.control.plugin.api.PriorPaymentControlResult;
 import org.killbill.billing.invoice.api.InvoiceInternalApi;
 import org.killbill.billing.payment.api.DefaultPaymentMethod;
 import org.killbill.billing.payment.api.PaymentApiException;
 import org.killbill.billing.payment.api.PaymentMethod;
 import org.killbill.billing.payment.api.PaymentMethodPlugin;
 import org.killbill.billing.payment.api.PluginProperty;
+import org.killbill.billing.payment.core.sm.control.ControlPluginRunner;
+import org.killbill.billing.payment.core.sm.control.PaymentControlApiAbortException;
 import org.killbill.billing.payment.dao.PaymentDao;
 import org.killbill.billing.payment.dao.PaymentMethodModelDao;
 import org.killbill.billing.payment.dispatcher.PluginDispatcher;
@@ -50,6 +56,7 @@ import org.killbill.billing.payment.provider.DefaultNoOpPaymentMethodPlugin;
 import org.killbill.billing.payment.provider.DefaultPaymentMethodInfoPlugin;
 import org.killbill.billing.payment.provider.ExternalPaymentProviderPlugin;
 import org.killbill.billing.tag.TagInternalApi;
+import org.killbill.billing.util.PluginProperties;
 import org.killbill.billing.util.UUIDs;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
@@ -65,6 +72,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Function;
+import com.google.common.base.Joiner;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
@@ -80,9 +88,12 @@ import static org.killbill.billing.util.entity.dao.DefaultPaginationHelper.getEn
 public class PaymentMethodProcessor extends ProcessorBase {
 
     private static final Logger log = LoggerFactory.getLogger(PaymentMethodProcessor.class);
+    private static final Joiner JOINER = Joiner.on(", ");
 
     private final PluginDispatcher<UUID> uuidPluginNotificationDispatcher;
 
+    private final ControlPluginRunner controlPluginRunner;
+
     private final PaymentConfig paymentConfig;
 
     @Inject
@@ -94,11 +105,13 @@ public class PaymentMethodProcessor extends ProcessorBase {
                                   final GlobalLocker locker,
                                   final PaymentConfig paymentConfig,
                                   final PaymentExecutors executors,
+                                  final ControlPluginRunner controlPluginRunner,
                                   final InternalCallContextFactory internalCallContextFactory,
                                   final Clock clock) {
         super(paymentPluginServiceRegistration, accountInternalApi, paymentDao, tagUserApi, locker, internalCallContextFactory, invoiceApi, clock);
         final long paymentPluginTimeoutSec = TimeUnit.SECONDS.convert(paymentConfig.getPaymentPluginTimeout().getPeriod(), paymentConfig.getPaymentPluginTimeout().getUnit());
         this.paymentConfig = paymentConfig;
+        this.controlPluginRunner = controlPluginRunner;
         this.uuidPluginNotificationDispatcher = new PluginDispatcher<UUID>(paymentPluginTimeoutSec, executors);
     }
 
@@ -145,7 +158,6 @@ public class PaymentMethodProcessor extends ProcessorBase {
                                                                                                             return PluginDispatcher.createPluginDispatcherReturnType(pm.getId());
                                                                                                         }
 
-
                                                                                                         private void validateUniqueExternalPaymentMethod(final UUID accountId, final String pluginName) throws PaymentApiException {
                                                                                                             if (ExternalPaymentProviderPlugin.PLUGIN_NAME.equals(pluginName)) {
                                                                                                                 final List<PaymentMethodModelDao> accountPaymentMethods = paymentDao.getPaymentMethods(context);
@@ -163,6 +175,119 @@ public class PaymentMethodProcessor extends ProcessorBase {
                                              uuidPluginNotificationDispatcher);
     }
 
+    public UUID addPaymentMethodWithControl(final String paymentMethodExternalKey, final String paymentPluginServiceName, final Account account,
+                                            final boolean setDefault, final PaymentMethodPlugin paymentMethodProps, final Iterable<PluginProperty> properties,
+                                            final List<String> paymentControlPluginNames, final CallContext callContext, final InternalCallContext context) throws PaymentApiException {
+        final Iterable<PluginProperty> mergedProperties = PluginProperties.merge(paymentMethodProps.getProperties(), properties);
+        return executeWithPaymentMethodControl(paymentPluginServiceName, account, mergedProperties, paymentControlPluginNames, callContext, uuidPluginNotificationDispatcher, new WithPaymentMethodControlCallback<UUID>() {
+            @Override
+            public UUID doPaymentMethodApiOperation(final String adjustedPaymentPluginServiceName, final Iterable<PluginProperty> adjustedPluginProperties) throws PaymentApiException {
+                if (adjustedPaymentPluginServiceName == null) {
+                    return addPaymentMethod(paymentMethodExternalKey, paymentPluginServiceName, account, setDefault, paymentMethodProps, properties, callContext, context);
+                } else {
+                    return addPaymentMethod(paymentMethodExternalKey, adjustedPaymentPluginServiceName, account, setDefault, paymentMethodProps, properties, callContext, context);
+                }
+            }
+        });
+    }
+
+
+    private interface WithPaymentMethodControlCallback<T> {
+        T doPaymentMethodApiOperation(final String adjustedPluginName, final Iterable<PluginProperty> adjustedPluginProperties) throws PaymentApiException;
+    }
+
+    private <T> T executeWithPaymentMethodControl(final String paymentPluginServiceName,
+                                                  final Account account,
+                                                  final Iterable<PluginProperty> properties,
+                                                  final List<String> paymentControlPluginNames,
+                                                  final CallContext callContext,
+                                                  final PluginDispatcher<T> pluginDispatcher,
+                                                  final WithPaymentMethodControlCallback<T> callback) throws PaymentApiException {
+
+        return dispatchWithExceptionHandling(account,
+                                             JOINER.join(paymentControlPluginNames),
+                                             new Callable<PluginDispatcherReturnType<T>>() {
+                                                 @Override
+                                                 public PluginDispatcherReturnType<T> call() throws Exception {
+                                                     final PriorPaymentControlResult priorCallResult;
+                                                     try {
+                                                         priorCallResult = controlPluginRunner.executePluginPriorCalls(account,
+                                                                                                                       null,
+                                                                                                                       paymentPluginServiceName,
+                                                                                                                       null,
+                                                                                                                       null,
+                                                                                                                       null,
+                                                                                                                       null,
+                                                                                                                       null,
+                                                                                                                       PaymentApiType.PAYMENT_METHOD,
+                                                                                                                       null,
+                                                                                                                       null,
+                                                                                                                       null,
+                                                                                                                       null,
+                                                                                                                       null,
+                                                                                                                       null,
+                                                                                                                       true,
+                                                                                                                       paymentControlPluginNames,
+                                                                                                                       properties,
+                                                                                                                       callContext);
+
+                                                     } catch (final PaymentControlApiAbortException e) {
+                                                         throw new PaymentApiException(ErrorCode.PAYMENT_PLUGIN_API_ABORTED, e.getPluginName());
+                                                     } catch (final PaymentControlApiException e) {
+                                                         throw new PaymentApiException(e, ErrorCode.PAYMENT_PLUGIN_EXCEPTION, e);
+                                                     }
+
+                                                     try {
+                                                         final T result = callback.doPaymentMethodApiOperation(priorCallResult.getAdjustedPluginName(), priorCallResult.getAdjustedPluginProperties());
+                                                         controlPluginRunner.executePluginOnSuccessCalls(account,
+                                                                                                         null,
+                                                                                                         priorCallResult.getAdjustedPluginName(),
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         PaymentApiType.PAYMENT_METHOD,
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         true,
+                                                                                                         paymentControlPluginNames,
+                                                                                                         priorCallResult.getAdjustedPluginProperties(),
+                                                                                                         callContext);
+                                                         return PluginDispatcher.createPluginDispatcherReturnType(result);
+                                                     } catch (final PaymentApiException e) {
+                                                         controlPluginRunner.executePluginOnFailureCalls(account,
+                                                                                                         null,
+                                                                                                         priorCallResult.getAdjustedPluginName(),
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         PaymentApiType.PAYMENT_METHOD,
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         null,
+                                                                                                         true,
+                                                                                                         paymentControlPluginNames,
+                                                                                                         priorCallResult.getAdjustedPluginProperties(),
+                                                                                                         callContext);
+                                                         throw e;
+                                                     }
+                                                 }
+                                             },
+                                             pluginDispatcher);
+    }
+
+
+
     private String retrieveActualPaymentMethodExternalKey(final Account account, final PaymentMethod pm, final PaymentPluginApi pluginApi, final Iterable<PluginProperty> properties, final TenantContext callContext, final InternalCallContext context) {
         // If the user specified an external key, use it
         if (pm.getExternalKey() != null) {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/control/CompletionControlOperation.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/control/CompletionControlOperation.java
index 9ba0ab2..7c503ea 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/control/CompletionControlOperation.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/control/CompletionControlOperation.java
@@ -67,6 +67,7 @@ public class CompletionControlOperation extends OperationControlCallback {
                 final PaymentTransactionModelDao transaction = paymentStateContext.getPaymentTransactionModelDao();
                 final PaymentControlContext updatedPaymentControlContext = new DefaultPaymentControlContext(paymentStateContext.getAccount(),
                                                                                                             paymentStateContext.getPaymentMethodId(),
+                                                                                                            null,
                                                                                                             paymentStateControlContext.getAttemptId(),
                                                                                                             transaction.getPaymentId(),
                                                                                                             paymentStateContext.getPaymentExternalKey(),
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/control/ControlPluginRunner.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/control/ControlPluginRunner.java
index c132bea..15da0e2 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/control/ControlPluginRunner.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/control/ControlPluginRunner.java
@@ -59,6 +59,7 @@ public class ControlPluginRunner {
 
     public PriorPaymentControlResult executePluginPriorCalls(final Account account,
                                                              final UUID paymentMethodId,
+                                                             final String pluginName,
                                                              final UUID paymentAttemptId,
                                                              final UUID paymentId,
                                                              final String paymentExternalKey,
@@ -76,15 +77,17 @@ public class ControlPluginRunner {
                                                              final Iterable<PluginProperty> pluginProperties,
                                                              final CallContext callContext) throws PaymentControlApiException {
         // Return as soon as the first plugin aborts, or the last result for the last plugin
-        PriorPaymentControlResult prevResult = new DefaultPriorPaymentControlResult(false, amount, currency, paymentMethodId, pluginProperties);
+        PriorPaymentControlResult prevResult = new DefaultPriorPaymentControlResult(false, amount, currency, paymentMethodId, null, pluginProperties);
 
         // Those values are adjusted prior each call with the result of what previous call to plugin returned
         UUID inputPaymentMethodId = paymentMethodId;
+        String inputPaymentMethodName = pluginName;
         BigDecimal inputAmount = amount;
         Currency inputCurrency = currency;
         Iterable<PluginProperty> inputPluginProperties = pluginProperties;
         PaymentControlContext inputPaymentControlContext = new DefaultPaymentControlContext(account,
                                                                                             paymentMethodId,
+                                                                                            pluginName,
                                                                                             paymentAttemptId,
                                                                                             paymentId,
                                                                                             paymentExternalKey,
@@ -100,16 +103,16 @@ public class ControlPluginRunner {
                                                                                             isApiPayment,
                                                                                             callContext);
 
-        for (final String pluginName : paymentControlPluginNames) {
-            final PaymentControlPluginApi plugin = paymentControlPluginRegistry.getServiceForName(pluginName);
+        for (final String controlPluginName : paymentControlPluginNames) {
+            final PaymentControlPluginApi plugin = paymentControlPluginRegistry.getServiceForName(controlPluginName);
             if (plugin == null) {
                 // First call to plugin, we log warn, if plugin is not registered
-                log.warn("Skipping unknown payment control plugin {} when fetching results", pluginName);
+                log.warn("Skipping unknown payment control plugin {} when fetching results", controlPluginName);
                 continue;
             }
-            log.debug("Calling priorCall of plugin {}", pluginName);
+            log.debug("Calling priorCall of plugin {}", controlPluginName);
             prevResult = plugin.priorCall(inputPaymentControlContext, inputPluginProperties);
-            log.debug("Successful executed priorCall of plugin {}", pluginName);
+            log.debug("Successful executed priorCall of plugin {}", controlPluginName);
             if (prevResult == null) {
                 // Nothing returned by the plugin
                 continue;
@@ -118,6 +121,9 @@ public class ControlPluginRunner {
             if (prevResult.getAdjustedPaymentMethodId() != null) {
                 inputPaymentMethodId = prevResult.getAdjustedPaymentMethodId();
             }
+            if (prevResult.getAdjustedPluginName() != null) {
+                inputPaymentMethodName = prevResult.getAdjustedPluginName();
+            }
             if (prevResult.getAdjustedAmount() != null) {
                 inputAmount = prevResult.getAdjustedAmount();
             }
@@ -128,10 +134,11 @@ public class ControlPluginRunner {
                 inputPluginProperties = prevResult.getAdjustedPluginProperties();
             }
             if (prevResult.isAborted()) {
-                throw new PaymentControlApiAbortException(pluginName);
+                throw new PaymentControlApiAbortException(controlPluginName);
             }
             inputPaymentControlContext = new DefaultPaymentControlContext(account,
                                                                           inputPaymentMethodId,
+                                                                          controlPluginName,
                                                                           paymentAttemptId,
                                                                           paymentId,
                                                                           paymentExternalKey,
@@ -148,12 +155,13 @@ public class ControlPluginRunner {
                                                                           callContext);
         }
         // Rebuild latest result to include inputPluginProperties
-        prevResult = new DefaultPriorPaymentControlResult(prevResult != null && prevResult.isAborted(), inputPaymentMethodId, inputAmount, inputCurrency, inputPluginProperties);
+        prevResult = new DefaultPriorPaymentControlResult(prevResult != null && prevResult.isAborted(), inputPaymentMethodId, inputPaymentMethodName, inputAmount, inputCurrency, inputPluginProperties);
         return prevResult;
     }
 
     public OnSuccessPaymentControlResult executePluginOnSuccessCalls(final Account account,
                                                                      final UUID paymentMethodId,
+                                                                     final String pluginName,
                                                                      final UUID paymentAttemptId,
                                                                      final UUID paymentId,
                                                                      final String paymentExternalKey,
@@ -173,6 +181,7 @@ public class ControlPluginRunner {
 
         final PaymentControlContext inputPaymentControlContext = new DefaultPaymentControlContext(account,
                                                                                                   paymentMethodId,
+                                                                                                  pluginName,
                                                                                                   paymentAttemptId,
                                                                                                   paymentId,
                                                                                                   paymentExternalKey,
@@ -189,13 +198,13 @@ public class ControlPluginRunner {
                                                                                                   callContext);
 
         Iterable<PluginProperty> inputPluginProperties = pluginProperties;
-        for (final String pluginName : paymentControlPluginNames) {
-            final PaymentControlPluginApi plugin = paymentControlPluginRegistry.getServiceForName(pluginName);
+        for (final String controlPluginName : paymentControlPluginNames) {
+            final PaymentControlPluginApi plugin = paymentControlPluginRegistry.getServiceForName(controlPluginName);
             if (plugin != null) {
                 try {
-                    log.debug("Calling onSuccessCall of plugin {}", pluginName);
+                    log.debug("Calling onSuccessCall of plugin {}", controlPluginName);
                     final OnSuccessPaymentControlResult result = plugin.onSuccessCall(inputPaymentControlContext, inputPluginProperties);
-                    log.debug("Successful executed onSuccessCall of plugin {}", pluginName);
+                    log.debug("Successful executed onSuccessCall of plugin {}", controlPluginName);
                     if (result == null) {
                         // Nothing returned by the plugin
                         continue;
@@ -206,9 +215,9 @@ public class ControlPluginRunner {
                     }
                     // Exceptions from the control plugins are ignored (and logged) because the semantics on what to do are undefined.
                 } catch (final PaymentControlApiException e) {
-                    log.warn("Error during onSuccessCall for plugin='{}', paymentExternalKey='{}'", pluginName, inputPaymentControlContext.getPaymentExternalKey(), e);
+                    log.warn("Error during onSuccessCall for plugin='{}', paymentExternalKey='{}'", controlPluginName, inputPaymentControlContext.getPaymentExternalKey(), e);
                 } catch (final RuntimeException e) {
-                    log.warn("Error during onSuccessCall for plugin='{}', paymentExternalKey='{}'", pluginName, inputPaymentControlContext.getPaymentExternalKey(), e);
+                    log.warn("Error during onSuccessCall for plugin='{}', paymentExternalKey='{}'", controlPluginName, inputPaymentControlContext.getPaymentExternalKey(), e);
                 }
             }
         }
@@ -217,6 +226,7 @@ public class ControlPluginRunner {
 
     public OnFailurePaymentControlResult executePluginOnFailureCalls(final Account account,
                                                                      final UUID paymentMethodId,
+                                                                     final String pluginName,
                                                                      final UUID paymentAttemptId,
                                                                      final UUID paymentId,
                                                                      final String paymentExternalKey,
@@ -236,6 +246,7 @@ public class ControlPluginRunner {
 
         final PaymentControlContext inputPaymentControlContext = new DefaultPaymentControlContext(account,
                                                                                                   paymentMethodId,
+                                                                                                  pluginName,
                                                                                                   paymentAttemptId,
                                                                                                   paymentId,
                                                                                                   paymentExternalKey,
@@ -254,13 +265,13 @@ public class ControlPluginRunner {
         DateTime candidate = null;
         Iterable<PluginProperty> inputPluginProperties = pluginProperties;
 
-        for (final String pluginName : paymentControlPluginNames) {
-            final PaymentControlPluginApi plugin = paymentControlPluginRegistry.getServiceForName(pluginName);
+        for (final String controlPluginName : paymentControlPluginNames) {
+            final PaymentControlPluginApi plugin = paymentControlPluginRegistry.getServiceForName(controlPluginName);
             if (plugin != null) {
                 try {
-                    log.debug("Calling onSuccessCall of plugin {}", pluginName);
+                    log.debug("Calling onSuccessCall of plugin {}", controlPluginName);
                     final OnFailurePaymentControlResult result = plugin.onFailureCall(inputPaymentControlContext, inputPluginProperties);
-                    log.debug("Successful executed onSuccessCall of plugin {}", pluginName);
+                    log.debug("Successful executed onSuccessCall of plugin {}", controlPluginName);
                     if (result == null) {
                         // Nothing returned by the plugin
                         continue;
@@ -277,7 +288,7 @@ public class ControlPluginRunner {
                     }
 
                 } catch (final PaymentControlApiException e) {
-                    log.warn("Error during onFailureCall for plugin='{}', paymentExternalKey='{}'", pluginName, inputPaymentControlContext.getPaymentExternalKey(), e);
+                    log.warn("Error during onFailureCall for plugin='{}', paymentExternalKey='{}'", controlPluginName, inputPaymentControlContext.getPaymentExternalKey(), e);
                     return new DefaultFailureCallResult(candidate, inputPluginProperties);
                 }
             }
@@ -289,6 +300,7 @@ public class ControlPluginRunner {
 
         private final Account account;
         private final UUID paymentMethodId;
+        private final String pluginName;
         private final UUID attemptId;
         private final UUID paymentId;
         private final String paymentExternalKey;
@@ -305,6 +317,7 @@ public class ControlPluginRunner {
 
         public DefaultPaymentControlContext(final Account account,
                                             final UUID paymentMethodId,
+                                            @Nullable String pluginName,
                                             final UUID attemptId,
                                             @Nullable final UUID paymentId,
                                             final String paymentExternalKey,
@@ -322,6 +335,7 @@ public class ControlPluginRunner {
             super(account.getId(), callContext.getTenantId(), callContext.getUserName(), callContext.getCallOrigin(), callContext.getUserType(), callContext.getReasonCode(), callContext.getComments(), callContext.getUserToken(), callContext.getCreatedDate(), callContext.getUpdatedDate());
             this.account = account;
             this.paymentMethodId = paymentMethodId;
+            this.pluginName = pluginName;
             this.attemptId = attemptId;
             this.paymentId = paymentId;
             this.paymentExternalKey = paymentExternalKey;
@@ -383,6 +397,11 @@ public class ControlPluginRunner {
         }
 
         @Override
+        public String getPaymentPluginName() {
+            return pluginName;
+        }
+
+        @Override
         public UUID getPaymentId() {
             return paymentId;
         }
@@ -416,6 +435,7 @@ public class ControlPluginRunner {
             return "DefaultPaymentControlContext{" +
                    "account=" + account +
                    ", paymentMethodId=" + paymentMethodId +
+                   ", pluginName=" + pluginName +
                    ", attemptId=" + attemptId +
                    ", paymentId=" + paymentId +
                    ", paymentExternalKey='" + paymentExternalKey + '\'' +
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/control/OperationControlCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/control/OperationControlCallback.java
index a562e32..65348af 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/control/OperationControlCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/control/OperationControlCallback.java
@@ -88,6 +88,7 @@ public abstract class OperationControlCallback extends OperationCallbackBase<Pay
 
                 final PaymentControlContext paymentControlContext = new DefaultPaymentControlContext(paymentStateContext.getAccount(),
                                                                                                      paymentStateContext.getPaymentMethodId(),
+                                                                                                     null,
                                                                                                      paymentStateControlContext.getAttemptId(),
                                                                                                      paymentStateContext.getPaymentId(),
                                                                                                      paymentStateContext.getPaymentExternalKey(),
@@ -123,6 +124,7 @@ public abstract class OperationControlCallback extends OperationCallbackBase<Pay
                     success = transaction.getTransactionStatus() == TransactionStatus.SUCCESS || transaction.getTransactionStatus() == TransactionStatus.PENDING;
                     final PaymentControlContext updatedPaymentControlContext = new DefaultPaymentControlContext(paymentStateContext.getAccount(),
                                                                                                                 paymentStateContext.getPaymentMethodId(),
+                                                                                                                null,
                                                                                                                 paymentStateControlContext.getAttemptId(),
                                                                                                                 result.getId(),
                                                                                                                 result.getExternalKey(),
@@ -173,6 +175,7 @@ public abstract class OperationControlCallback extends OperationCallbackBase<Pay
 
         final PriorPaymentControlResult result = controlPluginRunner.executePluginPriorCalls(paymentStateContext.getAccount(),
                                                                                              paymentControlContextArg.getPaymentMethodId(),
+                                                                                             null,
                                                                                              paymentStateControlContext.getAttemptId(),
                                                                                              paymentStateContext.getPaymentId(),
                                                                                              paymentStateContext.getPaymentExternalKey(),
@@ -199,6 +202,7 @@ public abstract class OperationControlCallback extends OperationCallbackBase<Pay
         // paymentId, paymentExternalKey, transactionAmount, transaction currency are extracted from  paymentControlContext which was update from the operation result.
         final OnSuccessPaymentControlResult result = controlPluginRunner.executePluginOnSuccessCalls(paymentStateContext.getAccount(),
                                                                                                      paymentStateContext.getPaymentMethodId(),
+                                                                                                     null,
                                                                                                      paymentStateControlContext.getAttemptId(),
                                                                                                      paymentControlContext.getPaymentId(),
                                                                                                      paymentControlContext.getPaymentExternalKey(),
@@ -230,6 +234,7 @@ public abstract class OperationControlCallback extends OperationCallbackBase<Pay
 
         final OnFailurePaymentControlResult result = controlPluginRunner.executePluginOnFailureCalls(paymentStateContext.getAccount(),
                                                                                                      paymentControlContext.getPaymentMethodId(),
+                                                                                                     null,
                                                                                                      paymentStateControlContext.getAttemptId(),
                                                                                                      paymentControlContext.getPaymentId(),
                                                                                                      paymentControlContext.getPaymentExternalKey(),
diff --git a/payment/src/main/java/org/killbill/billing/payment/retry/DefaultPriorPaymentControlResult.java b/payment/src/main/java/org/killbill/billing/payment/retry/DefaultPriorPaymentControlResult.java
index 27ce65b..4ab3d4b 100644
--- a/payment/src/main/java/org/killbill/billing/payment/retry/DefaultPriorPaymentControlResult.java
+++ b/payment/src/main/java/org/killbill/billing/payment/retry/DefaultPriorPaymentControlResult.java
@@ -30,22 +30,25 @@ public class DefaultPriorPaymentControlResult implements PriorPaymentControlResu
     private final BigDecimal adjustedRetryAmount;
     private final Currency adjustedCurrency;
     private final UUID adjustedPaymentMethodId;
+    private final String adjustedPaymentPluginName;
     private final Iterable<PluginProperty> adjustedPluginProperties;
 
     public DefaultPriorPaymentControlResult(final boolean isAborted,
                                             final BigDecimal adjustedRetryAmount,
                                             final Currency adjustedCurrency,
                                             final UUID adjustedPaymentMethodId,
+                                            final String adjustedPaymentPluginName,
                                             final Iterable<PluginProperty> adjustedPluginProperties) {
         this.isAborted = isAborted;
         this.adjustedRetryAmount = adjustedRetryAmount;
         this.adjustedCurrency = adjustedCurrency;
         this.adjustedPaymentMethodId = adjustedPaymentMethodId;
         this.adjustedPluginProperties = adjustedPluginProperties;
+        this.adjustedPaymentPluginName = adjustedPaymentPluginName;
     }
 
     public DefaultPriorPaymentControlResult(final boolean isAborted, final BigDecimal adjustedRetryAmount) {
-        this(isAborted, adjustedRetryAmount, null, null, null);
+        this(isAborted, adjustedRetryAmount, null, null, null, null);
     }
 
     public DefaultPriorPaymentControlResult(final boolean isAborted) {
@@ -53,8 +56,8 @@ public class DefaultPriorPaymentControlResult implements PriorPaymentControlResu
     }
 
 
-    public DefaultPriorPaymentControlResult(final boolean isAborted, final UUID adjustedPaymentMethodId, final BigDecimal adjustedAmount, final Currency adjustedCurrency, final Iterable<PluginProperty> adjustedPluginProperties) {
-        this(isAborted, adjustedAmount, adjustedCurrency, adjustedPaymentMethodId, adjustedPluginProperties);
+    public DefaultPriorPaymentControlResult(final boolean isAborted, final UUID adjustedPaymentMethodId, final String adjustedPaymentPluginName, final BigDecimal adjustedAmount, final Currency adjustedCurrency, final Iterable<PluginProperty> adjustedPluginProperties) {
+        this(isAborted, adjustedAmount, adjustedCurrency, adjustedPaymentMethodId, adjustedPaymentPluginName, adjustedPluginProperties);
     }
 
     @Override
@@ -78,6 +81,11 @@ public class DefaultPriorPaymentControlResult implements PriorPaymentControlResu
     }
 
     @Override
+    public String getAdjustedPluginName() {
+        return adjustedPaymentPluginName;
+    }
+
+    @Override
     public Iterable<PluginProperty> getAdjustedPluginProperties() {
         return adjustedPluginProperties;
     }
diff --git a/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApiWithControl.java b/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApiWithControl.java
index 545fcc4..22fd0b3 100644
--- a/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApiWithControl.java
+++ b/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApiWithControl.java
@@ -645,6 +645,28 @@ public class TestPaymentApiWithControl extends PaymentTestSuiteWithEmbeddedDB {
                                               Currency.USD);
     }
 
+    @Test(groups = "slow")
+    public void testAddPaymentMethodWithControl() throws PaymentApiException {
+        final PaymentMethodPlugin paymentMethodInfo = new DefaultNoOpPaymentMethodPlugin(UUID.randomUUID().toString(), false, null);
+        testPaymentControlPluginApi.setNewPaymentMethodName(MockPaymentProviderPlugin.PLUGIN_NAME);
+        final UUID newPaymentMethodId = paymentApi.addPaymentMethodWithPaymentControl(account, null, "SomeDummyValueToBeChanged", false, paymentMethodInfo, ImmutableList.<PluginProperty>of(), PAYMENT_OPTIONS, callContext);
+
+
+        final PaymentMethod paymentMethod = paymentApi.getPaymentMethodById(newPaymentMethodId, false, false, ImmutableList.<PluginProperty>of(), callContext);
+        Assert.assertEquals(paymentMethod.getPluginName(), MockPaymentProviderPlugin.PLUGIN_NAME);
+
+        final Payment payment = paymentApi.createAuthorizationWithPaymentControl(account, newPaymentMethodId, null, BigDecimal.TEN, Currency.USD, UUID.randomUUID().toString(),
+                                                                                 UUID.randomUUID().toString(), ImmutableList.<PluginProperty>of(), PAYMENT_OPTIONS, callContext);
+        Assert.assertEquals(payment.getPaymentMethodId(), newPaymentMethodId);
+
+        verifyOnSuccess(payment.getId(),
+                        payment.getExternalKey(),
+                        payment.getTransactions().get(0).getId(),
+                        payment.getTransactions().get(0).getExternalKey(),
+                        BigDecimal.TEN,
+                        Currency.USD);
+    }
+
     private void verifyPriorAndOnSuccess(final UUID paymentId,
                                          final String paymentExternalKey,
                                          final UUID paymentTransactionId,
@@ -830,6 +852,7 @@ public class TestPaymentApiWithControl extends PaymentTestSuiteWithEmbeddedDB {
         public static final String PLUGIN_NAME = "TEST_CONTROL_API_PLUGIN_NAME";
 
         private UUID newPaymentMethodId;
+        private String newPaymentMethodName;
 
         private UUID actualPriorCallPaymentId;
         private String actualPriorCallPaymentExternalKey;
@@ -856,6 +879,10 @@ public class TestPaymentApiWithControl extends PaymentTestSuiteWithEmbeddedDB {
             this.newPaymentMethodId = newPaymentMethodId;
         }
 
+        public void setNewPaymentMethodName(final String newPaymentMethodName) {
+            this.newPaymentMethodName = newPaymentMethodName;
+        }
+
         public UUID getActualPriorCallPaymentId() {
             return actualPriorCallPaymentId;
         }
@@ -959,6 +986,11 @@ public class TestPaymentApiWithControl extends PaymentTestSuiteWithEmbeddedDB {
                 }
 
                 @Override
+                public String getAdjustedPluginName() {
+                    return newPaymentMethodName;
+                }
+
+                @Override
                 public Iterable<PluginProperty> getAdjustedPluginProperties() {
                     return null;
                 }
diff --git a/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentGatewayApiWithPaymentControl.java b/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentGatewayApiWithPaymentControl.java
index 3aa3554..4698e0d 100644
--- a/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentGatewayApiWithPaymentControl.java
+++ b/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentGatewayApiWithPaymentControl.java
@@ -257,7 +257,7 @@ public class TestPaymentGatewayApiWithPaymentControl extends PaymentTestSuiteNoD
 
         @Override
         public PriorPaymentControlResult priorCall(final PaymentControlContext paymentControlContext, final Iterable<PluginProperty> properties) throws PaymentControlApiException {
-            return new DefaultPriorPaymentControlResult(aborted, account.getPaymentMethodId(), null, null, getAdjustedProperties(properties, newPriorCallProperties, removedPriorCallProperties));
+            return new DefaultPriorPaymentControlResult(aborted, account.getPaymentMethodId(), null, null, null, getAdjustedProperties(properties, newPriorCallProperties, removedPriorCallProperties));
         }
 
         @Override
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/sm/control/TestControlPluginRunner.java b/payment/src/test/java/org/killbill/billing/payment/core/sm/control/TestControlPluginRunner.java
index 80cb640..1e114e4 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/sm/control/TestControlPluginRunner.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/sm/control/TestControlPluginRunner.java
@@ -54,6 +54,7 @@ public class TestControlPluginRunner extends PaymentTestSuiteNoDB {
         final PriorPaymentControlResult paymentControlResult = controlPluginRunner.executePluginPriorCalls(account,
                                                                                                            paymentMethodId,
                                                                                                            null,
+                                                                                                           null,
                                                                                                            paymentId,
                                                                                                            paymentExternalKey,
                                                                                                            paymentTransactionId,
diff --git a/payment/src/test/java/org/killbill/billing/payment/provider/MockPaymentControlProviderPlugin.java b/payment/src/test/java/org/killbill/billing/payment/provider/MockPaymentControlProviderPlugin.java
index f451943..f7c949e 100644
--- a/payment/src/test/java/org/killbill/billing/payment/provider/MockPaymentControlProviderPlugin.java
+++ b/payment/src/test/java/org/killbill/billing/payment/provider/MockPaymentControlProviderPlugin.java
@@ -77,7 +77,7 @@ public class MockPaymentControlProviderPlugin implements PaymentControlPluginApi
         } else if (exception instanceof RuntimeException) {
             throw (RuntimeException) exception;
         }
-        return new DefaultPriorPaymentControlResult(isAborted, adjustedPaymentMethodId, null, null, null);
+        return new DefaultPriorPaymentControlResult(isAborted, adjustedPaymentMethodId, null, null, null, null);
     }
 
     @Override