killbill-aplcache

Details

diff --git a/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java b/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java
index f7bf292..632da11 100644
--- a/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java
+++ b/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java
@@ -19,21 +19,27 @@ package com.ning.billing.util.tag;
 import java.util.UUID;
 
 public enum ControlTagType {
-    AUTO_PAY_OFF("Suspends payments until removed.", true, false),
-    AUTO_INVOICING_OFF("Suspends invoicing until removed.", false, true),
-    OVERDUE_ENFORCEMENT_OFF("Suspends overdue enforcement behaviour until removed.", false, false),
-    WRITTEN_OFF("Indicated that an invoice is written off. No billing or payment effect.", false, false);
+    AUTO_PAY_OFF(new UUID(0, 1), "Suspends payments until removed.", true, false),
+    AUTO_INVOICING_OFF(new UUID(0, 2), "Suspends invoicing until removed.", false, true),
+    OVERDUE_ENFORCEMENT_OFF(new UUID(0, 3), "Suspends overdue enforcement behaviour until removed.", false, false),
+    WRITTEN_OFF(new UUID(0, 4), "Indicated that an invoice is written off. No billing or payment effect.", false, false);
 
+    private final UUID id;
     private final String description;
     private final boolean autoPaymentOff;
     private final boolean autoInvoicingOff;
 
-    ControlTagType(final String description, final boolean autoPaymentOff, final boolean autoInvoicingOff) {
+    ControlTagType(final UUID id, final String description, final boolean autoPaymentOff, final boolean autoInvoicingOff) {
+        this.id = id;
         this.description = description;
         this.autoPaymentOff = autoPaymentOff;
         this.autoInvoicingOff = autoInvoicingOff;
     }
 
+    public UUID getId() {
+        return id;
+    }
+
     public String getDescription() {
         return this.description;
     }
@@ -65,7 +71,7 @@ public enum ControlTagType {
 
             @Override
             public UUID getId() {
-                return null;
+                return id;
             }
         };
     }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java
index ed9cf13..069a325 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright 2010-2011 Ning, Inc.
  *
  * Ning licenses this file to you under the Apache License, version 2.0
@@ -16,6 +16,7 @@
 
 package com.ning.billing.entitlement.engine.dao;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -26,6 +27,8 @@ import java.util.Set;
 import java.util.TreeSet;
 import java.util.UUID;
 
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
 import com.ning.billing.entitlement.api.SubscriptionFactory;
 import com.ning.billing.entitlement.api.migration.AccountMigrationData;
 import com.ning.billing.entitlement.api.timeline.RepairEntitlementLifecycleDao;
@@ -43,27 +46,69 @@ public class RepairEntitlementDao implements EntitlementDao, RepairEntitlementLi
 
     private final ThreadLocal<Map<UUID, SubscriptionRepairEvent>> preThreadsInRepairSubscriptions = new ThreadLocal<Map<UUID, SubscriptionRepairEvent>>();
 
+
+    private final static class EntitlementEventWithOrderingId {
+
+        private final EntitlementEvent event;
+        private final long orderingId;
+
+        public EntitlementEventWithOrderingId(EntitlementEvent event, long orderingId) {
+            this.event = event;
+            this.orderingId = orderingId;
+        }
+
+        public EntitlementEvent getEvent() {
+            return event;
+        }
+        public long getOrderingId() {
+            return orderingId;
+        }
+
+    }
+
     private static final class SubscriptionRepairEvent {
-        private final Set<EntitlementEvent> events;
+
+        private final Set<EntitlementEventWithOrderingId> events;
+        private long curOrderingId;
 
         public SubscriptionRepairEvent(final List<EntitlementEvent> initialEvents) {
-            events = new TreeSet<EntitlementEvent>(new Comparator<EntitlementEvent>() {
+            this.events = new TreeSet<EntitlementEventWithOrderingId>(new Comparator<EntitlementEventWithOrderingId>() {
                 @Override
-                public int compare(final EntitlementEvent o1, final EntitlementEvent o2) {
-                    return o1.compareTo(o2);
+                public int compare(final EntitlementEventWithOrderingId o1, final EntitlementEventWithOrderingId o2) {
+                    int result = o1.getEvent().getEffectiveDate().compareTo(o2.getEvent().getEffectiveDate());
+                    if (result == 0) {
+                        if (o1.getOrderingId() < o2.getOrderingId()) {
+                            return -1;
+                        } else if (o1.getOrderingId() > o2.getOrderingId()) {
+                            return 1;
+                        } else {
+                            throw new RuntimeException("Repair entitlement events should not have the same orderingId");
+                        }
+                    }
+                    return result;
                 }
             });
+
+            this.curOrderingId = 0;
+
             if (initialEvents != null) {
-                events.addAll(initialEvents);
+                addEvents(initialEvents);
             }
         }
 
-        public Set<EntitlementEvent> getEvents() {
-            return events;
+        public List<EntitlementEvent> getEvents() {
+            return new ArrayList<EntitlementEvent>(Collections2.transform(events, new Function<EntitlementEventWithOrderingId, EntitlementEvent>() {
+                @Override
+                public EntitlementEvent apply(EntitlementEventWithOrderingId in) {
+                    return in.getEvent();
+                }
+            }));
         }
 
         public void addEvents(final List<EntitlementEvent> newEvents) {
-            events.addAll(newEvents);
+            for (EntitlementEvent cur : newEvents) {
+                events.add(new EntitlementEventWithOrderingId(cur, curOrderingId++));
+            }
         }
     }
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairBP.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairBP.java
index de7a40d..6ff4c51 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairBP.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairBP.java
@@ -122,8 +122,7 @@ public class TestRepairBP extends TestApiBaseRepair {
         assertListenerStatus();
     }
 
-    //TODO MDW: Temporary disable need to look at this with Stephane
-    @Test(groups = "slow", enabled = false)
+    @Test(groups = "slow")
     public void testBPRepairWithCancellationOnstart() throws Exception {
         final String baseProduct = "Shotgun";
         final DateTime startDate = clock.getUTCNow();
diff --git a/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java b/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java
index f129496..e01e6a9 100644
--- a/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java
+++ b/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java
@@ -16,6 +16,7 @@
 
 package com.ning.billing.util.dao;
 
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -112,7 +113,7 @@ public abstract class AuditedCollectionDaoBase<T extends Entity, V> implements A
         // Find all pairs <entity id, record id> (including those that are about to be deleted) for this parent object
         final List<Mapper<UUID, Long>> recordIds = dao.getRecordIds(objectId.toString(), objectType);
         // Flip the map to look up the record id associated with an entity id
-        final Map<UUID, Long> recordIdMap = convertToHistoryMap(recordIds);
+        final Map<UUID, Long> recordIdMap = convertToHistoryMap(recordIds, objectType);
 
         // Perform the deletes
         if (objsToRemove.size() != 0) {
@@ -169,7 +170,12 @@ public abstract class AuditedCollectionDaoBase<T extends Entity, V> implements A
 
         for (final T entity : entities) {
             final UUID id = entity.getId();
-            histories.add(new EntityHistory<T>(id, recordIds.get(id), entity, changeType));
+
+            final Long recordId = recordIds.get(id);
+            if (recordId == null) {
+                throw new IllegalStateException("recordId for object " + entity.getClass() + " is null ");
+            }
+            histories.add(new EntityHistory<T>(id, recordId, entity, changeType));
         }
 
         return histories;
@@ -187,9 +193,16 @@ public abstract class AuditedCollectionDaoBase<T extends Entity, V> implements A
         return audits;
     }
 
-    protected Map<UUID, Long> convertToHistoryMap(final List<Mapper<UUID, Long>> recordIds) {
+    protected Map<UUID, Long> convertToHistoryMap(final List<Mapper<UUID, Long>> recordIds, final ObjectType objectType) {
         final Map<UUID, Long> recordIdMap = new HashMap<UUID, Long>();
         for (final Mapper<UUID, Long> recordId : recordIds) {
+            if (recordId.getKey() == null) {
+                throw new IllegalStateException("UUID for object " + objectType + " is null for recordId " + recordId.getValue());
+            }
+            if (recordId.getValue() == null) {
+                throw new IllegalStateException("recordId for object " + objectType + " is null for UUID " + recordId.getKey());
+            }
+
             recordIdMap.put(recordId.getKey(), recordId.getValue());
         }
 
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/AuditedTagDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/AuditedTagDao.java
index 67410ee..d990f7e 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/AuditedTagDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/AuditedTagDao.java
@@ -83,7 +83,7 @@ public class AuditedTagDao extends AuditedCollectionDaoBase<Tag, Tag> implements
 
                 // Gather the tag ids for this object id
                 final List<Mapper<UUID, Long>> recordIds = tagSqlDao.getRecordIds(objectId.toString(), objectType);
-                final Map<UUID, Long> recordIdMap = convertToHistoryMap(recordIds);
+                final Map<UUID, Long> recordIdMap = convertToHistoryMap(recordIds, objectType);
 
                 // Update the history table
                 final List<EntityHistory<Tag>> entityHistories = convertToHistory(tagList, recordIdMap, ChangeType.INSERT);
@@ -131,7 +131,7 @@ public class AuditedTagDao extends AuditedCollectionDaoBase<Tag, Tag> implements
 
                     // Before the deletion, gather the tag ids for this object id
                     final List<Mapper<UUID, Long>> recordIds = tagSqlDao.getRecordIds(objectId.toString(), objectType);
-                    final Map<UUID, Long> recordIdMap = convertToHistoryMap(recordIds);
+                    final Map<UUID, Long> recordIdMap = convertToHistoryMap(recordIds, objectType);
 
                     // Delete the tag
                     tagSqlDao.deleteFromTransaction(objectId.toString(), objectType, tagList, context);
@@ -163,6 +163,7 @@ public class AuditedTagDao extends AuditedCollectionDaoBase<Tag, Tag> implements
                 }
             });
         } catch (TransactionFailedException exception) {
+
             if (exception.getCause() instanceof TagDefinitionApiException) {
                 throw (TagApiException) exception.getCause();
             } else {