From 0151cda7dddc2c01b13fb36281ab23aea0b74764 Mon Sep 17 00:00:00 2001 From: Abhinandan Prateek Date: Sat, 5 Dec 2015 17:37:11 +0530 Subject: [PATCH] CLOUDSTACK-8592: optimization and fixes 1. Process usage entries that have greater than 0 usage 2. Process quota entries only if tariff is non zero 3. If there are credit entries but no balance entry create a dummy balance entry 4. Remove any credit entries that are before the last balance entry when displaying balance statement 5. Bug: write the balance entry, boundary condition --- .../classes/resources/messages.properties | 2 +- .../src/com/cloud/usage/dao/UsageDaoImpl.java | 1 + .../cloudstack/quota/QuotaManagerImpl.java | 94 +++++++++++++------ .../quota/dao/QuotaBalanceDaoImpl.java | 4 +- .../cloudstack/quota/vo/QuotaAccountVO.java | 7 ++ .../cloudstack/quota/vo/QuotaBalanceVO.java | 9 +- .../cloudstack/quota/vo/QuotaUsageVO.java | 12 ++- .../response/QuotaResponseBuilderImpl.java | 39 +++++++- 8 files changed, 130 insertions(+), 38 deletions(-) diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index 84e5be57e9a..6bd55daae99 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -1399,7 +1399,7 @@ label.quota.configuration=Quota Configuration label.quota.configure=Configure Quota label.quota.remove=Remove Quota label.quota.totalusage=Total Usage -label.quota.balance=Balance +label.quota.balance=Free Credits label.quota.minbalance=Min Balance label.quota.enforcequota=Enforce Quota label.quota.summary=Summary diff --git a/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java index d6a8123aa9a..9b311e5ad85 100644 --- a/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java +++ b/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java @@ -477,6 +477,7 @@ public class UsageDaoImpl extends GenericDaoBase implements Usage qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId); } qb.and(qb.entity().getQuotaCalculated(), SearchCriteria.Op.NEQ, 1); + qb.and(qb.entity().getRawUsage(), SearchCriteria.Op.GT, 0); if (s_logger.isDebugEnabled()) { s_logger.debug("Getting usage records" + usageFilter.getOrderBy()); } diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java index e63a276975b..ede48260ba0 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java +++ b/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java @@ -143,17 +143,26 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { BigDecimal aggregationRatio = new BigDecimal(_aggregationDuration).divide(s_minutesInMonth, 8, RoundingMode.HALF_EVEN); switch (usageRecord.getUsageType()) { case QuotaTypes.RUNNING_VM: - quotaListForAccount.addAll(updateQuotaRunningVMUsage(usageRecord, aggregationRatio)); + List lq = updateQuotaRunningVMUsage(usageRecord, aggregationRatio); + if (!lq.isEmpty()) { + quotaListForAccount.addAll(lq); + } break; case QuotaTypes.ALLOCATED_VM: - quotaListForAccount.add(updateQuotaAllocatedVMUsage(usageRecord, aggregationRatio)); + QuotaUsageVO qu = updateQuotaAllocatedVMUsage(usageRecord, aggregationRatio); + if (qu != null) { + quotaListForAccount.add(qu); + } break; case QuotaTypes.SNAPSHOT: case QuotaTypes.TEMPLATE: case QuotaTypes.ISO: case QuotaTypes.VOLUME: case QuotaTypes.VM_SNAPSHOT: - quotaListForAccount.add(updateQuotaDiskUsage(usageRecord, aggregationRatio, usageRecord.getUsageType())); + qu = updateQuotaDiskUsage(usageRecord, aggregationRatio, usageRecord.getUsageType()); + if (qu != null) { + quotaListForAccount.add(qu); + } break; case QuotaTypes.LOAD_BALANCER_POLICY: case QuotaTypes.PORT_FORWARDING_RULE: @@ -161,11 +170,17 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { case QuotaTypes.NETWORK_OFFERING: case QuotaTypes.SECURITY_GROUP: case QuotaTypes.VPN_USERS: - quotaListForAccount.add(updateQuotaRaw(usageRecord, aggregationRatio, usageRecord.getUsageType())); + qu = updateQuotaRaw(usageRecord, aggregationRatio, usageRecord.getUsageType()); + if (qu != null) { + quotaListForAccount.add(qu); + } break; case QuotaTypes.NETWORK_BYTES_RECEIVED: case QuotaTypes.NETWORK_BYTES_SENT: - quotaListForAccount.add(updateQuotaNetwork(usageRecord, usageRecord.getUsageType())); + qu = updateQuotaNetwork(usageRecord, usageRecord.getUsageType()); + if (qu != null) { + quotaListForAccount.add(qu); + } break; case QuotaTypes.VM_DISK_IO_READ: case QuotaTypes.VM_DISK_IO_WRITE: @@ -182,9 +197,17 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { if (quotaListForAccount == null || quotaListForAccount.isEmpty()) { return; } - quotaListForAccount.add(new QuotaUsageVO()); + if (s_logger.isDebugEnabled()) { + s_logger.debug(quotaListForAccount.get(0)); + } Date startDate = quotaListForAccount.get(0).getStartDate(); Date endDate = quotaListForAccount.get(0).getEndDate(); + if (s_logger.isDebugEnabled()) { + s_logger.debug("processQuotaBalanceForAccount startDate " + startDate + " endDate=" + endDate); + s_logger.debug("processQuotaBalanceForAccount last items startDate " + quotaListForAccount.get(quotaListForAccount.size() - 1).getStartDate() + " items endDate=" + + quotaListForAccount.get(quotaListForAccount.size() - 1).getEndDate()); + } + quotaListForAccount.add(new QuotaUsageVO()); BigDecimal aggrUsage = new BigDecimal(0); List creditsReceived = null; @@ -192,14 +215,21 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { QuotaUsageVO lastQuotaUsage = _quotaUsageDao.findLastQuotaUsageEntry(account.getAccountId(), account.getDomainId(), startDate); if (lastQuotaUsage == null) { creditsReceived = _quotaBalanceDao.findCreditBalance(account.getAccountId(), account.getDomainId(), new Date(0), startDate); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Credit entries count " + creditsReceived.size() + " on Before Date=" + startDate); + } if (creditsReceived != null) { for (QuotaBalanceVO credit : creditsReceived) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Credit entry found " + aggrUsage.setScale(6, RoundingMode.HALF_EVEN).toString() + " on Date=" + startDate); + s_logger.debug("Credit entry found " + credit); + s_logger.debug("Total = " + aggrUsage); } aggrUsage = aggrUsage.add(credit.getCreditBalance()); } } + // create a balance entry for these accumulated credits + QuotaBalanceVO firstBalance = new QuotaBalanceVO(account.getAccountId(), account.getDomainId(), aggrUsage, startDate); + _quotaBalanceDao.saveQuotaBalance(firstBalance); } for (QuotaUsageVO entry : quotaListForAccount) { if (entry.getQuotaUsed().compareTo(BigDecimal.ZERO) == 0) { @@ -208,7 +238,8 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { if (creditsReceived != null) { for (QuotaBalanceVO credit : creditsReceived) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Credit entry found " + aggrUsage.setScale(6, RoundingMode.HALF_EVEN).toString() + " on Date=" + entry.getStartDate()); + s_logger.debug("Credit entry found " + credit); + s_logger.debug("Total = " + aggrUsage); } aggrUsage = aggrUsage.add(credit.getCreditBalance()); } @@ -216,16 +247,14 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { continue; } if (s_logger.isDebugEnabled()) { - s_logger.debug(account.getAccountName() + ", Entry=" + entry.getQuotaUsed().setScale(6, RoundingMode.HALF_EVEN).toString() + " SD=" + entry.getStartDate() + " ED=" - + entry.getEndDate()); + s_logger.debug("Entry=" + entry); } if (startDate.compareTo(entry.getStartDate()) != 0) { - if (s_logger.isDebugEnabled()) { - s_logger.debug( - "Saving Balance" + account.getAccountName() + ",Balance entry=" + aggrUsage.setScale(6, RoundingMode.HALF_EVEN).toString() + " on Date=" + endDate); - } QuotaBalanceVO newBalance = new QuotaBalanceVO(account.getAccountId(), account.getDomainId(), aggrUsage, endDate); _quotaBalanceDao.saveQuotaBalance(newBalance); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Saving Balance" + newBalance); + } //New balance entry aggrUsage = new BigDecimal(0); @@ -245,26 +274,34 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { } } if (s_logger.isDebugEnabled()) { - s_logger.debug( - "Getting Balance" + account.getAccountName() + ",Balance entry=" + aggrUsage.setScale(6, RoundingMode.HALF_EVEN).toString() + " on Date=" + endDate); + s_logger.debug("Getting Balance" + account.getAccountName() + ",Balance entry=" + aggrUsage + " on Date=" + endDate); } } aggrUsage = aggrUsage.subtract(entry.getQuotaUsed()); } + QuotaBalanceVO newBalance = new QuotaBalanceVO(account.getAccountId(), account.getDomainId(), aggrUsage, endDate); + _quotaBalanceDao.saveQuotaBalance(newBalance); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Saving Balance" + newBalance); + } // update quota_accounts QuotaAccountVO quota_account = _quotaAcc.findByIdQuotaAccount(account.getAccountId()); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Updating quota account bal=" + aggrUsage.setScale(6, RoundingMode.HALF_EVEN).toString() + " date=" + endDate); - } + if (quota_account == null) { quota_account = new QuotaAccountVO(account.getAccountId()); quota_account.setQuotaBalance(aggrUsage); quota_account.setQuotaBalanceDate(endDate); + if (s_logger.isDebugEnabled()) { + s_logger.debug(quota_account); + } _quotaAcc.persistQuotaAccount(quota_account); } else { quota_account.setQuotaBalance(aggrUsage); quota_account.setQuotaBalanceDate(endDate); + if (s_logger.isDebugEnabled()) { + s_logger.debug(quota_account); + } _quotaAcc.updateQuotaAccount(account.getAccountId(), quota_account); } } @@ -274,6 +311,9 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { List accounts = _accountDao.listAll(); for (AccountVO account : accounts) { Pair, Integer> usageRecords = _usageDao.getUsageRecordsPendingQuotaAggregation(account.getAccountId(), account.getDomainId()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Usage entries size = " + usageRecords.second().intValue() + ", accId" + account.getAccountId() + ", domId" + account.getDomainId()); + } List quotaListForAccount = aggregatePendingQuotaRecordsForAccount(account, usageRecords); if (s_logger.isDebugEnabled()) { s_logger.debug("Quota entries size = " + quotaListForAccount.size() + ", accId" + account.getAccountId() + ", domId" + account.getDomainId()); @@ -286,7 +326,7 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { public QuotaUsageVO updateQuotaDiskUsage(UsageVO usageRecord, final BigDecimal aggregationRatio, final int quotaType) { QuotaUsageVO quota_usage = null; QuotaTariffVO tariff = _quotaTariffDao.findTariffPlanByUsageType(quotaType, usageRecord.getEndDate()); - if (tariff != null && !tariff.getCurrencyValue().equals(0)) { + if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) { BigDecimal quotaUsgage; BigDecimal onehourcostpergb; BigDecimal noofgbinuse; @@ -313,7 +353,7 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { rawusage = new BigDecimal(usageRecord.getRawUsage()); QuotaTariffVO tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.CPU_NUMBER, usageRecord.getEndDate()); - if (tariff != null && !tariff.getCurrencyValue().equals(0)) { + if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) { BigDecimal cpu = new BigDecimal(serviceoffering.getCpu()); onehourcostpercpu = tariff.getCurrencyValue().multiply(aggregationRatio); cpuquotausgage = rawusage.multiply(onehourcostpercpu).multiply(cpu); @@ -323,7 +363,7 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { quotalist.add(quota_usage); } tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.CPU_CLOCK_RATE, usageRecord.getEndDate()); - if (tariff != null && !tariff.getCurrencyValue().equals(0)) { + if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) { BigDecimal speed = new BigDecimal(serviceoffering.getSpeed() / 100.00); onehourcostper100mhz = tariff.getCurrencyValue().multiply(aggregationRatio); speedquotausage = rawusage.multiply(onehourcostper100mhz).multiply(speed); @@ -333,7 +373,7 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { quotalist.add(quota_usage); } tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.MEMORY, usageRecord.getEndDate()); - if (tariff != null && !tariff.getCurrencyValue().equals(0)) { + if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) { BigDecimal memory = new BigDecimal(serviceoffering.getRamSize()); onehourcostper1mb = tariff.getCurrencyValue().multiply(aggregationRatio); memoryquotausage = rawusage.multiply(onehourcostper1mb).multiply(memory); @@ -343,7 +383,7 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { quotalist.add(quota_usage); } tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.RUNNING_VM, usageRecord.getEndDate()); - if (tariff != null && !tariff.getCurrencyValue().equals(0)) { + if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) { onehourcostforvmusage = tariff.getCurrencyValue().multiply(aggregationRatio); vmusage = rawusage.multiply(onehourcostforvmusage); quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), QuotaTypes.RUNNING_VM, vmusage, @@ -360,7 +400,7 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { public QuotaUsageVO updateQuotaAllocatedVMUsage(UsageVO usageRecord, final BigDecimal aggregationRatio) { QuotaUsageVO quota_usage = null; QuotaTariffVO tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.ALLOCATED_VM, usageRecord.getEndDate()); - if (tariff != null && !tariff.getCurrencyValue().equals(0)) { + if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) { BigDecimal vmusage; BigDecimal onehourcostforvmusage; onehourcostforvmusage = tariff.getCurrencyValue().multiply(aggregationRatio); @@ -378,7 +418,7 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { public QuotaUsageVO updateQuotaRaw(UsageVO usageRecord, final BigDecimal aggregationRatio, final int ruleType) { QuotaUsageVO quota_usage = null; QuotaTariffVO tariff = _quotaTariffDao.findTariffPlanByUsageType(ruleType, usageRecord.getEndDate()); - if (tariff != null && !tariff.getCurrencyValue().equals(0)) { + if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) { BigDecimal ruleusage; BigDecimal onehourcost; onehourcost = tariff.getCurrencyValue().multiply(aggregationRatio); @@ -396,7 +436,7 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { public QuotaUsageVO updateQuotaNetwork(UsageVO usageRecord, final int transferType) { QuotaUsageVO quota_usage = null; QuotaTariffVO tariff = _quotaTariffDao.findTariffPlanByUsageType(transferType, usageRecord.getEndDate()); - if (tariff != null && !tariff.getCurrencyValue().equals(0)) { + if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) { BigDecimal onegbcost; BigDecimal rawusageingb; BigDecimal networkusage; diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java index 4a075bca624..aa650e165ad 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java @@ -156,7 +156,7 @@ public class QuotaBalanceDaoImpl extends GenericDaoBase im // get records before startDate to find start balance for (QuotaBalanceVO entry : quotaUsageRecords) { if (s_logger.isDebugEnabled()) { - s_logger.debug("FindQuotaBalIance Date=" + entry.getUpdatedOn().toGMTString() + " balance=" + entry.getCreditBalance() + " credit=" + entry.getCreditsId()); + s_logger.debug("FindQuotaBalIance Entry=" + entry); } if (entry.getCreditsId() > 0) { trimmedRecords.add(entry); @@ -179,7 +179,7 @@ public class QuotaBalanceDaoImpl extends GenericDaoBase im } for (QuotaBalanceVO entry : quotaBalance) { if (s_logger.isDebugEnabled()) { - s_logger.debug("lastQuotaBalance Date=" + entry.getUpdatedOn().toGMTString() + " balance=" + entry.getCreditBalance() + " credit=" + entry.getCreditsId()); + s_logger.debug("lastQuotaBalance Entry=" + entry); } finalBalance = finalBalance.add(entry.getCreditBalance()); } diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaAccountVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaAccountVO.java index fc1270f724c..20c2dc2bd82 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaAccountVO.java +++ b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaAccountVO.java @@ -139,4 +139,11 @@ public class QuotaAccountVO implements InternalIdentity { this.lastStatementDate = lastStatementDate; } + @Override + public String toString() { + return "QuotaAccountVO [accountId=" + accountId + ", quotaEnforce=" + quotaEnforce + ", quotaBalance=" + quotaBalance + ", quotaBalanceDate=" + quotaBalanceDate + + ", quotaMinBalance=" + quotaMinBalance + ", quotaAlertType=" + quotaAlertType + ", quotaAlertDate=" + quotaAlertDate + ", lastStatementDate=" + lastStatementDate + + "]"; + } + } diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaBalanceVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaBalanceVO.java index f88e4d7c247..c60163e83f2 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaBalanceVO.java +++ b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaBalanceVO.java @@ -71,7 +71,7 @@ public class QuotaBalanceVO implements InternalIdentity { this.accountId = accountId; this.domainId = domainId; this.creditBalance = creditBalance; - this.creditsId=0L; + this.creditsId = 0L; this.updatedOn = updatedOn; } @@ -123,4 +123,11 @@ public class QuotaBalanceVO implements InternalIdentity { public void setUpdatedOn(Date updatedOn) { this.updatedOn = updatedOn; } + + @Override + public String toString() { + return "QuotaBalanceVO [id=" + id + ", accountId=" + accountId + ", domainId=" + domainId + ", creditBalance=" + creditBalance + ", creditsId=" + creditsId + ", updatedOn=" + + updatedOn + "]"; + } + } diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaUsageVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaUsageVO.java index b5199e16319..f0b65ef2c35 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaUsageVO.java +++ b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaUsageVO.java @@ -65,13 +65,13 @@ public class QuotaUsageVO implements InternalIdentity { private Date endDate = null; public QuotaUsageVO() { - usageType=-1; + usageType = -1; quotaUsed = new BigDecimal(0); - endDate = new Date(); + endDate = new Date(); startDate = new Date(); } - public QuotaUsageVO(Long usageItemId, Long zoneId, Long accountId, Long domainId, int usageType, BigDecimal quotaUsed, Date startDate, Date endDate) { + public QuotaUsageVO(Long usageItemId, Long zoneId, Long accountId, Long domainId, int usageType, BigDecimal quotaUsed, Date startDate, Date endDate) { super(); this.usageItemId = usageItemId; this.zoneId = zoneId; @@ -168,4 +168,10 @@ public class QuotaUsageVO implements InternalIdentity { this.id = id; } + @Override + public String toString() { + return "QuotaUsageVO [id=" + id + ", zoneId=" + zoneId + ", accountId=" + accountId + ", domainId=" + domainId + ", usageItemId=" + usageItemId + ", usageType=" + usageType + + ", quotaUsed=" + quotaUsed + ", startDate=" + startDate + ", endDate=" + endDate + "]"; + } + } diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java index 78365ee5d14..23b136363c1 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java @@ -66,6 +66,7 @@ import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.ListIterator; @Component @Local(value = QuotaResponseBuilderImpl.class) @@ -181,6 +182,33 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder { } }); + boolean have_balance_entries = false; + //check that there is at least one balance entry + for (Iterator it = quotaBalance.iterator(); it.hasNext();) { + QuotaBalanceVO entry = it.next(); + if (entry.getCreditsId() > 0) { + have_balance_entries = true; + break; + } + } + //if last entry is a credit deposit then remove that as that is already + //accounted for in the starting balance after that entry, note the sort is desc + if (have_balance_entries) { + ListIterator li = quotaBalance.listIterator(quotaBalance.size()); + // Iterate in reverse. + while (li.hasPrevious()) { + QuotaBalanceVO entry = li.previous(); + if (s_logger.isDebugEnabled()) { + s_logger.debug("createQuotaBalanceResponse: Entry=" + entry); + } + if (entry.getCreditsId() > 0) { + li.remove(); + } else { + break; + } + } + } + int quota_activity = quotaBalance.size(); QuotaBalanceResponse resp = new QuotaBalanceResponse(); BigDecimal lastCredits = new BigDecimal(0); @@ -188,8 +216,7 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder { for (Iterator it = quotaBalance.iterator(); it.hasNext();) { QuotaBalanceVO entry = it.next(); if (s_logger.isDebugEnabled()) { - s_logger.debug( - "createQuotaBalanceResponse: Date=" + entry.getUpdatedOn().toGMTString() + " balance=" + entry.getCreditBalance() + " credit=" + entry.getCreditsId()); + s_logger.debug("createQuotaBalanceResponse: All Credit Entry=" + entry); } if (entry.getCreditsId() > 0) { if (consecutive) { @@ -206,9 +233,13 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder { // order is desc last item is the start item QuotaBalanceVO startItem = quotaBalance.get(quotaBalance.size() - 1); QuotaBalanceVO endItem = quotaBalance.get(0); - resp.setStartDate(startDate); + resp.setStartDate(startItem.getUpdatedOn()); resp.setStartQuota(startItem.getCreditBalance()); - resp.setEndDate(endDate); + resp.setEndDate(endItem.getUpdatedOn()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("createQuotaBalanceResponse: Start Entry=" + startItem); + s_logger.debug("createQuotaBalanceResponse: End Entry=" + endItem); + } resp.setEndQuota(endItem.getCreditBalance().add(lastCredits)); } else if (quota_activity > 0) { // order is desc last item is the start item