killbill-memoizeit

payment: cleanup payment method and plugins retrieval code This

3/14/2017 5:54:16 AM

Changes

Details

diff --git a/payment/src/main/java/org/killbill/billing/payment/core/janitor/CompletionTaskBase.java b/payment/src/main/java/org/killbill/billing/payment/core/janitor/CompletionTaskBase.java
index 71fee5f..f29b8b6 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/janitor/CompletionTaskBase.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/janitor/CompletionTaskBase.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -25,11 +25,9 @@ import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.DefaultCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.events.PaymentInternalEvent;
-import org.killbill.billing.osgi.api.OSGIServiceRegistration;
 import org.killbill.billing.payment.core.sm.PaymentControlStateMachineHelper;
 import org.killbill.billing.payment.core.sm.PaymentStateMachineHelper;
 import org.killbill.billing.payment.dao.PaymentDao;
-import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
 import org.killbill.billing.util.UUIDs;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.CallOrigin;
@@ -57,17 +55,20 @@ abstract class CompletionTaskBase<T> implements Runnable {
     protected final PaymentStateMachineHelper paymentStateMachineHelper;
     protected final PaymentControlStateMachineHelper retrySMHelper;
     protected final AccountInternalApi accountInternalApi;
-    protected final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry;
     protected final GlobalLocker locker;
 
     protected NotificationQueue janitorQueue;
 
     private volatile boolean isStopped;
 
-    public CompletionTaskBase(final InternalCallContextFactory internalCallContextFactory, final PaymentConfig paymentConfig,
-                              final PaymentDao paymentDao, final Clock clock, final PaymentStateMachineHelper paymentStateMachineHelper,
-                              final PaymentControlStateMachineHelper retrySMHelper, final AccountInternalApi accountInternalApi,
-                              final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry, final GlobalLocker locker) {
+    public CompletionTaskBase(final InternalCallContextFactory internalCallContextFactory,
+                              final PaymentConfig paymentConfig,
+                              final PaymentDao paymentDao,
+                              final Clock clock,
+                              final PaymentStateMachineHelper paymentStateMachineHelper,
+                              final PaymentControlStateMachineHelper retrySMHelper,
+                              final AccountInternalApi accountInternalApi,
+                              final GlobalLocker locker) {
         this.internalCallContextFactory = internalCallContextFactory;
         this.paymentConfig = paymentConfig;
         this.paymentDao = paymentDao;
@@ -75,7 +76,6 @@ abstract class CompletionTaskBase<T> implements Runnable {
         this.paymentStateMachineHelper = paymentStateMachineHelper;
         this.retrySMHelper = retrySMHelper;
         this.accountInternalApi = accountInternalApi;
-        this.pluginRegistry = pluginRegistry;
         this.locker = locker;
         this.isStopped = false;
     }
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/janitor/IncompletePaymentAttemptTask.java b/payment/src/main/java/org/killbill/billing/payment/core/janitor/IncompletePaymentAttemptTask.java
index 568ec94..400b332 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/janitor/IncompletePaymentAttemptTask.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/janitor/IncompletePaymentAttemptTask.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -28,7 +28,6 @@ import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.events.PaymentInternalEvent;
-import org.killbill.billing.osgi.api.OSGIServiceRegistration;
 import org.killbill.billing.payment.api.PaymentApiException;
 import org.killbill.billing.payment.api.TransactionStatus;
 import org.killbill.billing.payment.core.sm.PaymentControlStateMachineHelper;
@@ -40,7 +39,6 @@ import org.killbill.billing.payment.dao.PaymentDao;
 import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
 import org.killbill.billing.payment.dao.PluginPropertySerializer;
 import org.killbill.billing.payment.dao.PluginPropertySerializer.PluginPropertySerializerException;
-import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.config.definition.PaymentConfig;
@@ -82,9 +80,8 @@ public class IncompletePaymentAttemptTask extends CompletionTaskBase<PaymentAtte
                                         final PaymentControlStateMachineHelper retrySMHelper,
                                         final AccountInternalApi accountInternalApi,
                                         final PluginControlPaymentAutomatonRunner pluginControlledPaymentAutomatonRunner,
-                                        final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry,
                                         final GlobalLocker locker) {
-        super(internalCallContextFactory, paymentConfig, paymentDao, clock, paymentStateMachineHelper, retrySMHelper, accountInternalApi, pluginRegistry, locker);
+        super(internalCallContextFactory, paymentConfig, paymentDao, clock, paymentStateMachineHelper, retrySMHelper, accountInternalApi, locker);
         this.pluginControlledPaymentAutomatonRunner = pluginControlledPaymentAutomatonRunner;
     }
 
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/janitor/IncompletePaymentTransactionTask.java b/payment/src/main/java/org/killbill/billing/payment/core/janitor/IncompletePaymentTransactionTask.java
index 72f050f..b49b5f7 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/janitor/IncompletePaymentTransactionTask.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/janitor/IncompletePaymentTransactionTask.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -31,14 +31,13 @@ import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.events.PaymentInternalEvent;
-import org.killbill.billing.osgi.api.OSGIServiceRegistration;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.killbill.billing.payment.api.TransactionStatus;
+import org.killbill.billing.payment.core.PaymentPluginServiceRegistration;
 import org.killbill.billing.payment.core.PaymentTransactionInfoPluginConverter;
 import org.killbill.billing.payment.core.sm.PaymentControlStateMachineHelper;
 import org.killbill.billing.payment.core.sm.PaymentStateMachineHelper;
 import org.killbill.billing.payment.dao.PaymentDao;
-import org.killbill.billing.payment.dao.PaymentMethodModelDao;
 import org.killbill.billing.payment.dao.PaymentModelDao;
 import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
 import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
@@ -59,7 +58,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableList;
@@ -74,12 +72,20 @@ public class IncompletePaymentTransactionTask extends CompletionTaskBase<Payment
                                                                                                           .add(TransactionStatus.UNKNOWN)
                                                                                                           .build();
 
+    private final PaymentPluginServiceRegistration paymentPluginServiceRegistration;
+
     @Inject
-    public IncompletePaymentTransactionTask(final InternalCallContextFactory internalCallContextFactory, final PaymentConfig paymentConfig,
-                                            final PaymentDao paymentDao, final Clock clock,
-                                            final PaymentStateMachineHelper paymentStateMachineHelper, final PaymentControlStateMachineHelper retrySMHelper, final AccountInternalApi accountInternalApi,
-                                            final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry, final GlobalLocker locker) {
-        super(internalCallContextFactory, paymentConfig, paymentDao, clock, paymentStateMachineHelper, retrySMHelper, accountInternalApi, pluginRegistry, locker);
+    public IncompletePaymentTransactionTask(final InternalCallContextFactory internalCallContextFactory,
+                                            final PaymentConfig paymentConfig,
+                                            final PaymentDao paymentDao,
+                                            final Clock clock,
+                                            final PaymentStateMachineHelper paymentStateMachineHelper,
+                                            final PaymentControlStateMachineHelper retrySMHelper,
+                                            final AccountInternalApi accountInternalApi,
+                                            final PaymentPluginServiceRegistration paymentPluginServiceRegistration,
+                                            final GlobalLocker locker) {
+        super(internalCallContextFactory, paymentConfig, paymentDao, clock, paymentStateMachineHelper, retrySMHelper, accountInternalApi, locker);
+        this.paymentPluginServiceRegistration = paymentPluginServiceRegistration;
     }
 
     @Override
@@ -113,9 +119,6 @@ public class IncompletePaymentTransactionTask extends CompletionTaskBase<Payment
                 final TenantContext tenantContext = internalCallContextFactory.createTenantContext(internalTenantContext);
                 final PaymentModelDao payment = paymentDao.getPayment(rehydratedPaymentTransaction.getPaymentId(), internalTenantContext);
 
-                final PaymentMethodModelDao paymentMethod = paymentDao.getPaymentMethod(payment.getPaymentMethodId(), internalTenantContext);
-                final PaymentPluginApi paymentPluginApi = getPaymentPluginApi(payment, paymentMethod.getPluginName());
-
                 final PaymentTransactionInfoPlugin undefinedPaymentTransaction = new DefaultNoOpPaymentInfoPlugin(payment.getId(),
                                                                                                                   rehydratedPaymentTransaction.getId(),
                                                                                                                   rehydratedPaymentTransaction.getTransactionType(),
@@ -128,6 +131,7 @@ public class IncompletePaymentTransactionTask extends CompletionTaskBase<Payment
                                                                                                                   null);
                 PaymentTransactionInfoPlugin paymentTransactionInfoPlugin;
                 try {
+                    final PaymentPluginApi paymentPluginApi = paymentPluginServiceRegistration.getPaymentPluginApi(payment.getPaymentMethodId(), false, internalTenantContext);
                     final List<PaymentTransactionInfoPlugin> result = paymentPluginApi.getPaymentInfo(payment.getAccountId(), payment.getId(), ImmutableList.<PluginProperty>of(), tenantContext);
                     paymentTransactionInfoPlugin = Iterables.tryFind(result, new Predicate<PaymentTransactionInfoPlugin>() {
                         @Override
@@ -261,12 +265,6 @@ public class IncompletePaymentTransactionTask extends CompletionTaskBase<Payment
         return (newTransactionStatus != TransactionStatus.UNKNOWN) ? newTransactionStatus : currentTransactionStatus;
     }
 
-    private PaymentPluginApi getPaymentPluginApi(final PaymentModelDao item, final String pluginName) {
-        final PaymentPluginApi pluginApi = pluginRegistry.getServiceForName(pluginName);
-        Preconditions.checkState(pluginApi != null, "Janitor IncompletePaymentTransactionTask cannot retrieve PaymentPluginApi for plugin %s (payment id %s), skipping", pluginName, item.getId());
-        return pluginApi;
-    }
-
     @VisibleForTesting
     DateTime getNextNotificationTime(final Integer attemptNumber, final InternalTenantContext tenantContext) {
 
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PaymentGatewayProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PaymentGatewayProcessor.java
index ea40106..1ae2416 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PaymentGatewayProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PaymentGatewayProcessor.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -29,7 +29,6 @@ import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.invoice.api.InvoiceInternalApi;
-import org.killbill.billing.osgi.api.OSGIServiceRegistration;
 import org.killbill.billing.payment.api.PaymentApiException;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.killbill.billing.payment.dao.PaymentDao;
@@ -58,7 +57,7 @@ public class PaymentGatewayProcessor extends ProcessorBase {
     private final PluginDispatcher<GatewayNotification> paymentPluginNotificationDispatcher;
 
     @Inject
-    public PaymentGatewayProcessor(final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry,
+    public PaymentGatewayProcessor(final PaymentPluginServiceRegistration paymentPluginServiceRegistration,
                                    final AccountInternalApi accountUserApi,
                                    final InvoiceInternalApi invoiceApi,
                                    final TagInternalApi tagUserApi,
@@ -68,26 +67,27 @@ public class PaymentGatewayProcessor extends ProcessorBase {
                                    final PaymentExecutors executors,
                                    final InternalCallContextFactory internalCallContextFactory,
                                    final Clock clock) {
-        super(pluginRegistry, accountUserApi, paymentDao, tagUserApi, locker, internalCallContextFactory, invoiceApi, clock);
+        super(paymentPluginServiceRegistration, accountUserApi, paymentDao, tagUserApi, locker, internalCallContextFactory, invoiceApi, clock);
         final long paymentPluginTimeoutSec = TimeUnit.SECONDS.convert(paymentConfig.getPaymentPluginTimeout().getPeriod(), paymentConfig.getPaymentPluginTimeout().getUnit());
         this.paymentPluginFormDispatcher = new PluginDispatcher<HostedPaymentPageFormDescriptor>(paymentPluginTimeoutSec, executors);
         this.paymentPluginNotificationDispatcher = new PluginDispatcher<GatewayNotification>(paymentPluginTimeoutSec, executors);
     }
 
     public GatewayNotification processNotification(final boolean shouldDispatch, final String notification, final UUID paymentMethodId, final Iterable<PluginProperty> properties, final CallContext callContext) throws PaymentApiException {
-        final String pluginName = getPaymentProviderPluginName(paymentMethodId, internalCallContextFactory.createInternalCallContext(paymentMethodId, ObjectType.PAYMENT_METHOD, callContext));
+        final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(paymentMethodId, ObjectType.PAYMENT_METHOD, callContext);
+        final String pluginName = getPaymentMethodById(paymentMethodId, true, internalCallContext).getPluginName();
         return processNotification(shouldDispatch, notification, pluginName, properties, callContext);
     }
 
     public GatewayNotification processNotification(final boolean shouldDispatch, final String notification, final String pluginName, final Iterable<PluginProperty> properties, final CallContext callContext) throws PaymentApiException {
+        final PaymentPluginApi plugin = getPaymentPluginApi(pluginName);
+
         if (shouldDispatch) {
             return dispatchWithExceptionHandling(null,
                                                  pluginName,
                                                  new Callable<PluginDispatcherReturnType<GatewayNotification>>() {
                                                      @Override
                                                      public PluginDispatcherReturnType<GatewayNotification> call() throws PaymentApiException {
-                                                         final PaymentPluginApi plugin = getPaymentPluginApi(pluginName);
-
                                                          try {
                                                              final GatewayNotification result = plugin.processNotification(notification, properties, callContext);
                                                              return PluginDispatcher.createPluginDispatcherReturnType(result == null ? new DefaultNoOpGatewayNotification() : result);
@@ -97,7 +97,6 @@ public class PaymentGatewayProcessor extends ProcessorBase {
                                                      }
                                                  }, paymentPluginNotificationDispatcher);
         } else {
-            final PaymentPluginApi plugin = getPaymentPluginApi(pluginName);
             try {
                 return plugin.processNotification(notification, properties, callContext);
             } catch (final PaymentPluginApiException e) {
@@ -107,7 +106,8 @@ public class PaymentGatewayProcessor extends ProcessorBase {
     }
 
     public HostedPaymentPageFormDescriptor buildFormDescriptor(final boolean shouldDispatch, final Account account, final UUID paymentMethodId, final Iterable<PluginProperty> customFields, final Iterable<PluginProperty> properties, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
-        final String pluginName = getPaymentProviderPluginName(paymentMethodId, internalCallContext);
+        final String pluginName = getPaymentMethodById(paymentMethodId, true, internalCallContext).getPluginName();
+        final PaymentPluginApi plugin = getPaymentPluginApi(pluginName);
 
         if (shouldDispatch) {
             return dispatchWithExceptionHandling(account,
@@ -115,8 +115,6 @@ public class PaymentGatewayProcessor extends ProcessorBase {
                                                  new Callable<PluginDispatcherReturnType<HostedPaymentPageFormDescriptor>>() {
                                                      @Override
                                                      public PluginDispatcherReturnType<HostedPaymentPageFormDescriptor> call() throws PaymentApiException {
-                                                         final PaymentPluginApi plugin = getPaymentPluginApi(pluginName);
-
                                                          try {
                                                              final HostedPaymentPageFormDescriptor result = plugin.buildFormDescriptor(account.getId(), customFields, properties, callContext);
                                                              return PluginDispatcher.createPluginDispatcherReturnType(result == null ? new DefaultNoOpHostedPaymentPageFormDescriptor(account.getId()) : result);
@@ -128,7 +126,6 @@ public class PaymentGatewayProcessor extends ProcessorBase {
                                                      }
                                                  }, paymentPluginFormDispatcher);
         } else {
-            final PaymentPluginApi plugin = getPaymentPluginApi(pluginName);
             try {
                 return plugin.buildFormDescriptor(account.getId(), customFields, properties, callContext);
             } catch (final PaymentPluginApiException e) {
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 ebc4fe5..6c308f0 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
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -34,7 +34,6 @@ import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.invoice.api.InvoiceInternalApi;
-import org.killbill.billing.osgi.api.OSGIServiceRegistration;
 import org.killbill.billing.payment.api.DefaultPaymentMethod;
 import org.killbill.billing.payment.api.PaymentApiException;
 import org.killbill.billing.payment.api.PaymentMethod;
@@ -87,7 +86,7 @@ public class PaymentMethodProcessor extends ProcessorBase {
     private final PaymentConfig paymentConfig;
 
     @Inject
-    public PaymentMethodProcessor(final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry,
+    public PaymentMethodProcessor(final PaymentPluginServiceRegistration paymentPluginServiceRegistration,
                                   final AccountInternalApi accountInternalApi,
                                   final InvoiceInternalApi invoiceApi,
                                   final PaymentDao paymentDao,
@@ -97,7 +96,7 @@ public class PaymentMethodProcessor extends ProcessorBase {
                                   final PaymentExecutors executors,
                                   final InternalCallContextFactory internalCallContextFactory,
                                   final Clock clock) {
-        super(pluginRegistry, accountInternalApi, paymentDao, tagUserApi, locker, internalCallContextFactory, invoiceApi, 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.uuidPluginNotificationDispatcher = new PluginDispatcher<UUID>(paymentPluginTimeoutSec, executors);
@@ -186,7 +185,13 @@ public class PaymentMethodProcessor extends ProcessorBase {
         if (paymentMethodPlugin != null && paymentMethodPlugin.getExternalPaymentMethodId() != null) {
             // An external payment method id is set but make sure it doesn't conflict with an existing one
             final String externalKey = paymentMethodPlugin.getExternalPaymentMethodId();
-            return paymentDao.getPaymentMethodByExternalKeyIncludedDeleted(externalKey, context) == null ? externalKey : null;
+            try {
+                @SuppressWarnings("unused")
+                final PaymentMethodModelDao paymentMethodModelDao = getPaymentMethodByExternalKey(externalKey, true, context);
+                return null;
+            } catch (final PaymentApiException e) {
+                return externalKey;
+            }
         } else {
             return null;
         }
@@ -206,20 +211,13 @@ public class PaymentMethodProcessor extends ProcessorBase {
 
     public PaymentMethod getPaymentMethodById(final UUID paymentMethodId, final boolean includedDeleted, final boolean withPluginInfo, final Iterable<PluginProperty> properties, final TenantContext tenantContext, final InternalTenantContext context)
             throws PaymentApiException {
-        final PaymentMethodModelDao paymentMethodModel = includedDeleted ? paymentDao.getPaymentMethodIncludedDeleted(paymentMethodId, context) : paymentDao.getPaymentMethod(paymentMethodId, context);
-        if (paymentMethodModel == null) {
-            throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, paymentMethodId);
-        }
-
+        final PaymentMethodModelDao paymentMethodModel = getPaymentMethodById(paymentMethodId, includedDeleted, context);
         return buildDefaultPaymentMethod(paymentMethodModel, withPluginInfo, properties, tenantContext, context);
     }
 
     public PaymentMethod getPaymentMethodByExternalKey(final String paymentMethodExternalKey, final boolean includedDeleted, final boolean withPluginInfo, final Iterable<PluginProperty> properties, final TenantContext tenantContext, final InternalTenantContext context)
             throws PaymentApiException {
-        final PaymentMethodModelDao paymentMethodModel = includedDeleted ? paymentDao.getPaymentMethodByExternalKeyIncludedDeleted(paymentMethodExternalKey, context) : paymentDao.getPaymentMethodByExternalKey(paymentMethodExternalKey, context);
-        if (paymentMethodModel == null) {
-            throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, paymentMethodExternalKey);
-        }
+        final PaymentMethodModelDao paymentMethodModel = getPaymentMethodByExternalKey(paymentMethodExternalKey, includedDeleted, context);
         return buildDefaultPaymentMethod(paymentMethodModel, withPluginInfo, properties, tenantContext, context);
     }
 
@@ -407,10 +405,8 @@ public class PaymentMethodProcessor extends ProcessorBase {
 
                 @Override
                 public PluginDispatcherReturnType<Void> doOperation() throws PaymentApiException {
-                    final PaymentMethodModelDao paymentMethodModel = paymentDao.getPaymentMethod(paymentMethodId, context);
-                    if (paymentMethodModel == null) {
-                        throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, paymentMethodId);
-                    }
+                    @SuppressWarnings("unused")
+                    final PaymentMethodModelDao paymentMethodModel = getPaymentMethodById(paymentMethodId, false, context);
 
                     try {
                         // Note: account.getPaymentMethodId() may be null
@@ -425,7 +421,7 @@ public class PaymentMethodProcessor extends ProcessorBase {
                                 accountInternalApi.removePaymentMethod(account.getId(), context);
                             }
                         }
-                        final PaymentPluginApi pluginApi = getPluginApi(paymentMethodId, context);
+                        final PaymentPluginApi pluginApi = getPaymentProviderPlugin(paymentMethodId, false, context);
                         pluginApi.deletePaymentMethod(account.getId(), paymentMethodId, properties, callContext);
                         paymentDao.deletedPaymentMethod(paymentMethodId, context);
                         return PluginDispatcher.createPluginDispatcherReturnType(null);
@@ -448,17 +444,14 @@ public class PaymentMethodProcessor extends ProcessorBase {
 
                 @Override
                 public PluginDispatcherReturnType<Void> doOperation() throws PaymentApiException {
-                    final PaymentMethodModelDao paymentMethodModel = paymentDao.getPaymentMethod(paymentMethodId, context);
-                    if (paymentMethodModel == null) {
-                        throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, paymentMethodId);
-                    }
+                    final PaymentMethodModelDao paymentMethodModel = getPaymentMethodById(paymentMethodId, false, context);
 
                     if (!paymentMethodModel.getAccountId().equals(account.getId())) {
                         throw new PaymentApiException(ErrorCode.PAYMENT_METHOD_DIFFERENT_ACCOUNT_ID, paymentMethodId);
                     }
 
                     try {
-                        final PaymentPluginApi pluginApi = getPluginApi(paymentMethodId, context);
+                        final PaymentPluginApi pluginApi = getPaymentProviderPlugin(paymentMethodId, false, context);
 
                         pluginApi.setDefaultPaymentMethod(account.getId(), paymentMethodId, properties, callContext);
                         accountInternalApi.updatePaymentMethod(account.getId(), paymentMethodId, context);
@@ -475,15 +468,6 @@ public class PaymentMethodProcessor extends ProcessorBase {
         }
     }
 
-    private PaymentPluginApi getPluginApi(final UUID paymentMethodId, final InternalTenantContext context)
-            throws PaymentApiException {
-        final PaymentMethodModelDao paymentMethod = paymentDao.getPaymentMethod(paymentMethodId, context);
-        if (paymentMethod == null) {
-            throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, paymentMethodId);
-        }
-        return getPaymentPluginApi(paymentMethod.getPluginName());
-    }
-
     /**
      * This refreshed the payment methods from the plugin for cases when adding payment method does not flow through KB because of PCI compliance
      * issues. The logic below is not optimal because there is no atomicity in the step but the good news is that this is idempotent so can always be
@@ -580,7 +564,7 @@ public class PaymentMethodProcessor extends ProcessorBase {
 
         boolean shouldUpdateDefaultPaymentMethod = true;
         if (account.getPaymentMethodId() != null) {
-            final PaymentMethodModelDao currentDefaultPaymentMethod = paymentDao.getPaymentMethod(account.getPaymentMethodId(), context);
+            final PaymentMethodModelDao currentDefaultPaymentMethod = getPaymentMethodById(account.getPaymentMethodId(), false, context);
             shouldUpdateDefaultPaymentMethod = pluginName.equals(currentDefaultPaymentMethod.getPluginName());
         }
         if (shouldUpdateDefaultPaymentMethod) {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PaymentPluginServiceRegistration.java b/payment/src/main/java/org/killbill/billing/payment/core/PaymentPluginServiceRegistration.java
new file mode 100644
index 0000000..016be05
--- /dev/null
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PaymentPluginServiceRegistration.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2017 Groupon, Inc
+ * Copyright 2017 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.payment.core;
+
+import java.util.Set;
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import org.killbill.billing.ErrorCode;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.osgi.api.OSGIServiceRegistration;
+import org.killbill.billing.payment.api.PaymentApiException;
+import org.killbill.billing.payment.dao.PaymentDao;
+import org.killbill.billing.payment.dao.PaymentMethodModelDao;
+import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
+
+public class PaymentPluginServiceRegistration {
+
+    private final PaymentDao paymentDao;
+    private final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry;
+
+    @Inject
+    public PaymentPluginServiceRegistration(final PaymentDao paymentDao, final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry) {
+        this.paymentDao = paymentDao;
+        this.pluginRegistry = pluginRegistry;
+    }
+
+    public Set<String> getAvailablePlugins() {
+        return pluginRegistry.getAllServices();
+    }
+
+    public PaymentMethodModelDao getPaymentMethodById(final UUID paymentMethodId, final boolean includedDeleted, final InternalTenantContext context) throws PaymentApiException {
+        final PaymentMethodModelDao paymentMethodModel;
+        if (includedDeleted) {
+            paymentMethodModel = paymentDao.getPaymentMethodIncludedDeleted(paymentMethodId, context);
+        } else {
+            paymentMethodModel = paymentDao.getPaymentMethod(paymentMethodId, context);
+        }
+
+        if (paymentMethodModel == null) {
+            throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, paymentMethodId);
+        }
+
+        return paymentMethodModel;
+    }
+
+    public PaymentMethodModelDao getPaymentMethodByExternalKey(final String paymentMethodExternalKey, final boolean includedDeleted, final InternalTenantContext context) throws PaymentApiException {
+        final PaymentMethodModelDao paymentMethodModel;
+        if (includedDeleted) {
+            paymentMethodModel = paymentDao.getPaymentMethodByExternalKeyIncludedDeleted(paymentMethodExternalKey, context);
+        } else {
+            paymentMethodModel = paymentDao.getPaymentMethodByExternalKey(paymentMethodExternalKey, context);
+        }
+
+        if (paymentMethodModel == null) {
+            throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, paymentMethodExternalKey);
+        }
+        return paymentMethodModel;
+    }
+
+    public PaymentPluginApi getPaymentPluginApi(final UUID paymentMethodId, final boolean includedDeleted, final InternalTenantContext context) throws PaymentApiException {
+        final PaymentMethodModelDao paymentMethodModelDao = getPaymentMethodById(paymentMethodId, includedDeleted, context);
+        return getPaymentPluginApi(paymentMethodModelDao.getPluginName());
+    }
+
+    public PaymentPluginApi getPaymentPluginApi(final String pluginName) throws PaymentApiException {
+        final PaymentPluginApi pluginApi = pluginRegistry.getServiceForName(pluginName);
+        if (pluginApi == null) {
+            throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_PLUGIN, pluginName);
+        }
+        return pluginApi;
+    }
+}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
index b35e99a..68b6f91 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
@@ -41,7 +41,6 @@ import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.invoice.api.InvoiceInternalApi;
-import org.killbill.billing.osgi.api.OSGIServiceRegistration;
 import org.killbill.billing.payment.api.DefaultPayment;
 import org.killbill.billing.payment.api.DefaultPaymentAttempt;
 import org.killbill.billing.payment.api.DefaultPaymentTransaction;
@@ -114,7 +113,7 @@ public class PaymentProcessor extends ProcessorBase {
 
 
     @Inject
-    public PaymentProcessor(final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry,
+    public PaymentProcessor(final PaymentPluginServiceRegistration paymentPluginServiceRegistration,
                             final AccountInternalApi accountUserApi,
                             final InvoiceInternalApi invoiceApi,
                             final TagInternalApi tagUserApi,
@@ -125,7 +124,7 @@ public class PaymentProcessor extends ProcessorBase {
                             final IncompletePaymentTransactionTask incompletePaymentTransactionTask,
                             final NotificationQueueService notificationQueueService,
                             final Clock clock) {
-        super(pluginRegistry, accountUserApi, paymentDao, tagUserApi, locker, internalCallContextFactory, invoiceApi, clock);
+        super(paymentPluginServiceRegistration, accountUserApi, paymentDao, tagUserApi, locker, internalCallContextFactory, invoiceApi, clock);
         this.paymentAutomatonRunner = paymentAutomatonRunner;
         this.incompletePaymentTransactionTask = incompletePaymentTransactionTask;
         this.notificationQueueService = notificationQueueService;
@@ -206,7 +205,7 @@ public class PaymentProcessor extends ProcessorBase {
                                                                                                         PaymentPluginApi pluginApi = paymentPluginByPaymentMethodId.get(paymentModelDao.getPaymentMethodId());
                                                                                                         if (pluginApi == null && !absentPlugins.contains(paymentModelDao.getPaymentMethodId())) {
                                                                                                             try {
-                                                                                                                pluginApi = getPaymentProviderPlugin(paymentModelDao.getPaymentMethodId(), tenantContext);
+                                                                                                                pluginApi = getPaymentProviderPlugin(paymentModelDao.getPaymentMethodId(), true, tenantContext);
                                                                                                                 paymentPluginByPaymentMethodId.put(paymentModelDao.getPaymentMethodId(), pluginApi);
                                                                                                             } catch (final PaymentApiException e) {
                                                                                                                 log.warn("Unable to retrieve pluginApi for payment method " + paymentModelDao.getPaymentMethodId());
@@ -263,7 +262,7 @@ public class PaymentProcessor extends ProcessorBase {
                                                } else {
                                                    if (paymentMethodIdToPaymentPluginApi.get(paymentModelDao.getPaymentMethodId()) == null) {
                                                        try {
-                                                           final PaymentPluginApi paymentProviderPlugin = getPaymentProviderPlugin(paymentModelDao.getPaymentMethodId(), internalTenantContext);
+                                                           final PaymentPluginApi paymentProviderPlugin = getPaymentProviderPlugin(paymentModelDao.getPaymentMethodId(), true, internalTenantContext);
                                                            paymentMethodIdToPaymentPluginApi.put(paymentModelDao.getPaymentMethodId(), Optional.<PaymentPluginApi>of(paymentProviderPlugin));
                                                        } catch (final PaymentApiException e) {
                                                            log.warn("Unable to retrieve PaymentPluginApi for paymentMethodId='{}'", paymentModelDao.getPaymentMethodId(), e);
@@ -503,7 +502,7 @@ public class PaymentProcessor extends ProcessorBase {
             // Always invoke the Janitor first to get the latest state. The state machine will then
             // prevent disallowed transitions in case the state couldn't be fixed (or if it's already in a final state).
             if (runJanitor) {
-                final PaymentPluginApi plugin = getPaymentProviderPlugin(paymentModelDao.getPaymentMethodId(), internalCallContext);
+                final PaymentPluginApi plugin = getPaymentProviderPlugin(paymentModelDao.getPaymentMethodId(), true, internalCallContext);
                 final List<PaymentTransactionInfoPlugin> pluginTransactions = getPaymentTransactionInfoPlugins(plugin, paymentModelDao, properties, callContext);
                 paymentModelDao = invokeJanitor(paymentModelDao, paymentTransactionsForCurrentPayment, pluginTransactions, internalCallContext);
             }
@@ -642,7 +641,7 @@ public class PaymentProcessor extends ProcessorBase {
 
     // Used in single get APIs (getPayment / getPaymentByExternalKey)
     private Payment toPayment(final PaymentModelDao paymentModelDao, final boolean withPluginInfo, final boolean withAttempts, final Iterable<PluginProperty> properties, final TenantContext context, final InternalTenantContext tenantContext) throws PaymentApiException {
-        final PaymentPluginApi plugin = getPaymentProviderPlugin(paymentModelDao.getPaymentMethodId(), tenantContext);
+        final PaymentPluginApi plugin = getPaymentProviderPlugin(paymentModelDao.getPaymentMethodId(), true, tenantContext);
         final List<PaymentTransactionInfoPlugin> pluginTransactions = withPluginInfo ? getPaymentTransactionInfoPlugins(plugin, paymentModelDao, properties, context) : null;
 
         return toPayment(paymentModelDao, pluginTransactions, withAttempts, tenantContext);
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PluginControlPaymentProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PluginControlPaymentProcessor.java
index 736fa84..9491e51 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PluginControlPaymentProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PluginControlPaymentProcessor.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -34,7 +34,6 @@ import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.invoice.api.InvoiceInternalApi;
-import org.killbill.billing.osgi.api.OSGIServiceRegistration;
 import org.killbill.billing.payment.api.Payment;
 import org.killbill.billing.payment.api.PaymentApiException;
 import org.killbill.billing.payment.api.PaymentTransaction;
@@ -50,7 +49,6 @@ import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
 import org.killbill.billing.payment.dao.PluginPropertySerializer;
 import org.killbill.billing.payment.dao.PluginPropertySerializer.PluginPropertySerializerException;
 import org.killbill.billing.payment.invoice.InvoicePaymentControlPluginApi;
-import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
 import org.killbill.billing.tag.TagInternalApi;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
@@ -78,7 +76,7 @@ public class PluginControlPaymentProcessor extends ProcessorBase {
     private final PaymentControlStateMachineHelper paymentControlStateMachineHelper;
 
     @Inject
-    public PluginControlPaymentProcessor(final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry,
+    public PluginControlPaymentProcessor(final PaymentPluginServiceRegistration paymentPluginServiceRegistration,
                                          final AccountInternalApi accountInternalApi,
                                          final InvoiceInternalApi invoiceApi,
                                          final TagInternalApi tagUserApi,
@@ -88,7 +86,7 @@ public class PluginControlPaymentProcessor extends ProcessorBase {
                                          final PluginControlPaymentAutomatonRunner pluginControlledPaymentAutomatonRunner,
                                          final PaymentControlStateMachineHelper paymentControlStateMachineHelper,
                                          final Clock clock) {
-        super(pluginRegistry, accountInternalApi, paymentDao, tagUserApi, locker, internalCallContextFactory, invoiceApi, clock);
+        super(paymentPluginServiceRegistration, accountInternalApi, paymentDao, tagUserApi, locker, internalCallContextFactory, invoiceApi, clock);
         this.paymentControlStateMachineHelper = paymentControlStateMachineHelper;
         this.pluginControlledPaymentAutomatonRunner = pluginControlledPaymentAutomatonRunner;
     }
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/ProcessorBase.java b/payment/src/main/java/org/killbill/billing/payment/core/ProcessorBase.java
index 5866bcc..32c6cab 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/ProcessorBase.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/ProcessorBase.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -27,12 +27,10 @@ import javax.annotation.Nullable;
 
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.ObjectType;
-import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.invoice.api.InvoiceInternalApi;
-import org.killbill.billing.osgi.api.OSGIServiceRegistration;
 import org.killbill.billing.payment.api.PaymentApiException;
 import org.killbill.billing.payment.dao.PaymentDao;
 import org.killbill.billing.payment.dao.PaymentMethodModelDao;
@@ -61,7 +59,8 @@ public abstract class ProcessorBase {
 
     private static final Logger log = LoggerFactory.getLogger(ProcessorBase.class);
 
-    protected final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry;
+    private final PaymentPluginServiceRegistration paymentPluginServiceRegistration;
+
     protected final AccountInternalApi accountInternalApi;
     protected final GlobalLocker locker;
     protected final PaymentDao paymentDao;
@@ -70,7 +69,7 @@ public abstract class ProcessorBase {
     protected final Clock clock;
     protected final InvoiceInternalApi invoiceApi;
 
-    public ProcessorBase(final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry,
+    public ProcessorBase(final PaymentPluginServiceRegistration paymentPluginServiceRegistration,
                          final AccountInternalApi accountInternalApi,
                          final PaymentDao paymentDao,
                          final TagInternalApi tagInternalApi,
@@ -78,7 +77,7 @@ public abstract class ProcessorBase {
                          final InternalCallContextFactory internalCallContextFactory,
                          final InvoiceInternalApi invoiceApi,
                          final Clock clock) {
-        this.pluginRegistry = pluginRegistry;
+        this.paymentPluginServiceRegistration = paymentPluginServiceRegistration;
         this.accountInternalApi = accountInternalApi;
         this.paymentDao = paymentDao;
         this.locker = locker;
@@ -110,42 +109,23 @@ public abstract class ProcessorBase {
     }
 
     public Set<String> getAvailablePlugins() {
-        return pluginRegistry.getAllServices();
+        return paymentPluginServiceRegistration.getAvailablePlugins();
     }
 
     protected PaymentPluginApi getPaymentPluginApi(final String pluginName) throws PaymentApiException {
-        final PaymentPluginApi pluginApi = pluginRegistry.getServiceForName(pluginName);
-        if (pluginApi == null) {
-            throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_PLUGIN, pluginName);
-        }
-        return pluginApi;
-    }
-
-    protected PaymentPluginApi getPaymentProviderPlugin(final UUID paymentMethodId, final InternalTenantContext context) throws PaymentApiException {
-        final String pluginName = getPaymentProviderPluginName(paymentMethodId, context);
-        return getPaymentPluginApi(pluginName);
+        return paymentPluginServiceRegistration.getPaymentPluginApi(pluginName);
     }
 
-    protected String getPaymentProviderPluginName(final UUID paymentMethodId, final InternalTenantContext context) throws PaymentApiException {
-        final PaymentMethodModelDao methodDao = paymentDao.getPaymentMethodIncludedDeleted(paymentMethodId, context);
-        if (methodDao == null) {
-            log.error("PaymentMethod does not exist", paymentMethodId);
-            throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, paymentMethodId);
-        }
-        return methodDao.getPluginName();
+    protected PaymentPluginApi getPaymentProviderPlugin(final UUID paymentMethodId, final boolean includedDeleted, final InternalTenantContext context) throws PaymentApiException {
+        return paymentPluginServiceRegistration.getPaymentPluginApi(paymentMethodId, includedDeleted, context);
     }
 
-    protected PaymentPluginApi getPaymentProviderPlugin(final Account account, final InternalTenantContext context) throws PaymentApiException {
-        final UUID paymentMethodId = getDefaultPaymentMethodId(account);
-        return getPaymentProviderPlugin(paymentMethodId, context);
+    protected PaymentMethodModelDao getPaymentMethodById(final UUID paymentMethodId, final boolean includedDeleted, final InternalTenantContext context) throws PaymentApiException {
+        return paymentPluginServiceRegistration.getPaymentMethodById(paymentMethodId, includedDeleted, context);
     }
 
-    protected UUID getDefaultPaymentMethodId(final Account account) throws PaymentApiException {
-        final UUID paymentMethodId = account.getPaymentMethodId();
-        if (paymentMethodId == null) {
-            throw new PaymentApiException(ErrorCode.PAYMENT_NO_DEFAULT_PAYMENT_METHOD, account.getId());
-        }
-        return paymentMethodId;
+    protected PaymentMethodModelDao getPaymentMethodByExternalKey(final String paymentMethodExternalKey, final boolean includedDeleted, final InternalTenantContext context) throws PaymentApiException {
+        return paymentPluginServiceRegistration.getPaymentMethodByExternalKey(paymentMethodExternalKey, includedDeleted, context);
     }
 
     protected TenantContext buildTenantContext(final InternalTenantContext context) {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonDAOHelper.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonDAOHelper.java
index c546b0c..c9a2ae0 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonDAOHelper.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonDAOHelper.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * Groupon licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -27,10 +27,10 @@ import org.joda.time.DateTime;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.Currency;
-import org.killbill.billing.osgi.api.OSGIServiceRegistration;
 import org.killbill.billing.payment.api.PaymentApiException;
 import org.killbill.billing.payment.api.TransactionStatus;
 import org.killbill.billing.payment.api.TransactionType;
+import org.killbill.billing.payment.core.PaymentPluginServiceRegistration;
 import org.killbill.billing.payment.dao.PaymentDao;
 import org.killbill.billing.payment.dao.PaymentMethodModelDao;
 import org.killbill.billing.payment.dao.PaymentModelDao;
@@ -54,7 +54,7 @@ public class PaymentAutomatonDAOHelper {
 
     protected final PaymentDao paymentDao;
 
-    private final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry;
+    private final PaymentPluginServiceRegistration paymentPluginServiceRegistration;
     private final PersistentBus eventBus;
 
     // Cached
@@ -64,14 +64,14 @@ public class PaymentAutomatonDAOHelper {
     // Used to build new payments and transactions
     public PaymentAutomatonDAOHelper(final PaymentStateContext paymentStateContext,
                                      final DateTime utcNow, final PaymentDao paymentDao,
-                                     final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry,
+                                     final PaymentPluginServiceRegistration paymentPluginServiceRegistration,
                                      final InternalCallContext internalCallContext,
                                      final PersistentBus eventBus,
                                      final PaymentStateMachineHelper paymentSMHelper) throws PaymentApiException {
         this.paymentStateContext = paymentStateContext;
         this.utcNow = utcNow;
         this.paymentDao = paymentDao;
-        this.pluginRegistry = pluginRegistry;
+        this.paymentPluginServiceRegistration = paymentPluginServiceRegistration;
         this.internalCallContext = internalCallContext;
         this.eventBus = eventBus;
         this.paymentSMHelper = paymentSMHelper;
@@ -149,18 +149,14 @@ public class PaymentAutomatonDAOHelper {
         paymentStateContext.setPaymentTransactionModelDao(paymentDao.getPaymentTransaction(paymentStateContext.getPaymentTransactionModelDao().getId(), internalCallContext));
     }
 
-    public String getPaymentProviderPluginName(final boolean includeDeteled) throws PaymentApiException {
+    public String getPaymentProviderPluginName(final boolean includeDeleted) throws PaymentApiException {
         if (pluginName != null) {
             return pluginName;
         }
 
-        final UUID paymentMethodId = paymentStateContext.getPaymentMethodId();
-        final PaymentMethodModelDao methodDao = (includeDeteled) ? paymentDao.getPaymentMethodIncludedDeleted(paymentMethodId, internalCallContext) :
-                paymentDao.getPaymentMethod(paymentMethodId, internalCallContext);
-        if (methodDao == null) {
-            throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, paymentMethodId);
-        }
+        final PaymentMethodModelDao methodDao = paymentPluginServiceRegistration.getPaymentMethodById(paymentStateContext.getPaymentMethodId(), includeDeleted, internalCallContext);
         pluginName = methodDao.getPluginName();
+
         return pluginName;
     }
 
@@ -191,10 +187,7 @@ public class PaymentAutomatonDAOHelper {
             return paymentPluginApi;
         }
 
-        paymentPluginApi = pluginRegistry.getServiceForName(pluginName);
-        if (paymentPluginApi == null) {
-            throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_PLUGIN, pluginName);
-        }
+        paymentPluginApi = paymentPluginServiceRegistration.getPaymentPluginApi(pluginName);
         return paymentPluginApi;
     }
 
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonRunner.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonRunner.java
index 2a238a5..04c768b 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonRunner.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonRunner.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -40,12 +40,12 @@ import org.killbill.billing.ErrorCode;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.Currency;
-import org.killbill.billing.osgi.api.OSGIServiceRegistration;
 import org.killbill.billing.payment.api.PaymentApiException;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.killbill.billing.payment.api.TransactionStatus;
 import org.killbill.billing.payment.api.TransactionType;
 import org.killbill.billing.payment.core.PaymentExecutors;
+import org.killbill.billing.payment.core.PaymentPluginServiceRegistration;
 import org.killbill.billing.payment.core.sm.payments.AuthorizeCompleted;
 import org.killbill.billing.payment.core.sm.payments.AuthorizeInitiated;
 import org.killbill.billing.payment.core.sm.payments.AuthorizeOperation;
@@ -71,7 +71,6 @@ import org.killbill.billing.payment.dao.PaymentDao;
 import org.killbill.billing.payment.dao.PaymentModelDao;
 import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
 import org.killbill.billing.payment.dispatcher.PluginDispatcher;
-import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.config.definition.PaymentConfig;
 import org.killbill.bus.api.PersistentBus;
@@ -86,7 +85,7 @@ public class PaymentAutomatonRunner {
     protected final PaymentDao paymentDao;
     protected final GlobalLocker locker;
     protected final PluginDispatcher<OperationResult> paymentPluginDispatcher;
-    protected final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry;
+    protected final PaymentPluginServiceRegistration paymentPluginServiceRegistration;
     protected final Clock clock;
 
     private final PersistentBus eventBus;
@@ -96,7 +95,7 @@ public class PaymentAutomatonRunner {
     public PaymentAutomatonRunner(final PaymentConfig paymentConfig,
                                   final PaymentDao paymentDao,
                                   final GlobalLocker locker,
-                                  final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry,
+                                  final PaymentPluginServiceRegistration paymentPluginServiceRegistration,
                                   final Clock clock,
                                   final PaymentExecutors executors,
                                   final PersistentBus eventBus,
@@ -104,7 +103,7 @@ public class PaymentAutomatonRunner {
         this.paymentSMHelper = paymentSMHelper;
         this.paymentDao = paymentDao;
         this.locker = locker;
-        this.pluginRegistry = pluginRegistry;
+        this.paymentPluginServiceRegistration = paymentPluginServiceRegistration;
         this.clock = clock;
         this.eventBus = eventBus;
         this.paymentConfig = paymentConfig;
@@ -154,7 +153,7 @@ public class PaymentAutomatonRunner {
                                                     final InternalCallContext internalCallContext) throws PaymentApiException {
         final DateTime utcNow = clock.getUTCNow();
 
-        return new PaymentAutomatonDAOHelper(paymentStateContext, utcNow, paymentDao, pluginRegistry, internalCallContext, eventBus, paymentSMHelper);
+        return new PaymentAutomatonDAOHelper(paymentStateContext, utcNow, paymentDao, paymentPluginServiceRegistration, internalCallContext, eventBus, paymentSMHelper);
     }
 
     public UUID run(final PaymentStateContext paymentStateContext,
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/PluginControlPaymentAutomatonRunner.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/PluginControlPaymentAutomatonRunner.java
index d4b2b39..72f3d08 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/PluginControlPaymentAutomatonRunner.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/PluginControlPaymentAutomatonRunner.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -43,6 +43,7 @@ import org.killbill.billing.payment.api.PaymentApiException;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.killbill.billing.payment.api.TransactionType;
 import org.killbill.billing.payment.core.PaymentExecutors;
+import org.killbill.billing.payment.core.PaymentPluginServiceRegistration;
 import org.killbill.billing.payment.core.PaymentProcessor;
 import org.killbill.billing.payment.core.sm.control.AuthorizeControlOperation;
 import org.killbill.billing.payment.core.sm.control.CaptureControlOperation;
@@ -60,7 +61,6 @@ import org.killbill.billing.payment.core.sm.control.PurchaseControlOperation;
 import org.killbill.billing.payment.core.sm.control.RefundControlOperation;
 import org.killbill.billing.payment.core.sm.control.VoidControlOperation;
 import org.killbill.billing.payment.dao.PaymentDao;
-import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
 import org.killbill.billing.payment.retry.BaseRetryService.RetryServiceScheduler;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.config.definition.PaymentConfig;
@@ -96,11 +96,11 @@ public class PluginControlPaymentAutomatonRunner extends PaymentAutomatonRunner 
     private final PaymentConfig paymentConfig;
 
     @Inject
-    public PluginControlPaymentAutomatonRunner(final PaymentDao paymentDao, final GlobalLocker locker, final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry,
+    public PluginControlPaymentAutomatonRunner(final PaymentDao paymentDao, final GlobalLocker locker, final PaymentPluginServiceRegistration paymentPluginServiceRegistration,
                                                final OSGIServiceRegistration<PaymentControlPluginApi> paymentControlPluginRegistry, final Clock clock, final PaymentProcessor paymentProcessor, @Named(RETRYABLE_NAMED) final RetryServiceScheduler retryServiceScheduler,
                                                final PaymentConfig paymentConfig, final PaymentExecutors executors, final PaymentStateMachineHelper paymentSMHelper, final PaymentControlStateMachineHelper paymentControlStateMachineHelper,
                                                final ControlPluginRunner controlPluginRunner, final PersistentBus eventBus) {
-        super(paymentConfig, paymentDao, locker, pluginRegistry, clock, executors, eventBus, paymentSMHelper);
+        super(paymentConfig, paymentDao, locker, paymentPluginServiceRegistration, clock, executors, eventBus, paymentSMHelper);
         this.paymentProcessor = paymentProcessor;
         this.paymentControlPluginRegistry = paymentControlPluginRegistry;
         this.retryServiceScheduler = retryServiceScheduler;
diff --git a/payment/src/main/java/org/killbill/billing/payment/glue/PaymentModule.java b/payment/src/main/java/org/killbill/billing/payment/glue/PaymentModule.java
index 0a31eee..7586a8b 100644
--- a/payment/src/main/java/org/killbill/billing/payment/glue/PaymentModule.java
+++ b/payment/src/main/java/org/killbill/billing/payment/glue/PaymentModule.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2014 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -39,6 +39,7 @@ import org.killbill.billing.payment.caching.StateMachineConfigCacheInvalidationC
 import org.killbill.billing.payment.core.PaymentExecutors;
 import org.killbill.billing.payment.core.PaymentGatewayProcessor;
 import org.killbill.billing.payment.core.PaymentMethodProcessor;
+import org.killbill.billing.payment.core.PaymentPluginServiceRegistration;
 import org.killbill.billing.payment.core.PaymentProcessor;
 import org.killbill.billing.payment.core.PluginControlPaymentProcessor;
 import org.killbill.billing.payment.core.janitor.IncompletePaymentAttemptTask;
@@ -147,6 +148,8 @@ public class PaymentModule extends KillBillModule {
         bind(new TypeLiteral<OSGIServiceRegistration<PaymentPluginApi>>() {}).toProvider(DefaultPaymentProviderPluginRegistryProvider.class).asEagerSingleton();
         bind(new TypeLiteral<OSGIServiceRegistration<PaymentControlPluginApi>>() {}).toProvider(DefaultPaymentControlProviderPluginRegistryProvider.class).asEagerSingleton();
 
+        bind(PaymentPluginServiceRegistration.class).asEagerSingleton();
+
         bind(PaymentApi.class).to(DefaultPaymentApi.class).asEagerSingleton();
         bind(PaymentGatewayApi.class).to(DefaultPaymentGatewayApi.class).asEagerSingleton();
         bind(AdminPaymentApi.class).to(DefaultAdminPaymentApi.class).asEagerSingleton();
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/sm/MockRetryablePaymentAutomatonRunner.java b/payment/src/test/java/org/killbill/billing/payment/core/sm/MockRetryablePaymentAutomatonRunner.java
index 24ae2a7..6380bfa 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/sm/MockRetryablePaymentAutomatonRunner.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/sm/MockRetryablePaymentAutomatonRunner.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -36,6 +36,7 @@ import org.killbill.billing.payment.api.PaymentApiException;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.killbill.billing.payment.api.TransactionType;
 import org.killbill.billing.payment.core.PaymentExecutors;
+import org.killbill.billing.payment.core.PaymentPluginServiceRegistration;
 import org.killbill.billing.payment.core.PaymentProcessor;
 import org.killbill.billing.payment.core.sm.control.ControlPluginRunner;
 import org.killbill.billing.payment.core.sm.control.PaymentStateControlContext;
@@ -58,10 +59,10 @@ public class MockRetryablePaymentAutomatonRunner extends PluginControlPaymentAut
     private PaymentStateControlContext context;
 
     @Inject
-    public MockRetryablePaymentAutomatonRunner(final PaymentDao paymentDao, final GlobalLocker locker, final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry, final OSGIServiceRegistration<PaymentControlPluginApi> retryPluginRegistry, final Clock clock, final TagInternalApi tagApi, final PaymentProcessor paymentProcessor,
+    public MockRetryablePaymentAutomatonRunner(final PaymentDao paymentDao, final GlobalLocker locker, final PaymentPluginServiceRegistration paymentPluginServiceRegistration, final OSGIServiceRegistration<PaymentControlPluginApi> retryPluginRegistry, final Clock clock, final TagInternalApi tagApi, final PaymentProcessor paymentProcessor,
                                                @Named(RETRYABLE_NAMED) final RetryServiceScheduler retryServiceScheduler, final PaymentConfig paymentConfig, final PaymentExecutors executors,
                                                final PaymentStateMachineHelper paymentSMHelper, final PaymentControlStateMachineHelper retrySMHelper, final ControlPluginRunner controlPluginRunner, final PersistentBus eventBus) {
-        super(paymentDao, locker, pluginRegistry, retryPluginRegistry, clock, paymentProcessor, retryServiceScheduler, paymentConfig, executors, paymentSMHelper, retrySMHelper, controlPluginRunner, eventBus);
+        super(paymentDao, locker, paymentPluginServiceRegistration, retryPluginRegistry, clock, paymentProcessor, retryServiceScheduler, paymentConfig, executors, paymentSMHelper, retrySMHelper, controlPluginRunner, eventBus);
     }
 
     @Override
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentAutomatonDAOHelper.java b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentAutomatonDAOHelper.java
index 65586e8..3d37638 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentAutomatonDAOHelper.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentAutomatonDAOHelper.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * Groupon licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -128,6 +128,6 @@ public class TestPaymentAutomatonDAOHelper extends PaymentTestSuiteWithEmbeddedD
                                                       internalCallContext,
                                                       callContext);
 
-        return new PaymentAutomatonDAOHelper(paymentStateContext, clock.getUTCNow(), paymentDao, registry, internalCallContext, eventBus, paymentSMHelper);
+        return new PaymentAutomatonDAOHelper(paymentStateContext, clock.getUTCNow(), paymentDao, paymentPluginServiceRegistration, internalCallContext, eventBus, paymentSMHelper);
     }
 }
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentEnteringStateCallback.java b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentEnteringStateCallback.java
index e146a6e..287e297 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentEnteringStateCallback.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentEnteringStateCallback.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * Groupon licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -69,7 +69,7 @@ public class TestPaymentEnteringStateCallback extends PaymentTestSuiteWithEmbedd
                                                       ImmutableList.<PluginProperty>of(),
                                                       internalCallContext,
                                                       callContext);
-        daoHelper = new PaymentAutomatonDAOHelper(paymentStateContext, clock.getUTCNow(), paymentDao, registry, internalCallContext, eventBus, paymentSMHelper);
+        daoHelper = new PaymentAutomatonDAOHelper(paymentStateContext, clock.getUTCNow(), paymentDao, paymentPluginServiceRegistration, internalCallContext, eventBus, paymentSMHelper);
         callback = new PaymentEnteringStateTestCallback(daoHelper, paymentStateContext);
 
         Mockito.when(state.getName()).thenReturn("NEW_STATE");
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java
index 38a1e9b..91576ee 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -23,10 +23,8 @@ import java.util.UUID;
 
 import javax.annotation.Nullable;
 
-import org.killbill.automaton.OperationException;
 import org.killbill.automaton.State;
 import org.killbill.billing.account.api.Account;
-import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.payment.PaymentTestSuiteWithEmbeddedDB;
 import org.killbill.billing.payment.api.PaymentApiException;
@@ -144,7 +142,7 @@ public class TestPaymentLeavingStateCallback extends PaymentTestSuiteWithEmbedde
             paymentDao.insertPaymentWithFirstTransaction(newPaymentModelDao, newPaymentTransactionModelDao, internalCallContext);
         }
 
-        final PaymentAutomatonDAOHelper daoHelper = new PaymentAutomatonDAOHelper(paymentStateContext, clock.getUTCNow(), paymentDao, registry, internalCallContext, eventBus, paymentSMHelper);
+        final PaymentAutomatonDAOHelper daoHelper = new PaymentAutomatonDAOHelper(paymentStateContext, clock.getUTCNow(), paymentDao, paymentPluginServiceRegistration, internalCallContext, eventBus, paymentSMHelper);
         callback = new PaymentLeavingStateTestCallback(daoHelper, paymentStateContext);
 
         Mockito.when(state.getName()).thenReturn("NEW_STATE");
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentOperation.java b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentOperation.java
index cc32c53..fef77fb 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentOperation.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentOperation.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * Groupon licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -30,6 +30,7 @@ import org.killbill.billing.payment.PaymentTestSuiteNoDB;
 import org.killbill.billing.payment.api.PaymentApiException;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.killbill.billing.payment.api.TransactionType;
+import org.killbill.billing.payment.core.PaymentPluginServiceRegistration;
 import org.killbill.billing.payment.core.sm.payments.PaymentOperation;
 import org.killbill.billing.payment.dao.PaymentDao;
 import org.killbill.billing.payment.dao.PaymentMethodModelDao;
@@ -125,7 +126,8 @@ public class TestPaymentOperation extends PaymentTestSuiteNoDB {
         final PaymentDao paymentDao = Mockito.mock(PaymentDao.class);
         Mockito.when(paymentDao.getPaymentMethod(paymentStateContext.getPaymentMethodId(), internalCallContext)).thenReturn(paymentMethodModelDao);
 
-        final PaymentAutomatonDAOHelper daoHelper = new PaymentAutomatonDAOHelper(paymentStateContext, clock.getUTCNow(), paymentDao, registry, internalCallContext, eventBus, paymentSMHelper);
+        final PaymentPluginServiceRegistration paymentPluginServiceRegistration = new PaymentPluginServiceRegistration(paymentDao, registry);
+        final PaymentAutomatonDAOHelper daoHelper = new PaymentAutomatonDAOHelper(paymentStateContext, clock.getUTCNow(), paymentDao, paymentPluginServiceRegistration, internalCallContext, eventBus, paymentSMHelper);
         paymentOperation = new PaymentOperationTest(paymentPluginStatus, daoHelper, locker, paymentPluginDispatcher, paymentConfig, paymentStateContext);
     }
 
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestRetryablePayment.java b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestRetryablePayment.java
index 752f40c..0be4a2f 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestRetryablePayment.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestRetryablePayment.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -160,7 +160,7 @@ public class TestRetryablePayment extends PaymentTestSuiteNoDB {
         runner = new MockRetryablePaymentAutomatonRunner(
                 paymentDao,
                 locker,
-                pluginRegistry,
+                paymentPluginServiceRegistration,
                 retryPluginRegistry,
                 clock,
                 tagApi,
@@ -200,7 +200,7 @@ public class TestRetryablePayment extends PaymentTestSuiteNoDB {
                                                         paymentDao,
                                                         clock);
 
-        processor = new PluginControlPaymentProcessor(pluginRegistry,
+        processor = new PluginControlPaymentProcessor(paymentPluginServiceRegistration,
                                                       accountInternalApi,
                                                       null,
                                                       tagApi,
diff --git a/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteNoDB.java b/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteNoDB.java
index b50ce2c..a41e524 100644
--- a/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteNoDB.java
+++ b/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteNoDB.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -29,6 +29,7 @@ import org.killbill.billing.payment.api.PaymentGatewayApi;
 import org.killbill.billing.payment.caching.StateMachineConfigCache;
 import org.killbill.billing.payment.core.PaymentExecutors;
 import org.killbill.billing.payment.core.PaymentMethodProcessor;
+import org.killbill.billing.payment.core.PaymentPluginServiceRegistration;
 import org.killbill.billing.payment.core.PaymentProcessor;
 import org.killbill.billing.payment.core.PluginControlPaymentProcessor;
 import org.killbill.billing.payment.core.sm.PaymentStateMachineHelper;
@@ -67,6 +68,8 @@ public abstract class PaymentTestSuiteNoDB extends GuicyKillbillTestSuiteNoDB {
     @Inject
     protected InvoiceInternalApi invoiceApi;
     @Inject
+    protected PaymentPluginServiceRegistration paymentPluginServiceRegistration;
+    @Inject
     protected OSGIServiceRegistration<PaymentPluginApi> registry;
     @Inject
     protected PersistentBus eventBus;
diff --git a/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java b/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java
index 061bbc5..0210596 100644
--- a/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java
+++ b/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -29,6 +29,7 @@ import org.killbill.billing.payment.api.PaymentGatewayApi;
 import org.killbill.billing.payment.caching.StateMachineConfigCache;
 import org.killbill.billing.payment.core.PaymentExecutors;
 import org.killbill.billing.payment.core.PaymentMethodProcessor;
+import org.killbill.billing.payment.core.PaymentPluginServiceRegistration;
 import org.killbill.billing.payment.core.PaymentProcessor;
 import org.killbill.billing.payment.core.janitor.IncompletePaymentTransactionTask;
 import org.killbill.billing.payment.core.janitor.Janitor;
@@ -69,6 +70,8 @@ public abstract class PaymentTestSuiteWithEmbeddedDB extends GuicyKillbillTestSu
     @Inject
     protected InvoiceInternalApi invoiceApi;
     @Inject
+    protected PaymentPluginServiceRegistration paymentPluginServiceRegistration;
+    @Inject
     protected OSGIServiceRegistration<PaymentPluginApi> registry;
     @Inject
     protected OSGIServiceRegistration<PaymentControlPluginApi> controlPluginRegistry;