killbill-memoizeit

Changes

payment/src/main/java/com/ning/billing/payment/PaymentInfoRequest.java 45(+0 -45)

pom.xml 2(+1 -1)

Details

diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
index 189e87c..8ecae71 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
@@ -49,4 +49,8 @@ public interface PaymentApi {
 
     PaymentAttempt getPaymentAttemptForPaymentId(String id);
 
+    List<PaymentInfo> getPaymentInfo(List<String> invoiceIds);
+
+    PaymentAttempt getPaymentAttemptForInvoiceId(String invoiceId);
+
 }
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentService.java b/api/src/main/java/com/ning/billing/payment/api/PaymentService.java
index 988a00a..ede2506 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentService.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentService.java
@@ -23,4 +23,5 @@ public interface PaymentService extends KillbillService {
     String getName();
 
     PaymentApi getPaymentApi();
+
 }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/glue/InvoiceModule.java b/invoice/src/main/java/com/ning/billing/invoice/glue/InvoiceModule.java
index 20765eb..372952b 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/glue/InvoiceModule.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/glue/InvoiceModule.java
@@ -16,8 +16,8 @@
 
 package com.ning.billing.invoice.glue;
 
-import com.ning.billing.util.glue.GlobalLockerModule;
 import org.skife.config.ConfigurationObjectFactory;
+
 import com.google.inject.AbstractModule;
 import com.ning.billing.config.InvoiceConfig;
 import com.ning.billing.invoice.InvoiceListener;
@@ -34,6 +34,7 @@ import com.ning.billing.invoice.model.InvoiceGenerator;
 import com.ning.billing.invoice.notification.DefaultNextBillingDateNotifier;
 import com.ning.billing.invoice.notification.NextBillingDateNotifier;
 import com.ning.billing.util.glue.ClockModule;
+import com.ning.billing.util.glue.GlobalLockerModule;
 
 
 public class InvoiceModule extends AbstractModule {
@@ -66,8 +67,11 @@ public class InvoiceModule extends AbstractModule {
         bind(NextBillingDateNotifier.class).to(DefaultNextBillingDateNotifier.class).asEagerSingleton();
     }
 
-    protected void installInvoiceListener() {
+    protected void installGlobalLocker() {
         install(new GlobalLockerModule());
+    }
+
+    protected void installInvoiceListener() {
         bind(InvoiceListener.class).asEagerSingleton();
     }
 
@@ -81,5 +85,6 @@ public class InvoiceModule extends AbstractModule {
         installInvoiceDao();
         installInvoiceUserApi();
         installInvoicePaymentApi();
+        installGlobalLocker();
     }
 }
diff --git a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithMocks.java b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithMocks.java
index ec36375..e5e699b 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithMocks.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithMocks.java
@@ -30,6 +30,11 @@ public class InvoiceModuleWithMocks extends InvoiceModule {
     }
 
     @Override
+    protected void installGlobalLocker() {
+        bind(GlobalLocker.class).to(MockGlobalLocker.class).asEagerSingleton();
+    }
+
+    @Override
     protected void installInvoiceListener() {
 
     }
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
index 6dc04e4..7b05c71 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
@@ -23,8 +23,6 @@ import java.util.UUID;
 
 import javax.annotation.Nullable;
 
-import com.ning.billing.invoice.api.InvoicePayment;
-import com.ning.billing.invoice.model.DefaultInvoicePayment;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,6 +31,7 @@ import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoicePaymentApi;
+import com.ning.billing.invoice.model.DefaultInvoicePayment;
 import com.ning.billing.payment.dao.PaymentDao;
 import com.ning.billing.payment.provider.PaymentProviderPlugin;
 import com.ning.billing.payment.provider.PaymentProviderPluginRegistry;
@@ -212,4 +211,14 @@ public class DefaultPaymentApi implements PaymentApi {
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public List<PaymentInfo> getPaymentInfo(List<String> invoiceIds) {
+        return paymentDao.getPaymentInfo(invoiceIds);
+    }
+
+    @Override
+    public PaymentAttempt getPaymentAttemptForInvoiceId(String invoiceId) {
+        return paymentDao.getPaymentAttemptForInvoiceId(invoiceId);
+    }
+
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java
index eacc226..9a96631 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java
@@ -16,6 +16,7 @@
 
 package com.ning.billing.payment.dao;
 
+import java.util.List;
 import java.util.UUID;
 
 import org.skife.jdbi.v2.IDBI;
@@ -44,6 +45,12 @@ public class DefaultPaymentDao implements PaymentDao {
     }
 
     @Override
+    public PaymentAttempt createPaymentAttempt(PaymentAttempt paymentAttempt) {
+        sqlDao.insertPaymentAttempt(paymentAttempt);
+        return paymentAttempt;
+    }
+
+    @Override
     public PaymentAttempt createPaymentAttempt(Invoice invoice) {
         final PaymentAttempt paymentAttempt = new PaymentAttempt(UUID.randomUUID(), invoice);
 
@@ -66,4 +73,14 @@ public class DefaultPaymentDao implements PaymentDao {
         sqlDao.updatePaymentInfo(type, paymentId, cardType, cardCountry);
     }
 
+    @Override
+    public List<PaymentInfo> getPaymentInfo(List<String> invoiceIds) {
+        return sqlDao.getPaymentInfos(invoiceIds);
+    }
+
+    @Override
+    public List<PaymentAttempt> getPaymentAttemptsForInvoiceIds(List<String> invoiceIds) {
+        return sqlDao.getPaymentAttemptsForInvoiceIds(invoiceIds);
+    }
+
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
index 5cf065b..4d4a411 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
@@ -16,6 +16,7 @@
 
 package com.ning.billing.payment.dao;
 
+import java.util.List;
 import java.util.UUID;
 
 import com.ning.billing.invoice.api.Invoice;
@@ -25,10 +26,12 @@ import com.ning.billing.payment.api.PaymentInfo;
 public interface PaymentDao {
 
     PaymentAttempt createPaymentAttempt(Invoice invoice);
+    PaymentAttempt createPaymentAttempt(PaymentAttempt paymentAttempt);
 
     void savePaymentInfo(PaymentInfo right);
 
     PaymentAttempt getPaymentAttemptForPaymentId(String paymentId);
+    List<PaymentAttempt> getPaymentAttemptsForInvoiceIds(List<String> invoiceIds);
 
     void updatePaymentAttemptWithPaymentId(UUID paymentAttemptId, String paymentId);
 
@@ -36,4 +39,6 @@ public interface PaymentDao {
 
     void updatePaymentInfo(String paymentMethodType, String paymentId, String cardType, String cardCountry);
 
+    List<PaymentInfo> getPaymentInfo(List<String> invoiceIds);
+
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
index 972ee64..13b5f51 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
@@ -21,6 +21,7 @@ import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Timestamp;
 import java.util.Date;
+import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
@@ -37,6 +38,7 @@ import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
 import org.skife.jdbi.v2.tweak.ResultSetMapper;
+import org.skife.jdbi.v2.unstable.BindIn;
 
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.payment.api.PaymentAttempt;
@@ -55,6 +57,10 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Tr
     @Mapper(PaymentAttemptMapper.class)
     PaymentAttempt getPaymentAttemptForInvoiceId(@Bind("invoice_id") String invoiceId);
 
+    @SqlQuery
+    @Mapper(PaymentAttemptMapper.class)
+    List<PaymentAttempt> getPaymentAttemptsForInvoiceIds(@BindIn("invoiceIds") List<String> invoiceIds);
+
     @SqlUpdate
     void updatePaymentAttemptWithPaymentId(@Bind("payment_attempt_id") String paymentAttemptId,
                                            @Bind("payment_id") String paymentId);
@@ -65,6 +71,10 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Tr
                            @Bind("card_type") String cardType,
                            @Bind("card_country") String cardCountry);
 
+    @SqlQuery
+    @Mapper(PaymentInfoMapper.class)
+    List<PaymentInfo> getPaymentInfos(@BindIn("invoiceIds") List<String> invoiceIds);
+
     @SqlUpdate
     void insertPaymentInfo(@Bind(binder = PaymentInfoBinder.class) PaymentInfo paymentInfo);
 
diff --git a/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java b/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
index 9700450..2c86e3b 100644
--- a/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
@@ -31,7 +31,6 @@ import com.ning.billing.payment.api.Either;
 import com.ning.billing.payment.api.PaymentApi;
 import com.ning.billing.payment.api.PaymentError;
 import com.ning.billing.payment.api.PaymentInfo;
-import com.ning.billing.payment.provider.PaymentProviderPlugin;
 import com.ning.billing.payment.provider.PaymentProviderPluginRegistry;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.bus.Bus.EventBusException;
@@ -40,7 +39,6 @@ public class RequestProcessor {
     public static final String PAYMENT_PROVIDER_KEY = "paymentProvider";
     private final AccountUserApi accountUserApi;
     private final PaymentApi paymentApi;
-    private final PaymentProviderPluginRegistry pluginRegistry;
     private final Bus eventBus;
 
     private static final Logger log = LoggerFactory.getLogger(RequestProcessor.class);
@@ -52,7 +50,6 @@ public class RequestProcessor {
                             Bus eventBus) {
         this.accountUserApi = accountUserApi;
         this.paymentApi = paymentApi;
-        this.pluginRegistry = pluginRegistry;
         this.eventBus = eventBus;
     }
 
@@ -81,20 +78,4 @@ public class RequestProcessor {
             throw new RuntimeException(ex);
         }
     }
-
-    @Subscribe
-    public void receivePaymentInfoRequest(PaymentInfoRequest paymentInfoRequest) throws EventBusException {
-        final Account account = accountUserApi.getAccountById(paymentInfoRequest.getAccountId());
-        if (account == null) {
-            log.info("could not process payment info request: could not find a valid account for event {}", paymentInfoRequest);
-        }
-        else {
-            final String paymentProviderName = account.getFieldValue(PAYMENT_PROVIDER_KEY);
-            final PaymentProviderPlugin plugin = pluginRegistry.getPlugin(paymentProviderName);
-
-            Either<PaymentError, PaymentInfo> result = plugin.getPaymentInfo(paymentInfoRequest.getPaymentId());
-
-            eventBus.post(result.isLeft() ? result.getLeft() : result.getRight());
-        }
-    }
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/RetryService.java b/payment/src/main/java/com/ning/billing/payment/RetryService.java
new file mode 100644
index 0000000..49acce3
--- /dev/null
+++ b/payment/src/main/java/com/ning/billing/payment/RetryService.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2010-2012 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.payment;
+
+import org.joda.time.DateTime;
+import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
+
+import com.google.inject.Inject;
+import com.ning.billing.lifecycle.KillbillService;
+import com.ning.billing.lifecycle.LifecycleHandlerType;
+import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel;
+import com.ning.billing.payment.setup.PaymentConfig;
+import com.ning.billing.util.notificationq.NotificationKey;
+import com.ning.billing.util.notificationq.NotificationQueue;
+import com.ning.billing.util.notificationq.NotificationQueueService;
+import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueAlreadyExists;
+import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
+
+public class RetryService implements KillbillService {
+    public static final String SERVICE_NAME = "retry-service";
+    public static final String QUEUE_NAME = "retry-events";
+
+    private final NotificationQueueService notificationQueueService;
+    private final PaymentConfig config;
+    private NotificationQueue retryQueue;
+
+    @Inject
+    public RetryService(NotificationQueueService notificationQueueService, PaymentConfig config) {
+        this.notificationQueueService = notificationQueueService;
+        this.config = config;
+    }
+
+    @Override
+    public String getName() {
+        return SERVICE_NAME;
+    }
+
+    @LifecycleHandlerType(LifecycleLevel.INIT_SERVICE)
+    public void initialize() throws NotificationQueueAlreadyExists {
+        retryQueue = notificationQueueService.createNotificationQueue(SERVICE_NAME, QUEUE_NAME, new NotificationQueueHandler() {
+            @Override
+            public void handleReadyNotification(String notificationKey) {
+                retry(notificationKey);
+            }
+        },
+        config);
+    }
+
+    @LifecycleHandlerType(LifecycleLevel.START_SERVICE)
+    public void start() {
+        retryQueue.startQueue();
+    }
+
+    @LifecycleHandlerType(LifecycleLevel.STOP_SERVICE)
+    public void stop() {
+        if (retryQueue != null) {
+            retryQueue.stopQueue();
+         }
+    }
+
+    public void scheduleRetry(Transmogrifier transactionalDao, PaymentAttempt paymentAttempt, DateTime timeOfRetry) {
+        final String id = paymentAttempt.getPaymentAttemptId().toString();
+
+        NotificationKey key = new NotificationKey() {
+            @Override
+            public String toString() {
+                return id;
+            }
+        };
+        retryQueue.recordFutureNotificationFromTransaction(transactionalDao, timeOfRetry, key);
+    }
+
+    private void retry(String paymentAttemptId) {
+        // TODO
+    }
+}
diff --git a/payment/src/main/java/com/ning/billing/payment/setup/PaymentConfig.java b/payment/src/main/java/com/ning/billing/payment/setup/PaymentConfig.java
index cdc5384..6837ec7 100644
--- a/payment/src/main/java/com/ning/billing/payment/setup/PaymentConfig.java
+++ b/payment/src/main/java/com/ning/billing/payment/setup/PaymentConfig.java
@@ -17,10 +17,29 @@
 package com.ning.billing.payment.setup;
 
 import org.skife.config.Config;
+import org.skife.config.Default;
 import org.skife.config.DefaultNull;
 
-public interface PaymentConfig {
+import com.ning.billing.util.notificationq.NotificationConfig;
+
+public interface PaymentConfig extends NotificationConfig {
     @Config("killbill.payment.provider.default")
     @DefaultNull
     public String getDefaultPaymentProvider();
+
+    @Config("killbill.payment.dao.claim.time")
+    @Default("60000")
+    public long getDaoClaimTimeMs();
+
+    @Config("killbill.payment.dao.ready.max")
+    @Default("10")
+    public int getDaoMaxReadyEvents();
+
+    @Config("killbill.payment.engine.notifications.sleep")
+    @Default("500")
+    public long getNotificationSleepTimeMs();
+
+    @Config("killbill.payment.engine.events.off")
+    @Default("false")
+    public boolean isNotificationProcessingOff();
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/setup/PaymentModule.java b/payment/src/main/java/com/ning/billing/payment/setup/PaymentModule.java
index cbff01b..b8af029 100644
--- a/payment/src/main/java/com/ning/billing/payment/setup/PaymentModule.java
+++ b/payment/src/main/java/com/ning/billing/payment/setup/PaymentModule.java
@@ -22,6 +22,7 @@ import org.skife.config.ConfigurationObjectFactory;
 
 import com.google.inject.AbstractModule;
 import com.ning.billing.payment.RequestProcessor;
+import com.ning.billing.payment.RetryService;
 import com.ning.billing.payment.api.DefaultPaymentApi;
 import com.ning.billing.payment.api.PaymentApi;
 import com.ning.billing.payment.dao.DefaultPaymentDao;
@@ -46,6 +47,10 @@ public class PaymentModule extends AbstractModule {
     protected void installPaymentProviderPlugins(PaymentConfig config) {
     }
 
+    protected void installRetryEngine() {
+        bind(RetryService.class).asEagerSingleton();
+    }
+
     @Override
     protected void configure() {
         final ConfigurationObjectFactory factory = new ConfigurationObjectFactory(props);
diff --git a/payment/src/main/resources/com/ning/billing/payment/dao/PaymentSqlDao.sql.stg b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentSqlDao.sql.stg
index a62c366..aea2272 100644
--- a/payment/src/main/resources/com/ning/billing/payment/dao/PaymentSqlDao.sql.stg
+++ b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentSqlDao.sql.stg
@@ -24,6 +24,7 @@ paymentInfoFields(prefix) ::= <<
     <prefix>payment_type,
     <prefix>status,
     <prefix>reference_id,
+    <prefix>payment_method_id,
     <prefix>payment_method,
     <prefix>card_type,
     <prefix>card_country,
@@ -43,6 +44,12 @@ getPaymentAttemptForPaymentId() ::= <<
      WHERE payment_id = :payment_id
 >>
 
+getPaymentAttemptsForInvoiceIds(invoiceIds) ::= <<
+    SELECT <paymentAttemptFields()>
+      FROM payment_attempts
+     WHERE invoice_id in (<invoiceIds>)
+>>
+
 getPaymentAttemptForInvoiceId() ::= <<
     SELECT <paymentAttemptFields()>
       FROM payment_attempts
@@ -58,7 +65,7 @@ updatePaymentAttemptWithPaymentId() ::= <<
 
 insertPaymentInfo() ::= <<
     INSERT INTO payments (<paymentInfoFields()>)
-    VALUES (:payment_id, :amount, :refund_amount, :bank_identification_number, :payment_number, :payment_type, :status, :reference_id, :payment_method, :card_type, :card_country, :effective_dt, :created_dt, :updated_dt);
+    VALUES (:payment_id, :amount, :refund_amount, :bank_identification_number, :payment_number, :payment_type, :status, :reference_id, :payment_method_id, :payment_method, :card_type, :card_country, :effective_dt, :created_dt, :updated_dt);
 >>
 
 updatePaymentInfo() ::= <<
@@ -68,4 +75,11 @@ updatePaymentInfo() ::= <<
            card_country = :card_country,
            updated_dt = NOW()
      WHERE payment_id = :payment_id
+>>
+
+getPaymentInfos(invoiceIds) ::= <<
+    SELECT <paymentInfoFields("p.")>
+      FROM payments p, payment_attempts pa
+     WHERE pa.invoice_id in (<invoiceIds>)
+       AND pa.payment_id = p.payment_id
 >>
\ No newline at end of file
diff --git a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
index 367f61b..786ef34 100644
--- a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
+++ b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
@@ -101,6 +101,16 @@ public abstract class TestPaymentApi {
         assertEquals(paymentAttempt.getPaymentId(), paymentInfo.getPaymentId());
         assertEquals(paymentAttempt.getPaymentAttemptDate().withMillisOfSecond(0).withSecondOfMinute(0), now.withMillisOfSecond(0).withSecondOfMinute(0));
 
+        List<PaymentInfo> paymentInfos = paymentApi.getPaymentInfo(Arrays.asList(invoice.getId().toString()));
+        assertNotNull(paymentInfos);
+        assertTrue(paymentInfos.size() > 0);
+
+        PaymentInfo paymentInfoFromGet = paymentInfos.get(0);
+        assertEquals(paymentInfo, paymentInfoFromGet);
+
+        PaymentAttempt paymentAttemptFromGet = paymentApi.getPaymentAttemptForInvoiceId(invoice.getId().toString());
+        assertEquals(paymentAttempt, paymentAttemptFromGet);
+
     }
 
     private PaymentProviderAccount setupAccountWithPaymentMethod() throws AccountApiException {
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java b/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
index bb83927..071ce94 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
@@ -16,10 +16,14 @@
 
 package com.ning.billing.payment.dao;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.payment.api.PaymentAttempt;
 import com.ning.billing.payment.api.PaymentInfo;
@@ -46,6 +50,12 @@ public class MockPaymentDao implements PaymentDao {
     }
 
     @Override
+    public PaymentAttempt createPaymentAttempt(PaymentAttempt paymentAttempt) {
+        paymentAttempts.put(paymentAttempt.getPaymentAttemptId(), paymentAttempt);
+        return paymentAttempt;
+    }
+
+    @Override
     public void savePaymentInfo(PaymentInfo paymentInfo) {
         payments.put(paymentInfo.getPaymentId(), paymentInfo);
     }
@@ -63,7 +73,7 @@ public class MockPaymentDao implements PaymentDao {
     @Override
     public PaymentAttempt getPaymentAttemptForInvoiceId(String invoiceId) {
         for (PaymentAttempt paymentAttempt : paymentAttempts.values()) {
-            if (invoiceId.equals(paymentAttempt.getInvoiceId())) {
+            if (invoiceId.equals(paymentAttempt.getInvoiceId().toString())) {
                 return paymentAttempt;
             }
         }
@@ -76,4 +86,32 @@ public class MockPaymentDao implements PaymentDao {
 
     }
 
+    @Override
+    public List<PaymentInfo> getPaymentInfo(List<String> invoiceIds) {
+        List<PaymentAttempt> attempts = getPaymentAttemptsForInvoiceIds(invoiceIds);
+        List<PaymentInfo> paymentsToReturn = new ArrayList<PaymentInfo>(invoiceIds.size());
+
+        for (final PaymentAttempt attempt : attempts) {
+            paymentsToReturn.addAll(Collections2.filter(payments.values(), new Predicate<PaymentInfo>() {
+                @Override
+                public boolean apply(PaymentInfo input) {
+                    return input.getPaymentId().equals(attempt.getPaymentId());
+                }
+            }));
+        }
+        return paymentsToReturn;
+    }
+
+    @Override
+    public List<PaymentAttempt> getPaymentAttemptsForInvoiceIds(List<String> invoiceIds) {
+        List<PaymentAttempt> paymentAttempts = new ArrayList<PaymentAttempt>(invoiceIds.size());
+        for (String invoiceId : invoiceIds) {
+            PaymentAttempt attempt = getPaymentAttemptForInvoiceId(invoiceId);
+            if (attempt != null) {
+                paymentAttempts.add(attempt);
+            }
+        }
+        return paymentAttempts;
+    }
+
 }
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
index 6c57c77..7d65b8b 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
@@ -17,17 +17,22 @@
 package com.ning.billing.payment.dao;
 
 import java.math.BigDecimal;
+import java.util.Arrays;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
+import org.testng.Assert;
 import org.testng.annotations.Test;
 
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.payment.api.PaymentAttempt;
 import com.ning.billing.payment.api.PaymentInfo;
 
 public abstract class TestPaymentDao {
 
-    protected PaymentDao dao;
+    protected PaymentDao paymentDao;
 
     @Test
     public void testCreatePayment() {
@@ -44,7 +49,7 @@ public abstract class TestPaymentDao {
                                                            .setEffectiveDate(new DateTime(DateTimeZone.UTC))
                                                            .build();
 
-        dao.savePaymentInfo(paymentInfo);
+        paymentDao.savePaymentInfo(paymentInfo);
     }
 
     @Test
@@ -62,10 +67,51 @@ public abstract class TestPaymentDao {
                                                            .setEffectiveDate(new DateTime(DateTimeZone.UTC))
                                                            .build();
 
-        dao.savePaymentInfo(paymentInfo);
+        paymentDao.savePaymentInfo(paymentInfo);
 
-        dao.updatePaymentInfo("CreditCard", paymentInfo.getPaymentId(), "Visa", "US");
+        paymentDao.updatePaymentInfo("CreditCard", paymentInfo.getPaymentId(), "Visa", "US");
 
     }
 
+    @Test
+    public void testGetPaymentForInvoice() throws AccountApiException {
+        final UUID invoiceId = UUID.randomUUID();
+        final UUID paymentAttemptId = UUID.randomUUID();
+        final UUID accountId = UUID.randomUUID();
+        final String paymentId = UUID.randomUUID().toString();
+        final BigDecimal invoiceAmount = BigDecimal.TEN;
+
+        final DateTime now = new DateTime(DateTimeZone.UTC);
+
+        PaymentAttempt originalPaymenAttempt = new PaymentAttempt(paymentAttemptId, invoiceId, accountId, invoiceAmount, Currency.USD, now, now, paymentId, null, null);
+
+        PaymentAttempt attempt = paymentDao.createPaymentAttempt(originalPaymenAttempt);
+
+        PaymentAttempt attempt2 = paymentDao.getPaymentAttemptForInvoiceId(invoiceId.toString());
+
+        Assert.assertEquals(attempt, attempt2);
+
+        PaymentAttempt attempt3 = paymentDao.getPaymentAttemptsForInvoiceIds(Arrays.asList(invoiceId.toString())).get(0);
+
+        Assert.assertEquals(attempt, attempt3);
+
+        PaymentInfo originalPaymentInfo = new PaymentInfo.Builder().setPaymentId(paymentId)
+                                                           .setAmount(invoiceAmount)
+                                                           .setStatus("Processed")
+                                                           .setBankIdentificationNumber("1234")
+                                                           .setPaymentNumber("12345")
+                                                           .setPaymentMethodId("12345")
+                                                           .setReferenceId("12345")
+                                                           .setType("Electronic")
+                                                           .setCreatedDate(now)
+                                                           .setUpdatedDate(now)
+                                                           .setEffectiveDate(now)
+                                                           .build();
+
+        paymentDao.savePaymentInfo(originalPaymentInfo);
+        PaymentInfo paymentInfo = paymentDao.getPaymentInfo(Arrays.asList(invoiceId.toString())).get(0);
+
+        Assert.assertEquals(originalPaymentInfo, paymentInfo);
+    }
+
 }
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithEmbeddedDb.java b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithEmbeddedDb.java
index da48c03..19ca39d 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithEmbeddedDb.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithEmbeddedDb.java
@@ -26,28 +26,25 @@ import org.testng.annotations.Test;
 
 import com.ning.billing.dbi.MysqlTestingHelper;
 
-public class TestPaymentDaoWithEmbeddedDb
-{
-    @Test(enabled = true, groups = { "slow", "database" })
-    public class TestPaymentDaoWithEmbeddedDB extends TestPaymentDao {
-        private final MysqlTestingHelper helper = new MysqlTestingHelper();
-
-        @BeforeClass(alwaysRun = true)
-        public void startMysql() throws IOException {
-            final String paymentddl = IOUtils.toString(MysqlTestingHelper.class.getResourceAsStream("/com/ning/billing/payment/ddl.sql"));
-
-            helper.startMysql();
-            helper.initDb(paymentddl);
-        }
-
-        @AfterClass(alwaysRun = true)
-        public void stopMysql() {
-            helper.stopMysql();
-        }
-
-        @BeforeMethod(alwaysRun = true)
-        public void setUp() throws IOException {
-            dao = new DefaultPaymentDao(helper.getDBI());
-        }
+@Test(enabled = true, groups = { "slow", "database" })
+public class TestPaymentDaoWithEmbeddedDb extends TestPaymentDao {
+    private final MysqlTestingHelper helper = new MysqlTestingHelper();
+
+    @BeforeClass(alwaysRun = true)
+    public void startMysql() throws IOException {
+        final String paymentddl = IOUtils.toString(MysqlTestingHelper.class.getResourceAsStream("/com/ning/billing/payment/ddl.sql"));
+
+        helper.startMysql();
+        helper.initDb(paymentddl);
+    }
+
+    @AfterClass(alwaysRun = true)
+    public void stopMysql() {
+        helper.stopMysql();
+    }
+
+    @BeforeMethod(alwaysRun = true)
+    public void setUp() throws IOException {
+        paymentDao = new DefaultPaymentDao(helper.getDBI());
     }
 }
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithMock.java b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithMock.java
index f5af240..6e31f90 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithMock.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithMock.java
@@ -25,6 +25,6 @@ import org.testng.annotations.Test;
 public class TestPaymentDaoWithMock extends TestPaymentDao {
     @BeforeMethod(alwaysRun = true)
     public void setUp() throws IOException {
-        dao = new MockPaymentDao();
+        paymentDao = new MockPaymentDao();
     }
 }
\ No newline at end of file
diff --git a/payment/src/test/java/com/ning/billing/payment/TestPaymentProvider.java b/payment/src/test/java/com/ning/billing/payment/TestPaymentProvider.java
index 2c0aa13..99870b7 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestPaymentProvider.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestPaymentProvider.java
@@ -18,7 +18,6 @@ package com.ning.billing.payment;
 
 import static com.jayway.awaitility.Awaitility.await;
 import static java.util.concurrent.TimeUnit.MINUTES;
-import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 
@@ -90,23 +89,5 @@ public class TestPaymentProvider {
         assertFalse(paymentInfoReceiver.getProcessedPayments().isEmpty());
         assertTrue(paymentInfoReceiver.getErrors().isEmpty());
 
-        final PaymentInfo paymentInfo = paymentInfoReceiver.getProcessedPayments().get(0);
-        final PaymentInfoRequest paymentInfoRequest = new PaymentInfoRequest(account.getId(), paymentInfo.getPaymentId());
-
-        paymentInfoReceiver.clear();
-        eventBus.post(paymentInfoRequest);
-        await().atMost(5, MINUTES).until(new Callable<Boolean>() {
-            @Override
-            public Boolean call() throws Exception {
-                List<PaymentInfo> processedPayments = paymentInfoReceiver.getProcessedPayments();
-                List<PaymentError> errors = paymentInfoReceiver.getErrors();
-
-                return processedPayments.size() == 1 || errors.size() == 1;
-            }
-        });
-
-        assertFalse(paymentInfoReceiver.getProcessedPayments().isEmpty());
-        assertTrue(paymentInfoReceiver.getErrors().isEmpty());
-        assertEquals(paymentInfoReceiver.getProcessedPayments().get(0), paymentInfo);
     }
 }

pom.xml 2(+1 -1)

diff --git a/pom.xml b/pom.xml
index d72a41e..b6f6e78 100644
--- a/pom.xml
+++ b/pom.xml
@@ -425,7 +425,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <version>2.6</version>
+                <version>2.11</version>
                 <configuration>
                     <useManifestOnlyJar>false</useManifestOnlyJar>
                     <systemPropertyVariables>
diff --git a/util/src/main/java/com/ning/billing/util/glue/TagStoreModule.java b/util/src/main/java/com/ning/billing/util/glue/TagStoreModule.java
index 10651be..a598275 100644
--- a/util/src/main/java/com/ning/billing/util/glue/TagStoreModule.java
+++ b/util/src/main/java/com/ning/billing/util/glue/TagStoreModule.java
@@ -18,8 +18,6 @@ package com.ning.billing.util.glue;
 
 import com.google.inject.AbstractModule;
 import com.ning.billing.util.api.TagDefinitionUserApi;
-import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.clock.DefaultClock;
 import com.ning.billing.util.tag.api.DefaultTagDefinitionUserApi;
 import com.ning.billing.util.tag.dao.DefaultTagDefinitionDao;
 import com.ning.billing.util.tag.dao.TagDefinitionDao;
@@ -28,13 +26,16 @@ import com.ning.billing.util.tag.dao.TagStoreSqlDao;
 
 public class TagStoreModule extends AbstractModule
 {
-    @Override
-    protected void configure()
-    {
+    protected void installDaos() {
         bind(TagDefinitionSqlDao.class).toProvider(TagDescriptionDaoProvider.class).asEagerSingleton();
         bind(TagDefinitionDao.class).to(DefaultTagDefinitionDao.class).asEagerSingleton();
         bind(TagStoreSqlDao.class).toProvider(TagStoreDaoProvider.class).asEagerSingleton();
+    }
+
+    @Override
+    protected void configure()
+    {
+        installDaos();
         bind(TagDefinitionUserApi.class).to(DefaultTagDefinitionUserApi.class).asEagerSingleton();
     }
-    
 }
diff --git a/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDefinitionDao.java b/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDefinitionDao.java
new file mode 100644
index 0000000..f09e851
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDefinitionDao.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.util.tag.dao;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.util.api.TagDefinitionApiException;
+import com.ning.billing.util.tag.DefaultTagDefinition;
+import com.ning.billing.util.tag.TagDefinition;
+
+public class MockTagDefinitionDao implements TagDefinitionDao {
+    private final Map<String, TagDefinition> tags = new ConcurrentHashMap<String, TagDefinition>();
+
+    @Override
+    public List<TagDefinition> getTagDefinitions() {
+        return new ArrayList<TagDefinition>(tags.values());
+    }
+
+    @Override
+    public TagDefinition getByName(String definitionName) {
+        return tags.get(definitionName);
+    }
+
+    @Override
+    public TagDefinition create(String definitionName, String description, String createdBy) throws TagDefinitionApiException {
+        TagDefinition tag = new DefaultTagDefinition(UUID.randomUUID(), definitionName, description, createdBy, new DateTime());
+
+        tags.put(definitionName, tag);
+        return tag;
+    }
+
+    @Override
+    public void deleteAllTagsForDefinition(String definitionName) throws TagDefinitionApiException {
+        tags.remove(definitionName);
+    }
+
+    @Override
+    public void deleteTagDefinition(String definitionName) throws TagDefinitionApiException {
+        tags.remove(definitionName);
+    }
+}