killbill-aplcache

usage: add configuration for the shutdown sequence Signed-off-by:

7/28/2012 6:19:12 PM

Details

diff --git a/usage/src/main/java/com/ning/billing/usage/timeline/shutdown/ShutdownSaveMode.java b/usage/src/main/java/com/ning/billing/usage/timeline/shutdown/ShutdownSaveMode.java
new file mode 100644
index 0000000..9ce0ebe
--- /dev/null
+++ b/usage/src/main/java/com/ning/billing/usage/timeline/shutdown/ShutdownSaveMode.java
@@ -0,0 +1,31 @@
+/*
+ * 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.timeline.shutdown;
+
+public enum ShutdownSaveMode {
+    SAVE_ALL_TIMELINES,    // Save all timelines in the db
+    SAVE_START_TIMES;      // Save just the start times for each timeline, and use the replay facility to reconstruct the accumulators on startup
+
+    public static ShutdownSaveMode fromString(final String mode) {
+        for (final ShutdownSaveMode s : ShutdownSaveMode.values()) {
+            if (s.name().equalsIgnoreCase(mode)) {
+                return s;
+            }
+        }
+        throw new IllegalArgumentException(String.format("The argument %s was supposed to be a ShutdownSaveMode, but was not", mode));
+    }
+}
diff --git a/usage/src/main/java/com/ning/billing/usage/timeline/shutdown/StartTimes.java b/usage/src/main/java/com/ning/billing/usage/timeline/shutdown/StartTimes.java
new file mode 100644
index 0000000..7e1bc9d
--- /dev/null
+++ b/usage/src/main/java/com/ning/billing/usage/timeline/shutdown/StartTimes.java
@@ -0,0 +1,88 @@
+/*
+ * 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.timeline.shutdown;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.joda.time.DateTime;
+
+/**
+ * This class is used solely as a Json mapping class when saving timelines in a database
+ * blob on shutdown, and restoring them on startup.
+ * <p/>
+ * The Map<Integer, Map<Integer, DateTime>> maps from sourceId to eventCategoryId to startTime.
+ */
+public class StartTimes {
+
+    private final DateTime timeInserted;
+    private final Map<Integer, Map<Integer, DateTime>> startTimesMap;
+    private DateTime minStartTime;
+
+    public StartTimes(final DateTime timeInserted, final Map<Integer, Map<Integer, DateTime>> startTimesMap) {
+        this.timeInserted = timeInserted;
+        this.startTimesMap = startTimesMap;
+        DateTime minDateTime = new DateTime(Long.MAX_VALUE);
+        for (final Map<Integer, DateTime> categoryMap : startTimesMap.values()) {
+            for (final DateTime startTime : categoryMap.values()) {
+                if (minDateTime.isAfter(startTime)) {
+                    minDateTime = startTime;
+                }
+            }
+        }
+        this.minStartTime = minDateTime;
+    }
+
+    public StartTimes() {
+        this.timeInserted = new DateTime();
+        minStartTime = new DateTime(Long.MAX_VALUE);
+        this.startTimesMap = new HashMap<Integer, Map<Integer, DateTime>>();
+    }
+
+    public void addTime(final int sourceId, final int categoryId, final DateTime dateTime) {
+        Map<Integer, DateTime> sourceTimes = startTimesMap.get(sourceId);
+        if (sourceTimes == null) {
+            sourceTimes = new HashMap<Integer, DateTime>();
+            startTimesMap.put(sourceId, sourceTimes);
+        }
+        sourceTimes.put(categoryId, dateTime);
+        if (dateTime.isBefore(minStartTime)) {
+            minStartTime = dateTime;
+        }
+    }
+
+    public DateTime getStartTimeForSourceIdAndCategoryId(final int sourceId, final int categoryId) {
+        final Map<Integer, DateTime> sourceTimes = startTimesMap.get(sourceId);
+        if (sourceTimes != null) {
+            return sourceTimes.get(categoryId);
+        } else {
+            return null;
+        }
+    }
+
+    public Map<Integer, Map<Integer, DateTime>> getStartTimesMap() {
+        return startTimesMap;
+    }
+
+    public DateTime getTimeInserted() {
+        return timeInserted;
+    }
+
+    public DateTime getMinStartTime() {
+        return minStartTime;
+    }
+}
diff --git a/usage/src/main/java/com/ning/billing/usage/timeline/shutdown/StartTimesBinder.java b/usage/src/main/java/com/ning/billing/usage/timeline/shutdown/StartTimesBinder.java
new file mode 100644
index 0000000..00c08c0
--- /dev/null
+++ b/usage/src/main/java/com/ning/billing/usage/timeline/shutdown/StartTimesBinder.java
@@ -0,0 +1,62 @@
+/*
+ * 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.timeline.shutdown;
+
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.ning.billing.usage.timeline.DateTimeUtils;
+import com.ning.billing.usage.timeline.shutdown.StartTimesBinder.StartTimesBinderFactory;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+@BindingAnnotation(StartTimesBinderFactory.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface StartTimesBinder {
+
+    public static class StartTimesBinderFactory implements BinderFactory {
+
+        private static final Logger log = LoggerFactory.getLogger(StartTimesBinderFactory.class);
+        private static final ObjectMapper mapper = new ObjectMapper();
+
+        public Binder build(final Annotation annotation) {
+            return new Binder<StartTimesBinder, StartTimes>() {
+                public void bind(final SQLStatement query, final StartTimesBinder binder, final StartTimes startTimes) {
+                    try {
+                        final String s = mapper.writeValueAsString(startTimes.getStartTimesMap());
+                        query.bind("startTimes", s)
+                             .bind("timeInserted", DateTimeUtils.unixSeconds(startTimes.getTimeInserted()));
+                    } catch (IOException e) {
+                        log.error("Exception while binding StartTimes", e);
+                    }
+                }
+            };
+        }
+    }
+}
diff --git a/usage/src/main/java/com/ning/billing/usage/timeline/shutdown/StartTimesMapper.java b/usage/src/main/java/com/ning/billing/usage/timeline/shutdown/StartTimesMapper.java
new file mode 100644
index 0000000..29ac314
--- /dev/null
+++ b/usage/src/main/java/com/ning/billing/usage/timeline/shutdown/StartTimesMapper.java
@@ -0,0 +1,47 @@
+/*
+ * 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.timeline.shutdown;
+
+import java.io.IOException;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Map;
+
+import org.joda.time.DateTime;
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.tweak.ResultSetMapper;
+
+import com.ning.billing.usage.timeline.DateTimeUtils;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class StartTimesMapper implements ResultSetMapper<StartTimes> {
+
+    private static final ObjectMapper mapper = new ObjectMapper();
+
+    @Override
+    public StartTimes map(final int index, final ResultSet r, final StatementContext ctx) throws SQLException {
+        try {
+            return new StartTimes(DateTimeUtils.dateTimeFromUnixSeconds(r.getInt("time_inserted")),
+                                  (Map<Integer, Map<Integer, DateTime>>) mapper.readValue(r.getBlob("start_times").getBinaryStream(), new TypeReference<Map<Integer, Map<Integer, DateTime>>>() {
+                                  }));
+        } catch (IOException e) {
+            throw new IllegalStateException(String.format("Could not decode the StartTimes map"), e);
+        }
+    }
+}