Details
diff --git a/api/src/main/java/com/ning/billing/usage/api/UsageUserApi.java b/api/src/main/java/com/ning/billing/usage/api/UsageUserApi.java
index c0cf5e0..eb6935c 100644
--- a/api/src/main/java/com/ning/billing/usage/api/UsageUserApi.java
+++ b/api/src/main/java/com/ning/billing/usage/api/UsageUserApi.java
@@ -22,7 +22,34 @@ import org.joda.time.DateTime;
public interface UsageUserApi {
+ /**
+ * Shortcut API to record a usage value of "1" for a given metric.
+ *
+ * @param bundleId bundle id source
+ * @param metricName metric name for this usage
+ */
public void incrementUsage(final UUID bundleId, final String metricName);
+ /**
+ * Fine grained usage API if the external system doesn't roll its usage data. This is used to record e.g. "X has used
+ * 2 credits from his plan at 2012/02/04 4:12pm".
+ *
+ * @param bundleId bundle id source
+ * @param metricName metric name for this usage
+ * @param timestamp timestamp of this usage
+ * @param value value to record
+ */
public void recordUsage(final UUID bundleId, final String metricName, final DateTime timestamp, final long value);
+
+ /**
+ * Bulk usage API if the external system rolls-up usage data. This is used to record e.g. "X has used 12 minutes
+ * of his data plan between 2012/02/04 and 2012/02/06".
+ *
+ * @param bundleId bundle id source
+ * @param metricName metric name for this usage
+ * @param startDate start date of the usage period
+ * @param endDate end date of the usage period
+ * @param value value to record
+ */
+ public void recordRolledUpUsage(final UUID bundleId, final String metricName, final DateTime startDate, final DateTime endDate, final long value);
}
diff --git a/usage/src/main/java/com/ning/billing/usage/api/user/DefaultUsageUserApi.java b/usage/src/main/java/com/ning/billing/usage/api/user/DefaultUsageUserApi.java
index 804766f..8f1e6a9 100644
--- a/usage/src/main/java/com/ning/billing/usage/api/user/DefaultUsageUserApi.java
+++ b/usage/src/main/java/com/ning/billing/usage/api/user/DefaultUsageUserApi.java
@@ -23,8 +23,8 @@ import javax.inject.Inject;
import org.joda.time.DateTime;
import com.ning.billing.usage.api.UsageUserApi;
+import com.ning.billing.usage.dao.RolledUpUsageDao;
import com.ning.billing.usage.timeline.TimelineEventHandler;
-import com.ning.billing.usage.timeline.persistent.TimelineDao;
import com.ning.billing.util.clock.Clock;
import com.google.common.collect.ImmutableMap;
@@ -33,13 +33,13 @@ public class DefaultUsageUserApi implements UsageUserApi {
private static final String DEFAULT_EVENT_TYPE = "__DefaultUsageUserApi__";
- private final TimelineDao timelineDao;
+ private final RolledUpUsageDao rolledUpUsageDao;
private final TimelineEventHandler timelineEventHandler;
private final Clock clock;
@Inject
- public DefaultUsageUserApi(final TimelineDao timelineDao, final TimelineEventHandler timelineEventHandler, final Clock clock) {
- this.timelineDao = timelineDao;
+ public DefaultUsageUserApi(final RolledUpUsageDao rolledUpUsageDao, final TimelineEventHandler timelineEventHandler, final Clock clock) {
+ this.rolledUpUsageDao = rolledUpUsageDao;
this.timelineEventHandler = timelineEventHandler;
this.clock = clock;
}
@@ -51,7 +51,18 @@ public class DefaultUsageUserApi implements UsageUserApi {
@Override
public void recordUsage(final UUID bundleId, final String metricName, final DateTime timestamp, final long value) {
- final int sourceId = timelineDao.getOrAddSource(bundleId.toString());
- timelineEventHandler.record(sourceId, DEFAULT_EVENT_TYPE, timestamp, ImmutableMap.<String, Object>of(metricName, value));
+ final String sourceName = getSourceNameFromBundleId(bundleId);
+ timelineEventHandler.record(sourceName, DEFAULT_EVENT_TYPE, timestamp, ImmutableMap.<String, Object>of(metricName, value));
+ }
+
+ @Override
+ public void recordRolledUpUsage(final UUID bundleId, final String metricName, final DateTime startDate, final DateTime endDate, final long value) {
+ final String sourceName = getSourceNameFromBundleId(bundleId);
+ rolledUpUsageDao.record(sourceName, DEFAULT_EVENT_TYPE, metricName, startDate, endDate, value);
+ }
+
+ private String getSourceNameFromBundleId(final UUID bundleId) {
+ // TODO we should do better
+ return bundleId.toString();
}
}
diff --git a/usage/src/main/java/com/ning/billing/usage/dao/DefaultRolledUpUsageDao.java b/usage/src/main/java/com/ning/billing/usage/dao/DefaultRolledUpUsageDao.java
new file mode 100644
index 0000000..58e3dce
--- /dev/null
+++ b/usage/src/main/java/com/ning/billing/usage/dao/DefaultRolledUpUsageDao.java
@@ -0,0 +1,70 @@
+/*
+ * 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.usage.dao;
+
+import javax.inject.Inject;
+
+import org.joda.time.DateTime;
+import org.skife.jdbi.v2.Transaction;
+import org.skife.jdbi.v2.TransactionStatus;
+
+import com.ning.billing.usage.timeline.persistent.TimelineSqlDao;
+
+public class DefaultRolledUpUsageDao implements RolledUpUsageDao {
+
+ private final RolledUpUsageSqlDao rolledUpUsageSqlDao;
+
+ @Inject
+ public DefaultRolledUpUsageDao(final RolledUpUsageSqlDao rolledUpUsageSqlDao) {
+ this.rolledUpUsageSqlDao = rolledUpUsageSqlDao;
+ }
+
+ @Override
+ public void record(final String source, final String eventType, final String metricName, final DateTime startDate, final DateTime endDate, final long value) {
+ rolledUpUsageSqlDao.inTransaction(new Transaction<Void, RolledUpUsageSqlDao>() {
+ @Override
+ public Void inTransaction(final RolledUpUsageSqlDao transactional, final TransactionStatus status) throws Exception {
+ final TimelineSqlDao timelineSqlDao = transactional.become(TimelineSqlDao.class);
+
+ // Create the source if it doesn't exist
+ Integer sourceId = timelineSqlDao.getSourceId(source);
+ if (sourceId == null) {
+ timelineSqlDao.addSource(source);
+ sourceId = timelineSqlDao.getSourceId(source);
+ }
+
+ // Create the category if it doesn't exist
+ Integer categoryId = timelineSqlDao.getEventCategoryId(eventType);
+ if (categoryId == null) {
+ timelineSqlDao.addEventCategory(eventType);
+ categoryId = timelineSqlDao.getEventCategoryId(eventType);
+ }
+
+ // Create the metric if it doesn't exist
+ Integer metricId = timelineSqlDao.getMetricId(categoryId, metricName);
+ if (metricId == null) {
+ timelineSqlDao.addMetric(categoryId, metricName);
+ metricId = timelineSqlDao.getMetricId(categoryId, metricName);
+ }
+
+ transactional.record(sourceId, metricId, startDate.toDate(), endDate.toDate(), value);
+
+ return null;
+ }
+ });
+ }
+}
diff --git a/usage/src/main/java/com/ning/billing/usage/dao/RolledUpUsageDao.java b/usage/src/main/java/com/ning/billing/usage/dao/RolledUpUsageDao.java
new file mode 100644
index 0000000..a75a882
--- /dev/null
+++ b/usage/src/main/java/com/ning/billing/usage/dao/RolledUpUsageDao.java
@@ -0,0 +1,28 @@
+/*
+ * 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.usage.dao;
+
+import org.joda.time.DateTime;
+
+/**
+ * Dao to record already rolled-up usage data (rolled-up by the user).
+ * For raw tracking of the data, @see TimelineEventHandler.
+ */
+public interface RolledUpUsageDao {
+
+ public void record(final String sourceName, final String eventType, final String metricName, final DateTime startDate, final DateTime endDate, final long value);
+}
diff --git a/usage/src/main/java/com/ning/billing/usage/dao/RolledUpUsageSqlDao.java b/usage/src/main/java/com/ning/billing/usage/dao/RolledUpUsageSqlDao.java
new file mode 100644
index 0000000..b495535
--- /dev/null
+++ b/usage/src/main/java/com/ning/billing/usage/dao/RolledUpUsageSqlDao.java
@@ -0,0 +1,34 @@
+/*
+ * 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.usage.dao;
+
+import java.util.Date;
+
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
+import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
+import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
+
+@ExternalizedSqlViaStringTemplate3()
+public interface RolledUpUsageSqlDao extends Transactional<RolledUpUsageSqlDao>, Transmogrifier {
+
+ @SqlUpdate
+ public void record(@Bind("sourceId") final int sourceId, @Bind("metricId") final int metricId,
+ @Bind("startTime") final Date startTime, @Bind("endTime") final Date endTime,
+ @Bind("value") final long value);
+}
diff --git a/usage/src/main/java/com/ning/billing/usage/timeline/persistent/TimelineSqlDao.java b/usage/src/main/java/com/ning/billing/usage/timeline/persistent/TimelineSqlDao.java
index 395ee3a..ce6c5bd 100644
--- a/usage/src/main/java/com/ning/billing/usage/timeline/persistent/TimelineSqlDao.java
+++ b/usage/src/main/java/com/ning/billing/usage/timeline/persistent/TimelineSqlDao.java
@@ -29,6 +29,7 @@ import org.skife.jdbi.v2.sqlobject.customizers.BatchChunkSize;
import org.skife.jdbi.v2.sqlobject.customizers.Mapper;
import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
+import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
import com.ning.billing.usage.timeline.categories.CategoryIdAndMetric;
@@ -44,7 +45,7 @@ import com.ning.billing.usage.timeline.sources.SourceIdAndMetricIdMapper;
@ExternalizedSqlViaStringTemplate3()
@RegisterMapper({CategoryIdAndMetricMapper.class, StartTimesMapper.class, SourceIdAndMetricIdMapper.class})
-public interface TimelineSqlDao extends Transactional<TimelineSqlDao> {
+public interface TimelineSqlDao extends Transactional<TimelineSqlDao>, Transmogrifier {
@SqlQuery
Integer getSourceId(@Bind("sourceName") final String source);
diff --git a/usage/src/main/java/com/ning/billing/usage/timeline/TimelineEventHandler.java b/usage/src/main/java/com/ning/billing/usage/timeline/TimelineEventHandler.java
index c7e3903..f36c1df 100644
--- a/usage/src/main/java/com/ning/billing/usage/timeline/TimelineEventHandler.java
+++ b/usage/src/main/java/com/ning/billing/usage/timeline/TimelineEventHandler.java
@@ -199,12 +199,12 @@ public class TimelineEventHandler {
/**
* Main entry point to the timeline subsystem. Record a series of sample for a given source, at a given timestamp.
*
- * @param sourceId id of the source
+ * @param sourceName name of the source
* @param eventType event category
* @param eventTimestamp event timestamp
* @param samples samples to record
*/
- public void record(final Integer sourceId, final String eventType, final DateTime eventTimestamp, final Map<String, Object> samples) {
+ public void record(final String sourceName, final String eventType, final DateTime eventTimestamp, final Map<String, Object> samples) {
if (shuttingDown.get()) {
eventsReceivedAfterShuttingDown.incrementAndGet();
return;
@@ -212,6 +212,9 @@ public class TimelineEventHandler {
try {
handledEventCount.incrementAndGet();
+ // Find the sourceId
+ final int sourceId = timelineDAO.getOrAddSource(sourceName);
+
// Extract and parse samples
final Map<Integer, ScalarSample> scalarSamples = new LinkedHashMap<Integer, ScalarSample>();
convertSamplesToScalarSamples(sourceId, eventType, samples, scalarSamples);
diff --git a/usage/src/main/resources/com/ning/billing/usage/ddl.sql b/usage/src/main/resources/com/ning/billing/usage/ddl.sql
index 4fbff70..fab0ce2 100644
--- a/usage/src/main/resources/com/ning/billing/usage/ddl.sql
+++ b/usage/src/main/resources/com/ning/billing/usage/ddl.sql
@@ -30,7 +30,7 @@ create table metrics (
) engine = innodb default charset = latin1;
create table timeline_chunks (
- chunk_id bigint not null auto_increment
+ record_id bigint not null auto_increment
, source_id integer not null
, metric_id integer not null
, sample_count integer not null
@@ -53,3 +53,15 @@ create table last_start_times (
insert ignore into timeline_chunks(chunk_id, source_id, metric_id, sample_count, start_time, end_time, in_row_samples, blob_samples)
values (0, 0, 0, 0, 0, 0, null, null);
+
+create table timeline_rolled_up_chunk (
+ record_id bigint not null auto_increment
+, source_id integer not null
+, metric_id integer not null
+, start_time date not null
+, end_time date not null
+, value bigint not null
+, account_record_id int(11) unsigned default null
+, tenant_record_id int(11) unsigned default null
+, primary key(record_id)
+) engine = innodb default charset = latin1;