killbill-aplcache
Changes
account/pom.xml 1(+0 -1)
beatrix/src/test/resources/log4j.xml 4(+4 -0)
entitlement/src/test/java/com/ning/billing/entitlement/api/billing/BrainDeadMockEntitlementDao.java 1(+1 -0)
entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java 9(+2 -7)
invoice/pom.xml 3(+0 -3)
invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg 6(+6 -0)
invoice/src/test/resources/log4j.xml 36(+36 -0)
pom.xml 2(+1 -1)
Details
account/pom.xml 1(+0 -1)
diff --git a/account/pom.xml b/account/pom.xml
index 141e6cb..8f2eeb1 100644
--- a/account/pom.xml
+++ b/account/pom.xml
@@ -94,7 +94,6 @@
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
- <version>2.0</version>
<scope>test</scope>
</dependency>
</dependencies>
diff --git a/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java b/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
index 3fb68dd..8e5c0b3 100644
--- a/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
+++ b/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
@@ -54,12 +54,27 @@ public class DefaultAccount extends CustomizableEntityBase implements Account {
private final DateTime createdDate;
private final DateTime updatedDate;
- public DefaultAccount(final AccountData data) {
- this(UUID.randomUUID(), data, null, null);
+ /**
+ * This call is used to create a new account
+ * @param data
+ * @param createdDate
+ */
+ public DefaultAccount(final AccountData data, DateTime createdDate) {
+ this(UUID.randomUUID(), data.getExternalKey(), data.getEmail(), data.getName(), data.getFirstNameLength(),
+ data.getCurrency(), data.getBillCycleDay(), data.getPaymentProviderName(),
+ data.getTimeZone(), data.getLocale(),
+ data.getAddress1(), data.getAddress2(), data.getCompanyName(),
+ data.getCity(), data.getStateOrProvince(), data.getCountry(),
+ data.getPostalCode(), data.getPhone(), createdDate, createdDate);
}
- public DefaultAccount(final UUID id, final AccountData data, DateTime createdDate, DateTime updatedDate) {
- this(id, data.getExternalKey(), data.getEmail(), data.getName(), data.getFirstNameLength(),
+ /**
+ * This call is used to migrate an account
+ * @param data
+ * @param createdDate
+ */
+ public DefaultAccount(final AccountData data, DateTime createdDate, DateTime updatedDate) {
+ this(UUID.randomUUID(), data.getExternalKey(), data.getEmail(), data.getName(), data.getFirstNameLength(),
data.getCurrency(), data.getBillCycleDay(), data.getPaymentProviderName(),
data.getTimeZone(), data.getLocale(),
data.getAddress1(), data.getAddress2(), data.getCompanyName(),
@@ -67,6 +82,45 @@ public class DefaultAccount extends CustomizableEntityBase implements Account {
data.getPostalCode(), data.getPhone(), createdDate, updatedDate);
}
+
+ /**
+ * This call is used to update an existing account
+ *
+ * @param id
+ * @param data
+ */
+ public DefaultAccount(final UUID id, final AccountData data) {
+ this(id, data.getExternalKey(), data.getEmail(), data.getName(), data.getFirstNameLength(),
+ data.getCurrency(), data.getBillCycleDay(), data.getPaymentProviderName(),
+ data.getTimeZone(), data.getLocale(),
+ data.getAddress1(), data.getAddress2(), data.getCompanyName(),
+ data.getCity(), data.getStateOrProvince(), data.getCountry(),
+ data.getPostalCode(), data.getPhone(), null, null);
+ }
+
+ /**
+ * This call is used for testing
+ * @param id
+ * @param externalKey
+ * @param email
+ * @param name
+ * @param firstNameLength
+ * @param currency
+ * @param billCycleDay
+ * @param paymentProviderName
+ * @param timeZone
+ * @param locale
+ * @param address1
+ * @param address2
+ * @param companyName
+ * @param city
+ * @param stateOrProvince
+ * @param country
+ * @param postalCode
+ * @param phone
+ * @param createdDate
+ * @param updatedDate
+ */
public DefaultAccount(final UUID id, final String externalKey, final String email, final String name, final int firstNameLength,
final Currency currency, final int billCycleDay, final String paymentProviderName,
final DateTimeZone timeZone, final String locale,
@@ -92,8 +146,8 @@ public class DefaultAccount extends CustomizableEntityBase implements Account {
this.postalCode = postalCode;
this.country = country;
this.phone = phone;
- this.createdDate = createdDate == null ? new DateTime(DateTimeZone.UTC) : createdDate;
- this.updatedDate = updatedDate == null ? new DateTime(DateTimeZone.UTC) : updatedDate;
+ this.createdDate = createdDate == null ? new DateTime(DateTimeZone.UTC) : createdDate; // This is a fallback, we are only expecting these to be set to null
+ this.updatedDate = updatedDate == null ? new DateTime(DateTimeZone.UTC) : updatedDate; // in the case that the account is being updated. In which case the values are ignored anyway
this.tags = new DefaultTagStore(id, getObjectName());
}
diff --git a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
index d128fc5..a6e2b7e 100644
--- a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
+++ b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
@@ -18,26 +18,30 @@ package com.ning.billing.account.api.user;
import java.util.List;
import java.util.UUID;
+
import com.google.inject.Inject;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountApiException;
import com.ning.billing.account.api.AccountData;
import com.ning.billing.account.api.DefaultAccount;
import com.ning.billing.account.dao.AccountDao;
+import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.customfield.CustomField;
import com.ning.billing.util.tag.Tag;
public class DefaultAccountUserApi implements com.ning.billing.account.api.AccountUserApi {
private final AccountDao dao;
+ private Clock clock;
@Inject
- public DefaultAccountUserApi(final AccountDao dao) {
+ public DefaultAccountUserApi(final AccountDao dao, final Clock clock) {
this.dao = dao;
+ this.clock = clock;
}
@Override
public Account createAccount(final AccountData data, final List<CustomField> fields, List<Tag> tags) throws AccountApiException {
- Account account = new DefaultAccount(data);
+ Account account = new DefaultAccount(data, clock.getUTCNow());
account.addFields(fields);
account.addTags(tags);
diff --git a/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java b/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
index 1f70152..1e00dba 100644
--- a/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
@@ -89,18 +89,18 @@ public class DefaultAccountDao implements AccountDao {
public void create(final Account account) throws AccountApiException {
final String key = account.getExternalKey();
try {
+
accountSqlDao.inTransaction(new Transaction<Void, AccountSqlDao>() {
@Override
- public Void inTransaction(final AccountSqlDao accountSqlDao, final TransactionStatus status) throws AccountApiException, Bus.EventBusException {
- Account currentAccount = accountSqlDao.getAccountByKey(key);
+ public Void inTransaction(final AccountSqlDao transactionalDao, final TransactionStatus status) throws AccountApiException, Bus.EventBusException {
+ Account currentAccount = transactionalDao.getAccountByKey(key);
if (currentAccount != null) {
throw new AccountApiException(ErrorCode.ACCOUNT_ALREADY_EXISTS, key);
}
- accountSqlDao.create(account);
-
- saveTagsFromWithinTransaction(account, accountSqlDao, true);
- saveCustomFieldsFromWithinTransaction(account, accountSqlDao, true);
+ transactionalDao.create(account);
+ saveTagsFromWithinTransaction(account, transactionalDao, true);
+ saveCustomFieldsFromWithinTransaction(account, transactionalDao, true);
AccountCreationNotification creationEvent = new DefaultAccountCreationEvent(account);
eventBus.post(creationEvent);
return null;
@@ -210,7 +210,7 @@ public class DefaultAccountDao implements AccountDao {
List<Tag> tagList = account.getTagList();
if (tagList != null) {
- tagStoreDao.save(accountId, objectType, tagList);
+ tagStoreDao.batchSaveFromTransaction(accountId, objectType, tagList);
}
}
@@ -225,7 +225,7 @@ public class DefaultAccountDao implements AccountDao {
List<CustomField> fieldList = account.getFieldList();
if (fieldList != null) {
- fieldStoreDao.save(accountId, objectType, fieldList);
+ fieldStoreDao.batchSaveFromTransaction(accountId, objectType, fieldList);
}
}
diff --git a/account/src/test/java/com/ning/billing/account/api/MockAccountUserApi.java b/account/src/test/java/com/ning/billing/account/api/MockAccountUserApi.java
index 433a663..28f0107 100644
--- a/account/src/test/java/com/ning/billing/account/api/MockAccountUserApi.java
+++ b/account/src/test/java/com/ning/billing/account/api/MockAccountUserApi.java
@@ -22,6 +22,7 @@ import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
+import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import com.ning.billing.catalog.api.Currency;
@@ -61,7 +62,7 @@ public class MockAccountUserApi implements AccountUserApi {
@Override
public Account createAccount(AccountData data, List<CustomField> fields, List<Tag> tags) throws AccountApiException {
- Account result = new DefaultAccount(data);
+ Account result = new DefaultAccount(data, new DateTime());
accounts.add(result);
return result;
}
diff --git a/account/src/test/java/com/ning/billing/account/dao/TestSimpleAccountDao.java b/account/src/test/java/com/ning/billing/account/dao/TestSimpleAccountDao.java
index fd5350b..1c118a9 100644
--- a/account/src/test/java/com/ning/billing/account/dao/TestSimpleAccountDao.java
+++ b/account/src/test/java/com/ning/billing/account/dao/TestSimpleAccountDao.java
@@ -252,7 +252,7 @@ public class TestSimpleAccountDao extends AccountDaoTestBase {
}
};
- Account updatedAccount = new DefaultAccount(account.getId(), accountData, null, null);
+ Account updatedAccount = new DefaultAccount(account.getId(), accountData);
accountDao.update(updatedAccount);
Account savedAccount = accountDao.getAccountByKey(account.getExternalKey());
diff --git a/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithEmbeddedDb.java b/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithEmbeddedDb.java
index f0e5022..1a894a7 100644
--- a/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithEmbeddedDb.java
+++ b/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithEmbeddedDb.java
@@ -17,6 +17,7 @@
package com.ning.billing.account.glue;
import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.util.clock.MockClockModule;
import com.ning.billing.util.glue.BusModule;
import org.skife.jdbi.v2.IDBI;
@@ -42,5 +43,6 @@ public class AccountModuleWithEmbeddedDb extends AccountModule {
bind(IDBI.class).toInstance(helper.getDBI());
super.configure();
install(new BusModule());
+ install(new MockClockModule());
}
}
diff --git a/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithMocks.java b/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithMocks.java
index fb72404..1c65c3c 100644
--- a/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithMocks.java
+++ b/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithMocks.java
@@ -18,6 +18,7 @@ package com.ning.billing.account.glue;
import com.ning.billing.account.dao.AccountDao;
import com.ning.billing.account.dao.MockAccountDao;
+import com.ning.billing.util.clock.MockClockModule;
public class AccountModuleWithMocks extends AccountModule {
@Override
@@ -25,4 +26,11 @@ public class AccountModuleWithMocks extends AccountModule {
bind(MockAccountDao.class).asEagerSingleton();
bind(AccountDao.class).to(MockAccountDao.class);
}
+
+
+ @Override
+ protected void configure() {
+ super.configure();
+ install(new MockClockModule());
+ }
}
diff --git a/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java b/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
index ec55586..25496b5 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
@@ -22,9 +22,10 @@ import com.ning.billing.analytics.setup.AnalyticsModule;
import com.ning.billing.catalog.glue.CatalogModule;
import com.ning.billing.dbi.MysqlTestingHelper;
import com.ning.billing.entitlement.glue.EntitlementModule;
-import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.clock.DefaultClock;
+
import com.ning.billing.util.glue.BusModule;
+
+import com.ning.billing.util.glue.ClockModule;
import com.ning.billing.util.glue.NotificationQueueModule;
import com.ning.billing.util.glue.TagStoreModule;
@@ -40,11 +41,10 @@ public class AnalyticsTestModule extends AnalyticsModule
install(new CatalogModule());
install(new BusModule());
install(new EntitlementModule());
+ install(new ClockModule());
install(new TagStoreModule());
install(new NotificationQueueModule());
- bind(Clock.class).to(DefaultClock.class).asEagerSingleton();
-
// Install the Dao layer
final MysqlTestingHelper helper = new MysqlTestingHelper();
bind(MysqlTestingHelper.class).toInstance(helper);
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockIAccountUserApi.java b/analytics/src/test/java/com/ning/billing/analytics/MockIAccountUserApi.java
index 2ce98b8..0722494 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockIAccountUserApi.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockIAccountUserApi.java
@@ -24,6 +24,7 @@ import com.ning.billing.account.api.AccountData;
import com.ning.billing.account.api.AccountUserApi;
import com.ning.billing.account.api.DefaultAccount;
import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.customfield.CustomField;
import com.ning.billing.util.tag.Tag;
@@ -31,11 +32,13 @@ public class MockIAccountUserApi implements AccountUserApi
{
private final AccountData account;
private final UUID id;
+ private Clock clock;
- public MockIAccountUserApi(final String accountKey, final Currency currency)
+ public MockIAccountUserApi(final String accountKey, final Currency currency, final Clock clock)
{
this.id = UUID.randomUUID();
account = new MockAccount(id, accountKey, currency);
+ this.clock = clock;
}
@Override
@@ -57,7 +60,7 @@ public class MockIAccountUserApi implements AccountUserApi
@Override
public Account getAccountById(final UUID uid) {
- return new DefaultAccount(account);
+ return new DefaultAccount(account, clock.getUTCNow());
}
@Override
diff --git a/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java b/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java
index 470263e..ec6d9ae 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java
@@ -16,6 +16,9 @@
package com.ning.billing.analytics;
+
+import java.util.UUID;
+
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.catalog.api.PhaseType;
import com.ning.billing.catalog.api.Plan;
@@ -26,13 +29,14 @@ import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
import com.ning.billing.entitlement.events.EntitlementEvent;
import com.ning.billing.entitlement.events.user.ApiEventType;
+import com.ning.billing.util.clock.ClockMock;
+
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-import java.util.UUID;
public class TestAnalyticsListener
{
@@ -53,7 +57,7 @@ public class TestAnalyticsListener
@BeforeMethod(alwaysRun = true)
public void setUp() throws Exception
{
- final BusinessSubscriptionTransitionRecorder recorder = new BusinessSubscriptionTransitionRecorder(dao, new MockIEntitlementUserApi(bundleUUID, KEY), new MockIAccountUserApi(ACCOUNT_KEY, CURRENCY));
+ final BusinessSubscriptionTransitionRecorder recorder = new BusinessSubscriptionTransitionRecorder(dao, new MockIEntitlementUserApi(bundleUUID, KEY), new MockIAccountUserApi(ACCOUNT_KEY, CURRENCY, new ClockMock()));
listener = new AnalyticsListener(recorder, null);
}
diff --git a/api/src/main/java/com/ning/billing/invoice/api/Invoice.java b/api/src/main/java/com/ning/billing/invoice/api/Invoice.java
index 0d13363..4a61849 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/Invoice.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/Invoice.java
@@ -31,6 +31,8 @@ public interface Invoice extends Entity {
List<InvoiceItem> getInvoiceItems();
+ List<InvoiceItem> getInvoiceItems(Class clazz);
+
int getNumberOfItems();
boolean addPayment(InvoicePayment payment);
diff --git a/api/src/main/java/com/ning/billing/payment/api/CreditCardPaymentMethodInfo.java b/api/src/main/java/com/ning/billing/payment/api/CreditCardPaymentMethodInfo.java
index 6f767ff..a9e25dc 100644
--- a/api/src/main/java/com/ning/billing/payment/api/CreditCardPaymentMethodInfo.java
+++ b/api/src/main/java/com/ning/billing/payment/api/CreditCardPaymentMethodInfo.java
@@ -36,6 +36,16 @@ public final class CreditCardPaymentMethodInfo extends PaymentMethodInfo {
public Builder(CreditCardPaymentMethodInfo src) {
super(Builder.class, src);
+ this.cardHolderName = src.cardHolderName;
+ this.cardType = src.cardType;
+ this.expirationDate = src.expirationDate;
+ this.cardAddress1 = src.cardAddress1;
+ this.cardAddress2 = src.cardAddress2;
+ this.cardCity = src.cardCity;
+ this.cardState = src.cardState;
+ this.cardPostalCode = src.cardPostalCode;
+ this.cardCountry = src.cardCountry;
+ this.maskNumber = src.maskNumber;
}
public Builder setCardHolderName(String cardHolderName) {
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 be1f649..189e87c 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
@@ -45,7 +45,7 @@ public interface PaymentApi {
Either<PaymentError, String> createPaymentProviderAccount(Account account);
- Either<PaymentError, Void> updatePaymentProviderAccount(Account account);
+ Either<PaymentError, Void> updatePaymentProviderAccountContact(Account account);
PaymentAttempt getPaymentAttemptForPaymentId(String id);
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentAttempt.java b/api/src/main/java/com/ning/billing/payment/api/PaymentAttempt.java
index 48d89e9..b5df043 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentAttempt.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentAttempt.java
@@ -35,6 +35,8 @@ public class PaymentAttempt {
private final String paymentId;
private final DateTime invoiceDate;
private final DateTime paymentAttemptDate;
+ private final Integer retryCount;
+ private final DateTime nextRetryDate;
private final DateTime createdDate;
private final DateTime updatedDate;
@@ -46,6 +48,8 @@ public class PaymentAttempt {
DateTime invoiceDate,
DateTime paymentAttemptDate,
String paymentId,
+ Integer retryCount,
+ DateTime nextRetryDate,
DateTime createdDate,
DateTime updatedDate) {
this.paymentAttemptId = paymentAttemptId;
@@ -56,8 +60,10 @@ public class PaymentAttempt {
this.invoiceDate = invoiceDate;
this.paymentAttemptDate = paymentAttemptDate == null ? new DateTime(DateTimeZone.UTC) : paymentAttemptDate;
this.paymentId = paymentId;
- this.createdDate = createdDate;
- this.updatedDate = updatedDate;
+ this.retryCount = retryCount;
+ this.nextRetryDate = nextRetryDate;
+ this.createdDate = createdDate == null ? new DateTime(DateTimeZone.UTC) : createdDate;
+ this.updatedDate = updatedDate == null ? new DateTime(DateTimeZone.UTC) : updatedDate;
}
public PaymentAttempt(UUID paymentAttemptId,
@@ -67,20 +73,33 @@ public class PaymentAttempt {
Currency currency,
DateTime invoiceDate,
DateTime paymentAttemptDate,
- String paymentId) {
- this(paymentAttemptId, invoiceId, accountId, amount, currency, invoiceDate, paymentAttemptDate, paymentId, new DateTime(DateTimeZone.UTC), new DateTime(DateTimeZone.UTC));
+ String paymentId,
+ Integer retryCount,
+ DateTime nextRetryDate) {
+ this(paymentAttemptId,
+ invoiceId,
+ accountId,
+ amount,
+ currency,
+ invoiceDate,
+ paymentAttemptDate,
+ paymentId,
+ retryCount,
+ nextRetryDate,
+ null,
+ null);
}
public PaymentAttempt(UUID paymentAttemptId, UUID invoiceId, UUID accountId, BigDecimal amount, Currency currency, DateTime invoiceDate, DateTime paymentAttemptDate) {
- this(paymentAttemptId, invoiceId, accountId, amount, currency, invoiceDate, paymentAttemptDate, null);
+ this(paymentAttemptId, invoiceId, accountId, amount, currency, invoiceDate, paymentAttemptDate, null, null, null);
}
public PaymentAttempt(UUID paymentAttemptId, UUID invoiceId, UUID accountId, DateTime invoiceDate, DateTime paymentAttemptDate) {
- this(paymentAttemptId, invoiceId, accountId, null, null, invoiceDate, paymentAttemptDate, null);
+ this(paymentAttemptId, invoiceId, accountId, null, null, invoiceDate, paymentAttemptDate, null, null, null);
}
public PaymentAttempt(UUID paymentAttemptId, Invoice invoice) {
- this(paymentAttemptId, invoice.getId(), invoice.getAccountId(), invoice.getBalance(), invoice.getCurrency(), invoice.getInvoiceDate(), null);
+ this(paymentAttemptId, invoice.getId(), invoice.getAccountId(), invoice.getBalance(), invoice.getCurrency(), invoice.getInvoiceDate(), null, null, null, null);
}
public DateTime getInvoiceDate() {
@@ -123,9 +142,17 @@ public class PaymentAttempt {
return currency;
}
+ public Integer getRetryCount() {
+ return retryCount;
+ }
+
+ public DateTime getNextRetryDate() {
+ return nextRetryDate;
+ }
+
@Override
public String toString() {
- return "PaymentAttempt [paymentAttemptId=" + paymentAttemptId + ", invoiceId=" + invoiceId + ", amount=" + amount + ", currency=" + currency + ", paymentId=" + paymentId + ", paymentAttemptDate=" + paymentAttemptDate + "]";
+ return "PaymentAttempt [paymentAttemptId=" + paymentAttemptId + ", invoiceId=" + invoiceId + ", accountId=" + accountId + ", amount=" + amount + ", currency=" + currency + ", paymentId=" + paymentId + ", invoiceDate=" + invoiceDate + ", paymentAttemptDate=" + paymentAttemptDate + ", retryCount=" + retryCount + ", nextRetryDate=" + nextRetryDate + ", createdDate=" + createdDate + ", updatedDate=" + updatedDate + "]";
}
public Builder cloner() {
@@ -141,6 +168,8 @@ public class PaymentAttempt {
private DateTime invoiceDate;
private DateTime paymentAttemptDate;
private String paymentId;
+ private Integer retryCount;
+ private DateTime nextRetryDate;
private DateTime createdDate;
private DateTime updatedDate;
@@ -156,6 +185,8 @@ public class PaymentAttempt {
this.invoiceDate = src.invoiceDate;
this.paymentAttemptDate = src.paymentAttemptDate;
this.paymentId = src.paymentId;
+ this.retryCount = src.retryCount;
+ this.nextRetryDate = src.nextRetryDate;
this.createdDate = src.createdDate;
this.updatedDate = src.updatedDate;
}
@@ -210,6 +241,16 @@ public class PaymentAttempt {
return this;
}
+ public Builder setRetryCount(Integer retryCount) {
+ this.retryCount = retryCount;
+ return this;
+ }
+
+ public Builder setNextRetryDate(DateTime nextRetryDate) {
+ this.nextRetryDate = nextRetryDate;
+ return this;
+ }
+
public PaymentAttempt build() {
return new PaymentAttempt(paymentAttemptId,
invoiceId,
@@ -219,6 +260,8 @@ public class PaymentAttempt {
invoiceDate,
paymentAttemptDate,
paymentId,
+ retryCount,
+ nextRetryDate,
createdDate,
updatedDate);
}
@@ -233,7 +276,11 @@ public class PaymentAttempt {
currency,
invoiceDate,
paymentAttemptDate,
- paymentId);
+ paymentId,
+ retryCount,
+ nextRetryDate,
+ createdDate,
+ updatedDate);
}
@Override
@@ -251,6 +298,8 @@ public class PaymentAttempt {
Objects.equal(currency, other.currency) &&
Objects.equal(invoiceDate, other.invoiceDate) &&
Objects.equal(paymentAttemptDate, other.paymentAttemptDate) &&
+ Objects.equal(retryCount, other.retryCount) &&
+ Objects.equal(nextRetryDate, other.nextRetryDate) &&
Objects.equal(paymentId, other.paymentId);
}
}
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentInfo.java b/api/src/main/java/com/ning/billing/payment/api/PaymentInfo.java
index b8dc8cd..943c5f7 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentInfo.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentInfo.java
@@ -21,6 +21,7 @@ import java.math.BigDecimal;
import org.codehaus.jackson.annotate.JsonCreator;
import org.codehaus.jackson.annotate.JsonProperty;
import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
import com.google.common.base.Objects;
import com.ning.billing.util.bus.BusEvent;
@@ -34,24 +35,14 @@ public class PaymentInfo implements BusEvent {
private final String status;
private final String type;
private final String referenceId;
+ private final String paymentMethodId;
+ private final String paymentMethod;
+ private final String cardType;
+ private final String cardCoutry;
private final DateTime effectiveDate;
private final DateTime createdDate;
private final DateTime updatedDate;
- public PaymentInfo(PaymentInfo src) {
- this.paymentId = src.paymentId;
- this.amount = src.amount;
- this.refundAmount = src.refundAmount;
- this.paymentNumber = src.paymentNumber;
- this.bankIdentificationNumber = src.bankIdentificationNumber;
- this.status = src.status;
- this.type = src.type;
- this.referenceId = src.referenceId;
- this.effectiveDate = src.effectiveDate;
- this.createdDate = src.createdDate;
- this.updatedDate = src.updatedDate;
- }
-
@JsonCreator
public PaymentInfo(@JsonProperty("paymentId") String paymentId,
@JsonProperty("amount") BigDecimal amount,
@@ -61,6 +52,10 @@ public class PaymentInfo implements BusEvent {
@JsonProperty("status") String status,
@JsonProperty("type") String type,
@JsonProperty("referenceId") String referenceId,
+ @JsonProperty("paymentMethodId") String paymentMethodId,
+ @JsonProperty("paymentMethod") String paymentMethod,
+ @JsonProperty("cardType") String cardType,
+ @JsonProperty("cardCountry") String cardCountry,
@JsonProperty("effectiveDate") DateTime effectiveDate,
@JsonProperty("createdDate") DateTime createdDate,
@JsonProperty("updatedDate") DateTime updatedDate) {
@@ -68,13 +63,35 @@ public class PaymentInfo implements BusEvent {
this.amount = amount;
this.refundAmount = refundAmount;
this.bankIdentificationNumber = bankIdentificationNumber;
- this.effectiveDate = effectiveDate;
this.paymentNumber = paymentNumber;
- this.referenceId = referenceId;
this.status = status;
this.type = type;
- this.createdDate = createdDate;
- this.updatedDate = updatedDate;
+ this.referenceId = referenceId;
+ this.paymentMethodId = paymentMethodId;
+ this.paymentMethod = paymentMethod;
+ this.cardType = cardType;
+ this.cardCoutry = cardCountry;
+ this.effectiveDate = effectiveDate;
+ this.createdDate = createdDate == null ? new DateTime(DateTimeZone.UTC) : createdDate;
+ this.updatedDate = updatedDate == null ? new DateTime(DateTimeZone.UTC) : updatedDate;
+ }
+
+ public PaymentInfo(PaymentInfo src) {
+ this(src.paymentId,
+ src.amount,
+ src.refundAmount,
+ src.bankIdentificationNumber,
+ src.paymentNumber,
+ src.status,
+ src.type,
+ src.referenceId,
+ src.paymentMethodId,
+ src.paymentMethod,
+ src.cardType,
+ src.cardCoutry,
+ src.effectiveDate,
+ src.createdDate,
+ src.updatedDate);
}
public Builder cloner() {
@@ -105,10 +122,26 @@ public class PaymentInfo implements BusEvent {
return paymentNumber;
}
+ public String getPaymentMethod() {
+ return paymentMethod;
+ }
+
+ public String getCardType() {
+ return cardType;
+ }
+
+ public String getCardCountry() {
+ return cardCoutry;
+ }
+
public String getReferenceId() {
return referenceId;
}
+ public String getPaymentMethodId() {
+ return paymentMethodId;
+ }
+
public BigDecimal getRefundAmount() {
return refundAmount;
}
@@ -134,6 +167,10 @@ public class PaymentInfo implements BusEvent {
private String type;
private String status;
private String referenceId;
+ private String paymentMethodId;
+ private String paymentMethod;
+ private String cardType;
+ private String cardCountry;
private DateTime effectiveDate;
private DateTime createdDate;
private DateTime updatedDate;
@@ -151,6 +188,10 @@ public class PaymentInfo implements BusEvent {
this.status = src.status;
this.effectiveDate = src.effectiveDate;
this.referenceId = src.referenceId;
+ this.paymentMethodId = src.paymentMethodId;
+ this.paymentMethod = src.paymentMethod;
+ this.cardType = src.cardType;
+ this.cardCountry = src.cardCoutry;
this.createdDate = src.createdDate;
this.updatedDate = src.updatedDate;
}
@@ -205,6 +246,26 @@ public class PaymentInfo implements BusEvent {
return this;
}
+ public Builder setPaymentMethodId(String paymentMethodId) {
+ this.paymentMethodId = paymentMethodId;
+ return this;
+ }
+
+ public Builder setPaymentMethod(String paymentMethod) {
+ this.paymentMethod = paymentMethod;
+ return this;
+ }
+
+ public Builder setCardType(String cardType) {
+ this.cardType = cardType;
+ return this;
+ }
+
+ public Builder setCardCountry(String cardCountry) {
+ this.cardCountry = cardCountry;
+ return this;
+ }
+
public Builder setUpdatedDate(DateTime updatedDate) {
this.updatedDate = updatedDate;
return this;
@@ -216,9 +277,13 @@ public class PaymentInfo implements BusEvent {
refundAmount,
bankIdentificationNumber,
paymentNumber,
- type,
status,
+ type,
referenceId,
+ paymentMethodId,
+ paymentMethod,
+ cardType,
+ cardCountry,
effectiveDate,
createdDate,
updatedDate);
@@ -227,16 +292,20 @@ public class PaymentInfo implements BusEvent {
@Override
public int hashCode() {
- return Objects.hashCode(amount,
+ return Objects.hashCode(paymentId,
+ amount,
+ refundAmount,
bankIdentificationNumber,
- createdDate,
- effectiveDate,
- paymentId,
paymentNumber,
- referenceId,
- refundAmount,
status,
type,
+ referenceId,
+ paymentMethodId,
+ paymentMethod,
+ cardType,
+ cardCoutry,
+ effectiveDate,
+ createdDate,
updatedDate);
}
@@ -250,14 +319,18 @@ public class PaymentInfo implements BusEvent {
else {
return Objects.equal(amount, other.amount) &&
Objects.equal(bankIdentificationNumber, other.bankIdentificationNumber) &&
- Objects.equal(createdDate, other.createdDate) &&
- Objects.equal(effectiveDate, other.effectiveDate) &&
Objects.equal(paymentId, other.paymentId) &&
Objects.equal(paymentNumber, other.paymentNumber) &&
Objects.equal(referenceId, other.referenceId) &&
Objects.equal(refundAmount, other.refundAmount) &&
Objects.equal(status, other.status) &&
Objects.equal(type, other.type) &&
+ Objects.equal(paymentMethodId, other.paymentMethodId) &&
+ Objects.equal(paymentMethod, other.paymentMethod) &&
+ Objects.equal(cardType, other.cardType) &&
+ Objects.equal(cardCoutry, other.cardCoutry) &&
+ Objects.equal(effectiveDate, other.effectiveDate) &&
+ Objects.equal(createdDate, other.createdDate) &&
Objects.equal(updatedDate, other.updatedDate);
}
}
@@ -266,6 +339,7 @@ public class PaymentInfo implements BusEvent {
@Override
public String toString() {
- return "PaymentInfo [paymentId=" + paymentId + ", amount=" + amount + ", refundAmount=" + refundAmount + ", paymentNumber=" + paymentNumber + ", bankIdentificationNumber=" + bankIdentificationNumber + ", status=" + status + ", type=" + type + ", referenceId=" + referenceId + ", effectiveDate=" + effectiveDate + ", createdDate=" + createdDate + ", updatedDate=" + updatedDate + "]";
+ return "PaymentInfo [paymentId=" + paymentId + ", amount=" + amount + ", refundAmount=" + refundAmount + ", paymentNumber=" + paymentNumber + ", bankIdentificationNumber=" + bankIdentificationNumber + ", status=" + status + ", type=" + type + ", referenceId=" + referenceId + ", paymentMethodId=" + paymentMethodId + ", paymentMethod=" + paymentMethod + ", cardType=" + cardType + ", cardCountry=" + cardCoutry + ", effectiveDate=" + effectiveDate + ", createdDate=" + createdDate + ", updatedDate=" + updatedDate + "]";
}
+
}
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentProviderAccount.java b/api/src/main/java/com/ning/billing/payment/api/PaymentProviderAccount.java
index 553d6a2..47cad39 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentProviderAccount.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentProviderAccount.java
@@ -20,18 +20,18 @@ import com.google.common.base.Objects;
public class PaymentProviderAccount {
private final String id;
- private final String accountNumber;
+ private final String accountKey;
private final String accountName;
private final String phoneNumber;
private final String defaultPaymentMethodId;
public PaymentProviderAccount(String id,
- String accountNumber,
+ String accountKey,
String accountName,
String phoneNumber,
String defaultPaymentMethodId) {
this.id = id;
- this.accountNumber = accountNumber;
+ this.accountKey = accountKey;
this.accountName = accountName;
this.phoneNumber = phoneNumber;
this.defaultPaymentMethodId = defaultPaymentMethodId;
@@ -41,8 +41,8 @@ public class PaymentProviderAccount {
return id;
}
- public String getAccountNumber() {
- return accountNumber;
+ public String getAccountKey() {
+ return accountKey;
}
public String getAccountName() {
@@ -59,18 +59,27 @@ public class PaymentProviderAccount {
public static class Builder {
private String id;
- private String accountNumber;
+ private String accountKey;
private String accountName;
private String phoneNumber;
private String defaultPaymentMethodId;
+ public Builder copyFrom(PaymentProviderAccount src) {
+ this.id = src.getId();
+ this.accountKey = src.getAccountKey();
+ this.accountName = src.getAccountName();
+ this.phoneNumber = src.getPhoneNumber();
+ this.defaultPaymentMethodId = src.getDefaultPaymentMethodId();
+ return this;
+ }
+
public Builder setId(String id) {
this.id = id;
return this;
}
- public Builder setAccountNumber(String accountNumber) {
- this.accountNumber = accountNumber;
+ public Builder setAccountKey(String accountKey) {
+ this.accountKey = accountKey;
return this;
}
@@ -90,7 +99,7 @@ public class PaymentProviderAccount {
}
public PaymentProviderAccount build() {
- return new PaymentProviderAccount(id, accountNumber, accountName, phoneNumber, defaultPaymentMethodId);
+ return new PaymentProviderAccount(id, accountKey, accountName, phoneNumber, defaultPaymentMethodId);
}
}
@@ -98,7 +107,7 @@ public class PaymentProviderAccount {
@Override
public int hashCode() {
return Objects.hashCode(id,
- accountNumber,
+ accountKey,
accountName,
phoneNumber,
defaultPaymentMethodId);
@@ -113,7 +122,8 @@ public class PaymentProviderAccount {
}
else {
return Objects.equal(id, other.id) &&
- Objects.equal(accountNumber, other.accountNumber) &&
+ Objects.equal(accountKey, other.accountKey) &&
+ Objects.equal(accountName, other.accountName) &&
Objects.equal(phoneNumber, other.phoneNumber) &&
Objects.equal(defaultPaymentMethodId, other.defaultPaymentMethodId);
}
@@ -121,4 +131,9 @@ public class PaymentProviderAccount {
return false;
}
+ @Override
+ public String toString() {
+ return "PaymentProviderAccount [id=" + id + ", accountKey=" + accountKey + ", accountName=" + accountName + ", phoneNumber=" + phoneNumber + ", defaultPaymentMethodId=" + defaultPaymentMethodId + "]";
+ }
+
}
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaypalPaymentMethodInfo.java b/api/src/main/java/com/ning/billing/payment/api/PaypalPaymentMethodInfo.java
index 8b94f15..0977071 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaypalPaymentMethodInfo.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaypalPaymentMethodInfo.java
@@ -32,6 +32,8 @@ public final class PaypalPaymentMethodInfo extends PaymentMethodInfo {
public Builder(PaypalPaymentMethodInfo src) {
super(Builder.class, src);
+ this.baid = src.baid;
+ this.email = src.email;
}
public Builder setBaid(String baid) {
@@ -59,8 +61,8 @@ public final class PaypalPaymentMethodInfo extends PaymentMethodInfo {
String email) {
super(id, accountId, defaultMethod, TYPE);
- if (Strings.isNullOrEmpty(accountId) || Strings.isNullOrEmpty(baid) || Strings.isNullOrEmpty(email)) {
- throw new IllegalArgumentException("accountId, baid and email should be present");
+ if (Strings.isNullOrEmpty(baid) || Strings.isNullOrEmpty(email)) {
+ throw new IllegalArgumentException("baid and email should be present");
}
this.baid = baid;
@@ -74,4 +76,10 @@ public final class PaypalPaymentMethodInfo extends PaymentMethodInfo {
public String getEmail() {
return email;
}
+
+ @Override
+ public String toString() {
+ return "PaypalPaymentMethodInfo [baid=" + baid + ", email=" + email + "]";
+ }
+
}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/MockModule.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/MockModule.java
index 8816190..28294f9 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/MockModule.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/MockModule.java
@@ -45,6 +45,7 @@ import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.clock.ClockMock;
import com.ning.billing.util.bus.BusService;
import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.GlobalLockerModule;
import com.ning.billing.util.glue.NotificationQueueModule;
@@ -67,6 +68,7 @@ public class MockModule extends AbstractModule {
install(new CatalogModule());
install(new EntitlementModule());
install(new InvoiceModule());
+ install(new GlobalLockerModule());
}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBasic.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBasic.java
index 83c699f..1f2adce 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBasic.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBasic.java
@@ -163,6 +163,7 @@ public class TestBasic {
}
private DateTime checkAndGetCTD(UUID subscriptionId) {
+
SubscriptionData subscription = (SubscriptionData) entitlementUserApi.getSubscriptionFromId(subscriptionId);
DateTime ctd = subscription.getChargedThroughDate();
assertNotNull(ctd);
@@ -206,13 +207,13 @@ public class TestBasic {
SubscriptionData subscription = (SubscriptionData) entitlementUserApi.createSubscription(bundle.getId(),
new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null), null);
assertNotNull(subscription);
-
assertTrue(busHandler.isCompleted(DELAY));
log.info("testSimple passed first busHandler checkpoint.");
//
// VERIFY CTD HAS BEEN SET
//
+
checkAndGetCTD(subscription.getId());
//
@@ -240,6 +241,7 @@ public class TestBasic {
busHandler.pushExpectedEvent(NextEvent.PHASE);
busHandler.pushExpectedEvent(NextEvent.INVOICE);
clock.setDeltaFromReality(AT_LEAST_ONE_MONTH_MS);
+
assertTrue(busHandler.isCompleted(DELAY));
//
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBusHandler.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBusHandler.java
index 54f4b4c..2cfd46d 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBusHandler.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBusHandler.java
@@ -55,7 +55,7 @@ public class TestBusHandler {
@Subscribe
public void handleEntitlementEvents(SubscriptionTransition event) {
- log.info(String.format("Got subscription event %s", event.toString()));
+ log.info(String.format("TestBusHandler Got subscription event %s", event.toString()));
switch (event.getTransitionType()) {
case MIGRATE_ENTITLEMENT:
assertEqualsNicely(NextEvent.MIGRATE_ENTITLEMENT);
@@ -101,7 +101,7 @@ public class TestBusHandler {
@Subscribe
public void handleInvoiceEvents(InvoiceCreationNotification event) {
- log.info(String.format("Got Invoice event %s", event.toString()));
+ log.info(String.format("TestBusHandler Got Invoice event %s", event.toString()));
assertEqualsNicely(NextEvent.INVOICE);
notifyIfStackEmpty();
@@ -130,13 +130,14 @@ public class TestBusHandler {
}
}
if (!completed) {
- log.debug("TestBusHandler did not complete in " + timeout + " ms");
+ Joiner joiner = Joiner.on(" ");
+ log.error("TestBusHandler did not complete in " + timeout + " ms, remaining events are " + joiner.join(nextExpectedEvent));
}
return completed;
}
private void notifyIfStackEmpty() {
- log.debug("notifyIfStackEmpty ENTER");
+ log.debug("TestBusHandler notifyIfStackEmpty ENTER");
synchronized (this) {
if (nextExpectedEvent.isEmpty()) {
log.debug("notifyIfStackEmpty EMPTY");
@@ -144,7 +145,7 @@ public class TestBusHandler {
notify();
}
}
- log.debug("notifyIfStackEmpty EXIT");
+ log.debug("TestBusHandler notifyIfStackEmpty EXIT");
}
private void assertEqualsNicely(NextEvent received) {
@@ -161,7 +162,7 @@ public class TestBusHandler {
}
if (!foundIt) {
Joiner joiner = Joiner.on(" ");
- System.err.println("Received event " + received + "; expected " + joiner.join(nextExpectedEvent));
+ log.error("TestBusHandler Received event " + received + "; expected " + joiner.join(nextExpectedEvent));
// System.exit(1);
}
}
beatrix/src/test/resources/log4j.xml 4(+4 -0)
diff --git a/beatrix/src/test/resources/log4j.xml b/beatrix/src/test/resources/log4j.xml
index 75abc76..ac530a1 100644
--- a/beatrix/src/test/resources/log4j.xml
+++ b/beatrix/src/test/resources/log4j.xml
@@ -29,6 +29,10 @@
<level value="info"/>
</logger>
+ <logger name="com.ning.billing.util.notificationq">
+ <level value="info"/>
+ </logger>
+
<root>
<priority value="info"/>
<appender-ref ref="stdout"/>
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java b/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
index 7c5eee6..c27a8f4 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
@@ -16,6 +16,8 @@
package com.ning.billing.entitlement.glue;
+import org.skife.config.ConfigurationObjectFactory;
+
import com.google.inject.AbstractModule;
import com.ning.billing.config.EntitlementConfig;
import com.ning.billing.entitlement.alignment.MigrationPlanAligner;
@@ -31,12 +33,8 @@ import com.ning.billing.entitlement.api.user.DefaultEntitlementUserApi;
import com.ning.billing.entitlement.api.user.EntitlementUserApi;
import com.ning.billing.entitlement.api.user.SubscriptionApiService;
import com.ning.billing.entitlement.engine.core.Engine;
-import com.ning.billing.entitlement.engine.core.EventNotifier;
import com.ning.billing.entitlement.engine.dao.EntitlementDao;
import com.ning.billing.entitlement.engine.dao.EntitlementSqlDao;
-import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.clock.DefaultClock;
-import org.skife.config.ConfigurationObjectFactory;
@@ -48,6 +46,7 @@ public class EntitlementModule extends AbstractModule {
bind(EntitlementConfig.class).toInstance(config);
}
+
protected void installEntitlementDao() {
bind(EntitlementDao.class).to(EntitlementSqlDao.class).asEagerSingleton();
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/BrainDeadMockEntitlementDao.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/BrainDeadMockEntitlementDao.java
index 7b49fde..4d57dac 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/BrainDeadMockEntitlementDao.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/BrainDeadMockEntitlementDao.java
@@ -134,6 +134,7 @@ class BrainDeadMockEntitlementDao implements EntitlementDao {
throw new UnsupportedOperationException();
}
+
@Override
public EntitlementEvent getEventById(final UUID eventId) {
throw new UnsupportedOperationException();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
index 46ad9a2..91ddc91 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
@@ -28,7 +28,6 @@ import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
@@ -57,7 +56,7 @@ import com.ning.billing.entitlement.events.EntitlementEvent.EventType;
import com.ning.billing.entitlement.events.user.ApiEventType;
import com.ning.billing.lifecycle.KillbillService.ServiceException;
import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.clock.DefaultClock;
+import com.ning.billing.util.glue.ClockModule;
import static org.testng.Assert.assertTrue;
@@ -79,11 +78,7 @@ public class TestDefaultEntitlementBillingApi {
@BeforeClass(groups={"setup"})
public void setup() throws ServiceException {
TestApiBase.loadSystemPropertiesFromClasspath("/entitlement.properties");
- final Injector g = Guice.createInjector(Stage.PRODUCTION, new CatalogModule(), new AbstractModule() {
- protected void configure() {
- bind(Clock.class).to(DefaultClock.class).asEagerSingleton();
- }
- });
+ final Injector g = Guice.createInjector(Stage.PRODUCTION, new CatalogModule(), new ClockModule());
catalogService = g.getInstance(CatalogService.class);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
index 271de3c..7ef459d 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
@@ -28,28 +28,22 @@ import java.util.UUID;
import org.joda.time.DateTime;
import org.testng.Assert;
-import org.testng.annotations.Test;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Stage;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.Duration;
import com.ning.billing.catalog.api.PhaseType;
import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.api.TestApiBase;
import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
-import com.ning.billing.entitlement.api.migration.EntitlementMigrationApiException;
+import com.ning.billing.entitlement.api.TestApiBase;
import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi.EntitlementAccountMigration;
import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi.EntitlementBundleMigration;
import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi.EntitlementSubscriptionMigration;
import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi.EntitlementSubscriptionMigrationCase;
import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
-import com.ning.billing.entitlement.glue.MockEngineModuleSql;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
public abstract class TestMigration extends TestApiBase {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
index 8743274..d46fe83 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
@@ -18,20 +18,17 @@ package com.ning.billing.entitlement.glue;
import com.ning.billing.account.glue.AccountModuleWithMocks;
import com.ning.billing.catalog.glue.CatalogModule;
-import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.clock.MockClockModule;
import com.ning.billing.util.glue.BusModule;
public class MockEngineModule extends EntitlementModule {
-
@Override
protected void configure() {
super.configure();
- bind(Clock.class).to(ClockMock.class).asEagerSingleton();
install(new BusModule());
install(new CatalogModule());
install(new AccountModuleWithMocks());
+ install(new MockClockModule());
}
-
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
index 54e8b66..e9e6134 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
@@ -35,7 +35,6 @@ public class MockEngineModuleSql extends MockEngineModule {
bind(EntitlementDao.class).to(MockEntitlementDaoSql.class).asEagerSingleton();
}
-
protected void installDBI() {
bind(IDBI.class).toProvider(DBIProvider.class).asEagerSingleton();
final DbiConfig config = new ConfigurationObjectFactory(System.getProperties()).build(DbiConfig.class);
invoice/pom.xml 3(+0 -3)
diff --git a/invoice/pom.xml b/invoice/pom.xml
index e685de0..cc98907 100644
--- a/invoice/pom.xml
+++ b/invoice/pom.xml
@@ -71,18 +71,15 @@
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
- <version>2.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
- <version>2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jdbi</groupId>
<artifactId>jdbi</artifactId>
- <version>2.27</version>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
index 947c782..824b239 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
@@ -22,6 +22,7 @@ import java.util.List;
import java.util.UUID;
import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
+import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
import com.ning.billing.invoice.model.RecurringInvoiceItem;
import org.joda.time.DateTime;
import org.skife.jdbi.v2.IDBI;
@@ -43,6 +44,7 @@ public class DefaultInvoiceDao implements InvoiceDao {
private final InvoiceSqlDao invoiceSqlDao;
private final RecurringInvoiceItemSqlDao recurringInvoiceItemSqlDao;
+ //private final FixedPriceInvoiceItemSqlDao fixedPriceInvoiceItemSqlDao;
private final InvoicePaymentSqlDao invoicePaymentSqlDao;
private final NextBillingDateNotifier notifier;
private final EntitlementBillingApi entitlementBillingApi;
@@ -54,6 +56,7 @@ public class DefaultInvoiceDao implements InvoiceDao {
final NextBillingDateNotifier notifier, final EntitlementBillingApi entitlementBillingApi) {
this.invoiceSqlDao = dbi.onDemand(InvoiceSqlDao.class);
this.recurringInvoiceItemSqlDao = dbi.onDemand(RecurringInvoiceItemSqlDao.class);
+ //this.fixedPriceInvoiceItemSqlDao = dbi.onDemand(FixedPriceInvoiceItemSqlDao.class);
this.invoicePaymentSqlDao = dbi.onDemand(InvoicePaymentSqlDao.class);
this.eventBus = eventBus;
this.notifier = notifier;
@@ -118,13 +121,8 @@ public class DefaultInvoiceDao implements InvoiceDao {
Invoice invoice = invoiceDao.getById(invoiceId.toString());
if (invoice != null) {
- RecurringInvoiceItemSqlDao recurringInvoiceItemDao = invoiceDao.become(RecurringInvoiceItemSqlDao.class);
- List<InvoiceItem> invoiceItems = recurringInvoiceItemDao.getInvoiceItemsByInvoice(invoiceId.toString());
- invoice.addInvoiceItems(invoiceItems);
-
- InvoicePaymentSqlDao invoicePaymentSqlDao = invoiceDao.become(InvoicePaymentSqlDao.class);
- List<InvoicePayment> invoicePayments = invoicePaymentSqlDao.getPaymentsForInvoice(invoiceId.toString());
- invoice.addPayments(invoicePayments);
+ getInvoiceItemsWithinTransaction(invoice, invoiceDao);
+ getInvoicePaymentsWithinTransaction(invoice, invoiceDao);
}
return invoice;
@@ -144,18 +142,21 @@ public class DefaultInvoiceDao implements InvoiceDao {
if (currentInvoice == null) {
invoiceDao.create(invoice);
- List<InvoiceItem> invoiceItems = invoice.getInvoiceItems();
+ List<InvoiceItem> recurringInvoiceItems = invoice.getInvoiceItems(RecurringInvoiceItem.class);
RecurringInvoiceItemSqlDao recurringInvoiceItemDao = invoiceDao.become(RecurringInvoiceItemSqlDao.class);
- recurringInvoiceItemDao.create(invoiceItems);
+ recurringInvoiceItemDao.batchCreateFromTransaction(recurringInvoiceItems);
- notifyOfFutureBillingEvents(invoiceSqlDao, invoiceItems);
- setChargedThroughDates(invoiceSqlDao, invoiceItems);
+ notifyOfFutureBillingEvents(invoiceSqlDao, recurringInvoiceItems);
+ setChargedThroughDates(invoiceSqlDao, recurringInvoiceItems);
+ List<InvoiceItem> fixedPriceInvoiceItems = invoice.getInvoiceItems(FixedPriceInvoiceItem.class);
+ FixedPriceInvoiceItemSqlDao fixedPriceInvoiceItemDao = invoiceDao.become(FixedPriceInvoiceItemSqlDao.class);
+ fixedPriceInvoiceItemDao.batchCreateFromTransaction(fixedPriceInvoiceItems);
// STEPH Why do we need that? Are the payments not always null at this point?
List<InvoicePayment> invoicePayments = invoice.getPayments();
InvoicePaymentSqlDao invoicePaymentSqlDao = invoiceDao.become(InvoicePaymentSqlDao.class);
- invoicePaymentSqlDao.create(invoicePayments);
+ invoicePaymentSqlDao.batchCreateFromTransaction(invoicePayments);
InvoiceCreationNotification event;
event = new DefaultInvoiceCreationNotification(invoice.getId(), invoice.getAccountId(),
@@ -215,33 +216,6 @@ public class DefaultInvoiceDao implements InvoiceDao {
}
@Override
- public boolean lockAccount(final UUID accountId) {
- /*
- try {
- invoiceSqlDao.lockAccount(accountId.toString());
- return true;
- } catch (Exception e) {
- log.error("Ouch! I broke", e);
- return false;
- }
- */
- return true;
- }
-
- @Override
- public boolean releaseAccount(final UUID accountId) {
- /*
- try {
- invoiceSqlDao.releaseAccount(accountId.toString());
- return true;
- } catch (Exception e) {
- return false;
- }
- */
- return true;
- }
-
- @Override
public UUID getInvoiceIdByPaymentAttemptId(UUID paymentAttemptId) {
return invoiceSqlDao.getInvoiceIdByPaymentAttemptId(paymentAttemptId.toString());
}
@@ -257,22 +231,34 @@ public class DefaultInvoiceDao implements InvoiceDao {
}
private void getInvoiceItemsWithinTransaction(final List<Invoice> invoices, final InvoiceSqlDao invoiceDao) {
- RecurringInvoiceItemSqlDao recurringInvoiceItemDao = invoiceDao.become(RecurringInvoiceItemSqlDao.class);
for (final Invoice invoice : invoices) {
- List<InvoiceItem> invoiceItems = recurringInvoiceItemDao.getInvoiceItemsByInvoice(invoice.getId().toString());
- invoice.addInvoiceItems(invoiceItems);
+ getInvoiceItemsWithinTransaction(invoice, invoiceDao);
}
}
+ private void getInvoiceItemsWithinTransaction(final Invoice invoice, final InvoiceSqlDao invoiceDao) {
+ RecurringInvoiceItemSqlDao recurringInvoiceItemDao = invoiceDao.become(RecurringInvoiceItemSqlDao.class);
+ List<InvoiceItem> recurringInvoiceItems = recurringInvoiceItemDao.getInvoiceItemsByInvoice(invoice.getId().toString());
+ invoice.addInvoiceItems(recurringInvoiceItems);
+
+ FixedPriceInvoiceItemSqlDao fixedPriceInvoiceItemDao = invoiceDao.become(FixedPriceInvoiceItemSqlDao.class);
+ List<InvoiceItem> fixedPriceInvoiceItems = fixedPriceInvoiceItemDao.getInvoiceItemsByInvoice(invoice.getId().toString());
+ invoice.addInvoiceItems(fixedPriceInvoiceItems);
+ }
+
private void getInvoicePaymentsWithinTransaction(final List<Invoice> invoices, final InvoiceSqlDao invoiceDao) {
- InvoicePaymentSqlDao invoicePaymentSqlDao = invoiceDao.become(InvoicePaymentSqlDao.class);
- for (final Invoice invoice : invoices) {
- String invoiceId = invoice.getId().toString();
- List<InvoicePayment> invoicePayments = invoicePaymentSqlDao.getPaymentsForInvoice(invoiceId);
- invoice.addPayments(invoicePayments);
+ for (Invoice invoice : invoices) {
+ getInvoicePaymentsWithinTransaction(invoice, invoiceDao);
}
}
+ private void getInvoicePaymentsWithinTransaction(final Invoice invoice, final InvoiceSqlDao invoiceDao) {
+ InvoicePaymentSqlDao invoicePaymentSqlDao = invoiceDao.become(InvoicePaymentSqlDao.class);
+ String invoiceId = invoice.getId().toString();
+ List<InvoicePayment> invoicePayments = invoicePaymentSqlDao.getPaymentsForInvoice(invoiceId);
+ invoice.addPayments(invoicePayments);
+ }
+
private void notifyOfFutureBillingEvents(final InvoiceSqlDao dao, final List<InvoiceItem> invoiceItems) {
for (final InvoiceItem item : invoiceItems) {
if (item instanceof RecurringInvoiceItem) {
@@ -281,9 +267,8 @@ public class DefaultInvoiceDao implements InvoiceDao {
(recurringInvoiceItem.getAmount() == null ||
recurringInvoiceItem.getAmount().compareTo(BigDecimal.ZERO) >= 0)) {
notifier.insertNextBillingNotification(dao, item.getSubscriptionId(), recurringInvoiceItem.getEndDate());
+ }
}
- }
-
}
}
@@ -298,7 +283,6 @@ public class DefaultInvoiceDao implements InvoiceDao {
entitlementBillingApi.setChargedThroughDateFromTransaction(dao, recurringInvoiceItem.getSubscriptionId(), recurringInvoiceItem.getEndDate());
}
}
-
}
}
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.java
index ed6ffe0..6070505 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.java
@@ -50,7 +50,10 @@ public interface FixedPriceInvoiceItemSqlDao extends EntityDao<InvoiceItem> {
void update(@FixedPriceInvoiceItemBinder final InvoiceItem invoiceItem);
@SqlBatch
- void create(@FixedPriceInvoiceItemBinder final List<FixedPriceInvoiceItem> items);
+ void create(@FixedPriceInvoiceItemBinder final List<InvoiceItem> items);
+
+ @SqlBatch(transactional=false)
+ void batchCreateFromTransaction(@FixedPriceInvoiceItemBinder final List<InvoiceItem> items);
@BindingAnnotation(FixedPriceInvoiceItemBinder.FixedPriceInvoiceItemBinderFactory.class)
@Retention(RetentionPolicy.RUNTIME)
@@ -74,7 +77,7 @@ public interface FixedPriceInvoiceItemSqlDao extends EntityDao<InvoiceItem> {
}
}
- public static class FixedPriceInvoiceItemMapper implements ResultSetMapper<FixedPriceInvoiceItem> {
+ public static class FixedPriceInvoiceItemMapper implements ResultSetMapper<InvoiceItem> {
@Override
public FixedPriceInvoiceItem map(int index, ResultSet result, StatementContext context) throws SQLException {
UUID id = UUID.fromString(result.getString("id"));
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
index a86cde7..7a7c280 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
@@ -53,9 +53,5 @@ public interface InvoiceDao {
List<Invoice> getUnpaidInvoicesByAccountId(final UUID accountId, final DateTime upToDate);
- boolean lockAccount(final UUID accountId);
-
- boolean releaseAccount(final UUID accountId);
-
void test();
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
index 7a05d5c..7179ec1 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
@@ -52,8 +52,8 @@ public interface InvoicePaymentSqlDao {
@SqlUpdate
public void create(@InvoicePaymentBinder InvoicePayment invoicePayment);
- @SqlBatch
- void create(@InvoicePaymentBinder List<InvoicePayment> items);
+ @SqlBatch(transactional=false)
+ void batchCreateFromTransaction(@InvoicePaymentBinder List<InvoicePayment> items);
@SqlUpdate
public void update(@InvoicePaymentBinder InvoicePayment invoicePayment);
@@ -85,7 +85,7 @@ public interface InvoicePaymentSqlDao {
final DateTime updatedDate = getDate(result, "updated_date");
return new InvoicePayment() {
- private DateTime now = new DateTime();
+ private final DateTime now = new DateTime();
@Override
public UUID getPaymentAttemptId() {
@@ -124,8 +124,10 @@ public interface InvoicePaymentSqlDao {
@Target({ElementType.PARAMETER})
public @interface InvoicePaymentBinder {
public static class InvoicePaymentBinderFactory implements BinderFactory {
+ @Override
public Binder build(Annotation annotation) {
return new Binder<InvoicePaymentBinder, InvoicePayment>() {
+ @Override
public void bind(SQLStatement q, InvoicePaymentBinder bind, InvoicePayment payment) {
q.bind("invoiceId", payment.getInvoiceId().toString());
q.bind("paymentAttemptId", payment.getPaymentAttemptId().toString());
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
index e580d05..05be556 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
@@ -78,7 +78,7 @@ public interface InvoiceSqlDao extends EntityDao<Invoice>, Transactional<Invoice
@RegisterMapper(UuidMapper.class)
List<UUID> getInvoicesForPayment(@Bind("targetDate") final Date targetDate,
@Bind("numberOfDays") final int numberOfDays);
-
+
@SqlQuery
@RegisterMapper(BalanceMapper.class)
BigDecimal getAccountBalance(@Bind("accountId") final String accountId);
@@ -86,13 +86,6 @@ public interface InvoiceSqlDao extends EntityDao<Invoice>, Transactional<Invoice
@SqlQuery
List<Invoice> getUnpaidInvoicesByAccountId(@Bind("accountId") final String accountId,
@Bind("upToDate") final Date upToDate);
-
- @SqlUpdate
- void lockAccount(@Bind("accountId") final String accountId);
-
- @SqlUpdate
- void releaseAccount(@Bind("accountId") final String accountId);
-
@BindingAnnotation(InvoiceBinder.InvoiceBinderFactory.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@@ -130,7 +123,7 @@ public interface InvoiceSqlDao extends EntityDao<Invoice>, Transactional<Invoice
return new DefaultInvoice(id, accountId, invoiceDate, targetDate, currency);
}
}
-
+
public static class BalanceMapper implements ResultSetMapper<BigDecimal> {
@Override
public BigDecimal map(final int index, final ResultSet result, final StatementContext context) throws SQLException {
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.java
index 9653cac..3409cfe 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.java
@@ -65,16 +65,18 @@ public interface RecurringInvoiceItemSqlDao extends EntityDao<InvoiceItem> {
@SqlUpdate
void update(@RecurringInvoiceItemBinder final InvoiceItem invoiceItem);
- @SqlBatch
- void create(@RecurringInvoiceItemBinder final List<InvoiceItem> items);
+ @SqlBatch(transactional=false)
+ void batchCreateFromTransaction(@RecurringInvoiceItemBinder final List<InvoiceItem> items);
@BindingAnnotation(RecurringInvoiceItemBinder.InvoiceItemBinderFactory.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface RecurringInvoiceItemBinder {
public static class InvoiceItemBinderFactory implements BinderFactory {
+ @Override
public Binder build(Annotation annotation) {
return new Binder<RecurringInvoiceItemBinder, RecurringInvoiceItem>() {
+ @Override
public void bind(SQLStatement q, RecurringInvoiceItemBinder bind, RecurringInvoiceItem item) {
q.bind("id", item.getId().toString());
q.bind("invoiceId", item.getInvoiceId().toString());
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 012d06f..20765eb 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
@@ -33,6 +33,8 @@ import com.ning.billing.invoice.model.DefaultInvoiceGenerator;
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;
+
public class InvoiceModule extends AbstractModule {
protected void installInvoiceDao() {
@@ -47,6 +49,10 @@ public class InvoiceModule extends AbstractModule {
bind(InvoicePaymentApi.class).to(DefaultInvoicePaymentApi.class).asEagerSingleton();
}
+ protected void installClock() {
+ install(new ClockModule());
+ }
+
protected void installConfig() {
final InvoiceConfig config = new ConfigurationObjectFactory(System.getProperties()).build(InvoiceConfig.class);
bind(InvoiceConfig.class).toInstance(config);
diff --git a/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java b/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
index 8cf0195..ea1fc12 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
@@ -43,15 +43,23 @@ import com.ning.billing.invoice.model.InvoiceGenerator;
import com.ning.billing.invoice.model.InvoiceItemList;
import com.ning.billing.invoice.notification.NextBillingDateEvent;
import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.globallocker.GlobalLock;
+import com.ning.billing.util.globallocker.GlobalLocker;
+import com.ning.billing.util.globallocker.GlobalLocker.LockerService;
+import com.ning.billing.util.globallocker.LockFailedException;
public class InvoiceListener {
+
+
private final static Logger log = LoggerFactory.getLogger(InvoiceListener.class);
+ private final static int NB_LOCK_TRY = 5;
private final InvoiceGenerator generator;
private final EntitlementBillingApi entitlementBillingApi;
private final AccountUserApi accountUserApi;
private final InvoiceDao invoiceDao;
private final Clock clock;
+ private final GlobalLocker locker;
private final static boolean VERBOSE_OUTPUT = false;
@@ -59,11 +67,13 @@ public class InvoiceListener {
public InvoiceListener(final InvoiceGenerator generator, final AccountUserApi accountUserApi,
final EntitlementBillingApi entitlementBillingApi,
final InvoiceDao invoiceDao,
+ final GlobalLocker locker,
final Clock clock) {
this.generator = generator;
this.entitlementBillingApi = entitlementBillingApi;
this.accountUserApi = accountUserApi;
this.invoiceDao = invoiceDao;
+ this.locker = locker;
this.clock = clock;
}
@@ -103,52 +113,62 @@ public class InvoiceListener {
UUID accountId = entitlementBillingApi.getAccountIdFromSubscriptionId(subscriptionId);
if (accountId == null) {
log.error("Failed handling entitlement change.",
- new InvoiceApiException(ErrorCode.INVOICE_NO_ACCOUNT_ID_FOR_SUBSCRIPTION_ID, subscriptionId.toString()));
+ new InvoiceApiException(ErrorCode.INVOICE_NO_ACCOUNT_ID_FOR_SUBSCRIPTION_ID, subscriptionId.toString()));
return;
}
- if (!invoiceDao.lockAccount(accountId)) {
- log.warn("Conflicting lock detected from InvoiceListener on account " + accountId.toString());
- } else {
- log.info("Locked " + accountId.toString());
+ GlobalLock lock = null;
+ try {
+ lock = locker.lockWithNumberOfTries(LockerService.INVOICE, accountId.toString(), NB_LOCK_TRY);
- Account account = accountUserApi.getAccountById(accountId);
- if (account == null) {
- log.error("Failed handling entitlement change.",
- new InvoiceApiException(ErrorCode.INVOICE_ACCOUNT_ID_INVALID, accountId.toString()));
- return;
+ processAccountWithLock(accountId, targetDate);
+
+ } catch (LockFailedException e) {
+ // Not good!
+ log.error(String.format("Failed to process invoice for account %s, subscription %s, targetDate %s",
+ accountId.toString(), subscriptionId.toString(), targetDate), e);
+ } finally {
+ if (lock != null) {
+ lock.release();
}
+ }
+ }
- SortedSet<BillingEvent> events = entitlementBillingApi.getBillingEventsForAccount(accountId);
- BillingEventSet billingEvents = new BillingEventSet(events);
+ private void processAccountWithLock(final UUID accountId, final DateTime targetDate) throws InvoiceApiException {
- Currency targetCurrency = account.getCurrency();
+ Account account = accountUserApi.getAccountById(accountId);
+ if (account == null) {
+ log.error("Failed handling entitlement change.",
+ new InvoiceApiException(ErrorCode.INVOICE_ACCOUNT_ID_INVALID, accountId.toString()));
+ return;
+ }
- List<InvoiceItem> items = invoiceDao.getInvoiceItemsByAccount(accountId);
- InvoiceItemList invoiceItemList = new InvoiceItemList(items);
- Invoice invoice = generator.generateInvoice(accountId, billingEvents, invoiceItemList, targetDate, targetCurrency);
+ SortedSet<BillingEvent> events = entitlementBillingApi.getBillingEventsForAccount(accountId);
+ BillingEventSet billingEvents = new BillingEventSet(events);
- if (invoice == null) {
- log.info("Generated null invoice.");
- outputDebugData(events, invoiceItemList);
- } else {
- log.info("Generated invoice {} with {} items.", invoice.getId().toString(), invoice.getNumberOfItems());
+ Currency targetCurrency = account.getCurrency();
- if (VERBOSE_OUTPUT) {
- log.info("New items");
- for (InvoiceItem item : invoice.getInvoiceItems()) {
- log.info(item.toString());
- }
- }
+ List<InvoiceItem> items = invoiceDao.getInvoiceItemsByAccount(accountId);
+ InvoiceItemList invoiceItemList = new InvoiceItemList(items);
+ Invoice invoice = generator.generateInvoice(accountId, billingEvents, invoiceItemList, targetDate, targetCurrency);
- outputDebugData(events, invoiceItemList);
+ if (invoice == null) {
+ log.info("Generated null invoice.");
+ outputDebugData(events, invoiceItemList);
+ } else {
+ log.info("Generated invoice {} with {} items.", invoice.getId().toString(), invoice.getNumberOfItems());
- if (invoice.getNumberOfItems() > 0) {
- invoiceDao.create(invoice);
+ if (VERBOSE_OUTPUT) {
+ log.info("New items");
+ for (InvoiceItem item : invoice.getInvoiceItems()) {
+ log.info(item.toString());
}
}
+ outputDebugData(events, invoiceItemList);
- invoiceDao.releaseAccount(accountId);
+ if (invoice.getNumberOfItems() > 0) {
+ invoiceDao.create(invoice);
+ }
}
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
index 8ee40e3..90eeae9 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
@@ -73,6 +73,17 @@ public class DefaultInvoice implements Invoice {
}
@Override
+ public List<InvoiceItem> getInvoiceItems(Class clazz) {
+ List<InvoiceItem> results = new ArrayList<InvoiceItem>();
+ for (InvoiceItem item : invoiceItems) {
+ if (item.getClass() == clazz) {
+ results.add(item);
+ }
+ }
+ return results;
+ }
+
+ @Override
public int getNumberOfItems() {
return invoiceItems.size();
}
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg
index 5fc1118..8e7e7be 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg
@@ -42,6 +42,12 @@ create() ::= <<
:date, :amount, :currency);
>>
+batchCreateFromTransaction() ::= <<
+ INSERT INTO fixed_invoice_items(<fields()>)
+ VALUES(:id, :invoiceId, :subscriptionId, :planName, :phaseName,
+ :date, :amount, :currency);
+>>
+
update() ::= <<
UPDATE fixed_invoice_items
SET invoice_id = :invoiceId, subscription_id = :subscriptionId, plan_name = :planName, phase_name = :phaseName,
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
index a635456..2172573 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
@@ -15,6 +15,12 @@ create() ::= <<
VALUES(:invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency, :createdDate, :updatedDate);
>>
+batchCreateFromTransaction() ::= <<
+ INSERT INTO invoice_payments(<invoicePaymentFields()>)
+ VALUES(:invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency, :createdDate, :updatedDate);
+>>
+
+
update() ::= <<
UPDATE invoice_payments
SET payment_date = :paymentAttemptDate, amount = :amount, currency = :currency, created_date = :createdDate, updated_date = :updatedDate
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
index a7aa135..35c45bf 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
@@ -92,14 +92,6 @@ getUnpaidInvoicesByAccountId() ::= <<
ORDER BY i.target_date ASC;
>>
-lockAccount() ::= <<
- INSERT INTO invoice_locking(account_id) VALUES (:accountId);
->>
-
-releaseAccount() ::= <<
- DELETE FROM invoice_locking
- WHERE account_id = :accountId;
->>
test() ::= <<
SELECT 1
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg
index 9d7cb0a..d50a1c5 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg
@@ -45,6 +45,12 @@ create() ::= <<
:amount, :rate, :currency, :reversedItemId);
>>
+batchCreateFromTransaction() ::= <<
+ INSERT INTO recurring_invoice_items(<fields()>)
+ VALUES(:id, :invoiceId, :subscriptionId, :planName, :phaseName, :startDate, :endDate,
+ :amount, :rate, :currency, :reversedItemId);
+>>
+
update() ::= <<
UPDATE recurring_invoice_items
SET invoice_id = :invoiceId, subscription_id = :subscriptionId, plan_name = :planName, phase_name = :phaseName,
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
index 47503f4..b1c919e 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
@@ -607,4 +607,45 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, new DateTime(), Currency.USD);
assertNull(invoice);
}
+
+ @Test
+ public void testMixedModeInvoicePersistence() throws InvoiceApiException {
+ DefaultPrice zeroPrice = new DefaultPrice(BigDecimal.ZERO, Currency.USD);
+ MockInternationalPrice fixedPrice = new MockInternationalPrice(zeroPrice);
+ MockPlanPhase phase1 = new MockPlanPhase(null, fixedPrice);
+
+ BigDecimal cheapAmount = new BigDecimal("24.95");
+ DefaultPrice cheapPrice = new DefaultPrice(cheapAmount, Currency.USD);
+ MockInternationalPrice recurringPrice = new MockInternationalPrice(cheapPrice);
+ MockPlanPhase phase2 = new MockPlanPhase(recurringPrice, null);
+
+ MockPlan plan = new MockPlan();
+ Subscription subscription = new MockSubscription();
+ DateTime effectiveDate1 = buildDateTime(2011, 1, 1);
+
+ BillingEvent event1 = new DefaultBillingEvent(subscription, effectiveDate1, plan, phase1, fixedPrice,
+ null, BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
+ "testEvent1", SubscriptionTransitionType.CREATE);
+ BillingEventSet events = new BillingEventSet();
+ events.add(event1);
+
+ DateTime effectiveDate2 = effectiveDate1.plusDays(30);
+ BillingEvent event2 = new DefaultBillingEvent(subscription, effectiveDate2, plan, phase2, null,
+ recurringPrice, BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
+ "testEvent2", SubscriptionTransitionType.CHANGE);
+ events.add(event2);
+
+ InvoiceGenerator generator = new DefaultInvoiceGenerator();
+ Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, effectiveDate2, Currency.USD);
+ assertNotNull(invoice);
+ assertEquals(invoice.getNumberOfItems(), 2);
+ assertEquals(invoice.getTotalAmount().compareTo(cheapAmount), 0);
+
+ invoiceDao.create(invoice);
+ Invoice savedInvoice = invoiceDao.getById(invoice.getId());
+
+ assertNotNull(savedInvoice);
+ assertEquals(savedInvoice.getNumberOfItems(), 2);
+ assertEquals(savedInvoice.getTotalAmount().compareTo(cheapAmount), 0);
+ }
}
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java b/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
index 8332e8c..cf6c112 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
@@ -215,14 +215,4 @@ public class MockInvoiceDao implements InvoiceDao {
return unpaidInvoices;
}
-
- @Override
- public boolean lockAccount(UUID accountId) {
- return true;
- }
-
- @Override
- public boolean releaseAccount(UUID accountId) {
- return true;
- }
}
diff --git a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
index c18e1bf..4ab3495 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
@@ -22,6 +22,7 @@ import com.ning.billing.invoice.api.test.InvoiceTestApi;
import com.ning.billing.invoice.api.test.DefaultInvoiceTestApi;
import com.ning.billing.invoice.dao.InvoicePaymentSqlDao;
import com.ning.billing.invoice.dao.RecurringInvoiceItemSqlDao;
+import com.ning.billing.util.glue.GlobalLockerModule;
import org.skife.jdbi.v2.IDBI;
import com.ning.billing.account.glue.AccountModule;
import com.ning.billing.catalog.glue.CatalogModule;
@@ -71,6 +72,7 @@ public class InvoiceModuleWithEmbeddedDb extends InvoiceModule {
install(new AccountModule());
install(new CatalogModule());
install(new EntitlementModule());
+ install(new GlobalLockerModule());
super.configure();
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 60015c1..5cb0228 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
@@ -18,12 +18,15 @@ package com.ning.billing.invoice.glue;
import com.ning.billing.invoice.dao.InvoiceDao;
import com.ning.billing.invoice.dao.MockInvoiceDao;
+import com.ning.billing.util.globallocker.GlobalLocker;
+import com.ning.billing.util.globallocker.MockGlobalLocker;
public class InvoiceModuleWithMocks extends InvoiceModule {
@Override
protected void installInvoiceDao() {
bind(MockInvoiceDao.class).asEagerSingleton();
bind(InvoiceDao.class).to(MockInvoiceDao.class);
+ bind(GlobalLocker.class).to(MockGlobalLocker.class).asEagerSingleton();
}
@Override
invoice/src/test/resources/log4j.xml 36(+36 -0)
diff --git a/invoice/src/test/resources/log4j.xml b/invoice/src/test/resources/log4j.xml
new file mode 100644
index 0000000..33b9662
--- /dev/null
+++ b/invoice/src/test/resources/log4j.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+ <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
+ <param name="Target" value="System.out"/>
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%p %d{ISO8601} %X{trace} %t %c %m%n"/>
+ </layout>
+ </appender>
+
+
+ <logger name="com.ning.billing.invoice">
+ <level value="info"/>
+ </logger>
+
+ <root>
+ <priority value="info"/>
+ <appender-ref ref="stdout"/>
+ </root>
+</log4j:configuration>
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 b8e5b9e..6dc04e4 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
@@ -153,9 +153,24 @@ public class DefaultPaymentApi implements PaymentApi {
if (paymentOrError.isRight()) {
paymentInfo = paymentOrError.getRight();
-
paymentDao.savePaymentInfo(paymentInfo);
+ Either<PaymentError, PaymentMethodInfo> paymentMethodInfoOrError = plugin.getPaymentMethodInfo(paymentInfo.getPaymentMethodId());
+
+ if (paymentMethodInfoOrError.isRight()) {
+ PaymentMethodInfo paymentMethodInfo = paymentMethodInfoOrError.getRight();
+
+ if (paymentMethodInfo instanceof CreditCardPaymentMethodInfo) {
+ CreditCardPaymentMethodInfo ccPaymentMethod = (CreditCardPaymentMethodInfo)paymentMethodInfo;
+ paymentDao.updatePaymentInfo(ccPaymentMethod.getType(), paymentInfo.getPaymentId(), ccPaymentMethod.getCardType(), ccPaymentMethod.getCardCountry());
+ }
+ else if (paymentMethodInfo instanceof PaypalPaymentMethodInfo) {
+ PaypalPaymentMethodInfo paypalPaymentMethodInfo = (PaypalPaymentMethodInfo)paymentMethodInfo;
+ paymentDao.updatePaymentInfo(paypalPaymentMethodInfo.getType(), paymentInfo.getPaymentId(), null, null);
+ }
+ }
+
+
if (paymentInfo.getPaymentId() != null) {
paymentDao.updatePaymentAttemptWithPaymentId(paymentAttempt.getPaymentAttemptId(), paymentInfo.getPaymentId());
}
@@ -181,9 +196,9 @@ public class DefaultPaymentApi implements PaymentApi {
}
@Override
- public Either<PaymentError, Void> updatePaymentProviderAccount(Account account) {
+ public Either<PaymentError, Void> updatePaymentProviderAccountContact(Account account) {
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(account);
- return plugin.updatePaymentProviderAccountWithExistingContact(account);
+ return plugin.updatePaymentProviderAccountExistingContact(account);
}
@Override
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 ceba7a7..eacc226 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
@@ -61,4 +61,9 @@ public class DefaultPaymentDao implements PaymentDao {
sqlDao.updatePaymentAttemptWithPaymentId(paymentAttemptId.toString(), paymentId);
}
+ @Override
+ public void updatePaymentInfo(String type, String paymentId, String cardType, String cardCountry) {
+ sqlDao.updatePaymentInfo(type, paymentId, cardType, cardCountry);
+ }
+
}
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 d40b264..5cf065b 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
@@ -34,4 +34,6 @@ public interface PaymentDao {
PaymentAttempt getPaymentAttemptForInvoiceId(String invoiceId);
+ void updatePaymentInfo(String paymentMethodType, String paymentId, String cardType, String cardCountry);
+
}
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 7cd8adb..972ee64 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
@@ -57,7 +57,13 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Tr
@SqlUpdate
void updatePaymentAttemptWithPaymentId(@Bind("payment_attempt_id") String paymentAttemptId,
- @Bind("payment_id") String payment_id);
+ @Bind("payment_id") String paymentId);
+
+ @SqlUpdate
+ void updatePaymentInfo(@Bind("payment_method") String paymentMethod,
+ @Bind("payment_id") String paymentId,
+ @Bind("card_type") String cardType,
+ @Bind("card_country") String cardCountry);
@SqlUpdate
void insertPaymentInfo(@Bind(binder = PaymentInfoBinder.class) PaymentInfo paymentInfo);
@@ -73,11 +79,13 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Tr
stmt.bind("payment_attempt_id", paymentAttempt.getPaymentAttemptId().toString());
stmt.bind("invoice_id", paymentAttempt.getInvoiceId().toString());
stmt.bind("account_id", paymentAttempt.getAccountId().toString());
- stmt.bind("amount", paymentAttempt.getAmount()); //TODO: suppport partial payments
+ stmt.bind("amount", paymentAttempt.getAmount());
stmt.bind("currency", paymentAttempt.getCurrency().toString());
stmt.bind("invoice_dt", getDate(paymentAttempt.getInvoiceDate()));
stmt.bind("payment_attempt_dt", getDate(paymentAttempt.getPaymentAttemptDate()));
stmt.bind("payment_id", paymentAttempt.getPaymentId());
+ stmt.bind("retry_count", paymentAttempt.getRetryCount());
+ stmt.bind("next_retry_dt", getDate(paymentAttempt.getNextRetryDate()));
stmt.bind("created_dt", getDate(paymentAttempt.getCreatedDate()));
stmt.bind("updated_dt", getDate(paymentAttempt.getUpdatedDate()));
}
@@ -101,10 +109,23 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Tr
DateTime invoiceDate = getDate(rs, "invoice_dt");
DateTime paymentAttemptDate = getDate(rs, "payment_attempt_dt");
String paymentId = rs.getString("payment_id");
+ Integer retryCount = rs.getInt("retry_count");
+ DateTime nextRetryDate = getDate(rs, "next_retry_dt");
DateTime createdDate = getDate(rs, "created_dt");
DateTime updatedDate = getDate(rs, "updated_dt");
- return new PaymentAttempt(paymentAttemptId, invoiceId, accountId, amount, currency, invoiceDate, paymentAttemptDate, paymentId, createdDate, updatedDate);
+ return new PaymentAttempt(paymentAttemptId,
+ invoiceId,
+ accountId,
+ amount,
+ currency,
+ invoiceDate,
+ paymentAttemptDate,
+ paymentId,
+ retryCount,
+ nextRetryDate,
+ createdDate,
+ updatedDate);
}
}
@@ -124,6 +145,10 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Tr
stmt.bind("status", paymentInfo.getStatus());
stmt.bind("payment_type", paymentInfo.getType());
stmt.bind("reference_id", paymentInfo.getReferenceId());
+ stmt.bind("payment_method_id", paymentInfo.getPaymentMethodId());
+ stmt.bind("payment_method", paymentInfo.getPaymentMethod());
+ stmt.bind("card_type", paymentInfo.getCardType());
+ stmt.bind("card_country", paymentInfo.getCardCountry());
stmt.bind("effective_dt", getDate(paymentInfo.getEffectiveDate()));
stmt.bind("created_dt", getDate(paymentInfo.getCreatedDate()));
stmt.bind("updated_dt", getDate(paymentInfo.getUpdatedDate()));
@@ -148,6 +173,10 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Tr
String status = rs.getString("status");
String type = rs.getString("payment_type");
String referenceId = rs.getString("reference_id");
+ String paymentMethodId = rs.getString("payment_method_id");
+ String paymentMethod = rs.getString("payment_method");
+ String cardType = rs.getString("card_type");
+ String cardCountry = rs.getString("card_country");
DateTime effectiveDate = getDate(rs, "effective_dt");
DateTime createdDate = getDate(rs, "created_dt");
DateTime updatedDate = getDate(rs, "updated_dt");
@@ -160,6 +189,10 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Tr
status,
type,
referenceId,
+ paymentMethodId,
+ paymentMethod,
+ cardType,
+ cardCountry,
effectiveDate,
createdDate,
updatedDate);
diff --git a/payment/src/main/java/com/ning/billing/payment/PaymentAttempt.java b/payment/src/main/java/com/ning/billing/payment/PaymentAttempt.java
index 8d65393..1c8e9f3 100644
--- a/payment/src/main/java/com/ning/billing/payment/PaymentAttempt.java
+++ b/payment/src/main/java/com/ning/billing/payment/PaymentAttempt.java
@@ -30,13 +30,21 @@ public class PaymentAttempt {
private final UUID invoiceId;
private final BigDecimal paymentAttemptAmount;
private final DateTime paymentAttemptDate;
+ private final Integer retryCount;
+ private final DateTime nextRetryDate;
public PaymentAttempt(UUID paymentAttemptId, Invoice invoice) {
+ this(paymentAttemptId, invoice, null, null);
+ }
+
+ public PaymentAttempt(UUID paymentAttemptId, Invoice invoice, Integer retryCount, DateTime nextRetryDate) {
this.paymentAttemptId = paymentAttemptId;
this.accountId = invoice.getAccountId();
this.invoiceId = invoice.getId();
this.paymentAttemptAmount = invoice.getBalance();
this.paymentAttemptDate = new DateTime(DateTimeZone.UTC);
+ this.retryCount = retryCount;
+ this.nextRetryDate = nextRetryDate;
}
public UUID getPaymentAttemptId() {
@@ -55,13 +63,21 @@ public class PaymentAttempt {
return paymentAttemptAmount;
}
- public DateTime getPaymentAttemptDate() {
- return paymentAttemptDate;
+ public DateTime getPaymentAttemptDate() {
+ return paymentAttemptDate;
+ }
+
+ public Integer getRetryCount() {
+ return retryCount;
+ }
+
+ public DateTime getNextRetryDate() {
+ return nextRetryDate;
}
@Override
public String toString() {
- return "PaymentAttempt [paymentAttemptId=" + paymentAttemptId + ", accountId=" + accountId + ", invoiceId=" + invoiceId + ", paymentAttemptAmount=" + paymentAttemptAmount + "]";
+ return "PaymentAttempt [paymentAttemptId=" + paymentAttemptId + ", accountId=" + accountId + ", invoiceId=" + invoiceId + ", paymentAttemptAmount=" + paymentAttemptAmount + ", paymentAttemptDate=" + paymentAttemptDate + ", retryCount=" + retryCount + ", nextRetryDate=" + nextRetryDate + "]";
}
}
diff --git a/payment/src/main/java/com/ning/billing/payment/provider/PaymentProviderPlugin.java b/payment/src/main/java/com/ning/billing/payment/provider/PaymentProviderPlugin.java
index e1bc1c3..7a9ae71 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/PaymentProviderPlugin.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/PaymentProviderPlugin.java
@@ -40,7 +40,7 @@ public interface PaymentProviderPlugin {
Either<PaymentError, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo);
Either<PaymentError, Void> deletePaymentMethod(String accountKey, String paymentMethodId);
- Either<PaymentError, Void> updatePaymentProviderAccountWithExistingContact(Account account);
+ Either<PaymentError, Void> updatePaymentProviderAccountExistingContact(Account account);
Either<PaymentError, Void> updatePaymentProviderAccountWithNewContact(Account account);
}
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 3c05c13..cbff01b 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
@@ -21,6 +21,7 @@ import java.util.Properties;
import org.skife.config.ConfigurationObjectFactory;
import com.google.inject.AbstractModule;
+import com.ning.billing.payment.RequestProcessor;
import com.ning.billing.payment.api.DefaultPaymentApi;
import com.ning.billing.payment.api.PaymentApi;
import com.ning.billing.payment.dao.DefaultPaymentDao;
@@ -53,6 +54,8 @@ public class PaymentModule extends AbstractModule {
bind(PaymentConfig.class).toInstance(paymentConfig);
bind(PaymentProviderPluginRegistry.class).asEagerSingleton();
bind(PaymentApi.class).to(DefaultPaymentApi.class).asEagerSingleton();
+ bind(RequestProcessor.class).asEagerSingleton();
+ bind(PaymentService.class).asEagerSingleton();
installPaymentProviderPlugins(paymentConfig);
installPaymentDao();
}
diff --git a/payment/src/main/java/com/ning/billing/payment/setup/PaymentService.java b/payment/src/main/java/com/ning/billing/payment/setup/PaymentService.java
new file mode 100644
index 0000000..5113068
--- /dev/null
+++ b/payment/src/main/java/com/ning/billing/payment/setup/PaymentService.java
@@ -0,0 +1,57 @@
+/*
+ * 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.payment.setup;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.ning.billing.lifecycle.KillbillService;
+import com.ning.billing.lifecycle.LifecycleHandlerType;
+import com.ning.billing.payment.RequestProcessor;
+import com.ning.billing.util.bus.Bus;
+
+public class PaymentService implements KillbillService {
+ private static final Logger log = LoggerFactory.getLogger(PaymentService.class);
+
+ private static final String SERVICE_NAME = "payment-service";
+
+ private final RequestProcessor requestProcessor;
+ private final Bus eventBus;
+
+ @Inject
+ public PaymentService(final RequestProcessor requestProcessor, final Bus eventBus) {
+ this.requestProcessor = requestProcessor;
+ this.eventBus = eventBus;
+ }
+
+ @Override
+ public String getName() {
+ return SERVICE_NAME;
+ }
+
+ @LifecycleHandlerType(LifecycleHandlerType.LifecycleLevel.REGISTER_EVENTS)
+ public void registerForNotifications() {
+ try {
+ eventBus.register(requestProcessor);
+ }
+ catch (Bus.EventBusException e) {
+ log.error("Unable to register with the EventBus!", e);
+ }
+ }
+
+}
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 5156b03..a62c366 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
@@ -9,6 +9,8 @@ paymentAttemptFields(prefix) ::= <<
<prefix>payment_id,
<prefix>payment_attempt_dt,
<prefix>invoice_dt,
+ <prefix>retry_count,
+ <prefix>next_retry_dt,
<prefix>created_dt,
<prefix>updated_dt
>>
@@ -22,6 +24,9 @@ paymentInfoFields(prefix) ::= <<
<prefix>payment_type,
<prefix>status,
<prefix>reference_id,
+ <prefix>payment_method,
+ <prefix>card_type,
+ <prefix>card_country,
<prefix>effective_dt,
<prefix>created_dt,
<prefix>updated_dt
@@ -29,7 +34,7 @@ paymentInfoFields(prefix) ::= <<
insertPaymentAttempt() ::= <<
INSERT INTO payment_attempts (<paymentAttemptFields()>)
- VALUES (:payment_attempt_id, :invoice_id, :account_id, :amount, :currency, :payment_id, :payment_attempt_dt, :invoice_dt, :created_dt, :updated_dt);
+ VALUES (:payment_attempt_id, :invoice_id, :account_id, :amount, :currency, :payment_id, :payment_attempt_dt, :invoice_dt, :retry_count, :next_retry_dt, :created_dt, :updated_dt);
>>
getPaymentAttemptForPaymentId() ::= <<
@@ -53,5 +58,14 @@ updatePaymentAttemptWithPaymentId() ::= <<
insertPaymentInfo() ::= <<
INSERT INTO payments (<paymentInfoFields()>)
- VALUES (:payment_id, :amount, :refund_amount, :bank_identification_number, :payment_number, :payment_type, :status, :reference_id, :effective_dt, NOW(), NOW());
+ 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);
>>
+
+updatePaymentInfo() ::= <<
+ UPDATE payments
+ SET payment_method = :payment_method,
+ card_type = :card_type,
+ card_country = :card_country,
+ updated_dt = NOW()
+ WHERE payment_id = :payment_id
+>>
\ No newline at end of file
diff --git a/payment/src/main/resources/com/ning/billing/payment/ddl.sql b/payment/src/main/resources/com/ning/billing/payment/ddl.sql
index fd6a1ea..a8bd47f 100644
--- a/payment/src/main/resources/com/ning/billing/payment/ddl.sql
+++ b/payment/src/main/resources/com/ning/billing/payment/ddl.sql
@@ -7,6 +7,8 @@ CREATE TABLE payment_attempts (
currency char(3),
payment_attempt_dt datetime NOT NULL,
payment_id varchar(36) COLLATE utf8_bin,
+ retry_count tinyint,
+ next_retry_dt datetime,
invoice_dt datetime NOT NULL,
created_dt datetime NOT NULL,
updated_dt datetime NOT NULL,
@@ -21,8 +23,12 @@ CREATE TABLE payments (
payment_number varchar(36) COLLATE utf8_bin,
bank_identification_number varchar(36) COLLATE utf8_bin,
status varchar(20) COLLATE utf8_bin,
- payment_type varchar(20) COLLATE utf8_bin,
reference_id varchar(36) COLLATE utf8_bin,
+ payment_type varchar(20) COLLATE utf8_bin,
+ payment_method_id varchar(20) COLLATE utf8_bin,
+ payment_method varchar(20) COLLATE utf8_bin,
+ card_type varchar(20) COLLATE utf8_bin,
+ card_country varchar(50) COLLATE utf8_bin,
effective_dt datetime,
created_dt datetime NOT NULL,
updated_dt datetime NOT NULL,
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 01bb03f..f7f682e 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
@@ -17,6 +17,7 @@
package com.ning.billing.payment.api;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
@@ -25,7 +26,9 @@ import java.util.Arrays;
import java.util.List;
import java.util.UUID;
+import org.apache.commons.lang.RandomStringUtils;
import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -33,6 +36,7 @@ import org.testng.annotations.Test;
import com.google.inject.Inject;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.account.api.user.AccountBuilder;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.model.RecurringInvoiceItem;
@@ -58,11 +62,10 @@ public abstract class TestPaymentApi {
eventBus.stop();
}
-// @Test(groups = "fast")
- @Test
- public void testCreatePayment() throws AccountApiException {
- final DateTime now = new DateTime();
- final Account account = testHelper.createTestAccount();
+ @Test(enabled=true)
+ public void testCreateCreditCardPayment() throws AccountApiException {
+ final DateTime now = new DateTime(DateTimeZone.UTC);
+ final Account account = testHelper.createTestCreditCardAccount();
final Invoice invoice = testHelper.createTestInvoice(account, now, Currency.USD);
final BigDecimal amount = new BigDecimal("10.00");
final UUID subscriptionId = UUID.randomUUID();
@@ -84,6 +87,114 @@ public abstract class TestPaymentApi {
PaymentInfo paymentInfo = results.get(0).getRight();
assertNotNull(paymentInfo.getPaymentId());
- assertEquals(paymentInfo.getAmount().doubleValue(), amount.doubleValue());
+ assertTrue(paymentInfo.getAmount().compareTo(amount) == 0);
+ assertNotNull(paymentInfo.getPaymentNumber());
+ assertFalse(paymentInfo.getStatus().equals("Error"));
+
+ PaymentAttempt paymentAttempt = paymentApi.getPaymentAttemptForPaymentId(paymentInfo.getPaymentId());
+ assertNotNull(paymentAttempt);
+ assertNotNull(paymentAttempt.getPaymentAttemptId());
+ assertEquals(paymentAttempt.getInvoiceId(), invoice.getId());
+ assertTrue(paymentAttempt.getAmount().compareTo(amount) == 0);
+ assertEquals(paymentAttempt.getCurrency(), Currency.USD);
+ assertEquals(paymentAttempt.getPaymentId(), paymentInfo.getPaymentId());
+ assertEquals(paymentAttempt.getPaymentAttemptDate().withMillisOfSecond(0).withSecondOfMinute(0), now.withMillisOfSecond(0).withSecondOfMinute(0));
+
+ }
+
+ private PaymentProviderAccount setupAccountWithPaymentMethod() throws AccountApiException {
+ final Account account = testHelper.createTestPayPalAccount();
+ paymentApi.createPaymentProviderAccount(account);
+
+ String accountKey = account.getExternalKey();
+
+ PaypalPaymentMethodInfo paymentMethod = new PaypalPaymentMethodInfo.Builder()
+ .setBaid("12345")
+ .setEmail(account.getEmail())
+ .setDefaultMethod(true)
+ .build();
+ Either<PaymentError, String> paymentMethodIdOrError = paymentApi.addPaymentMethod(accountKey, paymentMethod);
+
+ assertTrue(paymentMethodIdOrError.isRight());
+ assertNotNull(paymentMethodIdOrError.getRight());
+
+ Either<PaymentError, PaymentMethodInfo> paymentMethodInfoOrError = paymentApi.getPaymentMethod(accountKey, paymentMethodIdOrError.getRight());
+
+ assertTrue(paymentMethodInfoOrError.isRight());
+ assertNotNull(paymentMethodInfoOrError.getRight());
+
+ Either<PaymentError, PaymentProviderAccount> accountOrError = paymentApi.getPaymentProviderAccount(accountKey);
+
+ assertTrue(accountOrError.isRight());
+
+ return accountOrError.getRight();
+ }
+
+ @Test(enabled=true)
+ public void testCreatePaymentMethod() throws AccountApiException {
+ PaymentProviderAccount account = setupAccountWithPaymentMethod();
+ assertNotNull(account);
+ }
+
+ @Test(enabled=true)
+ public void testUpdatePaymentProviderAccountContact() throws AccountApiException {
+ final Account account = testHelper.createTestPayPalAccount();
+ paymentApi.createPaymentProviderAccount(account);
+
+ String newName = "Tester " + RandomStringUtils.randomAlphanumeric(10);
+ String newNumber = "888-888-" + RandomStringUtils.randomNumeric(4);
+
+ final Account accountToUpdate = new AccountBuilder(account.getId())
+ .name(newName)
+ .firstNameLength(newName.length())
+ .externalKey(account.getExternalKey())
+ .phone(newNumber)
+ .email(account.getEmail())
+ .currency(account.getCurrency())
+ .billingCycleDay(account.getBillCycleDay())
+ .build();
+
+ Either<PaymentError, Void> voidOrError = paymentApi.updatePaymentProviderAccountContact(accountToUpdate);
+ assertTrue(voidOrError.isRight());
+ }
+
+ @Test(enabled=true)
+ public void testCannotDeleteDefaultPaymentMethod() throws AccountApiException {
+ PaymentProviderAccount account = setupAccountWithPaymentMethod();
+
+ Either<PaymentError, Void> errorOrVoid = paymentApi.deletePaymentMethod(account.getAccountKey(), account.getDefaultPaymentMethodId());
+
+ assertTrue(errorOrVoid.isLeft());
+ }
+
+ @Test(enabled=true)
+ public void testDeleteNonDefaultPaymentMethod() throws AccountApiException {
+ final Account account = testHelper.createTestPayPalAccount();
+ paymentApi.createPaymentProviderAccount(account);
+
+ String accountKey = account.getExternalKey();
+
+ PaypalPaymentMethodInfo paymentMethod1 = new PaypalPaymentMethodInfo.Builder().setDefaultMethod(false).setBaid("12345").setEmail(account.getEmail()).build();
+ Either<PaymentError, String> paymentMethodIdOrError1 = paymentApi.addPaymentMethod(accountKey, paymentMethod1);
+
+ assertTrue(paymentMethodIdOrError1.isRight());
+ assertNotNull(paymentMethodIdOrError1.getRight());
+
+ PaypalPaymentMethodInfo paymentMethod2 = new PaypalPaymentMethodInfo.Builder().setDefaultMethod(true).setBaid("12345").setEmail(account.getEmail()).build();
+
+ Either<PaymentError, String> paymentMethodIdOrError2 = paymentApi.addPaymentMethod(accountKey, paymentMethod2);
+
+ assertTrue(paymentMethodIdOrError2.isRight());
+ assertNotNull(paymentMethodIdOrError2.getRight());
+
+ Either<PaymentError, List<PaymentMethodInfo>> paymentMethodsOrError = paymentApi.getPaymentMethods(accountKey);
+
+ assertTrue(paymentMethodsOrError.isRight());
+
+ Either<PaymentError, Void> errorOrVoid1 = paymentApi.deletePaymentMethod(accountKey, paymentMethodIdOrError1.getRight());
+ Either<PaymentError, Void> errorOrVoid2 = paymentApi.deletePaymentMethod(accountKey, paymentMethodIdOrError2.getRight());
+
+ assertTrue(errorOrVoid1.isRight());
+ assertTrue(errorOrVoid2.isLeft());
}
}
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 74d8552..bb83927 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
@@ -70,4 +70,10 @@ public class MockPaymentDao implements PaymentDao {
return null;
}
+ @Override
+ public void updatePaymentInfo(String paymentMethodType, String paymentId, String cardType, String cardCountry) {
+ // TODO Auto-generated method stub
+
+ }
+
}
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
new file mode 100644
index 0000000..6c57c77
--- /dev/null
+++ b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
@@ -0,0 +1,71 @@
+/*
+ * 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.payment.dao;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.testng.annotations.Test;
+
+import com.ning.billing.payment.api.PaymentInfo;
+
+public abstract class TestPaymentDao {
+
+ protected PaymentDao dao;
+
+ @Test
+ public void testCreatePayment() {
+ PaymentInfo paymentInfo = new PaymentInfo.Builder().setPaymentId(UUID.randomUUID().toString())
+ .setAmount(BigDecimal.TEN)
+ .setStatus("Processed")
+ .setBankIdentificationNumber("1234")
+ .setPaymentNumber("12345")
+ .setPaymentMethodId("12345")
+ .setReferenceId("12345")
+ .setType("Electronic")
+ .setCreatedDate(new DateTime(DateTimeZone.UTC))
+ .setUpdatedDate(new DateTime(DateTimeZone.UTC))
+ .setEffectiveDate(new DateTime(DateTimeZone.UTC))
+ .build();
+
+ dao.savePaymentInfo(paymentInfo);
+ }
+
+ @Test
+ public void testUpdatePayment() {
+ PaymentInfo paymentInfo = new PaymentInfo.Builder().setPaymentId(UUID.randomUUID().toString())
+ .setAmount(BigDecimal.TEN)
+ .setStatus("Processed")
+ .setBankIdentificationNumber("1234")
+ .setPaymentNumber("12345")
+ .setPaymentMethodId("12345")
+ .setReferenceId("12345")
+ .setType("Electronic")
+ .setCreatedDate(new DateTime(DateTimeZone.UTC))
+ .setUpdatedDate(new DateTime(DateTimeZone.UTC))
+ .setEffectiveDate(new DateTime(DateTimeZone.UTC))
+ .build();
+
+ dao.savePaymentInfo(paymentInfo);
+
+ dao.updatePaymentInfo("CreditCard", paymentInfo.getPaymentId(), "Visa", "US");
+
+ }
+
+}
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
new file mode 100644
index 0000000..da48c03
--- /dev/null
+++ b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithEmbeddedDb.java
@@ -0,0 +1,53 @@
+/*
+ * 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.payment.dao;
+
+import java.io.IOException;
+
+import org.apache.commons.io.IOUtils;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+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());
+ }
+ }
+}
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
new file mode 100644
index 0000000..f5af240
--- /dev/null
+++ b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithMock.java
@@ -0,0 +1,30 @@
+/*
+ * 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.payment.dao;
+
+import java.io.IOException;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+@Test(groups = { "fast" })
+public class TestPaymentDaoWithMock extends TestPaymentDao {
+ @BeforeMethod(alwaysRun = true)
+ public void setUp() throws IOException {
+ dao = new MockPaymentDao();
+ }
+}
\ No newline at end of file
diff --git a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
index 11f7ca9..375bcfd 100644
--- a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
+++ b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
@@ -74,10 +74,9 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
@Override
public Either<PaymentError, String> createPaymentProviderAccount(Account account) {
if (account != null) {
- String id = String.valueOf(RandomStringUtils.random(10));
+ String id = String.valueOf(RandomStringUtils.randomAlphanumeric(10));
accounts.put(account.getExternalKey(),
- new PaymentProviderAccount.Builder().setAccountNumber(String.valueOf(RandomStringUtils.random(10)))
- .setDefaultPaymentMethod(String.valueOf(RandomStringUtils.random(10)))
+ new PaymentProviderAccount.Builder().setAccountKey(account.getExternalKey())
.setId(id)
.build());
@@ -101,30 +100,76 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
@Override
public Either<PaymentError, String> addPaymentMethod(String accountKey, PaymentMethodInfo paymentMethod) {
if (paymentMethod != null) {
- String paymentMethodId = RandomStringUtils.random(10);
- PaymentMethodInfo realPaymentMethod = null;
-
- if (paymentMethod instanceof PaypalPaymentMethodInfo) {
- PaypalPaymentMethodInfo paypalPaymentMethod = (PaypalPaymentMethodInfo)paymentMethod;
- realPaymentMethod = new PaypalPaymentMethodInfo.Builder(paypalPaymentMethod).setId(paymentMethodId).build();
- }
- else if (paymentMethod instanceof CreditCardPaymentMethodInfo) {
- CreditCardPaymentMethodInfo ccPaymentMethod = (CreditCardPaymentMethodInfo)paymentMethod;
- realPaymentMethod = new CreditCardPaymentMethodInfo.Builder(ccPaymentMethod).setId(paymentMethodId).build();
- }
- if (realPaymentMethod == null) {
- return Either.left(new PaymentError("unsupported", "Payment method " + paymentMethod.getType() + " not supported by the plugin"));
- }
- else {
- paymentMethods.put(paymentMethodId, paymentMethod);
- return Either.right(paymentMethodId);
+ PaymentProviderAccount account = accounts.get(accountKey);
+
+ if (account != null && account.getId() != null) {
+ String existingDefaultMethod = account.getDefaultPaymentMethodId();
+
+ String paymentMethodId = RandomStringUtils.randomAlphanumeric(10);
+ boolean shouldBeDefault = Boolean.TRUE.equals(paymentMethod.getDefaultMethod()) || existingDefaultMethod == null;
+ PaymentMethodInfo realPaymentMethod = null;
+
+ if (paymentMethod instanceof PaypalPaymentMethodInfo) {
+ PaypalPaymentMethodInfo paypalPaymentMethod = (PaypalPaymentMethodInfo)paymentMethod;
+
+ realPaymentMethod = new PaypalPaymentMethodInfo.Builder(paypalPaymentMethod)
+ .setId(paymentMethodId)
+ .setAccountId(accountKey)
+ .setDefaultMethod(shouldBeDefault)
+ .setBaid(paypalPaymentMethod.getBaid())
+ .setEmail(paypalPaymentMethod.getEmail())
+ .build();
+ }
+ else if (paymentMethod instanceof CreditCardPaymentMethodInfo) {
+ CreditCardPaymentMethodInfo ccPaymentMethod = (CreditCardPaymentMethodInfo)paymentMethod;
+ realPaymentMethod = new CreditCardPaymentMethodInfo.Builder(ccPaymentMethod).setId(paymentMethodId).build();
+ }
+ if (realPaymentMethod == null) {
+ return Either.left(new PaymentError("unsupported", "Payment method " + paymentMethod.getType() + " not supported by the plugin"));
+ }
+ else {
+ if (shouldBeDefault) {
+ setDefaultPaymentMethodOnAccount(account, paymentMethodId);
+ }
+ paymentMethods.put(paymentMethodId, realPaymentMethod);
+ return Either.right(paymentMethodId);
+ }
}
+ else {
+ return Either.left(new PaymentError("noaccount", "Could not retrieve account for accountKey " + accountKey));
+ }
}
else {
return Either.left(new PaymentError("unknown", "Could not create add payment method " + paymentMethod + " for " + accountKey));
}
}
+ public void setDefaultPaymentMethodOnAccount(PaymentProviderAccount account, String paymentMethodId) {
+ if (paymentMethodId != null && account != null) {
+ accounts.put(account.getAccountKey(),
+ new PaymentProviderAccount.Builder()
+ .copyFrom(account)
+ .setDefaultPaymentMethod(paymentMethodId)
+ .build());
+ List<PaymentMethodInfo> paymentMethodsToUpdate = new ArrayList<PaymentMethodInfo>();
+ for (PaymentMethodInfo paymentMethod : paymentMethods.values()) {
+ if (account.getAccountKey().equals(paymentMethod.getAccountId()) && !paymentMethodId.equals(paymentMethod.getId())) {
+ if (paymentMethod instanceof PaypalPaymentMethodInfo) {
+ PaypalPaymentMethodInfo paypalPaymentMethod = (PaypalPaymentMethodInfo)paymentMethod;
+ paymentMethodsToUpdate.add(new PaypalPaymentMethodInfo.Builder(paypalPaymentMethod).setDefaultMethod(false).build());
+ }
+ else if (paymentMethod instanceof CreditCardPaymentMethodInfo) {
+ CreditCardPaymentMethodInfo ccPaymentMethod = (CreditCardPaymentMethodInfo)paymentMethod;
+ paymentMethodsToUpdate.add(new CreditCardPaymentMethodInfo.Builder(ccPaymentMethod).setDefaultMethod(false).build());
+ }
+ }
+ }
+ for (PaymentMethodInfo paymentMethod : paymentMethodsToUpdate) {
+ paymentMethods.put(paymentMethod.getId(), paymentMethod);
+ }
+ }
+ }
+
@Override
public Either<PaymentError, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethod) {
if (paymentMethod != null) {
@@ -153,17 +198,23 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
@Override
public Either<PaymentError, Void> deletePaymentMethod(String accountKey, String paymentMethodId) {
- if (paymentMethods.remove(paymentMethodId) == null) {
- return Either.left(new PaymentError("unknown", "Did not get any result back"));
- }
- else {
- return Either.right(null);
+ PaymentMethodInfo paymentMethodInfo = paymentMethods.get(paymentMethodId);
+ if (paymentMethodInfo != null) {
+ if (Boolean.FALSE.equals(paymentMethodInfo.getDefaultMethod()) || paymentMethodInfo.getDefaultMethod() == null) {
+ if (paymentMethods.remove(paymentMethodId) == null) {
+ return Either.left(new PaymentError("unknown", "Did not get any result back"));
+ }
+ }
+ else {
+ return Either.left(new PaymentError("error", "Cannot delete default payment method"));
+ }
}
+ return Either.right(null);
}
@Override
public Either<PaymentError, PaymentMethodInfo> getPaymentMethodInfo(String paymentMethodId) {
- if (paymentMethodId != null) {
+ if (paymentMethodId == null) {
return Either.left(new PaymentError("unknown", "Could not retrieve payment method for paymentMethodId " + paymentMethodId));
}
@@ -171,12 +222,12 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
}
@Override
- public Either<PaymentError, List<PaymentMethodInfo>> getPaymentMethods(final String accountId) {
+ public Either<PaymentError, List<PaymentMethodInfo>> getPaymentMethods(final String accountKey) {
Collection<PaymentMethodInfo> filteredPaymentMethods = Collections2.filter(paymentMethods.values(), new Predicate<PaymentMethodInfo>() {
@Override
public boolean apply(PaymentMethodInfo input) {
- return accountId.equals(input.getAccountId());
+ return accountKey.equals(input.getAccountId());
}
});
List<PaymentMethodInfo> result = new ArrayList<PaymentMethodInfo>(filteredPaymentMethods);
@@ -189,7 +240,7 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
}
@Override
- public Either<PaymentError, Void> updatePaymentProviderAccountWithExistingContact(Account account) {
+ public Either<PaymentError, Void> updatePaymentProviderAccountExistingContact(Account account) {
// nothing to do here
return Either.right(null);
}
diff --git a/payment/src/test/java/com/ning/billing/payment/TestHelper.java b/payment/src/test/java/com/ning/billing/payment/TestHelper.java
index 87ff44b..ac05da4 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestHelper.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestHelper.java
@@ -45,13 +45,30 @@ public class TestHelper {
this.invoiceDao = invoiceDao;
}
- public Account createTestAccount() throws AccountApiException {
- final String name = "First" + RandomStringUtils.random(5) + " " + "Last" + RandomStringUtils.random(5);
+ // These helper methods can be overridden in a plugin implementation
+ public Account createTestCreditCardAccount() throws AccountApiException {
+ final String name = "First" + RandomStringUtils.randomAlphanumeric(5) + " " + "Last" + RandomStringUtils.randomAlphanumeric(5);
+ final String externalKey = RandomStringUtils.randomAlphanumeric(10);
final Account account = new AccountBuilder(UUID.randomUUID()).name(name)
.firstNameLength(name.length())
- .externalKey("12345")
+ .externalKey(externalKey)
.phone("123-456-7890")
- .email("user@example.com")
+ .email("ccuser@example.com")
+ .currency(Currency.USD)
+ .billingCycleDay(1)
+ .build();
+ accountDao.create(account);
+ return account;
+ }
+
+ public Account createTestPayPalAccount() throws AccountApiException {
+ final String name = "First" + RandomStringUtils.randomAlphanumeric(5) + " " + "Last" + RandomStringUtils.randomAlphanumeric(5);
+ final String externalKey = RandomStringUtils.randomAlphanumeric(10);
+ final Account account = new AccountBuilder(UUID.randomUUID()).name(name)
+ .firstNameLength(name.length())
+ .externalKey(externalKey)
+ .phone("123-456-7890")
+ .email("ppuser@example.com")
.currency(Currency.USD)
.billingCycleDay(1)
.build();
diff --git a/payment/src/test/java/com/ning/billing/payment/TestNotifyInvoicePaymentApi.java b/payment/src/test/java/com/ning/billing/payment/TestNotifyInvoicePaymentApi.java
index 1bd7695..80de67f 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestNotifyInvoicePaymentApi.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestNotifyInvoicePaymentApi.java
@@ -63,7 +63,7 @@ public class TestNotifyInvoicePaymentApi {
@Test
public void testNotifyPaymentSuccess() throws AccountApiException {
- final Account account = testHelper.createTestAccount();
+ final Account account = testHelper.createTestCreditCardAccount();
final Invoice invoice = testHelper.createTestInvoice(account);
PaymentAttempt paymentAttempt = new PaymentAttempt(UUID.randomUUID(), invoice);
@@ -81,7 +81,7 @@ public class TestNotifyInvoicePaymentApi {
@Test
public void testNotifyPaymentFailure() throws AccountApiException {
- final Account account = testHelper.createTestAccount();
+ final Account account = testHelper.createTestCreditCardAccount();
final Invoice invoice = testHelper.createTestInvoice(account);
PaymentAttempt paymentAttempt = new PaymentAttempt(UUID.randomUUID(), invoice);
diff --git a/payment/src/test/java/com/ning/billing/payment/TestPaymentInvoiceIntegration.java b/payment/src/test/java/com/ning/billing/payment/TestPaymentInvoiceIntegration.java
index 0533bdc..8768117 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestPaymentInvoiceIntegration.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestPaymentInvoiceIntegration.java
@@ -53,6 +53,7 @@ import com.ning.billing.payment.api.PaymentInfo;
import com.ning.billing.payment.setup.PaymentTestModuleWithEmbeddedDb;
import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.bus.Bus.EventBusException;
+import com.ning.billing.util.clock.MockClockModule;
public class TestPaymentInvoiceIntegration {
// create payment for received invoice and save it -- positive and negative
@@ -97,6 +98,7 @@ public class TestPaymentInvoiceIntegration {
Injector injector = Guice.createInjector(new PaymentTestModuleWithEmbeddedDb(),
new AccountModule(),
new InvoiceModuleWithMocks(),
+ new MockClockModule(),
new AbstractModule() {
@Override
protected void configure() {
@@ -121,7 +123,7 @@ public class TestPaymentInvoiceIntegration {
@Test
public void testInvoiceIntegration() throws Exception {
- final Account account = testHelper.createTestAccount();
+ final Account account = testHelper.createTestCreditCardAccount();
final Invoice invoice = testHelper.createTestInvoice(account);
await().atMost(1, MINUTES).until(new Callable<Boolean>() {
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 d682e16..2c0aa13 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestPaymentProvider.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestPaymentProvider.java
@@ -73,7 +73,7 @@ public class TestPaymentProvider {
@Test
public void testSimpleInvoice() throws Exception {
- final Account account = testHelper.createTestAccount();
+ final Account account = testHelper.createTestCreditCardAccount();
testHelper.createTestInvoice(account);
pom.xml 2(+1 -1)
diff --git a/pom.xml b/pom.xml
index 5ec08b5..d72a41e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -232,7 +232,7 @@
<dependency>
<groupId>org.jdbi</groupId>
<artifactId>jdbi</artifactId>
- <version>2.27</version>
+ <version>2.31.2</version>
</dependency>
<dependency>
<groupId>org.skife.config</groupId>
diff --git a/util/src/main/java/com/ning/billing/util/customfield/dao/FieldStoreDao.java b/util/src/main/java/com/ning/billing/util/customfield/dao/FieldStoreDao.java
index 680a826..14c123a 100644
--- a/util/src/main/java/com/ning/billing/util/customfield/dao/FieldStoreDao.java
+++ b/util/src/main/java/com/ning/billing/util/customfield/dao/FieldStoreDao.java
@@ -33,6 +33,7 @@ import org.skife.jdbi.v2.sqlobject.BinderFactory;
import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
import org.skife.jdbi.v2.sqlobject.SqlBatch;
import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
+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;
@@ -42,10 +43,11 @@ import com.ning.billing.util.entity.EntityCollectionDao;
@ExternalizedSqlViaStringTemplate3
@RegisterMapper(FieldStoreDao.CustomFieldMapper.class)
-public interface FieldStoreDao extends EntityCollectionDao<CustomField>, Transmogrifier {
+public interface FieldStoreDao extends EntityCollectionDao<CustomField>, Transactional<FieldStoreDao>, Transmogrifier {
+
@Override
- @SqlBatch
- public void save(@Bind("objectId") final String objectId,
+ @SqlBatch(transactional=false)
+ public void batchSaveFromTransaction(@Bind("objectId") final String objectId,
@Bind("objectType") final String objectType,
@CustomFieldBinder final List<CustomField> entities);
@@ -65,8 +67,10 @@ public interface FieldStoreDao extends EntityCollectionDao<CustomField>, Transmo
@Target({ElementType.PARAMETER})
public @interface CustomFieldBinder {
public static class CustomFieldBinderFactory implements BinderFactory {
+ @Override
public Binder build(Annotation annotation) {
return new Binder<CustomFieldBinder, CustomField>() {
+ @Override
public void bind(SQLStatement q, CustomFieldBinder bind, CustomField customField) {
q.bind("id", customField.getId().toString());
q.bind("fieldName", customField.getName());
diff --git a/util/src/main/java/com/ning/billing/util/entity/EntityCollectionDao.java b/util/src/main/java/com/ning/billing/util/entity/EntityCollectionDao.java
index 8134203..11d149c 100644
--- a/util/src/main/java/com/ning/billing/util/entity/EntityCollectionDao.java
+++ b/util/src/main/java/com/ning/billing/util/entity/EntityCollectionDao.java
@@ -26,8 +26,9 @@ import java.util.List;
* @param <T>
*/
public interface EntityCollectionDao<T extends Entity> {
- @SqlBatch
- public void save(@Bind("objectId") final String objectId,
+
+ @SqlBatch(transactional=false)
+ public void batchSaveFromTransaction(@Bind("objectId") final String objectId,
@Bind("objectType") final String objectType,
@BindBean final List<T> entities);
diff --git a/util/src/main/java/com/ning/billing/util/globalLocker/GlobalLocker.java b/util/src/main/java/com/ning/billing/util/globalLocker/GlobalLocker.java
index 59adb44..d6ce0af 100644
--- a/util/src/main/java/com/ning/billing/util/globalLocker/GlobalLocker.java
+++ b/util/src/main/java/com/ning/billing/util/globalLocker/GlobalLocker.java
@@ -17,5 +17,24 @@
package com.ning.billing.util.globalLocker;
public interface GlobalLocker {
- GlobalLock lockWithNumberOfTries(String lockName, int i);
+
+ GlobalLock lockWithNumberOfTries(final LockerService service, final String lockKey, final int retry);
+ Boolean isFree(final LockerService service, final String lockKey);
+
+ public enum LockerService {
+
+ // Only service needing global lock
+ INVOICE("invoice");
+
+ private final String svcName;
+
+ LockerService(String svcName) {
+ this.svcName = svcName;
+ }
+
+ @Override
+ public String toString() {
+ return svcName;
+ }
+ }
}
\ No newline at end of file
diff --git a/util/src/main/java/com/ning/billing/util/globalLocker/MySqlGlobalLocker.java b/util/src/main/java/com/ning/billing/util/globalLocker/MySqlGlobalLocker.java
index 43a1993..762ddc7 100644
--- a/util/src/main/java/com/ning/billing/util/globalLocker/MySqlGlobalLocker.java
+++ b/util/src/main/java/com/ning/billing/util/globalLocker/MySqlGlobalLocker.java
@@ -19,16 +19,22 @@ package com.ning.billing.util.globalLocker;
import com.google.inject.Inject;
import org.skife.jdbi.v2.Handle;
import org.skife.jdbi.v2.IDBI;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class MySqlGlobalLocker implements GlobalLocker {
+
+ private final static Logger logger = LoggerFactory.getLogger(MySqlGlobalLocker.class);
+
+ private final static long DEFAULT_TIMEOUT = 3L; // 3 seconds
+
private final IDBI dbi;
private long timeout;
@Inject
- public MySqlGlobalLocker(IDBI dbi)
- {
+ public MySqlGlobalLocker(IDBI dbi) {
this.dbi = dbi;
- this.timeout = 1000L;
+ this.timeout = DEFAULT_TIMEOUT;
}
public void setTimeout(final long timeout) {
@@ -36,39 +42,65 @@ public class MySqlGlobalLocker implements GlobalLocker {
}
@Override
- public GlobalLock lockWithNumberOfTries(final String lockName, final int i)
- {
- int tries_left = i;
+ public GlobalLock lockWithNumberOfTries(final LockerService service, final String lockKey, final int retry) {
+
+ final String lockName = getLockName(service, lockKey);
+ int tries_left = retry;
while (tries_left-- > 0) {
GlobalLock lock = lock(lockName);
if (lock != null) {
return lock;
}
}
+ logger.error(String.format("Failed to acquire lock %s for service %s after %d retry", lockKey, service, retry));
throw new LockFailedException();
}
- private GlobalLock lock(final String lockName) throws LockFailedException
- {
+ private GlobalLock lock(final String lockName) throws LockFailedException {
+
final Handle h = dbi.open();
final MySqlGlobalLockerDao dao = h.attach(MySqlGlobalLockerDao.class);
final boolean obtained = dao.lock(lockName, timeout);
if (obtained) {
return new GlobalLock() {
- public void release()
- {
+ @Override
+ public void release() {
try {
dao.releaseLock(lockName);
}
finally {
- h.close();
+ if (h != null) {
+ h.close();
+ }
}
}
};
- }
- else {
+ } else {
return null;
}
}
+
+ @Override
+ public Boolean isFree(final LockerService service, final String lockKey) {
+
+ final String lockName = getLockName(service, lockKey);
+ final Handle h = dbi.open();
+ try {
+ final MySqlGlobalLockerDao dao = h.attach(MySqlGlobalLockerDao.class);
+ return dao.isFree(lockName);
+ } finally {
+ if (h != null) {
+ h.close();
+ }
+ }
+ }
+
+ private String getLockName(final LockerService service, final String lockKey) {
+ StringBuilder tmp = new StringBuilder()
+ .append(service.toString())
+ .append("-")
+ .append(lockKey);
+ return tmp.toString();
+ }
}
diff --git a/util/src/main/java/com/ning/billing/util/globalLocker/MySqlGlobalLockerDao.java b/util/src/main/java/com/ning/billing/util/globalLocker/MySqlGlobalLockerDao.java
index d9ff452..14a02d4 100644
--- a/util/src/main/java/com/ning/billing/util/globalLocker/MySqlGlobalLockerDao.java
+++ b/util/src/main/java/com/ning/billing/util/globalLocker/MySqlGlobalLockerDao.java
@@ -27,12 +27,16 @@ import java.sql.SQLException;
@RegisterMapper(MySqlGlobalLockerDao.LockMapper.class)
public interface MySqlGlobalLockerDao {
+
@SqlQuery("Select GET_LOCK(:lockName, :timeout);")
public Boolean lock(@Bind("lockName") final String lockName, @Bind("timeout") final long timeout);
@SqlQuery("Select RELEASE_LOCK(:lockName);")
public Boolean releaseLock(@Bind("lockName") final String lockName);
+ @SqlQuery("Select IS_FREE_LOCK(:lockName);")
+ public Boolean isFree(@Bind("lockName") final String lockName);
+
class LockMapper implements ResultSetMapper<Boolean> {
@Override
public Boolean map(int index, ResultSet r, StatementContext ctx) throws SQLException {
diff --git a/util/src/main/java/com/ning/billing/util/glue/ClockModule.java b/util/src/main/java/com/ning/billing/util/glue/ClockModule.java
index 187a500..e7c7c3f 100644
--- a/util/src/main/java/com/ning/billing/util/glue/ClockModule.java
+++ b/util/src/main/java/com/ning/billing/util/glue/ClockModule.java
@@ -22,8 +22,8 @@ import com.ning.billing.util.clock.DefaultClock;
public class ClockModule extends AbstractModule {
- @Override
- protected void configure() {
- bind(Clock.class).to(DefaultClock.class).asEagerSingleton();
- }
+ @Override
+ protected void configure() {
+ bind(Clock.class).to(DefaultClock.class).asEagerSingleton();
+ }
}
diff --git a/util/src/main/java/com/ning/billing/util/glue/GlobalLockerModule.java b/util/src/main/java/com/ning/billing/util/glue/GlobalLockerModule.java
index 93d31e0..a6e6f66 100644
--- a/util/src/main/java/com/ning/billing/util/glue/GlobalLockerModule.java
+++ b/util/src/main/java/com/ning/billing/util/glue/GlobalLockerModule.java
@@ -17,8 +17,8 @@
package com.ning.billing.util.glue;
import com.google.inject.AbstractModule;
-import com.ning.billing.util.globalLocker.GlobalLocker;
-import com.ning.billing.util.globalLocker.MySqlGlobalLocker;
+import com.ning.billing.util.globallocker.GlobalLocker;
+import com.ning.billing.util.globallocker.MySqlGlobalLocker;
public class GlobalLockerModule extends AbstractModule {
@Override
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 039ce2b..10651be 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
@@ -31,10 +31,10 @@ public class TagStoreModule extends AbstractModule
@Override
protected void configure()
{
- bind(Clock.class).to(DefaultClock.class).asEagerSingleton();
bind(TagDefinitionSqlDao.class).toProvider(TagDescriptionDaoProvider.class).asEagerSingleton();
bind(TagDefinitionDao.class).to(DefaultTagDefinitionDao.class).asEagerSingleton();
bind(TagStoreSqlDao.class).toProvider(TagStoreDaoProvider.class).asEagerSingleton();
bind(TagDefinitionUserApi.class).to(DefaultTagDefinitionUserApi.class).asEagerSingleton();
}
+
}
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/dao/NotificationSqlDao.java b/util/src/main/java/com/ning/billing/util/notificationq/dao/NotificationSqlDao.java
index a297581..2f511ec 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/dao/NotificationSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/dao/NotificationSqlDao.java
@@ -52,10 +52,10 @@ public interface NotificationSqlDao extends Transactional<NotificationSqlDao>, C
public List<Notification> getReadyNotifications(@Bind("now") Date now, @Bind("max") int max, @Bind("queue_name") String queueName);
@SqlUpdate
- public int claimNotification(@Bind("owner") String owner, @Bind("next_available") Date nextAvailable, @Bind("notification_id") String eventId, @Bind("now") Date now);
+ public int claimNotification(@Bind("owner") String owner, @Bind("next_available") Date nextAvailable, @Bind("id") long id, @Bind("now") Date now);
@SqlUpdate
- public void clearNotification(@Bind("notification_id") String eventId, @Bind("owner") String owner);
+ public void clearNotification(@Bind("id") long id, @Bind("owner") String owner);
@SqlUpdate
public void insertNotification(@Bind(binder = NotificationSqlDaoBinder.class) Notification evt);
@@ -71,7 +71,7 @@ public interface NotificationSqlDao extends Transactional<NotificationSqlDao>, C
@Override
public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, Notification evt) {
- stmt.bind("notification_id", evt.getId().toString());
+ stmt.bind("notification_id", evt.getUUID().toString());
stmt.bind("created_dt", getDate(new DateTime()));
stmt.bind("notification_key", evt.getNotificationKey());
stmt.bind("effective_dt", getDate(evt.getEffectiveDate()));
@@ -94,7 +94,8 @@ public interface NotificationSqlDao extends Transactional<NotificationSqlDao>, C
public Notification map(int index, ResultSet r, StatementContext ctx)
throws SQLException {
- final UUID id = UUID.fromString(r.getString("notification_id"));
+ final long id = r.getLong("id");
+ final UUID uuid = UUID.fromString(r.getString("notification_id"));
final String notificationKey = r.getString("notification_key");
final String queueName = r.getString("queue_name");
final DateTime effectiveDate = getDate(r, "effective_dt");
@@ -102,7 +103,7 @@ public interface NotificationSqlDao extends Transactional<NotificationSqlDao>, C
final String processingOwner = r.getString("processing_owner");
final NotificationLifecycleState processingState = NotificationLifecycleState.valueOf(r.getString("processing_state"));
- return new DefaultNotification(id, processingOwner, queueName, nextAvailableDate,
+ return new DefaultNotification(id, uuid, processingOwner, queueName, nextAvailableDate,
processingState, notificationKey, effectiveDate);
}
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotification.java b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotification.java
index 3c4c476..26e6c4e 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotification.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotification.java
@@ -22,7 +22,8 @@ import org.joda.time.DateTime;
public class DefaultNotification implements Notification {
- private final UUID id;
+ private final long id;
+ private final UUID uuid;
private final String owner;
private final String queueName;
private final DateTime nextAvailableDate;
@@ -31,11 +32,12 @@ public class DefaultNotification implements Notification {
private final DateTime effectiveDate;
- public DefaultNotification(UUID id, String owner, String queueName, DateTime nextAvailableDate,
+ public DefaultNotification(long id, UUID uuid, String owner, String queueName, DateTime nextAvailableDate,
NotificationLifecycleState lifecycleState,
String notificationKey, DateTime effectiveDate) {
super();
this.id = id;
+ this.uuid = uuid;
this.owner = owner;
this.queueName = queueName;
this.nextAvailableDate = nextAvailableDate;
@@ -44,13 +46,17 @@ public class DefaultNotification implements Notification {
this.effectiveDate = effectiveDate;
}
- public DefaultNotification(String queueName, String notificationKey, DateTime effectiveDate) {
- this(UUID.randomUUID(), null, queueName, null, NotificationLifecycleState.AVAILABLE, notificationKey, effectiveDate);
+ @Override
+ public long getId() {
+ return id;
}
+ public DefaultNotification(String queueName, String notificationKey, DateTime effectiveDate) {
+ this(-1L, UUID.randomUUID(), null, queueName, null, NotificationLifecycleState.AVAILABLE, notificationKey, effectiveDate);
+ }
@Override
- public UUID getId() {
- return id;
+ public UUID getUUID() {
+ return uuid;
}
@Override
@@ -101,4 +107,5 @@ public class DefaultNotification implements Notification {
public String getQueueName() {
return queueName;
}
+
}
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
index 3780ade..3c19a2b 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
@@ -17,14 +17,12 @@
package com.ning.billing.util.notificationq;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.joda.time.DateTime;
import org.skife.jdbi.v2.IDBI;
-import org.skife.jdbi.v2.Transaction;
-import org.skife.jdbi.v2.TransactionStatus;
import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
+
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
import com.ning.billing.util.notificationq.dao.NotificationSqlDao;
@@ -34,19 +32,32 @@ public class DefaultNotificationQueue extends NotificationQueueBase {
protected final NotificationSqlDao dao;
public DefaultNotificationQueue(final IDBI dbi, final Clock clock, final String svcName, final String queueName, final NotificationQueueHandler handler, final NotificationConfig config) {
+
super(clock, svcName, queueName, handler, config);
this.dao = dbi.onDemand(NotificationSqlDao.class);
}
@Override
protected void doProcessEvents(final int sequenceId) {
+
+ logDebug("ENTER doProcessEvents");
List<Notification> notifications = getReadyNotifications(sequenceId);
- for (Notification cur : notifications) {
+ if (notifications.size() == 0) {
+ logDebug("EXIT doProcessEvents");
+ return;
+ }
+
+ logDebug("START processing %d events at time %s", notifications.size(), clock.getUTCNow().toDate());
+
+ for (final Notification cur : notifications) {
nbProcessedEvents.incrementAndGet();
+ logDebug("handling notification %s, key = %s for time %s",
+ cur.getUUID(), cur.getNotificationKey(), cur.getEffectiveDate());
handler.handleReadyNotification(cur.getNotificationKey());
+ clearNotification(cur);
+ logDebug("done handling notification %s, key = %s for time %s",
+ cur.getUUID(), cur.getNotificationKey(), cur.getEffectiveDate());
}
- // If anything happens before we get to clear those notifications, somebody else will pick them up
- clearNotifications(notifications);
}
@Override
@@ -58,24 +69,8 @@ public class DefaultNotificationQueue extends NotificationQueueBase {
}
- private void clearNotifications(final Collection<Notification> cleared) {
-
- log.debug(String.format("NotificationQueue %s clearEventsReady START cleared size = %d",
- getFullQName(),
- cleared.size()));
-
- dao.inTransaction(new Transaction<Void, NotificationSqlDao>() {
-
- @Override
- public Void inTransaction(NotificationSqlDao transactional,
- TransactionStatus status) throws Exception {
- for (Notification cur : cleared) {
- transactional.clearNotification(cur.getId().toString(), hostname);
- log.debug(String.format("NotificationQueue %s cleared events %s", getFullQName(), cur.getId()));
- }
- return null;
- }
- });
+ private void clearNotification(final Notification cleared) {
+ dao.clearNotification(cleared.getId(), hostname);
}
private List<Notification> getReadyNotifications(final int seqId) {
@@ -83,28 +78,22 @@ public class DefaultNotificationQueue extends NotificationQueueBase {
final Date now = clock.getUTCNow().toDate();
final Date nextAvailable = clock.getUTCNow().plus(config.getDaoClaimTimeMs()).toDate();
- log.debug(String.format("NotificationQueue %s getEventsReady START effectiveNow = %s", getFullQName(), now));
-
- List<Notification> input = dao.inTransaction(new Transaction<List<Notification>, NotificationSqlDao>() {
- @Override
- public List<Notification> inTransaction(NotificationSqlDao transactionalDao,
- TransactionStatus status) throws Exception {
- return transactionalDao.getReadyNotifications(now, config.getDaoMaxReadyEvents(), getFullQName());
- }
- });
+ List<Notification> input = dao.getReadyNotifications(now, config.getDaoMaxReadyEvents(), getFullQName());
List<Notification> claimedNotifications = new ArrayList<Notification>();
for (Notification cur : input) {
- final boolean claimed = (dao.claimNotification(hostname, nextAvailable, cur.getId().toString(), now) == 1);
+ logDebug("about to claim notification %s, key = %s for time %s",
+ cur.getUUID(), cur.getNotificationKey(), cur.getEffectiveDate());
+ final boolean claimed = (dao.claimNotification(hostname, nextAvailable, cur.getId(), now) == 1);
+ logDebug("claimed notification %s, key = %s for time %s result = %s",
+ cur.getUUID(), cur.getNotificationKey(), cur.getEffectiveDate(), Boolean.valueOf(claimed));
if (claimed) {
claimedNotifications.add(cur);
- dao.insertClaimedHistory(seqId, hostname, now, cur.getId().toString());
+ dao.insertClaimedHistory(seqId, hostname, now, cur.getUUID().toString());
}
}
for (Notification cur : claimedNotifications) {
- log.debug(String.format("NotificationQueue %s claimed events %s",
- getFullQName(), cur.getId()));
if (cur.getOwner() != null && !cur.getOwner().equals(hostname)) {
log.warn(String.format("NotificationQueue %s stealing notification %s from %s",
getFullQName(), cur, cur.getOwner()));
@@ -112,4 +101,11 @@ public class DefaultNotificationQueue extends NotificationQueueBase {
}
return claimedNotifications;
}
+
+ private void logDebug(String format, Object...args) {
+ if (log.isDebugEnabled()) {
+ String realDebug = String.format(format, args);
+ log.debug(String.format("Thread %d [queue = %s] %s", Thread.currentThread().getId(), getFullQName(), realDebug));
+ }
+ }
}
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/Notification.java b/util/src/main/java/com/ning/billing/util/notificationq/Notification.java
index 8749fa0..d59098b 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/Notification.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/Notification.java
@@ -23,13 +23,15 @@ import org.joda.time.DateTime;
public interface Notification extends NotificationLifecycle {
- public UUID getId();
+ public long getId();
+
+ public UUID getUUID();
public String getNotificationKey();
public DateTime getEffectiveDate();
-
+
public String getQueueName();
-
+
}
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagStoreSqlDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagStoreSqlDao.java
index 33dcdb0..bf4ed62 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagStoreSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagStoreSqlDao.java
@@ -16,38 +16,23 @@
package com.ning.billing.util.tag.dao;
-import java.lang.annotation.Annotation;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.sql.ResultSet;
-import java.sql.SQLException;
+
import java.util.List;
-import java.util.UUID;
-import org.joda.time.DateTime;
-import org.skife.jdbi.v2.SQLStatement;
-import org.skife.jdbi.v2.StatementContext;
+
import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.Binder;
-import org.skife.jdbi.v2.sqlobject.BinderFactory;
-import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
import org.skife.jdbi.v2.sqlobject.SqlBatch;
import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
+import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
-import org.skife.jdbi.v2.tweak.ResultSetMapper;
import com.ning.billing.util.entity.EntityCollectionDao;
-import com.ning.billing.util.tag.DescriptiveTag;
-import com.ning.billing.util.tag.DefaultTagDefinition;
import com.ning.billing.util.tag.Tag;
-import com.ning.billing.util.tag.TagDefinition;
@ExternalizedSqlViaStringTemplate3
@RegisterMapper(TagMapper.class)
-public interface TagStoreSqlDao extends EntityCollectionDao<Tag> {
+public interface TagStoreSqlDao extends EntityCollectionDao<Tag>, Transactional<TagStoreSqlDao> {
@Override
- @SqlBatch
- public void save(@Bind("objectId") final String objectId,
+ @SqlBatch(transactional=false)
+ public void batchSaveFromTransaction(@Bind("objectId") final String objectId,
@Bind("objectType") final String objectType,
@TagBinder final List<Tag> entities);
}
\ No newline at end of file
diff --git a/util/src/main/resources/com/ning/billing/util/customfield/dao/FieldStoreDao.sql.stg b/util/src/main/resources/com/ning/billing/util/customfield/dao/FieldStoreDao.sql.stg
index 883f61b..9d3e96e 100644
--- a/util/src/main/resources/com/ning/billing/util/customfield/dao/FieldStoreDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/customfield/dao/FieldStoreDao.sql.stg
@@ -1,6 +1,6 @@
group FieldStoreDao;
-save() ::= <<
+batchSaveFromTransaction() ::= <<
INSERT INTO custom_fields(id, object_id, object_type, field_name, field_value)
VALUES (:id, :objectId, :objectType, :fieldName, :fieldValue)
ON DUPLICATE KEY UPDATE
diff --git a/util/src/main/resources/com/ning/billing/util/ddl.sql b/util/src/main/resources/com/ning/billing/util/ddl.sql
index cf2ceb2..a0ef302 100644
--- a/util/src/main/resources/com/ning/billing/util/ddl.sql
+++ b/util/src/main/resources/com/ning/billing/util/ddl.sql
@@ -48,9 +48,8 @@ CREATE TABLE notifications (
processing_state varchar(14) DEFAULT 'AVAILABLE',
PRIMARY KEY(id)
) ENGINE=innodb;
-CREATE INDEX `idx_comp_where` ON notifications (`effective_dt`,`processing_state`,`processing_owner`,`processing_available_dt`);
-CREATE INDEX `idx_update` ON notifications (`notification_id`,`processing_state`,`processing_owner`,`processing_available_dt`);
-CREATE INDEX `idx_update1` ON notifications (`notification_id`,`processing_owner`);
+CREATE INDEX `idx_comp_where` ON notifications (`effective_dt`, `queue_name`, `processing_state`,`processing_owner`,`processing_available_dt`);
+CREATE INDEX `idx_update` ON notifications (`processing_state`,`processing_owner`,`processing_available_dt`);
CREATE INDEX `idx_get_ready` ON notifications (`effective_dt`,`created_dt`,`id`);
DROP TABLE IF EXISTS claimed_notifications;
diff --git a/util/src/main/resources/com/ning/billing/util/notificationq/dao/NotificationSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/notificationq/dao/NotificationSqlDao.sql.stg
index efe7e4f..7a7ecab 100644
--- a/util/src/main/resources/com/ning/billing/util/notificationq/dao/NotificationSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/notificationq/dao/NotificationSqlDao.sql.stg
@@ -2,8 +2,9 @@ group NotificationSqlDao;
getReadyNotifications(now, max) ::= <<
select
- notification_id
- , notification_key
+ id
+ , notification_id
+ , notification_key
, created_dt
, effective_dt
, queue_name
@@ -19,33 +20,31 @@ getReadyNotifications(now, max) ::= <<
order by
effective_dt asc
, created_dt asc
- , id asc
+ , id
limit :max
;
>>
-claimNotification(owner, next_available, notification_id, now) ::= <<
+claimNotification(owner, next_available, id, now) ::= <<
update notifications
set
processing_owner = :owner
, processing_available_dt = :next_available
, processing_state = 'IN_PROCESSING'
where
- notification_id = :notification_id
+ id = :id
and processing_state != 'PROCESSED'
and (processing_owner IS NULL OR processing_available_dt \<= :now)
;
>>
-clearNotification(notification_id, owner) ::= <<
+clearNotification(id, owner) ::= <<
update notifications
set
- processing_owner = NULL
- , processing_state = 'PROCESSED'
+ processing_state = 'PROCESSED'
where
- notification_id = :notification_id
- and processing_owner = :owner
+ id = :id
;
>>
diff --git a/util/src/main/resources/com/ning/billing/util/tag/dao/TagStoreSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/tag/dao/TagStoreSqlDao.sql.stg
index 2d78f48..9d7ce5c 100644
--- a/util/src/main/resources/com/ning/billing/util/tag/dao/TagStoreSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/tag/dao/TagStoreSqlDao.sql.stg
@@ -1,6 +1,6 @@
group TagStoreDao;
-save() ::= <<
+batchSaveFromTransaction() ::= <<
INSERT INTO tags(id, tag_definition_name, object_id, object_type, added_date, added_by)
VALUES (:id, :tagDefinitionName, :objectId, :objectType, :addedDate, :addedBy)
ON DUPLICATE KEY UPDATE
diff --git a/util/src/test/java/com/ning/billing/dbi/DBIProvider.java b/util/src/test/java/com/ning/billing/dbi/DBIProvider.java
index 07ee518..d83c033 100644
--- a/util/src/test/java/com/ning/billing/dbi/DBIProvider.java
+++ b/util/src/test/java/com/ning/billing/dbi/DBIProvider.java
@@ -55,7 +55,7 @@ public class DBIProvider implements Provider<IDBI>
dbConfig.setMaxConnectionsPerPartition(config.getMaxActive());
dbConfig.setConnectionTimeout(config.getConnectionTimeout().getPeriod(), config.getConnectionTimeout().getUnit());
dbConfig.setPartitionCount(1);
- dbConfig.setDefaultTransactionIsolation("READ_COMMITTED");
+ dbConfig.setDefaultTransactionIsolation("REPEATABLE_READ");
dbConfig.setDisableJMX(false);
final BoneCPDataSource ds = new BoneCPDataSource(dbConfig);
diff --git a/util/src/test/java/com/ning/billing/util/customfield/TestFieldStore.java b/util/src/test/java/com/ning/billing/util/customfield/TestFieldStore.java
index 9619bd8..4512a5d 100644
--- a/util/src/test/java/com/ning/billing/util/customfield/TestFieldStore.java
+++ b/util/src/test/java/com/ning/billing/util/customfield/TestFieldStore.java
@@ -20,6 +20,8 @@ import java.io.IOException;
import java.util.UUID;
import org.apache.commons.io.IOUtils;
import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.Transaction;
+import org.skife.jdbi.v2.TransactionStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.AfterClass;
@@ -62,32 +64,48 @@ public class TestFieldStore {
@Test
public void testFieldStore() {
- UUID id = UUID.randomUUID();
- String objectType = "Test widget";
+ final UUID id = UUID.randomUUID();
+ final String objectType = "Test widget";
- FieldStore fieldStore = new DefaultFieldStore(id, objectType);
+ final FieldStore fieldStore1 = new DefaultFieldStore(id, objectType);
String fieldName = "TestField1";
String fieldValue = "Kitty Hawk";
- fieldStore.setValue(fieldName, fieldValue);
+ fieldStore1.setValue(fieldName, fieldValue);
FieldStoreDao fieldStoreDao = dbi.onDemand(FieldStoreDao.class);
- fieldStoreDao.save(id.toString(), objectType, fieldStore.getEntityList());
+ fieldStoreDao.inTransaction(new Transaction<Void, FieldStoreDao>() {
+ @Override
+ public Void inTransaction(FieldStoreDao transactional,
+ TransactionStatus status) throws Exception {
+ transactional.batchSaveFromTransaction(id.toString(), objectType, fieldStore1.getEntityList());
+ return null;
+ }
+ });
- fieldStore = DefaultFieldStore.create(id, objectType);
- fieldStore.add(fieldStoreDao.load(id.toString(), objectType));
- assertEquals(fieldStore.getValue(fieldName), fieldValue);
+ final FieldStore fieldStore2 = DefaultFieldStore.create(id, objectType);
+ fieldStore2.add(fieldStoreDao.load(id.toString(), objectType));
- fieldValue = "Cape Canaveral";
- fieldStore.setValue(fieldName, fieldValue);
- assertEquals(fieldStore.getValue(fieldName), fieldValue);
- fieldStoreDao.save(id.toString(), objectType, fieldStore.getEntityList());
-
- fieldStore = DefaultFieldStore.create(id, objectType);
- assertEquals(fieldStore.getValue(fieldName), null);
- fieldStore.add(fieldStoreDao.load(id.toString(), objectType));
+ assertEquals(fieldStore2.getValue(fieldName), fieldValue);
- assertEquals(fieldStore.getValue(fieldName), fieldValue);
+ fieldValue = "Cape Canaveral";
+ fieldStore2.setValue(fieldName, fieldValue);
+ assertEquals(fieldStore2.getValue(fieldName), fieldValue);
+ fieldStoreDao.inTransaction(new Transaction<Void, FieldStoreDao>() {
+ @Override
+ public Void inTransaction(FieldStoreDao transactional,
+ TransactionStatus status) throws Exception {
+ transactional.batchSaveFromTransaction(id.toString(), objectType, fieldStore2.getEntityList());
+ return null;
+ }
+ });
+
+
+ final FieldStore fieldStore3 = DefaultFieldStore.create(id, objectType);
+ assertEquals(fieldStore3.getValue(fieldName), null);
+ fieldStore3.add(fieldStoreDao.load(id.toString(), objectType));
+
+ assertEquals(fieldStore3.getValue(fieldName), fieldValue);
}
}
diff --git a/util/src/test/java/com/ning/billing/util/globalLocker/MockGlobalLocker.java b/util/src/test/java/com/ning/billing/util/globalLocker/MockGlobalLocker.java
new file mode 100644
index 0000000..18336df
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/globalLocker/MockGlobalLocker.java
@@ -0,0 +1,35 @@
+/*
+ * 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.globalLocker;
+
+public class MockGlobalLocker implements GlobalLocker {
+
+ @Override
+ public GlobalLock lockWithNumberOfTries(LockerService service,
+ String lockKey, int retry) {
+ return new GlobalLock() {
+ @Override
+ public void release() {
+ }
+ };
+ }
+
+ @Override
+ public Boolean isFree(LockerService service, String lockKey) {
+ return Boolean.TRUE;
+ }
+}
diff --git a/util/src/test/java/com/ning/billing/util/globalLocker/TestMysqlGlobalLocker.java b/util/src/test/java/com/ning/billing/util/globalLocker/TestMysqlGlobalLocker.java
new file mode 100644
index 0000000..b797522
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/globalLocker/TestMysqlGlobalLocker.java
@@ -0,0 +1,115 @@
+/*
+ * 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.globalLocker;
+
+import java.io.IOException;
+import java.util.UUID;
+
+import org.skife.jdbi.v2.Handle;
+import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.TransactionCallback;
+import org.skife.jdbi.v2.TransactionStatus;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
+import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.util.globalLocker.GlobalLocker.LockerService;
+
+@Guice(modules=TestMysqlGlobalLocker.TestMysqlGlobalLockerModule.class)
+public class TestMysqlGlobalLocker {
+
+ @Inject
+ private IDBI dbi;
+
+ @Inject
+ private MysqlTestingHelper helper;
+
+ @BeforeClass(alwaysRun=true)
+ public void setup() throws IOException {
+ helper.startMysql();
+ createSimpleTable(dbi);
+ }
+
+ @AfterClass(alwaysRun=true)
+ public void tearDown() {
+ helper.stopMysql();
+ }
+
+ // Used as a manual test to validate the simple DAO by stepping through that locking is done and release correctly
+ @Test(groups= "slow", enabled = true)
+ public void testSimpleLocking() {
+
+ final String lockName = UUID.randomUUID().toString();
+
+ GlobalLocker locker = new MySqlGlobalLocker(dbi);
+ GlobalLock lock = locker.lockWithNumberOfTries(LockerService.INVOICE, lockName, 3);
+
+ dbi.inTransaction(new TransactionCallback<Void>() {
+ @Override
+ public Void inTransaction(Handle conn, TransactionStatus status)
+ throws Exception {
+ conn.execute("insert into dummy (dummy_id) values ('" + UUID.randomUUID().toString() + "')");
+ return null;
+ }
+ });
+ Assert.assertEquals(locker.isFree(LockerService.INVOICE, lockName), Boolean.FALSE);
+
+ boolean gotException = false;
+ try {
+ locker.lockWithNumberOfTries(LockerService.INVOICE, lockName, 1);
+ } catch (LockFailedException e) {
+ gotException = true;
+ }
+ Assert.assertTrue(gotException);
+
+ lock.release();
+
+ Assert.assertEquals(locker.isFree(LockerService.INVOICE, lockName), Boolean.TRUE);
+ }
+
+ private void createSimpleTable(IDBI dbi) {
+ dbi.inTransaction(new TransactionCallback<Void>() {
+
+ @Override
+ public Void inTransaction(Handle h, TransactionStatus status)
+ throws Exception {
+ h.execute("create table dummy " +
+ "(id int(11) unsigned NOT NULL AUTO_INCREMENT, " +
+ "dummy_id char(36) NOT NULL, " +
+ "PRIMARY KEY(id)" +
+ ") ENGINE=innodb;");
+ return null;
+ }
+ });
+ }
+
+ public final static class TestMysqlGlobalLockerModule extends AbstractModule {
+
+ @Override
+ protected void configure() {
+ MysqlTestingHelper helper = new MysqlTestingHelper();
+ bind(MysqlTestingHelper.class).toInstance(helper);
+ final IDBI dbi = helper.getDBI();
+ bind(IDBI.class).toInstance(dbi);
+ }
+ }
+}
diff --git a/util/src/test/java/com/ning/billing/util/notificationq/dao/TestNotificationSqlDao.java b/util/src/test/java/com/ning/billing/util/notificationq/dao/TestNotificationSqlDao.java
index d744caf..cb01e00 100644
--- a/util/src/test/java/com/ning/billing/util/notificationq/dao/TestNotificationSqlDao.java
+++ b/util/src/test/java/com/ning/billing/util/notificationq/dao/TestNotificationSqlDao.java
@@ -120,23 +120,23 @@ public class TestNotificationSqlDao {
assertEquals(notification.getNextAvailableDate(), null);
DateTime nextAvailable = now.plusMinutes(5);
- int res = dao.claimNotification(ownerId, nextAvailable.toDate(), notification.getId().toString(), now.toDate());
+ int res = dao.claimNotification(ownerId, nextAvailable.toDate(), notification.getId(), now.toDate());
assertEquals(res, 1);
- dao.insertClaimedHistory(sequenceId.incrementAndGet(), ownerId, now.toDate(), notification.getId().toString());
+ dao.insertClaimedHistory(sequenceId.incrementAndGet(), ownerId, now.toDate(), notification.getUUID().toString());
- notification = fetchNotification(notification.getId().toString());
+ notification = fetchNotification(notification.getUUID().toString());
assertEquals(notification.getNotificationKey(), notificationKey);
validateDate(notification.getEffectiveDate(), effDt);
assertEquals(notification.getOwner().toString(), ownerId);
assertEquals(notification.getProcessingState(), NotificationLifecycleState.IN_PROCESSING);
validateDate(notification.getNextAvailableDate(), nextAvailable);
- dao.clearNotification(notification.getId().toString(), ownerId);
+ dao.clearNotification(notification.getId(), ownerId);
- notification = fetchNotification(notification.getId().toString());
+ notification = fetchNotification(notification.getUUID().toString());
assertEquals(notification.getNotificationKey(), notificationKey);
validateDate(notification.getEffectiveDate(), effDt);
- assertEquals(notification.getOwner(), null);
+ //assertEquals(notification.getOwner(), null);
assertEquals(notification.getProcessingState(), NotificationLifecycleState.PROCESSED);
validateDate(notification.getNextAvailableDate(), nextAvailable);
@@ -148,7 +148,8 @@ public class TestNotificationSqlDao {
@Override
public Notification withHandle(Handle handle) throws Exception {
Notification res = handle.createQuery(" select" +
- " notification_id" +
+ " id " +
+ ", notification_id" +
", notification_key" +
", created_dt" +
", effective_dt" +
diff --git a/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java b/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java
index 0fe65ec..e1da366 100644
--- a/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java
+++ b/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java
@@ -75,7 +75,7 @@ public class MockNotificationQueue extends NotificationQueueBase implements Noti
}
for (Notification cur : readyNotifications) {
handler.handleReadyNotification(cur.getNotificationKey());
- DefaultNotification processedNotification = new DefaultNotification(cur.getId(), hostname, "MockQueue", clock.getUTCNow().plus(config.getDaoClaimTimeMs()), NotificationLifecycleState.PROCESSED, cur.getNotificationKey(), cur.getEffectiveDate());
+ DefaultNotification processedNotification = new DefaultNotification(-1L, cur.getUUID(), hostname, "MockQueue", clock.getUTCNow().plus(config.getDaoClaimTimeMs()), NotificationLifecycleState.PROCESSED, cur.getNotificationKey(), cur.getEffectiveDate());
oldNotifications.add(cur);
processedNotifications.add(processedNotification);
@@ -87,5 +87,6 @@ public class MockNotificationQueue extends NotificationQueueBase implements Noti
notifications.addAll(processedNotifications);
}
}
+
}
}
diff --git a/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java b/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
index 6db48d0..eac2d78 100644
--- a/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
+++ b/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
@@ -48,6 +48,8 @@ import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import com.google.inject.name.Names;
import com.ning.billing.dbi.MysqlTestingHelper;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.clock.ClockMock;
@@ -57,8 +59,8 @@ import com.ning.billing.util.notificationq.dao.NotificationSqlDao;
@Guice(modules = TestNotificationQueue.TestNotificationQueueModule.class)
public class TestNotificationQueue {
Logger log = LoggerFactory.getLogger(TestNotificationQueue.class);
- @Inject
- private IDBI dbi;
+ @Inject
+ private IDBI dbi;
@Inject
MysqlTestingHelper helper;
@@ -67,7 +69,7 @@ public class TestNotificationQueue {
private Clock clock;
private DummySqlTest dao;
-
+
private int eventsReceived;
// private NotificationQueue queue;
@@ -107,7 +109,7 @@ public class TestNotificationQueue {
/**
* Test that we can post a notification in the future from a transaction and get the notification
* callback with the correct key when the time is ready
- * @throws Exception
+ * @throws Exception
*/
@Test(groups={"fast"}, enabled = true)
public void testSimpleNotification() throws Exception {
@@ -254,20 +256,20 @@ public class TestNotificationQueue {
assertEquals(success, true);
}
-
+
/**
* Test that we can post a notification in the future from a transaction and get the notification
* callback with the correct key when the time is ready
- * @throws Exception
+ * @throws Exception
*/
@Test(groups={"fast"}, enabled = true)
public void testMultipleHandlerNotification() throws Exception {
final Map<String, Boolean> expectedNotificationsFred = new TreeMap<String, Boolean>();
final Map<String, Boolean> expectedNotificationsBarney = new TreeMap<String, Boolean>();
-
- NotificationQueueService notificationQueueService = new DefaultNotificationQueueService(dbi, clock);
-
+
+ NotificationQueueService notificationQueueService = new DefaultNotificationQueueService(dbi, clock);
+
NotificationConfig config=new NotificationConfig() {
@Override
public boolean isNotificationProcessingOff() {
@@ -286,8 +288,8 @@ public class TestNotificationQueue {
return 60000;
}
};
-
-
+
+
final NotificationQueue queueFred = notificationQueueService.createNotificationQueue("UtilTest", "Fred", new NotificationQueueHandler() {
@Override
public void handleReadyNotification(String notificationKey) {
@@ -297,7 +299,7 @@ public class TestNotificationQueue {
}
},
config);
-
+
final NotificationQueue queueBarney = notificationQueueService.createNotificationQueue("UtilTest", "Barney", new NotificationQueueHandler() {
@Override
public void handleReadyNotification(String notificationKey) {
@@ -310,8 +312,8 @@ public class TestNotificationQueue {
queueFred.startQueue();
// We don't start Barney so it can never pick up notifications
-
-
+
+
final UUID key = UUID.randomUUID();
final DummyObject obj = new DummyObject("foo", key);
final DateTime now = new DateTime();
@@ -323,7 +325,7 @@ public class TestNotificationQueue {
}
};
-
+
final NotificationKey notificationKeyBarney = new NotificationKey() {
@Override
public String toString() {
@@ -372,7 +374,7 @@ public class TestNotificationQueue {
Assert.assertTrue(expectedNotificationsFred.get(notificationKeyFred.toString()));
Assert.assertFalse(expectedNotificationsFred.get(notificationKeyBarney.toString()));
-
+
}
NotificationConfig getNotificationConfig(final boolean off,
@@ -408,6 +410,8 @@ public class TestNotificationQueue {
bind(MysqlTestingHelper.class).toInstance(helper);
IDBI dbi = helper.getDBI();
bind(IDBI.class).toInstance(dbi);
+ IDBI otherDbi = helper.getDBI();
+ bind(IDBI.class).annotatedWith(Names.named("global-lock")).toInstance(otherDbi);
/*
bind(DBI.class).toProvider(DBIProvider.class).asEagerSingleton();
final DbiConfig config = new ConfigurationObjectFactory(System.getProperties()).build(DbiConfig.class);
diff --git a/util/src/test/java/com/ning/billing/util/tag/TagStoreModuleMock.java b/util/src/test/java/com/ning/billing/util/tag/TagStoreModuleMock.java
index 9fc4c78..7bf9572 100644
--- a/util/src/test/java/com/ning/billing/util/tag/TagStoreModuleMock.java
+++ b/util/src/test/java/com/ning/billing/util/tag/TagStoreModuleMock.java
@@ -17,7 +17,9 @@
package com.ning.billing.util.tag;
import java.io.IOException;
+
import org.skife.jdbi.v2.IDBI;
+
import com.ning.billing.dbi.MysqlTestingHelper;
import com.ning.billing.util.glue.TagStoreModule;
diff --git a/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java b/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
index 633095f..c913791 100644
--- a/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
+++ b/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
@@ -21,6 +21,8 @@ import java.util.List;
import java.util.UUID;
import org.apache.commons.io.IOUtils;
import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.Transaction;
+import org.skife.jdbi.v2.TransactionStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.AfterClass;
@@ -33,6 +35,7 @@ import com.ning.billing.account.api.ControlTagType;
import com.ning.billing.util.api.TagDefinitionApiException;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.clock.DefaultClock;
+import com.ning.billing.util.clock.MockClockModule;
import com.ning.billing.util.tag.dao.TagDefinitionDao;
import com.ning.billing.util.tag.dao.TagStoreSqlDao;
@@ -52,7 +55,7 @@ public class TestTagStore {
private TagStoreModuleMock module;
private TagStoreSqlDao tagStoreSqlDao;
private TagDefinitionDao tagDefinitionDao;
- private Logger log = LoggerFactory.getLogger(TestTagStore.class);
+ private final Logger log = LoggerFactory.getLogger(TestTagStore.class);
@BeforeClass(alwaysRun = true)
protected void setup() throws IOException {
@@ -64,7 +67,7 @@ public class TestTagStore {
module.startDb();
module.initDb(utilDdl);
- final Injector injector = Guice.createInjector(Stage.DEVELOPMENT, module);
+ final Injector injector = Guice.createInjector(Stage.DEVELOPMENT, module, new MockClockModule());
dbi = injector.getInstance(IDBI.class);
tagStoreSqlDao = injector.getInstance(TagStoreSqlDao.class);
@@ -86,6 +89,17 @@ public class TestTagStore {
module.stopDb();
}
+ private void saveTags(final TagStoreSqlDao dao, final String objectType, final String accountId, final List<Tag> tagList) {
+ dao.inTransaction(new Transaction<Void, TagStoreSqlDao>() {
+ @Override
+ public Void inTransaction(TagStoreSqlDao transactional,
+ TransactionStatus status) throws Exception {
+ dao.batchSaveFromTransaction(accountId.toString(), objectType, tagList);
+ return null;
+ }
+ });
+ }
+
@Test
public void testTagCreationAndRetrieval() {
UUID accountId = UUID.randomUUID();
@@ -95,7 +109,7 @@ public class TestTagStore {
tagStore.add(tag);
TagStoreSqlDao dao = dbi.onDemand(TagStoreSqlDao.class);
- dao.save(accountId.toString(), ACCOUNT_TYPE, tagStore.getEntityList());
+ saveTags(dao, ACCOUNT_TYPE, accountId.toString(), tagStore.getEntityList());
List<Tag> savedTags = dao.load(accountId.toString(), ACCOUNT_TYPE);
assertEquals(savedTags.size(), 1);
@@ -107,6 +121,7 @@ public class TestTagStore {
assertEquals(savedTag.getId(), tag.getId());
}
+
@Test
public void testControlTagCreation() {
UUID accountId = UUID.randomUUID();
@@ -117,7 +132,7 @@ public class TestTagStore {
assertEquals(tagStore.generateInvoice(), false);
List<Tag> tagList = tagStore.getEntityList();
- tagStoreSqlDao.save(accountId.toString(), ACCOUNT_TYPE, tagList);
+ saveTags(tagStoreSqlDao, ACCOUNT_TYPE, accountId.toString(), tagList);
tagStore.clear();
assertEquals(tagStore.getEntityList().size(), 0);
@@ -147,7 +162,7 @@ public class TestTagStore {
assertEquals(tagStore.generateInvoice(), true);
List<Tag> tagList = tagStore.getEntityList();
- tagStoreSqlDao.save(accountId.toString(), ACCOUNT_TYPE, tagList);
+ saveTags(tagStoreSqlDao, ACCOUNT_TYPE, accountId.toString(), tagList);
tagStore.clear();
assertEquals(tagStore.getEntityList().size(), 0);
@@ -181,7 +196,7 @@ public class TestTagStore {
assertEquals(tagStore.generateInvoice(), false);
List<Tag> tagList = tagStore.getEntityList();
- tagStoreSqlDao.save(accountId.toString(), ACCOUNT_TYPE, tagList);
+ saveTags(tagStoreSqlDao, ACCOUNT_TYPE, accountId.toString(), tagList);
tagStore.clear();
assertEquals(tagStore.getEntityList().size(), 0);
@@ -244,7 +259,8 @@ public class TestTagStore {
Tag tag = new DescriptiveTag(tagDefinition, "test", clock.getUTCNow());
tagStore.add(tag);
- tagStoreSqlDao.save(objectId.toString(), objectType, tagStore.getEntityList());
+ saveTags(tagStoreSqlDao, objectType, objectId.toString(), tagStore.getEntityList());
+
List<Tag> tags = tagStoreSqlDao.load(objectId.toString(), objectType);
assertEquals(tags.size(), 1);
@@ -269,7 +285,8 @@ public class TestTagStore {
Tag tag = new DescriptiveTag(tagDefinition, "test", clock.getUTCNow());
tagStore.add(tag);
- tagStoreSqlDao.save(objectId.toString(), objectType, tagStore.getEntityList());
+ saveTags(tagStoreSqlDao, objectType, objectId.toString(), tagStore.getEntityList());
+
List<Tag> tags = tagStoreSqlDao.load(objectId.toString(), objectType);
assertEquals(tags.size(), 1);