Skip to content

Commit

Permalink
account: use clock in DefaultChangedField
Browse files Browse the repository at this point in the history
This relates to #487.

Signed-off-by: Pierre-Alexandre Meyer <pierre@mouraf.org>
  • Loading branch information
pierre committed Feb 8, 2016
1 parent f12f5f4 commit cc2ce39
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 54 deletions.
@@ -1,7 +1,9 @@
/* /*
* Copyright 2010-2013 Ning, Inc. * Copyright 2010-2013 Ning, Inc.
* Copyright 2014-2016 Groupon, Inc
* Copyright 2014-2016 The Billing Project, LLC
* *
* Ning licenses this file to you under the Apache License, version 2.0 * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the * (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at: * License. You may obtain a copy of the License at:
* *
Expand All @@ -17,7 +19,6 @@
package org.killbill.billing.account.api; package org.killbill.billing.account.api;


import org.joda.time.DateTime; import org.joda.time.DateTime;

import org.killbill.billing.events.ChangedField; import org.killbill.billing.events.ChangedField;


import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonCreator;
Expand All @@ -41,12 +42,6 @@ public DefaultChangedField(@JsonProperty("fieldName") final String fieldName,
this.newValue = newValue; this.newValue = newValue;
} }


public DefaultChangedField(final String fieldName,
final String oldValue,
final String newValue) {
this(fieldName, oldValue, newValue, new DateTime());
}

@Override @Override
public String getFieldName() { public String getFieldName() {
return fieldName; return fieldName;
Expand Down Expand Up @@ -124,5 +119,4 @@ public boolean equals(final Object obj) {
} }
return true; return true;
} }

} }
@@ -1,7 +1,9 @@
/* /*
* Copyright 2010-2013 Ning, Inc. * Copyright 2010-2013 Ning, Inc.
* Copyright 2014-2016 Groupon, Inc
* Copyright 2014-2016 The Billing Project, LLC
* *
* Ning licenses this file to you under the Apache License, version 2.0 * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the * (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at: * License. You may obtain a copy of the License at:
* *
Expand All @@ -17,9 +19,11 @@
package org.killbill.billing.account.api.user; package org.killbill.billing.account.api.user;


import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;


import org.joda.time.DateTime;
import org.killbill.billing.account.api.DefaultChangedField; import org.killbill.billing.account.api.DefaultChangedField;
import org.killbill.billing.account.dao.AccountModelDao; import org.killbill.billing.account.dao.AccountModelDao;
import org.killbill.billing.events.AccountChangeInternalEvent; import org.killbill.billing.events.AccountChangeInternalEvent;
Expand Down Expand Up @@ -47,10 +51,16 @@ public DefaultAccountChangeEvent(@JsonProperty("changeFields") final List<Change
this.changedFields = changedFields; this.changedFields = changedFields;
} }


public DefaultAccountChangeEvent(final UUID id, final AccountModelDao oldData, final AccountModelDao newData, final Long searchKey1, final Long searchKey2, final UUID userToken) { public DefaultAccountChangeEvent(final UUID id,
final AccountModelDao oldData,
final AccountModelDao newData,
final Long searchKey1,
final Long searchKey2,
final UUID userToken,
final DateTime changeDate) {
super(searchKey1, searchKey2, userToken); super(searchKey1, searchKey2, userToken);
this.accountId = id; this.accountId = id;
this.changedFields = calculateChangedFields(oldData, newData); this.changedFields = calculateChangedFields(oldData, newData, changeDate);
} }


@JsonIgnore @JsonIgnore
Expand All @@ -73,7 +83,7 @@ public List<ChangedField> getChangedFields() {
@JsonIgnore @JsonIgnore
@Override @Override
public boolean hasChanges() { public boolean hasChanges() {
return (changedFields.size() > 0); return (!changedFields.isEmpty());
} }


@Override @Override
Expand Down Expand Up @@ -116,57 +126,56 @@ public boolean equals(final Object obj) {
return true; return true;
} }


private List<ChangedField> calculateChangedFields(final AccountModelDao oldData, final AccountModelDao newData) { private List<ChangedField> calculateChangedFields(final AccountModelDao oldData, final AccountModelDao newData, final DateTime changeDate) {

final List<ChangedField> tmpChangedFields = new ArrayList<ChangedField>(); final List<ChangedField> tmpChangedFields = new ArrayList<ChangedField>();


addIfValueChanged(tmpChangedFields, "externalKey", addIfValueChanged(tmpChangedFields, "externalKey",
oldData.getExternalKey(), newData.getExternalKey()); oldData.getExternalKey(), newData.getExternalKey(), changeDate);


addIfValueChanged(tmpChangedFields, "email", addIfValueChanged(tmpChangedFields, "email",
oldData.getEmail(), newData.getEmail()); oldData.getEmail(), newData.getEmail(), changeDate);


addIfValueChanged(tmpChangedFields, "firstName", addIfValueChanged(tmpChangedFields, "firstName",
oldData.getName(), newData.getName()); oldData.getName(), newData.getName(), changeDate);


addIfValueChanged(tmpChangedFields, "currency", addIfValueChanged(tmpChangedFields, "currency",
(oldData.getCurrency() != null) ? oldData.getCurrency().toString() : null, (oldData.getCurrency() != null) ? oldData.getCurrency().toString() : null,
(newData.getCurrency() != null) ? newData.getCurrency().toString() : null); (newData.getCurrency() != null) ? newData.getCurrency().toString() : null, changeDate);


addIfValueChanged(tmpChangedFields, addIfValueChanged(tmpChangedFields,
"billCycleDayLocal", "billCycleDayLocal",
String.valueOf(oldData.getBillingCycleDayLocal()), String.valueOf(newData.getBillingCycleDayLocal())); String.valueOf(oldData.getBillingCycleDayLocal()), String.valueOf(newData.getBillingCycleDayLocal()), changeDate);


addIfValueChanged(tmpChangedFields, "paymentMethodId", addIfValueChanged(tmpChangedFields, "paymentMethodId",
(oldData.getPaymentMethodId() != null) ? oldData.getPaymentMethodId().toString() : null, (oldData.getPaymentMethodId() != null) ? oldData.getPaymentMethodId().toString() : null,
(newData.getPaymentMethodId() != null) ? newData.getPaymentMethodId().toString() : null); (newData.getPaymentMethodId() != null) ? newData.getPaymentMethodId().toString() : null, changeDate);


addIfValueChanged(tmpChangedFields, "locale", oldData.getLocale(), newData.getLocale()); addIfValueChanged(tmpChangedFields, "locale", oldData.getLocale(), newData.getLocale(), changeDate);


addIfValueChanged(tmpChangedFields, "timeZone", addIfValueChanged(tmpChangedFields, "timeZone",
(oldData.getTimeZone() == null) ? null : oldData.getTimeZone().toString(), (oldData.getTimeZone() == null) ? null : oldData.getTimeZone().toString(),
(newData.getTimeZone() == null) ? null : newData.getTimeZone().toString()); (newData.getTimeZone() == null) ? null : newData.getTimeZone().toString(), changeDate);


addIfValueChanged(tmpChangedFields, "address1", oldData.getAddress1(), newData.getAddress1()); addIfValueChanged(tmpChangedFields, "address1", oldData.getAddress1(), newData.getAddress1(), changeDate);
addIfValueChanged(tmpChangedFields, "address2", oldData.getAddress2(), newData.getAddress2()); addIfValueChanged(tmpChangedFields, "address2", oldData.getAddress2(), newData.getAddress2(), changeDate);
addIfValueChanged(tmpChangedFields, "city", oldData.getCity(), newData.getCity()); addIfValueChanged(tmpChangedFields, "city", oldData.getCity(), newData.getCity(), changeDate);
addIfValueChanged(tmpChangedFields, "stateOrProvince", oldData.getStateOrProvince(), newData.getStateOrProvince()); addIfValueChanged(tmpChangedFields, "stateOrProvince", oldData.getStateOrProvince(), newData.getStateOrProvince(), changeDate);
addIfValueChanged(tmpChangedFields, "country", oldData.getCountry(), newData.getCountry()); addIfValueChanged(tmpChangedFields, "country", oldData.getCountry(), newData.getCountry(), changeDate);
addIfValueChanged(tmpChangedFields, "postalCode", oldData.getPostalCode(), newData.getPostalCode()); addIfValueChanged(tmpChangedFields, "postalCode", oldData.getPostalCode(), newData.getPostalCode(), changeDate);
addIfValueChanged(tmpChangedFields, "phone", oldData.getPhone(), newData.getPhone()); addIfValueChanged(tmpChangedFields, "phone", oldData.getPhone(), newData.getPhone(), changeDate);


return tmpChangedFields; return tmpChangedFields;
} }


private void addIfValueChanged(final List<ChangedField> inputList, final String key, final String oldData, final String newData) { private void addIfValueChanged(final Collection<ChangedField> inputList, final String key, final String oldData, final String newData, final DateTime changeDate) {
// If both null => no changes // If both null => no changes
if (newData == null && oldData == null) { if (newData == null && oldData == null) {
// If only one is null // If only one is null
} else if (newData == null || oldData == null) { } else if (newData == null || oldData == null) {
inputList.add(new DefaultChangedField(key, oldData, newData)); inputList.add(new DefaultChangedField(key, oldData, newData, changeDate));
// If neither are null we can safely compare values // If neither are null we can safely compare values
} else if (!newData.equals(oldData)) { } else if (!newData.equals(oldData)) {
inputList.add(new DefaultChangedField(key, oldData, newData)); inputList.add(new DefaultChangedField(key, oldData, newData, changeDate));
} }
} }
} }
@@ -1,7 +1,9 @@
/* /*
* Copyright 2010-2013 Ning, Inc. * Copyright 2010-2013 Ning, Inc.
* Copyright 2014-2016 Groupon, Inc
* Copyright 2014-2016 The Billing Project, LLC
* *
* Ning licenses this file to you under the Apache License, version 2.0 * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the * (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at: * License. You may obtain a copy of the License at:
* *
Expand Down Expand Up @@ -57,13 +59,15 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A


private final PersistentBus eventBus; private final PersistentBus eventBus;
private final InternalCallContextFactory internalCallContextFactory; private final InternalCallContextFactory internalCallContextFactory;
private final Clock clock;


@Inject @Inject
public DefaultAccountDao(final IDBI dbi, final PersistentBus eventBus, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, public DefaultAccountDao(final IDBI dbi, final PersistentBus eventBus, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
final InternalCallContextFactory internalCallContextFactory, final NonEntityDao nonEntityDao) { final InternalCallContextFactory internalCallContextFactory, final NonEntityDao nonEntityDao) {
super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao), AccountSqlDao.class); super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao), AccountSqlDao.class);
this.eventBus = eventBus; this.eventBus = eventBus;
this.internalCallContextFactory = internalCallContextFactory; this.internalCallContextFactory = internalCallContextFactory;
this.clock = clock;
} }


@Override @Override
Expand Down Expand Up @@ -157,8 +161,8 @@ public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFa
specifiedAccount, specifiedAccount,
context.getAccountRecordId(), context.getAccountRecordId(),
context.getTenantRecordId(), context.getTenantRecordId(),
context.getUserToken() context.getUserToken(),
); clock.getUTCNow());
try { try {
eventBus.postFromTransaction(changeEvent, entitySqlDaoWrapperFactory.getHandle().getConnection()); eventBus.postFromTransaction(changeEvent, entitySqlDaoWrapperFactory.getHandle().getConnection());
} catch (final EventBusException e) { } catch (final EventBusException e) {
Expand Down Expand Up @@ -195,8 +199,8 @@ public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFa
final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(accountId, currentAccount, account, final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(accountId, currentAccount, account,
context.getAccountRecordId(), context.getAccountRecordId(),
context.getTenantRecordId(), context.getTenantRecordId(),
context.getUserToken() context.getUserToken(),
); clock.getUTCNow());


try { try {
eventBus.postFromTransaction(changeEvent, entitySqlDaoWrapperFactory.getHandle().getConnection()); eventBus.postFromTransaction(changeEvent, entitySqlDaoWrapperFactory.getHandle().getConnection());
Expand Down
@@ -1,7 +1,7 @@
/* /*
* Copyright 2010-2013 Ning, Inc. * Copyright 2010-2013 Ning, Inc.
* Copyright 2014-2015 Groupon, Inc * Copyright 2014-2016 Groupon, Inc
* Copyright 2014-2015 The Billing Project, LLC * Copyright 2014-2016 The Billing Project, LLC
* *
* The Billing Project licenses this file to you under the Apache License, version 2.0 * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the * (the "License"); you may not use this file except in compliance with the
Expand Down Expand Up @@ -52,7 +52,7 @@ public class TestDefaultAccountUserApiWithMocks extends AccountTestSuiteNoDB {


@BeforeMethod(groups = "fast") @BeforeMethod(groups = "fast")
public void setUp() throws Exception { public void setUp() throws Exception {
accountDao = new MockAccountDao(Mockito.mock(PersistentBus.class)); accountDao = new MockAccountDao(Mockito.mock(PersistentBus.class), clock);
accountUserApi = new DefaultAccountUserApi(accountDao, nonEntityDao, controllerDispatcher, internalFactory); accountUserApi = new DefaultAccountUserApi(accountDao, nonEntityDao, controllerDispatcher, internalFactory);
} }


Expand Down
Expand Up @@ -37,8 +37,8 @@ public class TestEventJson extends AccountTestSuiteNoDB {
@Test(groups = "fast", description="Test Account event deserialization") @Test(groups = "fast", description="Test Account event deserialization")
public void testDefaultAccountChangeEvent() throws Exception { public void testDefaultAccountChangeEvent() throws Exception {
final List<ChangedField> changes = new ArrayList<ChangedField>(); final List<ChangedField> changes = new ArrayList<ChangedField>();
changes.add(new DefaultChangedField("fieldXX", "valueX", "valueXXX")); changes.add(new DefaultChangedField("fieldXX", "valueX", "valueXXX", clock.getUTCNow()));
changes.add(new DefaultChangedField("fieldYY", "valueY", "valueYYY")); changes.add(new DefaultChangedField("fieldYY", "valueY", "valueYYY", clock.getUTCNow()));
final AccountChangeInternalEvent e = new DefaultAccountChangeEvent(changes, UUID.randomUUID(), 1L, 2L, null); final AccountChangeInternalEvent e = new DefaultAccountChangeEvent(changes, UUID.randomUUID(), 1L, 2L, null);


final String json = mapper.writeValueAsString(e); final String json = mapper.writeValueAsString(e);
Expand Down
@@ -1,7 +1,9 @@
/* /*
* Copyright 2010-2013 Ning, Inc. * Copyright 2010-2013 Ning, Inc.
* Copyright 2014-2016 Groupon, Inc
* Copyright 2014-2016 The Billing Project, LLC
* *
* Ning licenses this file to you under the Apache License, version 2.0 * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the * (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at: * License. You may obtain a copy of the License at:
* *
Expand All @@ -16,13 +18,12 @@


package org.killbill.billing.account.dao; package org.killbill.billing.account.dao;


import java.util.Collection;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;


import org.testng.Assert;

import org.killbill.billing.BillingExceptionBase; import org.killbill.billing.BillingExceptionBase;
import org.killbill.billing.ErrorCode; import org.killbill.billing.ErrorCode;
import org.killbill.billing.account.api.Account; import org.killbill.billing.account.api.Account;
Expand All @@ -33,15 +34,17 @@
import org.killbill.billing.account.api.user.DefaultAccountChangeEvent; import org.killbill.billing.account.api.user.DefaultAccountChangeEvent;
import org.killbill.billing.account.api.user.DefaultAccountCreationEvent; import org.killbill.billing.account.api.user.DefaultAccountCreationEvent;
import org.killbill.billing.account.api.user.DefaultAccountCreationEvent.DefaultAccountData; import org.killbill.billing.account.api.user.DefaultAccountCreationEvent.DefaultAccountData;
import org.killbill.bus.api.PersistentBus;
import org.killbill.bus.api.PersistentBus.EventBusException;
import org.killbill.billing.callcontext.InternalCallContext; import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext; import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.events.AccountChangeInternalEvent; import org.killbill.billing.events.AccountChangeInternalEvent;
import org.killbill.billing.util.callcontext.InternalCallContextFactory; import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.entity.DefaultPagination; import org.killbill.billing.util.entity.DefaultPagination;
import org.killbill.billing.util.entity.Pagination; import org.killbill.billing.util.entity.Pagination;
import org.killbill.billing.util.entity.dao.MockEntityDaoBase; import org.killbill.billing.util.entity.dao.MockEntityDaoBase;
import org.killbill.bus.api.PersistentBus;
import org.killbill.bus.api.PersistentBus.EventBusException;
import org.killbill.clock.Clock;
import org.testng.Assert;


import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
Expand All @@ -52,10 +55,12 @@ public class MockAccountDao extends MockEntityDaoBase<AccountModelDao, Account,


private final MockEntityDaoBase<AccountEmailModelDao, AccountEmail, AccountApiException> accountEmailSqlDao = new MockEntityDaoBase<AccountEmailModelDao, AccountEmail, AccountApiException>(); private final MockEntityDaoBase<AccountEmailModelDao, AccountEmail, AccountApiException> accountEmailSqlDao = new MockEntityDaoBase<AccountEmailModelDao, AccountEmail, AccountApiException>();
private final PersistentBus eventBus; private final PersistentBus eventBus;
private final Clock clock;


@Inject @Inject
public MockAccountDao(final PersistentBus eventBus) { public MockAccountDao(final PersistentBus eventBus, final Clock clock) {
this.eventBus = eventBus; this.eventBus = eventBus;
this.clock = clock;
} }


@Override @Override
Expand All @@ -81,8 +86,8 @@ public void update(final AccountModelDao account, final InternalCallContext cont
final long tenantRecordId = context == null ? InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID final long tenantRecordId = context == null ? InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID
: context.getTenantRecordId(); : context.getTenantRecordId();
final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(account.getId(), currentAccount, account, final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(account.getId(), currentAccount, account,
accountRecordId, tenantRecordId, UUID.randomUUID() accountRecordId, tenantRecordId, UUID.randomUUID(),
); clock.getUTCNow());
if (changeEvent.hasChanges()) { if (changeEvent.hasChanges()) {
try { try {
eventBus.post(changeEvent); eventBus.post(changeEvent);
Expand All @@ -106,7 +111,7 @@ public AccountModelDao getAccountByKey(final String externalKey, final InternalT


@Override @Override
public Pagination<AccountModelDao> searchAccounts(final String searchKey, final Long offset, final Long limit, final InternalTenantContext context) { public Pagination<AccountModelDao> searchAccounts(final String searchKey, final Long offset, final Long limit, final InternalTenantContext context) {
final List<AccountModelDao> results = new LinkedList<AccountModelDao>(); final Collection<AccountModelDao> results = new LinkedList<AccountModelDao>();
int maxNbRecords = 0; int maxNbRecords = 0;
for (final AccountModelDao account : getAll(context)) { for (final AccountModelDao account : getAll(context)) {
maxNbRecords++; maxNbRecords++;
Expand Down Expand Up @@ -145,7 +150,7 @@ public void updatePaymentMethod(final UUID accountId, final UUID paymentMethodId
public void addEmail(final AccountEmailModelDao email, final InternalCallContext context) { public void addEmail(final AccountEmailModelDao email, final InternalCallContext context) {
try { try {
accountEmailSqlDao.create(email, context); accountEmailSqlDao.create(email, context);
} catch (BillingExceptionBase billingExceptionBase) { } catch (final BillingExceptionBase billingExceptionBase) {
Assert.fail(billingExceptionBase.toString()); Assert.fail(billingExceptionBase.toString());
} }
} }
Expand All @@ -170,5 +175,4 @@ public Integer getAccountBCD(final UUID accountId, final InternalTenantContext c
final AccountModelDao account = getById(accountId, context); final AccountModelDao account = getById(accountId, context);
return account != null ? account.getBillingCycleDayLocal() : 0; return account != null ? account.getBillingCycleDayLocal() : 0;
} }

} }

0 comments on commit cc2ce39

Please sign in to comment.