Details
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/api/user/DefaultTenantUserApi.java b/tenant/src/main/java/org/killbill/billing/tenant/api/user/DefaultTenantUserApi.java
index 5fec9ea..1fb59d8 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/api/user/DefaultTenantUserApi.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/api/user/DefaultTenantUserApi.java
@@ -130,6 +130,15 @@ public class DefaultTenantUserApi implements TenantUserApi {
}
@Override
+ public void updateTenantKeyValue(final String key, final String value, final CallContext context) throws TenantApiException {
+ // Invalidate tenantKVCache after we store (to avoid race conditions). Multi-node invalidation will follow the TenantBroadcast pattern
+ final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContextWithoutAccountRecordId(context);
+ final String tenantKey = getCacheKeyName(key, internalContext);
+ tenantDao.updateTenantLastKeyValue(key, value, internalContext);
+ tenantKVCache.remove(tenantKey);
+ }
+
+ @Override
public void deleteTenantKey(final String key, final CallContext context) throws TenantApiException {
// Invalidate tenantKVCache after we delete (to avoid race conditions). Multi-node invalidation will follow the TenantBroadcast pattern
final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContextWithoutAccountRecordId(context);
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantDao.java b/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantDao.java
index fa33b37..dea38c0 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantDao.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantDao.java
@@ -154,6 +154,28 @@ public class DefaultTenantDao extends EntityDaoBase<TenantModelDao, Tenant, Tena
}
@Override
+ public void updateTenantLastKeyValue(final String key, final String value, final InternalCallContext context) {
+ transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+ @Override
+ public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
+ final TenantKVModelDao tenantKVModelDao = new TenantKVModelDao(UUIDs.randomUUID(), context.getCreatedDate(), context.getUpdatedDate(), key, value);
+ final TenantKVSqlDao tenantKVSqlDao = entitySqlDaoWrapperFactory.become(TenantKVSqlDao.class);
+
+ // Retrieve all values for key ordered with recordId (last at the end)
+ final List<TenantKVModelDao> tenantKV = tenantKVSqlDao.getTenantValueForKey(key, context);
+ if (!tenantKV.isEmpty()) {
+ final String id = tenantKV.get(tenantKV.size() - 1).getId().toString();
+ tenantKVSqlDao.updateTenantValueKey(id, value, context);
+ final TenantKVModelDao rehydrated = tenantKVSqlDao.getById(id, context);
+ broadcastConfigurationChangeFromTransaction(rehydrated.getRecordId(), key, entitySqlDaoWrapperFactory, context);
+ }
+ return null;
+ }
+ });
+
+ }
+
+ @Override
public void deleteTenantKey(final String key, final InternalCallContext context) {
transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
@Override
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantDao.java b/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantDao.java
index 3913ae2..c665cda 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantDao.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantDao.java
@@ -110,6 +110,11 @@ public class NoCachingTenantDao extends EntityDaoBase<TenantModelDao, Tenant, Te
}
@Override
+ public void updateTenantLastKeyValue(final String key, final String value, final InternalCallContext context) {
+ throw new IllegalStateException("Not implemented by NoCachingTenantDao");
+ }
+
+ @Override
public void deleteTenantKey(final String key, final InternalCallContext context) {
throw new IllegalStateException("Not implemented by NoCachingTenantDao");
}
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantDao.java b/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantDao.java
index 8f48adc..d52b1b3 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantDao.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantDao.java
@@ -32,6 +32,8 @@ public interface TenantDao extends EntityDao<TenantModelDao, Tenant, TenantApiEx
public void addTenantKeyValue(final String key, final String value, final boolean uniqueKey, final InternalCallContext context);
+ public void updateTenantLastKeyValue(final String key, final String value, final InternalCallContext context);
+
public void deleteTenantKey(final String key, final InternalCallContext context);
public TenantKVModelDao getKeyByRecordId(Long recordId, InternalTenantContext context);
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantKVSqlDao.java b/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantKVSqlDao.java
index bdfed51..9e263cf 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantKVSqlDao.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantKVSqlDao.java
@@ -18,18 +18,17 @@ package org.killbill.billing.tenant.dao;
import java.util.List;
-import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
-import org.skife.jdbi.v2.sqlobject.SqlQuery;
-import org.skife.jdbi.v2.sqlobject.SqlUpdate;
-
-import org.killbill.billing.tenant.api.TenantKV;
-import org.killbill.billing.util.audit.ChangeType;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.tenant.api.TenantKV;
+import org.killbill.billing.util.audit.ChangeType;
import org.killbill.billing.util.entity.dao.Audited;
import org.killbill.billing.util.entity.dao.EntitySqlDao;
import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
@EntitySqlDaoStringTemplate
public interface TenantKVSqlDao extends EntitySqlDao<TenantKVModelDao, TenantKV> {
@@ -42,4 +41,12 @@ public interface TenantKVSqlDao extends EntitySqlDao<TenantKVModelDao, TenantKV>
@Audited(ChangeType.DELETE)
public void markTenantKeyAsDeleted(@Bind("id")final String id,
@BindBean final InternalCallContext context);
+
+ @SqlUpdate
+ @Audited(ChangeType.UPDATE)
+ public void updateTenantValueKey(@Bind("id") final String id,
+ @Bind("tenantValue") final String tenantValue,
+ @BindBean final InternalCallContext context);
+
+
}
diff --git a/tenant/src/main/resources/org/killbill/billing/tenant/dao/TenantKVSqlDao.sql.stg b/tenant/src/main/resources/org/killbill/billing/tenant/dao/TenantKVSqlDao.sql.stg
index 2895b30..c6aa736 100644
--- a/tenant/src/main/resources/org/killbill/billing/tenant/dao/TenantKVSqlDao.sql.stg
+++ b/tenant/src/main/resources/org/killbill/billing/tenant/dao/TenantKVSqlDao.sql.stg
@@ -36,6 +36,7 @@ from <tableName()> t
where t.tenant_key = :tenantKey
and t.is_active
<AND_CHECK_TENANT("t.")>
+<defaultOrderBy("t.")>
;
>>
@@ -46,3 +47,12 @@ where id = :id
<AND_CHECK_TENANT("")>
;
>>
+
+
+updateTenantValueKey() ::= <<
+update <tableName()>
+set tenant_value = :tenantValue
+where id = :id
+<AND_CHECK_TENANT("")>
+;
+>>
\ No newline at end of file
diff --git a/tenant/src/test/java/org/killbill/billing/tenant/dao/TestDefaultTenantDao.java b/tenant/src/test/java/org/killbill/billing/tenant/dao/TestDefaultTenantDao.java
index 112e3ba..5b56007 100644
--- a/tenant/src/test/java/org/killbill/billing/tenant/dao/TestDefaultTenantDao.java
+++ b/tenant/src/test/java/org/killbill/billing/tenant/dao/TestDefaultTenantDao.java
@@ -75,4 +75,31 @@ public class TestDefaultTenantDao extends TenantTestSuiteWithEmbeddedDb {
value = tenantDao.getTenantValueForKey("THE_KEY", internalCallContext);
Assert.assertEquals(value.size(), 0);
}
+
+
+
+
+ @Test(groups = "slow")
+ public void testTenantKeyValueUpdate() throws Exception {
+ final DefaultTenant tenant = new DefaultTenant(UUID.randomUUID(), null, null, UUID.randomUUID().toString(),
+ UUID.randomUUID().toString(), UUID.randomUUID().toString());
+ tenantDao.create(new TenantModelDao(tenant), internalCallContext);
+
+ tenantDao .addTenantKeyValue("MY_KEY", "TheValue1", false, internalCallContext);
+ tenantDao .addTenantKeyValue("MY_KEY", "TheValue2", false, internalCallContext);
+ tenantDao .addTenantKeyValue("MY_KEY", "TheValue3", false, internalCallContext);
+
+ final List<String> value = tenantDao.getTenantValueForKey("MY_KEY", internalCallContext);
+ Assert.assertEquals(value.size(), 3);
+
+
+ tenantDao.updateTenantLastKeyValue("MY_KEY", "NewValue3", internalCallContext);
+
+ final List<String> newValues = tenantDao.getTenantValueForKey("MY_KEY", internalCallContext);
+ Assert.assertEquals(newValues.size(), 3);
+
+ Assert.assertEquals(newValues.get(0), "TheValue1");
+ Assert.assertEquals(newValues.get(1), "TheValue2");
+ Assert.assertEquals(newValues.get(2), "NewValue3");
+ }
}