killbill-aplcache

Details

diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index b62ab79..3f85b27 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -285,6 +285,7 @@ public enum ErrorCode {
     TENANT_DOES_NOT_EXIST_FOR_API_KEY(10003, "Tenant does not exist for api key %s"),
     TENANT_CREATION_FAILED(10004, "Tenant creation failed."),
     TENANT_UPDATE_FAILED(10005, "Tenant update failed."),
+    TENANT_NO_SUCH_KEY(10006, "Tenant %s does not have a key %s"),
 
     __UNKNOWN_ERROR_CODE(-1, "Unknown ErrorCode");
 
diff --git a/api/src/main/java/com/ning/billing/tenant/api/TenantKV.java b/api/src/main/java/com/ning/billing/tenant/api/TenantKV.java
new file mode 100644
index 0000000..3c15086
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/tenant/api/TenantKV.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package com.ning.billing.tenant.api;
+
+import com.ning.billing.util.entity.Entity;
+
+public interface TenantKV extends Entity {
+
+    public String getKey();
+
+    public String getValue();
+}
diff --git a/api/src/main/java/com/ning/billing/tenant/api/TenantUserApi.java b/api/src/main/java/com/ning/billing/tenant/api/TenantUserApi.java
index cf49c1a..b403156 100644
--- a/api/src/main/java/com/ning/billing/tenant/api/TenantUserApi.java
+++ b/api/src/main/java/com/ning/billing/tenant/api/TenantUserApi.java
@@ -22,9 +22,15 @@ import com.ning.billing.util.callcontext.CallContext;
 
 public interface TenantUserApi {
 
-    public Tenant createTenant(TenantData data, CallContext context) throws TenantApiException;
+    public Tenant createTenant(final TenantData data, final CallContext context) throws TenantApiException;
 
-    public Tenant getTenantByApiKey(String key) throws TenantApiException;
+    public Tenant getTenantByApiKey(final String key) throws TenantApiException;
 
-    public Tenant getTenantById(UUID tenantId) throws TenantApiException;
+    public Tenant getTenantById(final UUID tenantId) throws TenantApiException;
+
+    public String getTenantValueForKey(final UUID tenantId, final String key) throws TenantApiException;
+
+    public void addTenantKeyValue(final UUID tenantId, final String key, final String value, final CallContext context) throws TenantApiException;
+
+    public void deleteTenantKey(final UUID tenantId, final String key) throws TenantApiException;
 }
diff --git a/tenant/src/main/java/com/ning/billing/tenant/api/DefaultTenantKV.java b/tenant/src/main/java/com/ning/billing/tenant/api/DefaultTenantKV.java
new file mode 100644
index 0000000..cbf185d
--- /dev/null
+++ b/tenant/src/main/java/com/ning/billing/tenant/api/DefaultTenantKV.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package com.ning.billing.tenant.api;
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.util.entity.EntityBase;
+
+public class DefaultTenantKV extends EntityBase implements TenantKV {
+
+    private final String key;
+    private final String value;
+
+    public DefaultTenantKV(final UUID tenantId, final String key, final String value, final DateTime createdDate, final DateTime updatedDate) {
+        super(tenantId, createdDate, updatedDate);
+        this.key = key;
+        this.value = value;
+    }
+
+    @Override
+    public String getKey() {
+        return key;
+    }
+
+    @Override
+    public String getValue() {
+        return value;
+    }
+}
diff --git a/tenant/src/main/java/com/ning/billing/tenant/api/user/DefaultTenantUserApi.java b/tenant/src/main/java/com/ning/billing/tenant/api/user/DefaultTenantUserApi.java
index 74c33df..7273fd5 100644
--- a/tenant/src/main/java/com/ning/billing/tenant/api/user/DefaultTenantUserApi.java
+++ b/tenant/src/main/java/com/ning/billing/tenant/api/user/DefaultTenantUserApi.java
@@ -26,6 +26,7 @@ import com.ning.billing.tenant.api.TenantData;
 import com.ning.billing.tenant.api.TenantUserApi;
 import com.ning.billing.tenant.dao.TenantDao;
 import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.entity.EntityPersistenceException;
@@ -49,7 +50,7 @@ public class DefaultTenantUserApi implements TenantUserApi {
 
         try {
             tenantDao.create(tenant, internalCallContextFactory.createInternalCallContext(context));
-        } catch (EntityPersistenceException e) {
+        } catch (final EntityPersistenceException e) {
             throw new TenantApiException(e, ErrorCode.TENANT_CREATION_FAILED);
         }
 
@@ -74,4 +75,37 @@ public class DefaultTenantUserApi implements TenantUserApi {
         }
         return tenant;
     }
+
+    @Override
+    public String getTenantValueForKey(final UUID tenantId, final String key)
+            throws TenantApiException {
+        final String value = tenantDao.getTenantValueForKey(tenantId, key);
+        if (value == null) {
+            throw new TenantApiException(ErrorCode.TENANT_NO_SUCH_KEY, tenantId, key);
+        }
+        return value;
+    }
+
+    @Override
+    public void addTenantKeyValue(final UUID tenantId, final String key, final String value, final CallContext context)
+            throws TenantApiException {
+
+        final InternalCallContext internalContext = new InternalCallContext(null, null, context);
+        final Tenant tenant = tenantDao.getById(tenantId, internalContext);
+        if (tenant == null) {
+            throw new TenantApiException(ErrorCode.TENANT_DOES_NOT_EXIST_FOR_ID, tenantId);
+        }
+        tenantDao.addTenantKeyValue(tenantId, key, value, internalContext);
+    }
+
+
+    @Override
+    public void deleteTenantKey(final UUID tenantId, final String key)
+            throws TenantApiException {
+        final Tenant tenant = tenantDao.getById(tenantId, new InternalTenantContext(null, null));
+        if (tenant == null) {
+            throw new TenantApiException(ErrorCode.TENANT_DOES_NOT_EXIST_FOR_ID, tenantId);
+        }
+        tenantDao.deleteTenantKey(tenantId, key);
+    }
 }
diff --git a/tenant/src/main/java/com/ning/billing/tenant/dao/DefaultTenantDao.java b/tenant/src/main/java/com/ning/billing/tenant/dao/DefaultTenantDao.java
index 4fe0f4e..6890832 100644
--- a/tenant/src/main/java/com/ning/billing/tenant/dao/DefaultTenantDao.java
+++ b/tenant/src/main/java/com/ning/billing/tenant/dao/DefaultTenantDao.java
@@ -29,10 +29,11 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.ning.billing.tenant.api.Tenant;
-import com.ning.billing.util.svcsapi.bus.InternalBus;
+import com.ning.billing.tenant.api.TenantKV;
 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.svcsapi.bus.InternalBus;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.inject.Inject;
@@ -44,12 +45,14 @@ public class DefaultTenantDao implements TenantDao {
     private final RandomNumberGenerator rng = new SecureRandomNumberGenerator();
 
     private final TenantSqlDao tenantSqlDao;
+    private final TenantKVSqlDao tenantKVSqlDao;
     private final InternalBus eventBus;
 
     @Inject
     public DefaultTenantDao(final IDBI dbi, final InternalBus eventBus) {
         this.eventBus = eventBus;
         this.tenantSqlDao = dbi.onDemand(TenantSqlDao.class);
+        this.tenantKVSqlDao = dbi.onDemand(TenantKVSqlDao.class);
     }
 
     @Override
@@ -92,4 +95,23 @@ public class DefaultTenantDao implements TenantDao {
     AuthenticationInfo getAuthenticationInfoForTenant(final UUID id) {
         return tenantSqlDao.getSecrets(id.toString()).toAuthenticationInfo();
     }
+
+    @Override
+    public String getTenantValueForKey(final UUID tenantId, final String key) {
+        final TenantKV tenantKV = tenantKVSqlDao.getTenantValueForKey(tenantId.toString(), key);
+        if (tenantKV == null) {
+            return null;
+        }
+        return tenantKV.getValue();
+    }
+
+    @Override
+    public void addTenantKeyValue(final UUID tenantId, final String key, final String value, final InternalCallContext context) {
+        tenantKVSqlDao.insertTenantKeyValue(tenantId.toString(), key, value, context);
+    }
+
+    @Override
+    public void deleteTenantKey(final UUID tenantId, final String key) {
+        tenantKVSqlDao.deleteTenantKey(tenantId.toString(), key);
+    }
 }
diff --git a/tenant/src/main/java/com/ning/billing/tenant/dao/TenantDao.java b/tenant/src/main/java/com/ning/billing/tenant/dao/TenantDao.java
index 88e956f..c73b52f 100644
--- a/tenant/src/main/java/com/ning/billing/tenant/dao/TenantDao.java
+++ b/tenant/src/main/java/com/ning/billing/tenant/dao/TenantDao.java
@@ -16,10 +16,19 @@
 
 package com.ning.billing.tenant.dao;
 
+import java.util.UUID;
+
 import com.ning.billing.tenant.api.Tenant;
+import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.entity.dao.EntityDao;
 
 public interface TenantDao extends EntityDao<Tenant> {
 
-    public Tenant getTenantByApiKey(String key);
+    public Tenant getTenantByApiKey(final String key);
+
+    public String getTenantValueForKey(final UUID tenantId, final String key);
+
+    public void addTenantKeyValue(final UUID tenantId, final String key, final String value, final InternalCallContext context);
+
+    public void deleteTenantKey(final UUID tenantId, final String key);
 }
diff --git a/tenant/src/main/java/com/ning/billing/tenant/dao/TenantKVSqlDao.java b/tenant/src/main/java/com/ning/billing/tenant/dao/TenantKVSqlDao.java
new file mode 100644
index 0000000..1535ffd
--- /dev/null
+++ b/tenant/src/main/java/com/ning/billing/tenant/dao/TenantKVSqlDao.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package com.ning.billing.tenant.dao;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
+import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
+import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
+import org.skife.jdbi.v2.tweak.ResultSetMapper;
+
+import com.ning.billing.tenant.api.DefaultTenantKV;
+import com.ning.billing.tenant.api.TenantKV;
+import com.ning.billing.tenant.dao.TenantKVSqlDao.TenantKVMapper;
+import com.ning.billing.util.callcontext.InternalCallContext;
+import com.ning.billing.util.callcontext.InternalTenantContextBinder;
+import com.ning.billing.util.dao.MapperBase;
+import com.ning.billing.util.dao.UuidMapper;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
+
+@ExternalizedSqlViaStringTemplate3
+@RegisterMapper({UuidMapper.class, TenantKVMapper.class})
+public interface TenantKVSqlDao extends EntitySqlDao<TenantKV>, Transactional<TenantKVSqlDao> {
+
+    @SqlQuery
+    public TenantKV getTenantValueForKey(@Bind("id") final String tenantId, @Bind("key") final String key);
+
+    @SqlUpdate
+    public void insertTenantKeyValue(@Bind("id") final String tenantId, @Bind("key") final String key, @Bind("value") final String value,
+            @InternalTenantContextBinder final InternalCallContext context);
+
+    @SqlUpdate
+    public void deleteTenantKey(@Bind("id") final String tenantId, @Bind("key") final String key);
+
+
+    public class TenantKVMapper extends MapperBase implements ResultSetMapper<TenantKV> {
+
+        @Override
+        public TenantKV map(final int index, final ResultSet result, final StatementContext context) throws SQLException {
+            final UUID id = getUUID(result, "id");
+            final String key = result.getString("t_key");
+            final String value = result.getString("t_value");
+            final DateTime createdDate = getDateTime(result, "created_date");
+            final DateTime updatedDate = getDateTime(result, "updated_date");
+            return new DefaultTenantKV(id, key, value, createdDate, updatedDate);
+        }
+    }
+}
diff --git a/tenant/src/main/java/com/ning/billing/tenant/dao/TenantSqlDao.java b/tenant/src/main/java/com/ning/billing/tenant/dao/TenantSqlDao.java
index 4841707..8ce298b 100644
--- a/tenant/src/main/java/com/ning/billing/tenant/dao/TenantSqlDao.java
+++ b/tenant/src/main/java/com/ning/billing/tenant/dao/TenantSqlDao.java
@@ -47,4 +47,5 @@ public interface TenantSqlDao extends EntitySqlDao<Tenant>, Transactional<Tenant
     @SqlQuery
     @Mapper(TenantSecretsMapper.class)
     public TenantSecrets getSecrets(@Bind("id") final String id);
+
 }
diff --git a/tenant/src/main/resources/com/ning/billing/tenant/dao/TenantKVSqlDao.sql.stg b/tenant/src/main/resources/com/ning/billing/tenant/dao/TenantKVSqlDao.sql.stg
new file mode 100644
index 0000000..3e2d0cb
--- /dev/null
+++ b/tenant/src/main/resources/com/ning/billing/tenant/dao/TenantKVSqlDao.sql.stg
@@ -0,0 +1,55 @@
+group TenantKVSqlDao;
+
+
+tenantKVFields(prefix) ::= <<
+    <prefix>record_id,
+    <prefix>id,
+    <prefix>t_key,
+    <prefix>t_value,
+    <prefix>created_date,
+    <prefix>created_by,
+    <prefix>updated_date,
+    <prefix>updated_by
+>>
+
+insertTenantKeyValue() ::= <<
+   INSERT INTO tenant_kvs (
+        id
+      , t_key
+      , t_value
+      , created_date
+      , created_by
+      , updated_date
+      , updated_by
+    ) VALUES (
+        :id
+      , :key
+      , :value
+      , :createdDate
+      , :userName
+      , :updatedDate
+      , :userName
+    );
+>>
+
+
+getTenantValueForKey() ::= <<
+    SELECT <tenantKVFields()>
+    FROM tenant_kvs
+    WHERE
+        id = :id AND t_key = :key
+    ;
+>>
+
+
+deleteTenantKey() ::= <<
+    DELETE FROM tenant_kvs
+    WHERE
+        id = :id AND t_key = :key
+    ;
+>>
+
+
+test() ::= <<
+    SELECT 1 FROM tenants;
+>>
\ No newline at end of file
diff --git a/tenant/src/main/resources/com/ning/billing/tenant/ddl.sql b/tenant/src/main/resources/com/ning/billing/tenant/ddl.sql
index f4e76e0..ac9d885 100644
--- a/tenant/src/main/resources/com/ning/billing/tenant/ddl.sql
+++ b/tenant/src/main/resources/com/ning/billing/tenant/ddl.sql
@@ -14,3 +14,19 @@ CREATE TABLE tenants (
 ) ENGINE=innodb;
 CREATE UNIQUE INDEX tenants_id ON tenants(id);
 CREATE UNIQUE INDEX tenants_api_key ON tenants(api_key);
+
+
+DROP TABLE IF EXISTS tenant_kvs;
+CREATE TABLE tenant_kvs (
+   record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+   -- This is the tenant id, no id is generated as this is not a customer facing object
+   id char(36) NOT NULL,
+   t_key varchar(64) NOT NULL,
+   t_value varchar(512) NOT NULL,
+   created_date datetime NOT NULL,
+   created_by varchar(50) NOT NULL,
+   updated_date datetime DEFAULT NULL,
+   updated_by varchar(50) DEFAULT NULL,
+   PRIMARY KEY(record_id)
+) ENGINE=innodb;
+CREATE INDEX tenant_kvs_key ON tenant_kvs(id, t_key);
\ No newline at end of file
diff --git a/tenant/src/test/java/com/ning/billing/tenant/dao/TestDefaultTenantDao.java b/tenant/src/test/java/com/ning/billing/tenant/dao/TestDefaultTenantDao.java
index 990f5fb..9a8cc58 100644
--- a/tenant/src/test/java/com/ning/billing/tenant/dao/TestDefaultTenantDao.java
+++ b/tenant/src/test/java/com/ning/billing/tenant/dao/TestDefaultTenantDao.java
@@ -37,7 +37,7 @@ public class TestDefaultTenantDao extends TenantTestSuiteWithEmbeddedDb {
         final DefaultTenantDao tenantDao = new DefaultTenantDao(getMysqlTestingHelper().getDBI(), Mockito.mock(InternalBus.class));
 
         final DefaultTenant tenant = new DefaultTenant(UUID.randomUUID(), null, null, UUID.randomUUID().toString(),
-                                                       UUID.randomUUID().toString(), UUID.randomUUID().toString());
+                UUID.randomUUID().toString(), UUID.randomUUID().toString());
         tenantDao.create(tenant, internalCallContext);
 
         // Verify we can retrieve it
@@ -54,4 +54,20 @@ public class TestDefaultTenantDao extends TenantTestSuiteWithEmbeddedDb {
         final AuthenticationToken badToken = new UsernamePasswordToken(tenant.getApiKey(), tenant.getApiSecret() + "T");
         Assert.assertFalse(KillbillCredentialsMatcher.getCredentialsMatcher().doCredentialsMatch(badToken, authenticationInfo));
     }
+
+    @Test(groups = "slow")
+    public void testTenantKeyValue() throws Exception {
+
+        final DefaultTenantDao tenantDao = new DefaultTenantDao(getMysqlTestingHelper().getDBI(), Mockito.mock(InternalBus.class));
+        final DefaultTenant tenant = new DefaultTenant(UUID.randomUUID(), null, null, UUID.randomUUID().toString(),
+                UUID.randomUUID().toString(), UUID.randomUUID().toString());
+        tenantDao.create(tenant, internalCallContext);
+
+        tenantDao.addTenantKeyValue(tenant.getId(), "TheKey", "TheValue", internalCallContext);
+
+        final String value  = tenantDao.getTenantValueForKey(tenant.getId(), "TheKey");
+        Assert.assertEquals(value, "TheValue");
+
+        tenantDao.deleteTenantKey(tenant.getId(), "TheKey");
+    }
 }