killbill-aplcache
Changes
account/src/main/java/com/ning/billing/account/api/user/DefaultAccountCreationEvent.java 37(+18 -19)
Details
diff --git a/account/src/main/java/com/ning/billing/account/api/DefaultAccountEmail.java b/account/src/main/java/com/ning/billing/account/api/DefaultAccountEmail.java
index e6bdb24..b738270 100644
--- a/account/src/main/java/com/ning/billing/account/api/DefaultAccountEmail.java
+++ b/account/src/main/java/com/ning/billing/account/api/DefaultAccountEmail.java
@@ -18,10 +18,10 @@ package com.ning.billing.account.api;
import java.util.UUID;
-import com.ning.billing.util.entity.Entity;
import com.ning.billing.util.entity.EntityBase;
public class DefaultAccountEmail extends EntityBase implements AccountEmail {
+
private final UUID accountId;
private final String email;
diff --git a/account/src/main/java/com/ning/billing/account/api/DefaultAccountService.java b/account/src/main/java/com/ning/billing/account/api/DefaultAccountService.java
index 9b0cfc1..d630f70 100644
--- a/account/src/main/java/com/ning/billing/account/api/DefaultAccountService.java
+++ b/account/src/main/java/com/ning/billing/account/api/DefaultAccountService.java
@@ -16,7 +16,6 @@
package com.ning.billing.account.api;
-
public class DefaultAccountService implements AccountService {
private static final String ACCOUNT_SERVICE_NAME = "account-service";
@@ -26,7 +25,7 @@ public class DefaultAccountService implements AccountService {
return ACCOUNT_SERVICE_NAME;
}
-// @LifecycleHandlerType(LifecycleLevel.INIT_SERVICE)
-// public void initialize() {
-// }
+ // @LifecycleHandlerType(LifecycleLevel.INIT_SERVICE)
+ // public void initialize() {
+ // }
}
diff --git a/account/src/main/java/com/ning/billing/account/api/DefaultBillCycleDay.java b/account/src/main/java/com/ning/billing/account/api/DefaultBillCycleDay.java
index e5587be..faa33e5 100644
--- a/account/src/main/java/com/ning/billing/account/api/DefaultBillCycleDay.java
+++ b/account/src/main/java/com/ning/billing/account/api/DefaultBillCycleDay.java
@@ -61,13 +61,21 @@ public class DefaultBillCycleDay implements BillCycleDay {
@Override
public boolean equals(final Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
final DefaultBillCycleDay that = (DefaultBillCycleDay) o;
- if (dayOfMonthLocal != that.dayOfMonthLocal) return false;
- if (dayOfMonthUTC != that.dayOfMonthUTC) return false;
+ if (dayOfMonthLocal != that.dayOfMonthLocal) {
+ return false;
+ }
+ if (dayOfMonthUTC != that.dayOfMonthUTC) {
+ return false;
+ }
return true;
}
diff --git a/account/src/main/java/com/ning/billing/account/api/DefaultChangedField.java b/account/src/main/java/com/ning/billing/account/api/DefaultChangedField.java
index 0b762fd..09a971e 100644
--- a/account/src/main/java/com/ning/billing/account/api/DefaultChangedField.java
+++ b/account/src/main/java/com/ning/billing/account/api/DefaultChangedField.java
@@ -47,7 +47,6 @@ public class DefaultChangedField implements ChangedField {
this(fieldName, oldValue, newValue, new DateTime());
}
-
@Override
public String getFieldName() {
return fieldName;
@@ -73,13 +72,13 @@ public class DefaultChangedField implements ChangedField {
final int prime = 31;
int result = 1;
result = prime * result
- + ((changeDate == null) ? 0 : changeDate.hashCode());
+ + ((changeDate == null) ? 0 : changeDate.hashCode());
result = prime * result
- + ((fieldName == null) ? 0 : fieldName.hashCode());
+ + ((fieldName == null) ? 0 : fieldName.hashCode());
result = prime * result
- + ((newValue == null) ? 0 : newValue.hashCode());
+ + ((newValue == null) ? 0 : newValue.hashCode());
result = prime * result
- + ((oldValue == null) ? 0 : oldValue.hashCode());
+ + ((oldValue == null) ? 0 : oldValue.hashCode());
return result;
}
diff --git a/account/src/main/java/com/ning/billing/account/api/svcs/DefaultAccountInternalApi.java b/account/src/main/java/com/ning/billing/account/api/svcs/DefaultAccountInternalApi.java
index 7a84076..d75cc23 100644
--- a/account/src/main/java/com/ning/billing/account/api/svcs/DefaultAccountInternalApi.java
+++ b/account/src/main/java/com/ning/billing/account/api/svcs/DefaultAccountInternalApi.java
@@ -31,7 +31,6 @@ import com.ning.billing.account.dao.AccountDao;
import com.ning.billing.account.dao.AccountEmailDao;
import com.ning.billing.util.callcontext.InternalCallContext;
import com.ning.billing.util.callcontext.InternalTenantContext;
-import com.ning.billing.util.entity.EntityPersistenceException;
import com.ning.billing.util.svcapi.account.AccountInternalApi;
public class DefaultAccountInternalApi implements AccountInternalApi {
@@ -46,8 +45,7 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
}
@Override
- public Account getAccountById(final UUID accountId, final InternalTenantContext context)
- throws AccountApiException {
+ public Account getAccountById(final UUID accountId, final InternalTenantContext context) throws AccountApiException {
final Account account = accountDao.getById(accountId, context);
if (account == null) {
throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
@@ -56,21 +54,16 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
}
@Override
- public Account getAccountByRecordId(final Long recordId,
- final InternalTenantContext context) throws AccountApiException {
+ public Account getAccountByRecordId(final Long recordId, final InternalTenantContext context) throws AccountApiException {
return accountDao.getByRecordId(recordId, context);
}
@Override
public void updateAccount(final String externalKey, final AccountData accountData,
final InternalCallContext context) throws AccountApiException {
- try {
- final Account account = getAccountByKey(externalKey, context);
- final Account updatedAccount = new DefaultAccount(account.getId(), accountData);
- accountDao.update(updatedAccount, context);
- } catch (EntityPersistenceException e) {
- throw new AccountApiException(e, ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID);
- }
+ final Account account = getAccountByKey(externalKey, context);
+ final Account updatedAccount = new DefaultAccount(account.getId(), accountData);
+ accountDao.update(updatedAccount, context);
}
@Override
@@ -80,8 +73,7 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
}
@Override
- public Account getAccountByKey(final String key, final InternalTenantContext context)
- throws AccountApiException {
+ public Account getAccountByKey(final String key, final InternalTenantContext context) throws AccountApiException {
final Account account = accountDao.getAccountByKey(key, context);
if (account == null) {
throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_KEY, key);
@@ -90,18 +82,13 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
}
@Override
- public void removePaymentMethod(final UUID accountId, final InternalCallContext context)
- throws AccountApiException {
+ public void removePaymentMethod(final UUID accountId, final InternalCallContext context) throws AccountApiException {
updatePaymentMethod(accountId, null, context);
}
@Override
public void updatePaymentMethod(final UUID accountId, final UUID paymentMethodId,
final InternalCallContext context) throws AccountApiException {
- try {
- accountDao.updatePaymentMethod(accountId, paymentMethodId, context);
- } catch (final EntityPersistenceException e) {
- throw new AccountApiException(e, e.getCode(), e.getMessage());
- }
+ accountDao.updatePaymentMethod(accountId, paymentMethodId, context);
}
}
diff --git a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountChangeEvent.java b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountChangeEvent.java
index 39cc93d..2d8ed85 100644
--- a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountChangeEvent.java
+++ b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountChangeEvent.java
@@ -21,9 +21,9 @@ import java.util.List;
import java.util.UUID;
import com.ning.billing.account.api.Account;
-import com.ning.billing.util.events.ChangedField;
import com.ning.billing.account.api.DefaultChangedField;
import com.ning.billing.util.events.AccountChangeInternalEvent;
+import com.ning.billing.util.events.ChangedField;
import com.ning.billing.util.events.DefaultBusInternalEvent;
import com.fasterxml.jackson.annotation.JsonCreator;
@@ -50,7 +50,7 @@ public class DefaultAccountChangeEvent extends DefaultBusInternalEvent implement
}
public DefaultAccountChangeEvent(final UUID id, final UUID userToken, final Account oldData, final Account newData,
- final Long accountRecordId, final Long tenantRecordId) {
+ final Long accountRecordId, final Long tenantRecordId) {
super(userToken, accountRecordId, tenantRecordId);
this.accountId = id;
this.userToken = userToken;
diff --git a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountCreationEvent.java b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountCreationEvent.java
index ba2210f..6980388 100644
--- a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountCreationEvent.java
+++ b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountCreationEvent.java
@@ -32,7 +32,7 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
-public class DefaultAccountCreationEvent extends DefaultBusInternalEvent implements AccountCreationInternalEvent {
+public class DefaultAccountCreationEvent extends DefaultBusInternalEvent implements AccountCreationInternalEvent {
private final UUID id;
private final AccountData data;
@@ -70,7 +70,6 @@ public class DefaultAccountCreationEvent extends DefaultBusInternalEvent implem
return data;
}
-
@Override
public int hashCode() {
final int prime = 31;
@@ -109,8 +108,8 @@ public class DefaultAccountCreationEvent extends DefaultBusInternalEvent implem
return true;
}
-
public static class DefaultAccountData implements AccountData {
+
private final String externalKey;
private final String name;
private final Integer firstNameLength;
@@ -303,41 +302,41 @@ public class DefaultAccountCreationEvent extends DefaultBusInternalEvent implem
final int prime = 31;
int result = 1;
result = prime * result
- + ((address1 == null) ? 0 : address1.hashCode());
+ + ((address1 == null) ? 0 : address1.hashCode());
result = prime * result
- + ((address2 == null) ? 0 : address2.hashCode());
+ + ((address2 == null) ? 0 : address2.hashCode());
result = prime * result
- + ((billCycleDay == null) ? 0 : billCycleDay.hashCode());
+ + ((billCycleDay == null) ? 0 : billCycleDay.hashCode());
result = prime * result + ((city == null) ? 0 : city.hashCode());
result = prime * result
- + ((companyName == null) ? 0 : companyName.hashCode());
+ + ((companyName == null) ? 0 : companyName.hashCode());
result = prime * result
- + ((country == null) ? 0 : country.hashCode());
+ + ((country == null) ? 0 : country.hashCode());
result = prime * result
- + ((currency == null) ? 0 : currency.hashCode());
+ + ((currency == null) ? 0 : currency.hashCode());
result = prime * result + ((email == null) ? 0 : email.hashCode());
result = prime * result
- + ((externalKey == null) ? 0 : externalKey.hashCode());
+ + ((externalKey == null) ? 0 : externalKey.hashCode());
result = prime
- * result
- + ((firstNameLength == null) ? 0 : firstNameLength
+ * result
+ + ((firstNameLength == null) ? 0 : firstNameLength
.hashCode());
result = prime * result
- + ((locale == null) ? 0 : locale.hashCode());
+ + ((locale == null) ? 0 : locale.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime
- * result
- + ((paymentMethodId == null) ? 0 : paymentMethodId
+ * result
+ + ((paymentMethodId == null) ? 0 : paymentMethodId
.hashCode());
result = prime * result + ((phone == null) ? 0 : phone.hashCode());
result = prime * result
- + ((postalCode == null) ? 0 : postalCode.hashCode());
+ + ((postalCode == null) ? 0 : postalCode.hashCode());
result = prime
- * result
- + ((stateOrProvince == null) ? 0 : stateOrProvince
+ * result
+ + ((stateOrProvince == null) ? 0 : stateOrProvince
.hashCode());
result = prime * result
- + ((timeZone == null) ? 0 : timeZone.hashCode());
+ + ((timeZone == null) ? 0 : timeZone.hashCode());
return result;
}
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 9869b97..5986385 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
@@ -36,7 +36,6 @@ import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallContextFactory;
import com.ning.billing.util.callcontext.InternalCallContextFactory;
import com.ning.billing.util.callcontext.TenantContext;
-import com.ning.billing.util.entity.EntityPersistenceException;
import com.google.inject.Inject;
@@ -58,14 +57,14 @@ public class DefaultAccountUserApi implements AccountUserApi {
@Override
public Account createAccount(final AccountData data, final CallContext context) throws AccountApiException {
- final Account account = new DefaultAccount(data);
-
- try {
- accountDao.create(account, internalCallContextFactory.createInternalCallContext(account.getId(), context));
- } catch (AccountApiException e) {
- throw new AccountApiException(e, ErrorCode.ACCOUNT_CREATION_FAILED);
+ // Not transactional, but there is a db constraint on that column
+ if (getIdFromKey(data.getExternalKey(), context) != null) {
+ throw new AccountApiException(ErrorCode.ACCOUNT_ALREADY_EXISTS, data.getExternalKey());
}
+ final Account account = new DefaultAccount(data);
+ accountDao.create(account, internalCallContextFactory.createInternalCallContext(account.getId(), context));
+
return account;
}
@@ -75,6 +74,7 @@ public class DefaultAccountUserApi implements AccountUserApi {
if (account == null) {
throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_KEY, key);
}
+
return account;
}
@@ -84,6 +84,7 @@ public class DefaultAccountUserApi implements AccountUserApi {
if (account == null) {
throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, id);
}
+
return account;
}
@@ -99,25 +100,13 @@ public class DefaultAccountUserApi implements AccountUserApi {
@Override
public void updateAccount(final Account account, final CallContext context) throws AccountApiException {
- try {
- accountDao.update(account, internalCallContextFactory.createInternalCallContext(account.getId(), context));
- } catch (EntityPersistenceException e) {
- throw new AccountApiException(e, ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, account.getId());
- }
-
+ accountDao.update(account, internalCallContextFactory.createInternalCallContext(account.getId(), context));
}
@Override
- public void updateAccount(final UUID accountId, final AccountData accountData, final CallContext context)
- throws AccountApiException {
- try {
- final Account account = new DefaultAccount(accountId, accountData);
- accountDao.update(account, internalCallContextFactory.createInternalCallContext(account.getId(), context));
- } catch (EntityPersistenceException e) {
- throw new AccountApiException(e, ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID);
- } catch (RuntimeException e /* EntityPersistenceException */) {
- throw new AccountApiException(e, ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
- }
+ public void updateAccount(final UUID accountId, final AccountData accountData, final CallContext context) throws AccountApiException {
+ final Account account = new DefaultAccount(accountId, accountData);
+ updateAccount(account, context);
}
@Override
@@ -130,20 +119,19 @@ public class DefaultAccountUserApi implements AccountUserApi {
}
@Override
- public Account migrateAccount(final MigrationAccountData data, final CallContext context)
- throws AccountApiException {
+ public Account migrateAccount(final MigrationAccountData data, final CallContext context) throws AccountApiException {
+ // Create a special (migration) context
final DateTime createdDate = data.getCreatedDate() == null ? context.getCreatedDate() : data.getCreatedDate();
final DateTime updatedDate = data.getUpdatedDate() == null ? context.getUpdatedDate() : data.getUpdatedDate();
final CallContext migrationContext = callContextFactory.toMigrationCallContext(context, createdDate, updatedDate);
+
+ // Create the account
final Account account = new DefaultAccount(data);
+ createAccount(account, migrationContext);
- try {
- accountDao.create(account, internalCallContextFactory.createInternalCallContext(account.getId(), migrationContext));
- for (final String cur : data.getAdditionalContactEmails()) {
- addEmail(account.getId(), new DefaultAccountEmail(account.getId(), cur), migrationContext);
- }
- } catch (AccountApiException e) {
- throw new AccountApiException(e, ErrorCode.ACCOUNT_CREATION_FAILED);
+ // Add associated contact emails
+ for (final String cur : data.getAdditionalContactEmails()) {
+ addEmail(account.getId(), new DefaultAccountEmail(account.getId(), cur), migrationContext);
}
return account;
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountBinder.java b/account/src/main/java/com/ning/billing/account/dao/AccountBinder.java
index 3a413f0..9f0e744 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountBinder.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountBinder.java
@@ -35,7 +35,9 @@ import com.ning.billing.catalog.api.Currency;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface AccountBinder {
+
public static class AccountBinderFactory implements BinderFactory {
+
@Override
public Binder<AccountBinder, Account> build(final Annotation annotation) {
return new Binder<AccountBinder, Account>() {
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountDao.java b/account/src/main/java/com/ning/billing/account/dao/AccountDao.java
index 4c2002e..3935b19 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountDao.java
@@ -22,9 +22,7 @@ import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountApiException;
import com.ning.billing.util.callcontext.InternalCallContext;
import com.ning.billing.util.callcontext.InternalTenantContext;
-import com.ning.billing.util.entity.EntityPersistenceException;
import com.ning.billing.util.entity.dao.EntityDao;
-import com.ning.billing.util.entity.dao.UpdatableEntityDao;
public interface AccountDao extends EntityDao<Account, AccountApiException> {
@@ -39,7 +37,7 @@ public interface AccountDao extends EntityDao<Account, AccountApiException> {
* @param accountId the id of the account
* @param paymentMethodId the is of the current default paymentMethod
*/
- public void updatePaymentMethod(UUID accountId, UUID paymentMethodId, InternalCallContext context) throws EntityPersistenceException;
+ public void updatePaymentMethod(UUID accountId, UUID paymentMethodId, InternalCallContext context) throws AccountApiException;
- public void update(Account account, InternalCallContext context) throws EntityPersistenceException;
+ public void update(Account account, InternalCallContext context) throws AccountApiException;
}
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountEmailBinder.java b/account/src/main/java/com/ning/billing/account/dao/AccountEmailBinder.java
index bf2cb77..7d60b3b 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountEmailBinder.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountEmailBinder.java
@@ -33,7 +33,9 @@ import com.ning.billing.account.api.AccountEmail;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface AccountEmailBinder {
+
public static class AccountEmailBinderFactory implements BinderFactory {
+
@Override
public Binder<AccountEmailBinder, AccountEmail> build(final Annotation annotation) {
return new Binder<AccountEmailBinder, AccountEmail>() {
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountEmailHistoryBinder.java b/account/src/main/java/com/ning/billing/account/dao/AccountEmailHistoryBinder.java
index 866063c..ef79ae4 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountEmailHistoryBinder.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountEmailHistoryBinder.java
@@ -34,7 +34,9 @@ import com.ning.billing.util.dao.EntityHistory;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface AccountEmailHistoryBinder {
+
public static class AccountEmailHistoryBinderFactory implements BinderFactory {
+
@Override
public Binder<AccountEmailHistoryBinder, EntityHistory<AccountEmail>> build(final Annotation annotation) {
return new Binder<AccountEmailHistoryBinder, EntityHistory<AccountEmail>>() {
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountEmailMapper.java b/account/src/main/java/com/ning/billing/account/dao/AccountEmailMapper.java
index 9bfcbee..e668bba 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountEmailMapper.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountEmailMapper.java
@@ -28,6 +28,7 @@ import com.ning.billing.account.api.DefaultAccountEmail;
import com.ning.billing.util.dao.MapperBase;
public class AccountEmailMapper extends MapperBase implements ResultSetMapper<AccountEmail> {
+
@Override
public AccountEmail map(final int index, final ResultSet result, final StatementContext context) throws SQLException {
final UUID id = UUID.fromString(result.getString("id"));
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountHistoryBinder.java b/account/src/main/java/com/ning/billing/account/dao/AccountHistoryBinder.java
index 7c70303..ba8eec0 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountHistoryBinder.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountHistoryBinder.java
@@ -36,7 +36,9 @@ import com.ning.billing.util.dao.EntityHistory;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface AccountHistoryBinder {
+
public static class AccountHistoryBinderFactory implements BinderFactory {
+
@Override
public Binder<AccountHistoryBinder, EntityHistory<Account>> build(final Annotation annotation) {
return new Binder<AccountHistoryBinder, EntityHistory<Account>>() {
diff --git a/account/src/main/java/com/ning/billing/account/glue/DefaultAccountModule.java b/account/src/main/java/com/ning/billing/account/glue/DefaultAccountModule.java
index b419725..bbbce7c 100644
--- a/account/src/main/java/com/ning/billing/account/glue/DefaultAccountModule.java
+++ b/account/src/main/java/com/ning/billing/account/glue/DefaultAccountModule.java
@@ -23,8 +23,8 @@ import com.ning.billing.account.api.svcs.DefaultAccountInternalApi;
import com.ning.billing.account.api.user.DefaultAccountUserApi;
import com.ning.billing.account.dao.AccountDao;
import com.ning.billing.account.dao.AccountEmailDao;
-import com.ning.billing.account.dao.AuditedAccountDao;
-import com.ning.billing.account.dao.AuditedAccountEmailDao;
+import com.ning.billing.account.dao.DefaultAccountDao;
+import com.ning.billing.account.dao.DefaultAccountEmailDao;
import com.ning.billing.glue.AccountModule;
import com.ning.billing.util.glue.RealImplementation;
import com.ning.billing.util.svcapi.account.AccountInternalApi;
@@ -32,12 +32,13 @@ import com.ning.billing.util.svcapi.account.AccountInternalApi;
import com.google.inject.AbstractModule;
public class DefaultAccountModule extends AbstractModule implements AccountModule {
+
private void installConfig() {
}
protected void installAccountDao() {
- bind(AccountEmailDao.class).to(AuditedAccountEmailDao.class).asEagerSingleton();
- bind(AccountDao.class).to(AuditedAccountDao.class).asEagerSingleton();
+ bind(AccountEmailDao.class).to(DefaultAccountEmailDao.class).asEagerSingleton();
+ bind(AccountDao.class).to(DefaultAccountDao.class).asEagerSingleton();
}
@Override
@@ -49,6 +50,7 @@ public class DefaultAccountModule extends AbstractModule implements AccountModul
public void installInternalApi() {
bind(AccountInternalApi.class).to(DefaultAccountInternalApi.class).asEagerSingleton();
}
+
private void installAccountService() {
bind(AccountService.class).to(DefaultAccountService.class).asEagerSingleton();
}
diff --git a/account/src/main/resources/com/ning/billing/account/dao/AccountSqlDao.sql.stg b/account/src/main/resources/com/ning/billing/account/dao/AccountSqlDao.sql.stg
index a3d6075..e50cc57 100644
--- a/account/src/main/resources/com/ning/billing/account/dao/AccountSqlDao.sql.stg
+++ b/account/src/main/resources/com/ning/billing/account/dao/AccountSqlDao.sql.stg
@@ -1,5 +1,7 @@
group AccountDaoSql: EntitySqlDao;
+tableName() ::= "accounts";
+historyTableName() ::= "account_history";
tableFields(prefix) ::= <<
<prefix>external_key
@@ -54,9 +56,9 @@ tableValues() ::= <<
, :updatedBy
>>
-historyTableName() ::= "account_history"
-
-accountRecordIdField(prefix) ::= ""
+/** The accounts table doesn't have an account_record_id column (it's the record_id) **/
+accountRecordIdFieldWithComma(prefix) ::= ""
+accountRecordIdValueWithComma(prefix) ::= ""
update() ::= <<
UPDATE accounts
diff --git a/account/src/test/java/com/ning/billing/account/api/user/TestDefaultAccountUserApi.java b/account/src/test/java/com/ning/billing/account/api/user/TestDefaultAccountUserApi.java
index 51111aa..9dd5f33 100644
--- a/account/src/test/java/com/ning/billing/account/api/user/TestDefaultAccountUserApi.java
+++ b/account/src/test/java/com/ning/billing/account/api/user/TestDefaultAccountUserApi.java
@@ -27,6 +27,7 @@ import org.testng.annotations.Test;
import com.ning.billing.account.AccountTestSuite;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountData;
+import com.ning.billing.account.api.AccountEmail;
import com.ning.billing.account.api.BillCycleDay;
import com.ning.billing.account.api.DefaultAccount;
import com.ning.billing.account.api.DefaultAccountEmail;
@@ -36,11 +37,11 @@ import com.ning.billing.account.dao.AccountEmailDao;
import com.ning.billing.account.dao.MockAccountDao;
import com.ning.billing.account.dao.MockAccountEmailDao;
import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.util.svcsapi.bus.InternalBus;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallContextFactory;
import com.ning.billing.util.callcontext.InternalCallContextFactory;
import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.svcsapi.bus.InternalBus;
public class TestDefaultAccountUserApi extends AccountTestSuite {
@@ -118,17 +119,19 @@ public class TestDefaultAccountUserApi extends AccountTestSuite {
Assert.assertEquals(accountEmailDao.getByAccountId(accountId, tenantContext).size(), 0);
// Add the first email
- final String email1 = UUID.randomUUID().toString();
- accountUserApi.addEmail(accountId, new DefaultAccountEmail(accountId, email1), callContext);
+ final String emailAddress1 = UUID.randomUUID().toString();
+ final AccountEmail email1 = new DefaultAccountEmail(accountId, emailAddress1);
+ accountUserApi.addEmail(accountId, email1, callContext);
Assert.assertEquals(accountEmailDao.getByAccountId(accountId, tenantContext).size(), 1);
// Add a second one
- final String email2 = UUID.randomUUID().toString();
- accountUserApi.addEmail(accountId, new DefaultAccountEmail(accountId, email2), callContext);
+ final String emailAddress2 = UUID.randomUUID().toString();
+ final AccountEmail email2 = new DefaultAccountEmail(accountId, emailAddress2);
+ accountUserApi.addEmail(accountId, email2, callContext);
Assert.assertEquals(accountEmailDao.getByAccountId(accountId, tenantContext).size(), 2);
// Remove the first second one
- accountUserApi.removeEmail(accountId, new DefaultAccountEmail(accountId, email1), callContext);
+ accountUserApi.removeEmail(accountId, email1, callContext);
Assert.assertEquals(accountEmailDao.getByAccountId(accountId, tenantContext).size(), 1);
}
}
diff --git a/account/src/test/java/com/ning/billing/account/api/user/TestEventJson.java b/account/src/test/java/com/ning/billing/account/api/user/TestEventJson.java
index 8dd87bb..f19d940 100644
--- a/account/src/test/java/com/ning/billing/account/api/user/TestEventJson.java
+++ b/account/src/test/java/com/ning/billing/account/api/user/TestEventJson.java
@@ -24,14 +24,15 @@ import org.testng.Assert;
import org.testng.annotations.Test;
import com.ning.billing.account.AccountTestSuite;
-import com.ning.billing.util.events.ChangedField;
import com.ning.billing.account.api.DefaultBillCycleDay;
import com.ning.billing.account.api.DefaultChangedField;
import com.ning.billing.account.api.user.DefaultAccountCreationEvent.DefaultAccountData;
import com.ning.billing.util.events.AccountChangeInternalEvent;
+import com.ning.billing.util.events.ChangedField;
import com.ning.billing.util.jackson.ObjectMapper;
public class TestEventJson extends AccountTestSuite {
+
private final ObjectMapper mapper = new ObjectMapper();
@Test(groups = "fast")
@@ -52,7 +53,7 @@ public class TestEventJson extends AccountTestSuite {
public void testAccountCreationEvent() throws Exception {
final DefaultAccountData data = new DefaultAccountData("dsfdsf", "bobo", 3, "bobo@yahoo.com", new DefaultBillCycleDay(12), "USD", UUID.randomUUID(),
"UTC", "US", "21 avenue", "", "Gling", "San Franciso", "CA", "94110", "USA", "4126789887", false, false);
- final DefaultAccountCreationEvent e = new DefaultAccountCreationEvent(data, UUID.randomUUID(), UUID.randomUUID(), 1L, 45L);
+ final DefaultAccountCreationEvent e = new DefaultAccountCreationEvent(data, UUID.randomUUID(), UUID.randomUUID(), 1L, 45L);
final String json = mapper.writeValueAsString(e);
final DefaultAccountCreationEvent obj = mapper.readValue(json, DefaultAccountCreationEvent.class);
diff --git a/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java b/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
index f28c777..1f8a9cb 100644
--- a/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
+++ b/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
@@ -22,13 +22,12 @@ import org.skife.jdbi.v2.IDBI;
import org.testng.annotations.BeforeClass;
import com.ning.billing.account.AccountTestSuiteWithEmbeddedDB;
+import com.ning.billing.util.bus.DefaultBusService;
+import com.ning.billing.util.bus.InMemoryInternalBus;
import com.ning.billing.util.callcontext.InternalCallContextFactory;
import com.ning.billing.util.clock.ClockMock;
-import com.ning.billing.util.clock.DefaultClock;
-import com.ning.billing.util.svcsapi.bus.InternalBus;
import com.ning.billing.util.svcsapi.bus.BusService;
-import com.ning.billing.util.bus.DefaultBusService;
-import com.ning.billing.util.bus.InMemoryInternalBus;
+import com.ning.billing.util.svcsapi.bus.InternalBus;
import com.ning.billing.util.tag.api.user.TagEventBuilder;
import static org.testng.Assert.fail;
@@ -51,11 +50,11 @@ public abstract class AccountDaoTestBase extends AccountTestSuiteWithEmbeddedDB
final BusService busService = new DefaultBusService(bus);
((DefaultBusService) busService).startBus();
- accountDao = new AuditedAccountDao(dbi, bus, new InternalCallContextFactory(dbi, new ClockMock()));
+ accountDao = new DefaultAccountDao(dbi, bus, new InternalCallContextFactory(dbi, new ClockMock()));
// Health check test to make sure MySQL is setup properly
accountDao.test(internalCallContext);
- accountEmailDao = new AuditedAccountEmailDao(dbi);
+ accountEmailDao = new DefaultAccountEmailDao(dbi);
// Health check test to make sure MySQL is setup properly
accountEmailDao.test(internalCallContext);
} catch (Throwable t) {
diff --git a/account/src/test/java/com/ning/billing/account/dao/MockAccountDao.java b/account/src/test/java/com/ning/billing/account/dao/MockAccountDao.java
index fddfbc1..adab356 100644
--- a/account/src/test/java/com/ning/billing/account/dao/MockAccountDao.java
+++ b/account/src/test/java/com/ning/billing/account/dao/MockAccountDao.java
@@ -16,28 +16,28 @@
package com.ning.billing.account.dao;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Map;
import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
+import com.ning.billing.ErrorCode;
import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.account.api.DefaultAccount;
+import com.ning.billing.account.api.DefaultMutableAccountData;
import com.ning.billing.account.api.user.DefaultAccountChangeEvent;
import com.ning.billing.account.api.user.DefaultAccountCreationEvent;
import com.ning.billing.util.callcontext.InternalCallContext;
import com.ning.billing.util.callcontext.InternalTenantContext;
-import com.ning.billing.util.entity.EntityPersistenceException;
+import com.ning.billing.util.entity.dao.MockEntityDaoBase;
import com.ning.billing.util.events.AccountChangeInternalEvent;
import com.ning.billing.util.svcsapi.bus.InternalBus;
import com.ning.billing.util.svcsapi.bus.InternalBus.EventBusException;
import com.google.inject.Inject;
-public class MockAccountDao implements AccountDao {
+public class MockAccountDao extends MockEntityDaoBase<Account, AccountApiException> implements AccountDao {
private final InternalBus eventBus;
- private final Map<UUID, Account> accounts = new ConcurrentHashMap<UUID, Account>();
@Inject
public MockAccountDao(final InternalBus eventBus) {
@@ -45,42 +45,41 @@ public class MockAccountDao implements AccountDao {
}
@Override
- public Long getRecordId(final UUID id, final InternalTenantContext context) {
- return 1L;
- }
-
- @Override
- public void create(final Account account, final InternalCallContext context) {
- accounts.put(account.getId(), account);
+ public void create(final Account account, final InternalCallContext context) throws AccountApiException {
+ super.create(account, context);
try {
- eventBus.post(new DefaultAccountCreationEvent(account, null, 1L, 1L), context);
+ eventBus.post(new DefaultAccountCreationEvent(account, null, getRecordId(account.getId(), context), context.getTenantRecordId()), context);
} catch (final EventBusException ex) {
throw new RuntimeException(ex);
}
}
@Override
- public Account getById(final UUID id, final InternalTenantContext context) {
- return accounts.get(id);
- }
-
- @Override
- public List<Account> get(final InternalTenantContext context) {
- return new ArrayList<Account>(accounts.values());
- }
+ public void update(final Account account, final InternalCallContext context) {
+ final Account currentAccount = getById(account.getId(), context);
+ super.update(account, context);
- @Override
- public void test(final InternalTenantContext context) {
+ final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(account.getId(), null, currentAccount, account,
+ getRecordId(account.getId(), context), context.getTenantRecordId());
+ if (changeEvent.hasChanges()) {
+ try {
+ eventBus.post(changeEvent, context);
+ } catch (final EventBusException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
}
@Override
public Account getAccountByKey(final String externalKey, final InternalTenantContext context) {
- for (final Account account : accounts.values()) {
- if (externalKey.equals(account.getExternalKey())) {
+ for (final Map<Long, Account> accountRow : entities.values()) {
+ final Account account = accountRow.values().iterator().next();
+ if (account.getExternalKey().equals(externalKey)) {
return account;
}
}
+
return null;
}
@@ -91,25 +90,15 @@ public class MockAccountDao implements AccountDao {
}
@Override
- public void update(final Account account, final InternalCallContext context) {
- final Account currentAccount = accounts.put(account.getId(), account);
-
- final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(account.getId(), null, currentAccount, account, 1L, 1L);
- if (changeEvent.hasChanges()) {
- try {
- eventBus.post(changeEvent, context);
- } catch (final EventBusException ex) {
- throw new RuntimeException(ex);
- }
+ public void updatePaymentMethod(final UUID accountId, final UUID paymentMethodId, final InternalCallContext context) throws AccountApiException {
+ final Account currentAccount = getById(accountId, context);
+ if (currentAccount == null) {
+ throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
}
- }
- @Override
- public void updatePaymentMethod(final UUID accountId, final UUID paymentMethodId, final InternalCallContext context) throws EntityPersistenceException {
- }
+ final DefaultMutableAccountData updatedAccount = new DefaultMutableAccountData(currentAccount);
+ updatedAccount.setPaymentMethodId(paymentMethodId);
- @Override
- public Account getByRecordId(final Long recordId, final InternalTenantContext context) {
- return null;
+ update(new DefaultAccount(updatedAccount), context);
}
}
diff --git a/account/src/test/java/com/ning/billing/account/dao/MockAccountEmailDao.java b/account/src/test/java/com/ning/billing/account/dao/MockAccountEmailDao.java
index aa4c401..f408592 100644
--- a/account/src/test/java/com/ning/billing/account/dao/MockAccountEmailDao.java
+++ b/account/src/test/java/com/ning/billing/account/dao/MockAccountEmailDao.java
@@ -16,69 +16,28 @@
package com.ning.billing.account.dao;
-import java.util.HashSet;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
import com.ning.billing.account.api.AccountApiException;
import com.ning.billing.account.api.AccountEmail;
-import com.ning.billing.util.callcontext.InternalCallContext;
import com.ning.billing.util.callcontext.InternalTenantContext;
-import com.ning.billing.util.entity.EntityPersistenceException;
+import com.ning.billing.util.entity.dao.MockEntityDaoBase;
-import com.google.common.collect.ImmutableList;
-
-public class MockAccountEmailDao implements AccountEmailDao {
-
- private final Map<UUID, Set<AccountEmail>> emails = new ConcurrentHashMap<UUID, Set<AccountEmail>>();
-
- @Override
- public void create(final AccountEmail entity, final InternalCallContext context) throws AccountApiException {
- Set<AccountEmail> theSet = emails.get(entity.getAccountId());
- theSet.add(entity);
- }
-
- @Override
- public Long getRecordId(final UUID id, final InternalTenantContext context) {
- return 1L;
- }
-
- @Override
- public AccountEmail getById(final UUID id, final InternalTenantContext context) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public List<AccountEmail> get(final InternalTenantContext context) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void delete(final AccountEmail email, final InternalCallContext context) {
- Set<AccountEmail> theSet = emails.get(email.getAccountId());
- theSet.remove(email);
- }
+public class MockAccountEmailDao extends MockEntityDaoBase<AccountEmail, AccountApiException> implements AccountEmailDao {
@Override
public List<AccountEmail> getByAccountId(final UUID accountId, final InternalTenantContext context) {
- final Set<AccountEmail> accountEmails = emails.get(accountId);
- if (accountEmails == null) {
- return ImmutableList.<AccountEmail>of();
- } else {
- return ImmutableList.<AccountEmail>copyOf(accountEmails.iterator());
+ final List<AccountEmail> accountEmails = new ArrayList<AccountEmail>();
+ for (final Map<Long, AccountEmail> accountEmail : entities.values()) {
+ final AccountEmail email = accountEmail.values().iterator().next();
+ if (email.getAccountId().equals(accountId)) {
+ accountEmails.add(email);
+ }
}
- }
- @Override
- public void test(final InternalTenantContext context) {
- }
-
- @Override
- public AccountEmail getByRecordId(final Long recordId,
- final InternalTenantContext context) {
- return null;
+ return accountEmails;
}
}
diff --git a/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java b/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java
index 05168f9..e69f69a 100644
--- a/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java
+++ b/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java
@@ -144,7 +144,7 @@ public class TestAccountDao extends AccountDaoTestBase {
}
@Test(groups = "slow")
- public void testCustomFields() throws CustomFieldApiException {
+ public void testCustomFields() throws CustomFieldApiException {
final String fieldName = "testField1";
final String fieldValue = "testField1_value";
@@ -170,7 +170,6 @@ public class TestAccountDao extends AccountDaoTestBase {
final TagDao tagDao = new AuditedTagDao(dbi, tagEventBuilder, bus, new DefaultClock());
-
final TagDefinition tagDefinition = tagDefinitionDao.getById(definition.getId().toString(), internalCallContext);
final Tag tag = tagDefinition.isControlTag() ? new DefaultControlTag(ControlTagType.getTypeFromId(tagDefinition.getId()), ObjectType.ACCOUNT, account.getId(), internalCallContext.getCreatedDate()) :
new DescriptiveTag(tagDefinition.getId(), ObjectType.ACCOUNT, account.getId(), internalCallContext.getCreatedDate());
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 5db6b80..226f505 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
@@ -25,6 +25,7 @@ import com.ning.billing.mock.glue.MockClockModule;
import com.ning.billing.util.glue.CallContextModule;
public class AccountModuleWithMocks extends DefaultAccountModule {
+
@Override
protected void installAccountDao() {
bind(MockAccountDao.class).asEagerSingleton();
diff --git a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java
index ccd29e0..4d9a939 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java
@@ -32,8 +32,8 @@ import com.ning.billing.account.api.svcs.DefaultAccountInternalApi;
import com.ning.billing.account.api.user.DefaultAccountUserApi;
import com.ning.billing.account.dao.AccountDao;
import com.ning.billing.account.dao.AccountEmailDao;
-import com.ning.billing.account.dao.AuditedAccountDao;
-import com.ning.billing.account.dao.AuditedAccountEmailDao;
+import com.ning.billing.account.dao.DefaultAccountDao;
+import com.ning.billing.account.dao.DefaultAccountEmailDao;
import com.ning.billing.analytics.dao.BusinessAccountTagSqlDao;
import com.ning.billing.analytics.dao.BusinessInvoicePaymentTagSqlDao;
import com.ning.billing.analytics.dao.BusinessInvoiceTagSqlDao;
@@ -59,7 +59,6 @@ import com.ning.billing.util.bus.InMemoryInternalBus;
import com.ning.billing.util.callcontext.DefaultCallContextFactory;
import com.ning.billing.util.callcontext.InternalCallContextFactory;
import com.ning.billing.util.clock.ClockMock;
-import com.ning.billing.util.clock.DefaultClock;
import com.ning.billing.util.notificationq.DefaultNotificationQueueService;
import com.ning.billing.util.svcapi.account.AccountInternalApi;
import com.ning.billing.util.svcapi.entitlement.EntitlementInternalApi;
@@ -85,8 +84,8 @@ public class TestBusinessTagRecorder extends AnalyticsTestSuiteWithEmbeddedDB {
final BusinessInvoicePaymentTagSqlDao invoicePaymentTagSqlDao = dbi.onDemand(BusinessInvoicePaymentTagSqlDao.class);
subscriptionTransitionTagSqlDao = dbi.onDemand(BusinessSubscriptionTransitionTagSqlDao.class);
eventBus = new InMemoryInternalBus();
- final AccountDao accountDao = new AuditedAccountDao(dbi, eventBus, new InternalCallContextFactory(dbi, new ClockMock()));
- final AccountEmailDao accountEmailDao = new AuditedAccountEmailDao(dbi);
+ final AccountDao accountDao = new DefaultAccountDao(dbi, eventBus, new InternalCallContextFactory(dbi, new ClockMock()));
+ final AccountEmailDao accountEmailDao = new DefaultAccountEmailDao(dbi);
callContextFactory = new DefaultCallContextFactory(clock);
final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(dbi, clock);
accountApi = new DefaultAccountInternalApi(accountDao, accountEmailDao);
diff --git a/api/src/main/java/com/ning/billing/util/api/AuditUserApi.java b/api/src/main/java/com/ning/billing/util/api/AuditUserApi.java
index d6a7a4f..ee9cc2a 100644
--- a/api/src/main/java/com/ning/billing/util/api/AuditUserApi.java
+++ b/api/src/main/java/com/ning/billing/util/api/AuditUserApi.java
@@ -21,6 +21,7 @@ import java.util.UUID;
import com.ning.billing.ObjectType;
import com.ning.billing.entitlement.api.timeline.BundleTimeline;
+import com.ning.billing.entitlement.api.timeline.EntitlementRepairException;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoicePayment;
import com.ning.billing.payment.api.Payment;
@@ -36,6 +37,16 @@ import com.ning.billing.util.callcontext.TenantContext;
public interface AuditUserApi {
/**
+ * Fetch all audit logs for a bundle.
+ *
+ * @param bundleId the bundle id to lookup
+ * @param auditLevel audit level (verbosity)
+ * @param context the tenant context
+ * @return all audit logs for these refunds
+ */
+ public AuditLogsForBundles getAuditLogsForBundle(UUID bundleId, AuditLevel auditLevel, TenantContext context) throws EntitlementRepairException;
+
+ /**
* Fetch all audit logs for bundles.
*
* @param bundles the bundles to lookup
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/util/AuditChecker.java b/beatrix/src/test/java/com/ning/billing/beatrix/util/AuditChecker.java
new file mode 100644
index 0000000..11a6a2d
--- /dev/null
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/util/AuditChecker.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2010-2012 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.beatrix.util;
+
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+
+import com.ning.billing.entitlement.api.timeline.EntitlementRepairException;
+import com.ning.billing.util.api.AuditLevel;
+import com.ning.billing.util.api.AuditUserApi;
+import com.ning.billing.util.audit.AuditLog;
+import com.ning.billing.util.audit.AuditLogsForBundles;
+import com.ning.billing.util.audit.ChangeType;
+import com.ning.billing.util.callcontext.CallContext;
+
+import com.google.inject.Inject;
+
+public class AuditChecker {
+
+ private static final Logger log = LoggerFactory.getLogger(AuditChecker.class);
+
+ private final AuditUserApi auditUserApi;
+
+ @Inject
+ public AuditChecker(final AuditUserApi auditUserApi) {
+ this.auditUserApi = auditUserApi;
+ }
+
+ // Pass the call context used to create the bundle
+ public void checkBundleCreated(final UUID bundleId, final CallContext context) {
+ final AuditLogsForBundles auditLogsForBundles = getAuditLogsForBundle(bundleId, context);
+
+ Assert.assertEquals(auditLogsForBundles.getBundlesAuditLogs().keySet().size(), 1);
+ Assert.assertEquals(auditLogsForBundles.getBundlesAuditLogs().get(bundleId).size(), 1);
+ checkAuditLog(ChangeType.INSERT, context, auditLogsForBundles.getBundlesAuditLogs().get(bundleId).get(0));
+ }
+
+ // Pass the call context used to update the bundle
+ public void checkBundleUpdated(final UUID bundleId, final CallContext context) {
+ final AuditLogsForBundles auditLogsForBundles = getAuditLogsForBundle(bundleId, context);
+
+ Assert.assertEquals(auditLogsForBundles.getBundlesAuditLogs().keySet().size(), 1);
+ Assert.assertEquals(auditLogsForBundles.getBundlesAuditLogs().get(bundleId).size(), 2);
+ checkAuditLog(ChangeType.INSERT, auditLogsForBundles.getBundlesAuditLogs().get(bundleId).get(0));
+ checkAuditLog(ChangeType.UPDATE, context, auditLogsForBundles.getBundlesAuditLogs().get(bundleId).get(1));
+ }
+
+ // Pass the call context used to create the subscription
+ public void checkSubscriptionCreated(final UUID bundleId, final UUID subscriptionId, final CallContext context) {
+ final AuditLogsForBundles auditLogsForBundles = getAuditLogsForBundle(bundleId, context);
+
+ Assert.assertEquals(auditLogsForBundles.getSubscriptionsAuditLogs().keySet().size(), 1);
+ Assert.assertEquals(auditLogsForBundles.getSubscriptionsAuditLogs().get(subscriptionId).size(), 1);
+ checkAuditLog(ChangeType.INSERT, context, auditLogsForBundles.getSubscriptionsAuditLogs().get(subscriptionId).get(0));
+ }
+
+ // Pass the call context used to update the subscription
+ public void checkSubscriptionUpdated(final UUID bundleId, final UUID subscriptionId, final CallContext context) {
+ final AuditLogsForBundles auditLogsForBundles = getAuditLogsForBundle(bundleId, context);
+
+ Assert.assertEquals(auditLogsForBundles.getSubscriptionsAuditLogs().keySet().size(), 1);
+ Assert.assertEquals(auditLogsForBundles.getSubscriptionsAuditLogs().get(subscriptionId).size(), 2);
+ checkAuditLog(ChangeType.INSERT, auditLogsForBundles.getSubscriptionsAuditLogs().get(subscriptionId).get(0));
+ checkAuditLog(ChangeType.UPDATE, context, auditLogsForBundles.getSubscriptionsAuditLogs().get(subscriptionId).get(1));
+ }
+
+ // Pass the call context used to create the subscription event
+ public void checkSubscriptionEventCreated(final UUID bundleId, final UUID subscriptionEventId, final CallContext context) {
+ final AuditLogsForBundles auditLogsForBundles = getAuditLogsForBundle(bundleId, context);
+
+ Assert.assertEquals(auditLogsForBundles.getSubscriptionEventsAuditLogs().keySet().size(), 1);
+ Assert.assertEquals(auditLogsForBundles.getSubscriptionEventsAuditLogs().get(subscriptionEventId).size(), 1);
+ checkAuditLog(ChangeType.INSERT, context, auditLogsForBundles.getSubscriptionEventsAuditLogs().get(subscriptionEventId).get(0));
+ }
+
+ // Pass the call context used to update the subscription event
+ public void checkSubscriptionEventUpdated(final UUID bundleId, final UUID subscriptionEventId, final CallContext context) {
+ final AuditLogsForBundles auditLogsForBundles = getAuditLogsForBundle(bundleId, context);
+
+ Assert.assertEquals(auditLogsForBundles.getSubscriptionEventsAuditLogs().keySet().size(), 1);
+ Assert.assertEquals(auditLogsForBundles.getSubscriptionEventsAuditLogs().get(subscriptionEventId).size(), 2);
+ checkAuditLog(ChangeType.INSERT, auditLogsForBundles.getSubscriptionEventsAuditLogs().get(subscriptionEventId).get(0));
+ checkAuditLog(ChangeType.UPDATE, context, auditLogsForBundles.getSubscriptionEventsAuditLogs().get(subscriptionEventId).get(1));
+ }
+
+ private AuditLogsForBundles getAuditLogsForBundle(final UUID bundleId, final CallContext context) {
+ try {
+ return auditUserApi.getAuditLogsForBundle(bundleId, AuditLevel.FULL, context);
+ } catch (EntitlementRepairException e) {
+ Assert.fail(e.toString());
+ return null;
+ }
+ }
+
+ private void checkAuditLog(final ChangeType insert, final AuditLog auditLog) {
+ checkAuditLog(insert, null, auditLog);
+ }
+
+ private void checkAuditLog(final ChangeType changeType, @Nullable final CallContext context, final AuditLog auditLog) {
+ Assert.assertEquals(auditLog.getChangeType(), changeType);
+
+ if (context != null) {
+ Assert.assertEquals(auditLog.getUserName(), context.getUserName());
+ Assert.assertEquals(auditLog.getReasonCode(), context.getReasonCode());
+ // TODO check 'Next Billing Date' and 'Transition' - add comment, maybe internal reason code and token
+ Assert.assertEquals(auditLog.getComment(), context.getComments());
+ Assert.assertEquals(auditLog.getUserToken(), context.getUserToken().toString());
+ Assert.assertEquals(auditLog.getCreatedDate(), context.getCreatedDate());
+ }
+ }
+}
diff --git a/util/src/main/java/com/ning/billing/util/audit/api/DefaultAuditUserApi.java b/util/src/main/java/com/ning/billing/util/audit/api/DefaultAuditUserApi.java
index 0429e67..e95e1b2 100644
--- a/util/src/main/java/com/ning/billing/util/audit/api/DefaultAuditUserApi.java
+++ b/util/src/main/java/com/ning/billing/util/audit/api/DefaultAuditUserApi.java
@@ -25,6 +25,8 @@ import javax.inject.Inject;
import com.ning.billing.ObjectType;
import com.ning.billing.entitlement.api.timeline.BundleTimeline;
+import com.ning.billing.entitlement.api.timeline.EntitlementRepairException;
+import com.ning.billing.entitlement.api.timeline.EntitlementTimelineApi;
import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.ExistingEvent;
import com.ning.billing.invoice.api.Invoice;
@@ -55,15 +57,22 @@ import com.google.common.collect.ImmutableList;
public class DefaultAuditUserApi implements AuditUserApi {
private final AuditDao auditDao;
+ private final EntitlementTimelineApi timelineApi;
private final InternalCallContextFactory internalCallContextFactory;
@Inject
- public DefaultAuditUserApi(final AuditDao auditDao, final InternalCallContextFactory internalCallContextFactory) {
+ public DefaultAuditUserApi(final AuditDao auditDao, final EntitlementTimelineApi timelineApi, final InternalCallContextFactory internalCallContextFactory) {
this.auditDao = auditDao;
+ this.timelineApi = timelineApi;
this.internalCallContextFactory = internalCallContextFactory;
}
@Override
+ public AuditLogsForBundles getAuditLogsForBundle(final UUID bundleId, final AuditLevel auditLevel, final TenantContext context) throws EntitlementRepairException {
+ return getAuditLogsForBundles(ImmutableList.<BundleTimeline>of(timelineApi.getBundleTimeline(bundleId, context)), auditLevel, context);
+ }
+
+ @Override
public AuditLogsForBundles getAuditLogsForBundles(final List<BundleTimeline> bundles, final AuditLevel auditLevel, final TenantContext context) {
final Map<UUID, List<AuditLog>> bundlesAuditLogs = new HashMap<UUID, List<AuditLog>>();
final Map<UUID, List<AuditLog>> subscriptionsAuditLogs = new HashMap<UUID, List<AuditLog>>();
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperFactory.java b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperFactory.java
index 03fdf7f..bd4ea2c 100644
--- a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperFactory.java
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperFactory.java
@@ -56,7 +56,7 @@ public class EntitySqlDaoWrapperFactory<InitialSqlDao extends EntitySqlDao> {
private <NewSqlDao extends EntitySqlDao<NewEntity>, NewEntity extends Entity> NewSqlDao create(final Class<NewSqlDao> newSqlDaoClass, final NewSqlDao newSqlDao) {
final ClassLoader classLoader = newSqlDao.getClass().getClassLoader();
final Class[] interfacesToImplement = {newSqlDaoClass};
- final EntitySqlDaoWrapperInvocationHandler<NewSqlDao, NewEntity> wrapperInvocationHandler = new EntitySqlDaoWrapperInvocationHandler<NewSqlDao, NewEntity>(newSqlDao);
+ final EntitySqlDaoWrapperInvocationHandler<NewSqlDao, NewEntity> wrapperInvocationHandler = new EntitySqlDaoWrapperInvocationHandler<NewSqlDao, NewEntity>(newSqlDaoClass, newSqlDao);
final Object newSqlDaoObject = Proxy.newProxyInstance(classLoader, interfacesToImplement, wrapperInvocationHandler);
return newSqlDaoClass.cast(newSqlDaoObject);
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
index d3cc502..fbf6a1c 100644
--- a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
@@ -19,15 +19,19 @@ package com.ning.billing.util.entity.dao;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.UUID;
+import org.skife.jdbi.v2.StatementContext;
import org.skife.jdbi.v2.exceptions.DBIException;
+import org.skife.jdbi.v2.exceptions.StatementException;
import org.skife.jdbi.v2.sqlobject.Bind;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.ning.billing.util.audit.ChangeType;
import com.ning.billing.util.callcontext.InternalCallContext;
@@ -47,9 +51,13 @@ import com.google.common.collect.ImmutableList.Builder;
*/
public class EntitySqlDaoWrapperInvocationHandler<T extends EntitySqlDao<U>, U extends Entity> implements InvocationHandler {
+ private final Logger logger = LoggerFactory.getLogger(EntitySqlDaoWrapperInvocationHandler.class);
+
+ private final Class<T> sqlDaoClass;
private final T sqlDao;
- public EntitySqlDaoWrapperInvocationHandler(final T sqlDao) {
+ public EntitySqlDaoWrapperInvocationHandler(final Class<T> sqlDaoClass, final T sqlDao) {
+ this.sqlDaoClass = sqlDaoClass;
this.sqlDao = sqlDao;
}
@@ -60,12 +68,23 @@ public class EntitySqlDaoWrapperInvocationHandler<T extends EntitySqlDao<U>, U e
} catch (Throwable t) {
if (t.getCause() != null && t.getCause().getCause() != null && DBIException.class.isAssignableFrom(t.getCause().getClass())) {
// Likely the JDBC exception or a Billing exception we have thrown in the transaction
- errorDuringTransaction(t.getCause().getCause());
+ // If it's a JDBC error, try to extract the SQL statement
+ if (t.getCause() instanceof StatementException) {
+ final StatementContext statementContext = ((StatementException) t.getCause()).getStatementContext();
+ if (statementContext != null) {
+ final PreparedStatement statement = statementContext.getStatement();
+ // Note: we rely on the JDBC driver to have a sane toString() method...
+ errorDuringTransaction(t.getCause().getCause(), method, statement.toString());
+ // Never reached
+ return null;
+ }
+ }
+ errorDuringTransaction(t.getCause().getCause(), method);
} else if (t.getCause() != null) {
// t is likely not interesting (java.lang.reflect.InvocationTargetException)
- errorDuringTransaction(t.getCause());
+ errorDuringTransaction(t.getCause(), method);
} else {
- errorDuringTransaction(t);
+ errorDuringTransaction(t, method);
}
}
@@ -74,7 +93,22 @@ public class EntitySqlDaoWrapperInvocationHandler<T extends EntitySqlDao<U>, U e
}
// Nice method name to ease debugging while looking at log files
- private void errorDuringTransaction(final Throwable t) throws Throwable {
+ private void errorDuringTransaction(final Throwable t, final Method method, final String extraErrorMessage) throws Throwable {
+ final StringBuilder errorMessageBuilder = new StringBuilder("Error during transaction for sql entity {} and method {}");
+ if (t instanceof SQLException) {
+ final SQLException sqlException = (SQLException) t;
+ errorMessageBuilder.append(" [SQL State: ")
+ .append(sqlException.getSQLState())
+ .append(", Vendor Error Code: ")
+ .append(sqlException.getErrorCode())
+ .append("]");
+ }
+ if (extraErrorMessage != null) {
+ // This is usually the SQL statement
+ errorMessageBuilder.append("\n").append(extraErrorMessage);
+ }
+ logger.warn(errorMessageBuilder.toString(), sqlDaoClass, method.getName());
+
// This is to avoid throwing an exception wrapped in an UndeclaredThrowableException
if (!(t instanceof RuntimeException)) {
throw new RuntimeException(t);
@@ -83,6 +117,10 @@ public class EntitySqlDaoWrapperInvocationHandler<T extends EntitySqlDao<U>, U e
}
}
+ private void errorDuringTransaction(final Throwable t, final Method method) throws Throwable {
+ errorDuringTransaction(t, method, null);
+ }
+
private Object invokeSafely(final Object proxy, final Method method, final Object[] args) throws Throwable {
final Audited annotation = method.getAnnotation(Audited.class);
@@ -225,8 +263,6 @@ public class EntitySqlDaoWrapperInvocationHandler<T extends EntitySqlDao<U>, U e
return sqlDao.getHistoryRecordId(entityRecordId, context);
}
-
-
private void insertAudits(final TableName tableName, final Long historyRecordId, final ChangeType changeType, final InternalCallContext context) {
// STEPH can we trust context or should we use Clock?
final TableName destinationTableName = Objects.firstNonNull(tableName.getHistoryTableName(), tableName);
diff --git a/util/src/test/java/com/ning/billing/util/audit/api/TestDefaultAuditUserApi.java b/util/src/test/java/com/ning/billing/util/audit/api/TestDefaultAuditUserApi.java
index d1fef2c..32912cf 100644
--- a/util/src/test/java/com/ning/billing/util/audit/api/TestDefaultAuditUserApi.java
+++ b/util/src/test/java/com/ning/billing/util/audit/api/TestDefaultAuditUserApi.java
@@ -67,7 +67,7 @@ public class TestDefaultAuditUserApi extends AuditLogsTestBase {
}
}
- auditUserApi = new DefaultAuditUserApi(auditDao, Mockito.mock(InternalCallContextFactory.class));
+ auditUserApi = new DefaultAuditUserApi(auditDao, null, Mockito.mock(InternalCallContextFactory.class));
}
@Test(groups = "fast")
diff --git a/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java b/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java
index a40dbb4..3706e15 100644
--- a/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java
+++ b/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java
@@ -30,16 +30,17 @@ import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import com.ning.billing.ObjectType;
+import com.ning.billing.mock.glue.MockEntitlementModule;
import com.ning.billing.util.UtilTestSuiteWithEmbeddedDB;
import com.ning.billing.util.api.AuditLevel;
import com.ning.billing.util.api.TagApiException;
import com.ning.billing.util.api.TagDefinitionApiException;
import com.ning.billing.util.audit.AuditLog;
import com.ning.billing.util.audit.ChangeType;
-import com.ning.billing.util.svcsapi.bus.InternalBus;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.dao.TableName;
import com.ning.billing.util.glue.AuditModule;
+import com.ning.billing.util.svcsapi.bus.InternalBus;
import com.ning.billing.util.tag.ControlTagType;
import com.ning.billing.util.tag.DefaultControlTag;
import com.ning.billing.util.tag.DescriptiveTag;
@@ -51,7 +52,7 @@ import com.ning.billing.util.tag.dao.TagDefinitionDao;
import com.google.inject.Inject;
-@Guice(modules = {MockTagStoreModuleSql.class, AuditModule.class})
+@Guice(modules = {MockTagStoreModuleSql.class, AuditModule.class, MockEntitlementModule.class})
public class TestDefaultAuditDao extends UtilTestSuiteWithEmbeddedDB {
@Inject
diff --git a/util/src/test/java/com/ning/billing/util/entity/dao/MockEntityDaoBase.java b/util/src/test/java/com/ning/billing/util/entity/dao/MockEntityDaoBase.java
index 53b8d91..d59dc79 100644
--- a/util/src/test/java/com/ning/billing/util/entity/dao/MockEntityDaoBase.java
+++ b/util/src/test/java/com/ning/billing/util/entity/dao/MockEntityDaoBase.java
@@ -26,19 +26,16 @@ import java.util.concurrent.atomic.AtomicLong;
import com.ning.billing.BillingExceptionBase;
import com.ning.billing.util.callcontext.InternalCallContext;
import com.ning.billing.util.callcontext.InternalTenantContext;
-import com.ning.billing.util.customfield.CustomField;
import com.ning.billing.util.entity.Entity;
import com.google.common.collect.ImmutableMap;
public class MockEntityDaoBase<T extends Entity, U extends BillingExceptionBase> implements EntityDao<T, U> {
-
- protected final static AtomicLong autoIncrement = new AtomicLong(1);
+ protected static final AtomicLong autoIncrement = new AtomicLong(1);
protected final Map<UUID, Map<Long, T>> entities = new HashMap<UUID, Map<Long, T>>();
-
@Override
public void create(final T entity, final InternalCallContext context) throws U {
entities.put(entity.getId(), ImmutableMap.<Long, T>of(autoIncrement.incrementAndGet(), entity));
@@ -51,7 +48,7 @@ public class MockEntityDaoBase<T extends Entity, U extends BillingExceptionBase>
@Override
public T getByRecordId(final Long recordId, final InternalTenantContext context) {
- for (Map<Long, T> cur : entities.values()) {
+ for (final Map<Long, T> cur : entities.values()) {
if (cur.keySet().iterator().next().equals(recordId)) {
cur.values().iterator().next();
}
@@ -66,13 +63,22 @@ public class MockEntityDaoBase<T extends Entity, U extends BillingExceptionBase>
@Override
public List<T> get(final InternalTenantContext context) {
- List<T> result = new ArrayList<T>();
- for (Map<Long, T> cur : entities.values()) {
- result.add(cur.values().iterator().next());
+ final List<T> result = new ArrayList<T>();
+ for (final Map<Long, T> cur : entities.values()) {
+ result.add(cur.values().iterator().next());
}
return result;
}
+ public void update(final T entity, final InternalCallContext context) {
+ final Long entityRecordId = getRecordId(entity.getId(), context);
+ entities.get(entity.getId()).put(entityRecordId, entity);
+ }
+
+ public void delete(final T entity, final InternalCallContext context) {
+ entities.remove(entity.getId());
+ }
+
@Override
public void test(final InternalTenantContext context) {
}