Details
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/CallContextSqlDao.java b/util/src/main/java/com/ning/billing/util/callcontext/CallContextSqlDao.java
index 5580273..eb05589 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/CallContextSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/CallContextSqlDao.java
@@ -26,5 +26,4 @@ public interface CallContextSqlDao {
@SqlQuery("select record_id from accounts where id = :accountId;")
public Long getAccountRecordId(@Bind("accountId") final String accountId);
-
}
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContextFactory.java b/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContextFactory.java
index cbadb35..17637d5 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContextFactory.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContextFactory.java
@@ -16,16 +16,22 @@
package com.ning.billing.util.callcontext;
+import java.util.List;
+import java.util.Map;
import java.util.UUID;
import javax.annotation.Nullable;
import javax.inject.Inject;
+import org.skife.jdbi.v2.Handle;
import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.tweak.HandleCallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.dao.TableName;
public class InternalCallContextFactory {
@@ -34,11 +40,13 @@ public class InternalCallContextFactory {
public static final UUID INTERNAL_TENANT_ID = new UUID(0L, 0L);
public static final long INTERNAL_TENANT_RECORD_ID = 0L;
+ private final IDBI dbi;
private final CallContextSqlDao callContextSqlDao;
private final Clock clock;
@Inject
public InternalCallContextFactory(final IDBI dbi, final Clock clock) {
+ this.dbi = dbi;
this.callContextSqlDao = dbi.onDemand(CallContextSqlDao.class);
this.clock = clock;
}
@@ -63,6 +71,49 @@ public class InternalCallContextFactory {
return createInternalCallContext(INTERNAL_TENANT_RECORD_ID, null, new DefaultCallContext(INTERNAL_TENANT_ID, userName, callOrigin, userType, userToken, clock));
}
+ /**
+ * Crate an internal call context from a call context, and retrieving the account_record_id from another table
+ *
+ * @param objectId the id of the row in the table pointed by object type where to look for account_record_id
+ * @param objectType the object type pointed by this objectId
+ * @param context original call context
+ * @return internal call context from context, with a non null account_record_id (if found)
+ */
+ public InternalCallContext createInternalCallContext(final UUID objectId, final ObjectType objectType, final CallContext context) {
+ final Long accountRecordId;
+
+ final TableName tableName = TableName.fromObjectType(objectType);
+ if (tableName != null) {
+ accountRecordId = dbi.withHandle(new HandleCallback<Long>() {
+ @Override
+ public Long withHandle(final Handle handle) throws Exception {
+ final String columnName;
+ if (TableName.TAG_DEFINITIONS.equals(tableName) || TableName.TAG_DEFINITION_HISTORY.equals(tableName)) {
+ // Not tied to an account
+ return null;
+ } else if (TableName.ACCOUNT.equals(tableName) || TableName.ACCOUNT_HISTORY.equals(tableName)) {
+ // Lookup the record_id directly
+ columnName = "record_id";
+ } else {
+ // The table should have an account_record_id column
+ columnName = "account_record_id";
+ }
+
+ final List<Map<String, Object>> values = handle.select(String.format("select %s from %s where id = ?;", columnName, tableName.getTableName()), objectId.toString());
+ if (values.size() == 0) {
+ return null;
+ } else {
+ return (Long) values.get(0).get(columnName);
+ }
+ }
+ });
+ } else {
+ accountRecordId = null;
+ }
+
+ return createInternalCallContext(getTenantRecordId(context), accountRecordId, context);
+ }
+
// Used for r/o or update/delete operations - we don't need the account id in that case
// TODO - more work is needed for this statement to hold (especially for junction, overdue, custom fields and tags)
public InternalCallContext createInternalCallContext(final CallContext context) {
diff --git a/util/src/main/java/com/ning/billing/util/dao/TableName.java b/util/src/main/java/com/ning/billing/util/dao/TableName.java
index 84e9710..e958798 100644
--- a/util/src/main/java/com/ning/billing/util/dao/TableName.java
+++ b/util/src/main/java/com/ning/billing/util/dao/TableName.java
@@ -39,7 +39,8 @@ public enum TableName {
SUBSCRIPTION_EVENTS("subscription_events", ObjectType.SUBSCRIPTION_EVENT),
REFUND_HISTORY("refund_history"),
REFUNDS("refunds", ObjectType.REFUND, REFUND_HISTORY),
- TAG_DEFINITIONS("tag_definitions", ObjectType.TAG_DEFINITION),
+ TAG_DEFINITION_HISTORY("tag_definition_history"),
+ TAG_DEFINITIONS("tag_definitions", ObjectType.TAG_DEFINITION, TAG_DEFINITION_HISTORY),
TAG_HISTORY("tag_history"),
TENANT("tenants", ObjectType.TENANT),
TAG("tags", TAG_HISTORY);
@@ -66,6 +67,15 @@ public enum TableName {
this(tableName, null, null);
}
+ public static TableName fromObjectType(final ObjectType objectType) {
+ for (final TableName tableName : values()) {
+ if (tableName.getObjectType() != null && tableName.getObjectType().equals(objectType)) {
+ return tableName;
+ }
+ }
+ return null;
+ }
+
public String getTableName() {
return tableName;
}
diff --git a/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagUserApi.java b/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagUserApi.java
index 87eba08..71b8274 100644
--- a/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagUserApi.java
+++ b/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagUserApi.java
@@ -79,29 +79,25 @@ public class DefaultTagUserApi implements TagUserApi {
public void addTags(final UUID objectId, final ObjectType objectType, final Collection<UUID> tagDefinitionIds, final CallContext context) throws TagApiException {
// TODO: consider making this batch
for (final UUID tagDefinitionId : tagDefinitionIds) {
- // TODO accountId?
- tagDao.insertTag(objectId, objectType, tagDefinitionId, internalCallContextFactory.createInternalCallContext(context));
+ tagDao.insertTag(objectId, objectType, tagDefinitionId, internalCallContextFactory.createInternalCallContext(objectId, objectType, context));
}
}
@Override
public void addTag(final UUID objectId, final ObjectType objectType, final UUID tagDefinitionId, final CallContext context) throws TagApiException {
- // TODO accountId?
- tagDao.insertTag(objectId, objectType, tagDefinitionId, internalCallContextFactory.createInternalCallContext(context));
+ tagDao.insertTag(objectId, objectType, tagDefinitionId, internalCallContextFactory.createInternalCallContext(objectId, objectType, context));
}
@Override
public void removeTag(final UUID objectId, final ObjectType objectType, final UUID tagDefinitionId, final CallContext context) throws TagApiException {
- // TODO accountId?
- tagDao.deleteTag(objectId, objectType, tagDefinitionId, internalCallContextFactory.createInternalCallContext(context));
+ tagDao.deleteTag(objectId, objectType, tagDefinitionId, internalCallContextFactory.createInternalCallContext(objectId, objectType, context));
}
@Override
public void removeTags(final UUID objectId, final ObjectType objectType, final Collection<UUID> tagDefinitionIds, final CallContext context) throws TagApiException {
// TODO: consider making this batch
for (final UUID tagDefinitionId : tagDefinitionIds) {
- // TODO accountId?
- tagDao.deleteTag(objectId, objectType, tagDefinitionId, internalCallContextFactory.createInternalCallContext(context));
+ tagDao.deleteTag(objectId, objectType, tagDefinitionId, internalCallContextFactory.createInternalCallContext(objectId, objectType, context));
}
}
diff --git a/util/src/test/java/com/ning/billing/util/callcontext/TestInternalCallContextFactory.java b/util/src/test/java/com/ning/billing/util/callcontext/TestInternalCallContextFactory.java
new file mode 100644
index 0000000..0ac9552
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/callcontext/TestInternalCallContextFactory.java
@@ -0,0 +1,107 @@
+/*
+ * 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.util.callcontext;
+
+import java.util.UUID;
+
+import org.skife.jdbi.v2.Handle;
+import org.skife.jdbi.v2.tweak.HandleCallback;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.ning.billing.util.UtilTestSuiteWithEmbeddedDB;
+import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.dao.ObjectType;
+
+public class TestInternalCallContextFactory extends UtilTestSuiteWithEmbeddedDB {
+
+ private InternalCallContextFactory internalCallContextFactory;
+
+ @BeforeMethod(groups = "slow")
+ public void setUp() throws Exception {
+ internalCallContextFactory = new InternalCallContextFactory(getMysqlTestingHelper().getDBI(), new ClockMock());
+ }
+
+ @Test(groups = "slow")
+ public void testCreateInternalCallContextWithAccountRecordIdFromSimpleObjectType() throws Exception {
+ final UUID invoiceId = UUID.randomUUID();
+ final Long accountRecordId = 19384012L;
+
+ getMysqlTestingHelper().getDBI().withHandle(new HandleCallback<Void>() {
+ @Override
+ public Void withHandle(final Handle handle) throws Exception {
+ handle.execute("DROP TABLE IF EXISTS invoices;\n" +
+ "CREATE TABLE invoices (\n" +
+ " record_id int(11) unsigned NOT NULL AUTO_INCREMENT,\n" +
+ " id char(36) NOT NULL,\n" +
+ " account_id char(36) NOT NULL,\n" +
+ " invoice_date date NOT NULL,\n" +
+ " target_date date NOT NULL,\n" +
+ " currency char(3) NOT NULL,\n" +
+ " migrated bool NOT NULL,\n" +
+ " created_by varchar(50) NOT NULL,\n" +
+ " created_date datetime NOT NULL,\n" +
+ " account_record_id int(11) unsigned default null,\n" +
+ " tenant_record_id int(11) unsigned default null,\n" +
+ " PRIMARY KEY(record_id)\n" +
+ ") ENGINE=innodb;");
+ handle.execute("insert into invoices (id, account_id, invoice_date, target_date, currency, migrated, created_by, created_date, account_record_id) values " +
+ "(?, ?, now(), now(), 'USD', 0, 'test', now(), ?)", invoiceId.toString(), UUID.randomUUID().toString(), accountRecordId);
+ return null;
+ }
+ });
+
+ final InternalCallContext context = internalCallContextFactory.createInternalCallContext(invoiceId, ObjectType.INVOICE, callContext);
+ // The account record id should have been looked up in the invoices table
+ Assert.assertEquals(context.getAccountRecordId(), accountRecordId);
+ verifyInternalCallContext(context);
+ }
+
+ @Test(groups = "slow")
+ public void testCreateInternalCallContextWithAccountRecordIdFromAccountObjectType() throws Exception {
+ final UUID accountId = UUID.randomUUID();
+ final Long accountRecordId = 19384012L;
+
+ getMysqlTestingHelper().getDBI().withHandle(new HandleCallback<Void>() {
+ @Override
+ public Void withHandle(final Handle handle) throws Exception {
+ // Note: we always create an accounts table, see MysqlTestingHelper
+ handle.execute("insert into accounts (record_id, id) values (?, ?)", accountRecordId, accountId.toString());
+ return null;
+ }
+ });
+
+ final InternalCallContext context = internalCallContextFactory.createInternalCallContext(accountId, ObjectType.ACCOUNT, callContext);
+ // The account record id should have been looked up in the accounts table
+ Assert.assertEquals(context.getAccountRecordId(), accountRecordId);
+ verifyInternalCallContext(context);
+ }
+
+ private void verifyInternalCallContext(final InternalCallContext context) {
+ Assert.assertEquals(context.getCallOrigin(), callContext.getCallOrigin());
+ Assert.assertEquals(context.getComment(), callContext.getComment());
+ Assert.assertEquals(context.getCreatedDate(), callContext.getCreatedDate());
+ Assert.assertEquals(context.getReasonCode(), callContext.getReasonCode());
+ Assert.assertEquals(context.getUpdatedDate(), callContext.getUpdatedDate());
+ Assert.assertEquals(context.getUserName(), callContext.getUserName());
+ Assert.assertEquals(context.getUserToken(), callContext.getUserToken());
+ Assert.assertEquals(context.getUserType(), callContext.getUserType());
+ // Our test callContext doesn't have a tenant id
+ Assert.assertEquals(context.getTenantRecordId(), (Long) InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID);
+ }
+}