You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by re...@apache.org on 2015/12/07 19:25:36 UTC

[6/8] git commit: updated refs/heads/master to 24d0609

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/987fcbd4/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java
----------------------------------------------------------------------
diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java
new file mode 100644
index 0000000..d7c301e
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java
@@ -0,0 +1,464 @@
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements.  See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership.  The ASF 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 org.apache.cloudstack.quota;
+
+import com.cloud.usage.UsageVO;
+import com.cloud.usage.dao.UsageDao;
+import com.cloud.user.AccountVO;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.Pair;
+import com.cloud.utils.component.ManagerBase;
+
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.quota.constant.QuotaTypes;
+import org.apache.cloudstack.quota.dao.QuotaAccountDao;
+import org.apache.cloudstack.quota.dao.QuotaBalanceDao;
+import org.apache.cloudstack.quota.dao.QuotaTariffDao;
+import org.apache.cloudstack.quota.dao.QuotaUsageDao;
+import org.apache.cloudstack.quota.dao.ServiceOfferingDao;
+import org.apache.cloudstack.quota.vo.QuotaAccountVO;
+import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
+import org.apache.cloudstack.quota.vo.QuotaTariffVO;
+import org.apache.cloudstack.quota.vo.QuotaUsageVO;
+import org.apache.cloudstack.quota.vo.ServiceOfferingVO;
+import org.apache.cloudstack.utils.usage.UsageUtils;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+
+@Component
+@Local(value = QuotaManager.class)
+public class QuotaManagerImpl extends ManagerBase implements QuotaManager {
+    private static final Logger s_logger = Logger.getLogger(QuotaManagerImpl.class.getName());
+
+    @Inject
+    private AccountDao _accountDao;
+    @Inject
+    private QuotaAccountDao _quotaAcc;
+    @Inject
+    private UsageDao _usageDao;
+    @Inject
+    private QuotaTariffDao _quotaTariffDao;
+    @Inject
+    private QuotaUsageDao _quotaUsageDao;
+    @Inject
+    private ServiceOfferingDao _serviceOfferingDao;
+    @Inject
+    private QuotaBalanceDao _quotaBalanceDao;
+    @Inject
+    private ConfigurationDao _configDao;
+
+    private TimeZone _usageTimezone;
+    private int _aggregationDuration = 0;
+
+    final static BigDecimal s_hoursInMonth = new BigDecimal(30 * 24);
+    final static BigDecimal s_minutesInMonth = new BigDecimal(30 * 24 * 60);
+    final static BigDecimal s_gb = new BigDecimal(1024 * 1024 * 1024);
+
+    public QuotaManagerImpl() {
+        super();
+    }
+
+    private void mergeConfigs(Map<String, String> dbParams, Map<String, Object> xmlParams) {
+        for (Map.Entry<String, Object> param : xmlParams.entrySet()) {
+            dbParams.put(param.getKey(), (String)param.getValue());
+        }
+    }
+
+    @Override
+    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+        super.configure(name, params);
+
+        Map<String, String> configs = _configDao.getConfiguration(params);
+
+        if (params != null) {
+            mergeConfigs(configs, params);
+        }
+
+        String aggregationRange = configs.get("usage.stats.job.aggregation.range");
+        String timeZoneStr = configs.get("usage.aggregation.timezone");
+
+        if (timeZoneStr == null) {
+            timeZoneStr = "GMT";
+        }
+        _usageTimezone = TimeZone.getTimeZone(timeZoneStr);
+
+        _aggregationDuration = Integer.parseInt(aggregationRange);
+        if (_aggregationDuration < UsageUtils.USAGE_AGGREGATION_RANGE_MIN) {
+            s_logger.warn("Usage stats job aggregation range is to small, using the minimum value of " + UsageUtils.USAGE_AGGREGATION_RANGE_MIN);
+            _aggregationDuration = UsageUtils.USAGE_AGGREGATION_RANGE_MIN;
+        }
+        s_logger.info("Usage timezone = " + _usageTimezone + " AggregationDuration=" + _aggregationDuration);
+
+        return true;
+    }
+
+    @Override
+    public boolean start() {
+        if (s_logger.isInfoEnabled()) {
+            s_logger.info("Starting Quota Manager");
+        }
+        return true;
+    }
+
+    @Override
+    public boolean stop() {
+        if (s_logger.isInfoEnabled()) {
+            s_logger.info("Stopping Quota Manager");
+        }
+        return true;
+    }
+
+    public List<QuotaUsageVO> aggregatePendingQuotaRecordsForAccount(final AccountVO account, final Pair<List<? extends UsageVO>, Integer> usageRecords) {
+        List<QuotaUsageVO> quotaListForAccount = new ArrayList<>();
+        if (usageRecords == null || usageRecords.first() == null || usageRecords.first().isEmpty()) {
+            return quotaListForAccount;
+        }
+        s_logger.info("Getting pending quota records for account=" + account.getAccountName());
+        for (UsageVO usageRecord : usageRecords.first()) {
+            BigDecimal aggregationRatio = new BigDecimal(_aggregationDuration).divide(s_minutesInMonth, 8, RoundingMode.HALF_EVEN);
+            switch (usageRecord.getUsageType()) {
+            case QuotaTypes.RUNNING_VM:
+                List<QuotaUsageVO> lq = updateQuotaRunningVMUsage(usageRecord, aggregationRatio);
+                if (!lq.isEmpty()) {
+                    quotaListForAccount.addAll(lq);
+                }
+                break;
+            case QuotaTypes.ALLOCATED_VM:
+                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:
+                qu = updateQuotaDiskUsage(usageRecord, aggregationRatio, usageRecord.getUsageType());
+                if (qu != null) {
+                    quotaListForAccount.add(qu);
+                }
+                break;
+            case QuotaTypes.LOAD_BALANCER_POLICY:
+            case QuotaTypes.PORT_FORWARDING_RULE:
+            case QuotaTypes.IP_ADDRESS:
+            case QuotaTypes.NETWORK_OFFERING:
+            case QuotaTypes.SECURITY_GROUP:
+            case QuotaTypes.VPN_USERS:
+                qu = updateQuotaRaw(usageRecord, aggregationRatio, usageRecord.getUsageType());
+                if (qu != null) {
+                    quotaListForAccount.add(qu);
+                }
+                break;
+            case QuotaTypes.NETWORK_BYTES_RECEIVED:
+            case QuotaTypes.NETWORK_BYTES_SENT:
+                qu = updateQuotaNetwork(usageRecord, usageRecord.getUsageType());
+                if (qu != null) {
+                    quotaListForAccount.add(qu);
+                }
+                break;
+            case QuotaTypes.VM_DISK_IO_READ:
+            case QuotaTypes.VM_DISK_IO_WRITE:
+            case QuotaTypes.VM_DISK_BYTES_READ:
+            case QuotaTypes.VM_DISK_BYTES_WRITE:
+            default:
+                break;
+            }
+        }
+        return quotaListForAccount;
+    }
+
+    public void processQuotaBalanceForAccount(final AccountVO account, final List<QuotaUsageVO> quotaListForAccount) {
+        if (quotaListForAccount == null || quotaListForAccount.isEmpty()) {
+            return;
+        }
+        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<QuotaBalanceVO> creditsReceived = null;
+
+        //bootstrapping
+        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 " + 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);
+        }
+        else {
+            QuotaBalanceVO lastRealBalanceEntry = _quotaBalanceDao.findLastBalanceEntry(account.getAccountId(), account.getDomainId(), endDate);
+            aggrUsage = aggrUsage.add(lastRealBalanceEntry.getCreditBalance());
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("Last balance entry  " + lastRealBalanceEntry + " AggrUsage=" + aggrUsage);
+            }
+        }
+
+        for (QuotaUsageVO entry : quotaListForAccount) {
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("Usage entry found " + entry);
+            }
+            if (entry.getQuotaUsed().compareTo(BigDecimal.ZERO) == 0) {
+                // check if there were credits
+                creditsReceived = _quotaBalanceDao.findCreditBalance(account.getAccountId(), account.getDomainId(), entry.getStartDate(), entry.getEndDate());
+                if (creditsReceived != null) {
+                    for (QuotaBalanceVO credit : creditsReceived) {
+                        if (s_logger.isDebugEnabled()) {
+                            s_logger.debug("Credit entry found " + credit);
+                            s_logger.debug("Total = " + aggrUsage);
+                        }
+                        aggrUsage = aggrUsage.add(credit.getCreditBalance());
+                    }
+                }
+                continue;
+            }
+            if (startDate.compareTo(entry.getStartDate()) != 0) {
+                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);
+                startDate = entry.getStartDate();
+                endDate = entry.getEndDate();
+
+                QuotaBalanceVO lastRealBalanceEntry = _quotaBalanceDao.findLastBalanceEntry(account.getAccountId(), account.getDomainId(), endDate);
+                Date lastBalanceDate = new Date(0);
+                if (lastRealBalanceEntry != null) {
+                    lastBalanceDate = lastRealBalanceEntry.getUpdatedOn();
+                    aggrUsage = aggrUsage.add(lastRealBalanceEntry.getCreditBalance());
+                }
+                creditsReceived = _quotaBalanceDao.findCreditBalance(account.getAccountId(), account.getDomainId(), lastBalanceDate, endDate);
+                if (creditsReceived != null) {
+                    for (QuotaBalanceVO credit : creditsReceived) {
+                        aggrUsage = aggrUsage.add(credit.getCreditBalance());
+                    }
+                }
+                if (s_logger.isDebugEnabled()) {
+                    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 (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);
+        }
+    }
+
+    @Override
+    public boolean calculateQuotaUsage() {
+        List<AccountVO> accounts = _accountDao.listAll();
+        for (AccountVO account : accounts) {
+            Pair<List<? extends UsageVO>, 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<QuotaUsageVO> quotaListForAccount = aggregatePendingQuotaRecordsForAccount(account, usageRecords);
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("Quota entries size = " + quotaListForAccount.size() + ", accId" + account.getAccountId() + ", domId" + account.getDomainId());
+            }
+            processQuotaBalanceForAccount(account, quotaListForAccount);
+        }
+        return true;
+    }
+
+    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().compareTo(BigDecimal.ZERO) != 0) {
+            BigDecimal quotaUsgage;
+            BigDecimal onehourcostpergb;
+            BigDecimal noofgbinuse;
+            onehourcostpergb = tariff.getCurrencyValue().multiply(aggregationRatio);
+            noofgbinuse = new BigDecimal(usageRecord.getSize()).divide(s_gb, 8, RoundingMode.HALF_EVEN);
+            quotaUsgage = new BigDecimal(usageRecord.getRawUsage()).multiply(onehourcostpergb).multiply(noofgbinuse);
+            quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), usageRecord.getUsageType(),
+                    quotaUsgage, usageRecord.getStartDate(), usageRecord.getEndDate());
+            _quotaUsageDao.persistQuotaUsage(quota_usage);
+        }
+        usageRecord.setQuotaCalculated(1);
+        _usageDao.persistUsage(usageRecord);
+        return quota_usage;
+    }
+
+    public List<QuotaUsageVO> updateQuotaRunningVMUsage(UsageVO usageRecord, final BigDecimal aggregationRatio) {
+        List<QuotaUsageVO> quotalist = new ArrayList<QuotaUsageVO>();
+        QuotaUsageVO quota_usage;
+        BigDecimal cpuquotausgage, speedquotausage, memoryquotausage, vmusage;
+        BigDecimal onehourcostpercpu, onehourcostper100mhz, onehourcostper1mb, onehourcostforvmusage;
+        BigDecimal rawusage;
+        // get service offering details
+        ServiceOfferingVO serviceoffering = _serviceOfferingDao.findServiceOffering(usageRecord.getVmInstanceId(), usageRecord.getOfferingId());
+        rawusage = new BigDecimal(usageRecord.getRawUsage());
+
+        QuotaTariffVO tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.CPU_NUMBER, usageRecord.getEndDate());
+        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);
+            quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), QuotaTypes.CPU_NUMBER,
+                    cpuquotausgage, usageRecord.getStartDate(), usageRecord.getEndDate());
+            _quotaUsageDao.persistQuotaUsage(quota_usage);
+            quotalist.add(quota_usage);
+        }
+        tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.CPU_CLOCK_RATE, usageRecord.getEndDate());
+        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);
+            quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), QuotaTypes.CPU_CLOCK_RATE,
+                    speedquotausage, usageRecord.getStartDate(), usageRecord.getEndDate());
+            _quotaUsageDao.persistQuotaUsage(quota_usage);
+            quotalist.add(quota_usage);
+        }
+        tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.MEMORY, usageRecord.getEndDate());
+        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);
+            quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), QuotaTypes.MEMORY, memoryquotausage,
+                    usageRecord.getStartDate(), usageRecord.getEndDate());
+            _quotaUsageDao.persistQuotaUsage(quota_usage);
+            quotalist.add(quota_usage);
+        }
+        tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.RUNNING_VM, usageRecord.getEndDate());
+        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,
+                    usageRecord.getStartDate(), usageRecord.getEndDate());
+            _quotaUsageDao.persistQuotaUsage(quota_usage);
+            quotalist.add(quota_usage);
+        }
+
+        usageRecord.setQuotaCalculated(1);
+        _usageDao.persistUsage(usageRecord);
+        return quotalist;
+    }
+
+    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().compareTo(BigDecimal.ZERO) != 0) {
+            BigDecimal vmusage;
+            BigDecimal onehourcostforvmusage;
+            onehourcostforvmusage = tariff.getCurrencyValue().multiply(aggregationRatio);
+            vmusage = new BigDecimal(usageRecord.getRawUsage()).multiply(onehourcostforvmusage);
+            quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), QuotaTypes.ALLOCATED_VM, vmusage,
+                    usageRecord.getStartDate(), usageRecord.getEndDate());
+            _quotaUsageDao.persistQuotaUsage(quota_usage);
+        }
+
+        usageRecord.setQuotaCalculated(1);
+        _usageDao.persistUsage(usageRecord);
+        return quota_usage;
+    }
+
+    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().compareTo(BigDecimal.ZERO) != 0) {
+            BigDecimal ruleusage;
+            BigDecimal onehourcost;
+            onehourcost = tariff.getCurrencyValue().multiply(aggregationRatio);
+            ruleusage = new BigDecimal(usageRecord.getRawUsage()).multiply(onehourcost);
+            quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), ruleType, ruleusage,
+                    usageRecord.getStartDate(), usageRecord.getEndDate());
+            _quotaUsageDao.persistQuotaUsage(quota_usage);
+        }
+
+        usageRecord.setQuotaCalculated(1);
+        _usageDao.persistUsage(usageRecord);
+        return quota_usage;
+    }
+
+    public QuotaUsageVO updateQuotaNetwork(UsageVO usageRecord, final int transferType) {
+        QuotaUsageVO quota_usage = null;
+        QuotaTariffVO tariff = _quotaTariffDao.findTariffPlanByUsageType(transferType, usageRecord.getEndDate());
+        if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) {
+            BigDecimal onegbcost;
+            BigDecimal rawusageingb;
+            BigDecimal networkusage;
+            onegbcost = tariff.getCurrencyValue();
+            rawusageingb = new BigDecimal(usageRecord.getRawUsage()).divide(s_gb, 8, RoundingMode.HALF_EVEN);
+            networkusage = rawusageingb.multiply(onegbcost);
+            quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), transferType, networkusage,
+                    usageRecord.getStartDate(), usageRecord.getEndDate());
+            _quotaUsageDao.persistQuotaUsage(quota_usage);
+        }
+
+        usageRecord.setQuotaCalculated(1);
+        _usageDao.persistUsage(usageRecord);
+        return quota_usage;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/987fcbd4/framework/quota/src/org/apache/cloudstack/quota/QuotaStatement.java
----------------------------------------------------------------------
diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaStatement.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaStatement.java
new file mode 100644
index 0000000..e6f5e25
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/QuotaStatement.java
@@ -0,0 +1,26 @@
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements.  See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership.  The ASF licenses this file
+//to you under the Apache License, Version 2.0 (the
+//"License"); you may not use this file except in compliance
+//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 org.apache.cloudstack.quota;
+
+import java.util.Calendar;
+
+import com.cloud.utils.component.Manager;
+
+public interface QuotaStatement extends Manager {
+    void sendStatement();
+    Calendar[] getCurrentStatementTime();
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/987fcbd4/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java
----------------------------------------------------------------------
diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java
new file mode 100644
index 0000000..682b2ef
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java
@@ -0,0 +1,376 @@
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements.  See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership.  The ASF 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 org.apache.cloudstack.quota;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.quota.QuotaAlertManagerImpl.DeferredQuotaEmail;
+import org.apache.cloudstack.quota.constant.QuotaConfig;
+import org.apache.cloudstack.quota.dao.QuotaAccountDao;
+import org.apache.cloudstack.quota.dao.QuotaUsageDao;
+import org.apache.cloudstack.quota.vo.QuotaAccountVO;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+import com.cloud.user.AccountVO;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.component.ManagerBase;
+
+@Component
+@Local(value = QuotaStatement.class)
+public class QuotaStatementImpl extends ManagerBase implements QuotaStatement {
+    private static final Logger s_logger = Logger.getLogger(QuotaStatementImpl.class);
+
+    @Inject
+    private AccountDao _accountDao;
+    @Inject
+    private QuotaAccountDao _quotaAcc;
+    @Inject
+    private QuotaUsageDao _quotaUsage;
+    @Inject
+    private QuotaAlertManager _quotaAlert;
+    @Inject
+    private ConfigurationDao _configDao;
+
+    final public static int s_LAST_STATEMENT_SENT_DAYS = 6; //ideally should be less than 7 days
+
+    public enum STATEMENT_PERIODS {
+        BIMONTHLY, MONTHLY, QUATERLY, HALFYEARLY, YEARLY
+    };
+
+    private STATEMENT_PERIODS _period = STATEMENT_PERIODS.MONTHLY;
+
+    public QuotaStatementImpl() {
+        super();
+    }
+
+    private void mergeConfigs(Map<String, String> dbParams, Map<String, Object> xmlParams) {
+        for (Map.Entry<String, Object> param : xmlParams.entrySet()) {
+            dbParams.put(param.getKey(), (String)param.getValue());
+        }
+    }
+
+    @Override
+    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+        super.configure(name, params);
+
+        Map<String, String> configs = _configDao.getConfiguration(params);
+
+        if (params != null) {
+            mergeConfigs(configs, params);
+        }
+        String period_str = configs.get(QuotaConfig.QuotaStatementPeriod.key());
+        int period = period_str == null ? 1 : Integer.valueOf(period_str);
+
+        STATEMENT_PERIODS _period = STATEMENT_PERIODS.values()[period];
+        return true;
+    }
+
+    @Override
+    public boolean start() {
+        if (s_logger.isInfoEnabled()) {
+            s_logger.info("Starting Statement Manager");
+        }
+        return true;
+    }
+
+    @Override
+    public boolean stop() {
+        if (s_logger.isInfoEnabled()) {
+            s_logger.info("Stopping Statement Manager");
+        }
+        return true;
+    }
+
+    @Override
+    public void sendStatement() {
+
+        List<DeferredQuotaEmail> deferredQuotaEmailList = new ArrayList<DeferredQuotaEmail>();
+        for (final QuotaAccountVO quotaAccount : _quotaAcc.listAllQuotaAccount()) {
+            if (quotaAccount.getQuotaBalance() == null) {
+                continue; // no quota usage for this account ever, ignore
+            }
+
+            //check if it is statement time
+            Calendar interval[] = statementTime(Calendar.getInstance(), _period);
+
+            Date lastStatementDate = quotaAccount.getLastStatementDate();
+            if (interval != null) {
+                AccountVO account = _accountDao.findById(quotaAccount.getId());
+                if (lastStatementDate == null || getDifferenceDays(lastStatementDate, new Date()) >= s_LAST_STATEMENT_SENT_DAYS + 1) {
+                    BigDecimal quotaUsage = _quotaUsage.findTotalQuotaUsage(account.getAccountId(), account.getDomainId(), null, interval[0].getTime(), interval[1].getTime());
+                    s_logger.info("For account=" + quotaAccount.getId() + ", quota used = " + quotaUsage);
+                    // send statement
+                    deferredQuotaEmailList.add(new DeferredQuotaEmail(account, quotaAccount, quotaUsage, QuotaConfig.QuotaEmailTemplateTypes.QUOTA_STATEMENT));
+                } else {
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.debug("For " + quotaAccount.getId() + " the statement has been sent recently");
+
+                    }
+                }
+            } else if (lastStatementDate != null) {
+                s_logger.info("For " + quotaAccount.getId() + " it is already more than " + getDifferenceDays(lastStatementDate, new Date())
+                        + " days, will send statement in next cycle");
+            }
+        }
+
+        for (DeferredQuotaEmail emailToBeSent : deferredQuotaEmailList) {
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("Attempting to send quota STATEMENT email to users of account: " + emailToBeSent.getAccount().getAccountName());
+            }
+            _quotaAlert.sendQuotaAlert(emailToBeSent);
+        }
+    }
+
+    @Override
+    public Calendar[] getCurrentStatementTime() {
+        final Calendar today = Calendar.getInstance();
+        int day_of_month = today.get(Calendar.DAY_OF_MONTH);
+        int month_of_year = today.get(Calendar.MONTH);
+
+        Calendar firstDateOfCurrentPeriod, lastDateOfCurrentPeriod;
+        Calendar aCalendar = (Calendar)today.clone();
+        aCalendar.add(Calendar.DATE, 1);
+        aCalendar.set(Calendar.HOUR, 0);
+        aCalendar.set(Calendar.MINUTE, 0);
+        aCalendar.set(Calendar.SECOND, 0);
+        lastDateOfCurrentPeriod = aCalendar;
+
+        switch (_period) {
+        case BIMONTHLY:
+            if (day_of_month < 16) {
+                aCalendar = (Calendar)today.clone();
+                aCalendar.add(Calendar.MONTH, 0);
+                aCalendar.set(Calendar.DATE, 1);
+                aCalendar.set(Calendar.HOUR, 0);
+                aCalendar.set(Calendar.MINUTE, 0);
+                aCalendar.set(Calendar.SECOND, 0);
+                firstDateOfCurrentPeriod = aCalendar;
+                return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
+            } else {
+                aCalendar = (Calendar)today.clone();
+                aCalendar.set(Calendar.DATE, 16);
+                aCalendar.set(Calendar.HOUR, 0);
+                aCalendar.set(Calendar.MINUTE, 0);
+                aCalendar.set(Calendar.SECOND, 0);
+                firstDateOfCurrentPeriod = aCalendar;
+                return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
+            }
+        case MONTHLY:
+            aCalendar = (Calendar)today.clone();
+            aCalendar.set(Calendar.DATE, 1);
+            aCalendar.set(Calendar.HOUR, 0);
+            aCalendar.set(Calendar.MINUTE, 0);
+            aCalendar.set(Calendar.SECOND, 0);
+            firstDateOfCurrentPeriod = aCalendar;
+            return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
+        case QUATERLY:
+            if (month_of_year < Calendar.APRIL) {
+                aCalendar = (Calendar)today.clone();
+                aCalendar.set(Calendar.MONTH, Calendar.JANUARY);
+                aCalendar.set(Calendar.DATE, 1);
+                aCalendar.set(Calendar.HOUR, 0);
+                aCalendar.set(Calendar.MINUTE, 0);
+                aCalendar.set(Calendar.SECOND, 0);
+                firstDateOfCurrentPeriod = aCalendar;
+                return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
+            } else if (month_of_year < Calendar.JULY) {
+                aCalendar = (Calendar)today.clone();
+                aCalendar.set(Calendar.MONTH, Calendar.APRIL);
+                aCalendar.set(Calendar.DATE, 1);
+                aCalendar.set(Calendar.HOUR, 0);
+                aCalendar.set(Calendar.MINUTE, 0);
+                aCalendar.set(Calendar.SECOND, 0);
+                firstDateOfCurrentPeriod = aCalendar;
+                return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
+            } else if (month_of_year < Calendar.OCTOBER) {
+                aCalendar = (Calendar)today.clone();
+                aCalendar.set(Calendar.MONTH, Calendar.JULY);
+                aCalendar.set(Calendar.DATE, 1);
+                aCalendar.set(Calendar.HOUR, 0);
+                aCalendar.set(Calendar.MINUTE, 0);
+                aCalendar.set(Calendar.SECOND, 0);
+                firstDateOfCurrentPeriod = aCalendar;
+                return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
+            } else {
+                aCalendar = (Calendar)today.clone();
+                aCalendar.set(Calendar.MONTH, Calendar.OCTOBER);
+                aCalendar.set(Calendar.DATE, 1);
+                aCalendar.set(Calendar.HOUR, 0);
+                aCalendar.set(Calendar.MINUTE, 0);
+                aCalendar.set(Calendar.SECOND, 0);
+                firstDateOfCurrentPeriod = aCalendar;
+                return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
+            }
+        case HALFYEARLY:
+            // statements are sent in Jan=1, Jul 7,
+            if (month_of_year < Calendar.JULY) {
+                aCalendar = (Calendar)today.clone();
+                aCalendar.set(Calendar.MONTH, Calendar.JANUARY);
+                aCalendar.set(Calendar.DATE, 1);
+                aCalendar.set(Calendar.HOUR, 0);
+                aCalendar.set(Calendar.MINUTE, 0);
+                aCalendar.set(Calendar.SECOND, 0);
+                firstDateOfCurrentPeriod = aCalendar;
+                return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
+            } else {
+                aCalendar = (Calendar)today.clone();
+                aCalendar.set(Calendar.MONTH, Calendar.JULY);
+                aCalendar.set(Calendar.DATE, 1);
+                aCalendar.set(Calendar.HOUR, 0);
+                aCalendar.set(Calendar.MINUTE, 0);
+                aCalendar.set(Calendar.SECOND, 0);
+                firstDateOfCurrentPeriod = aCalendar;
+                return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
+            }
+        case YEARLY:
+            aCalendar = (Calendar)today.clone();
+            aCalendar.add(Calendar.MONTH, Calendar.JANUARY);
+            aCalendar.set(Calendar.DATE, 1);
+            aCalendar.set(Calendar.HOUR, 0);
+            aCalendar.set(Calendar.MINUTE, 0);
+            aCalendar.set(Calendar.SECOND, 0);
+            firstDateOfCurrentPeriod = aCalendar;
+            return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
+        default:
+            break;
+        }
+        return null;
+    }
+
+    public Calendar[] statementTime(final Calendar today, final STATEMENT_PERIODS period) {
+        //check if it is statement time
+        int day_of_month = today.get(Calendar.DAY_OF_MONTH);
+        int month_of_year = today.get(Calendar.MONTH);
+        Calendar firstDateOfPreviousPeriod, lastDateOfPreviousPeriod;
+        switch (period) {
+        case BIMONTHLY:
+            if (day_of_month < s_LAST_STATEMENT_SENT_DAYS) {
+                Calendar aCalendar = (Calendar)today.clone();
+                aCalendar.add(Calendar.MONTH, 0);
+                aCalendar.set(Calendar.DATE, 1);
+                aCalendar.set(Calendar.HOUR, 0);
+                aCalendar.set(Calendar.MINUTE, 0);
+                aCalendar.set(Calendar.SECOND, 0);
+                firstDateOfPreviousPeriod = (Calendar)aCalendar.clone();
+                aCalendar.set(Calendar.DATE, 15);
+                lastDateOfPreviousPeriod = (Calendar)aCalendar.clone();
+                return new Calendar[] {firstDateOfPreviousPeriod, lastDateOfPreviousPeriod};
+            } else if (day_of_month > 15 && (day_of_month - 15) < s_LAST_STATEMENT_SENT_DAYS) {
+                Calendar aCalendar = (Calendar)today.clone();
+                aCalendar.add(Calendar.MONTH, -1);
+                aCalendar.set(Calendar.DATE, 16);
+                aCalendar.set(Calendar.HOUR, 0);
+                aCalendar.set(Calendar.MINUTE, 0);
+                aCalendar.set(Calendar.SECOND, 0);
+                firstDateOfPreviousPeriod = (Calendar)aCalendar.clone();
+                aCalendar.set(Calendar.DATE, aCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) + 1);
+                lastDateOfPreviousPeriod = (Calendar)aCalendar.clone();
+                return new Calendar[] {firstDateOfPreviousPeriod, lastDateOfPreviousPeriod};
+            }
+            return null;
+        case MONTHLY:
+            if (day_of_month < s_LAST_STATEMENT_SENT_DAYS) {
+                Calendar aCalendar = (Calendar)today.clone();
+                aCalendar.add(Calendar.MONTH, -1);
+                aCalendar.set(Calendar.DATE, 1);
+                aCalendar.set(Calendar.HOUR, 0);
+                aCalendar.set(Calendar.MINUTE, 0);
+                aCalendar.set(Calendar.SECOND, 0);
+                firstDateOfPreviousPeriod = (Calendar)aCalendar.clone();
+                aCalendar.set(Calendar.DATE, aCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) + 1);
+                lastDateOfPreviousPeriod = (Calendar)aCalendar.clone();
+                return new Calendar[] {firstDateOfPreviousPeriod, lastDateOfPreviousPeriod};
+            }
+            return null;
+        case QUATERLY:
+            // statements are sent in Jan=1, Apr 4, Jul 7, Oct 10
+            if (month_of_year == Calendar.JANUARY || month_of_year == Calendar.APRIL || month_of_year == Calendar.JULY || month_of_year == Calendar.OCTOBER) {
+                if (day_of_month < s_LAST_STATEMENT_SENT_DAYS) {
+                    Calendar aCalendar = (Calendar)today.clone();
+                    aCalendar.add(Calendar.MONTH, -3);
+                    aCalendar.set(Calendar.DATE, 1);
+                    aCalendar.set(Calendar.HOUR, 0);
+                    aCalendar.set(Calendar.MINUTE, 0);
+                    aCalendar.set(Calendar.SECOND, 0);
+                    firstDateOfPreviousPeriod = (Calendar)aCalendar.clone();
+                    aCalendar.add(Calendar.MONTH, 2);
+                    aCalendar.set(Calendar.DATE, aCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) + 1);
+                    lastDateOfPreviousPeriod = (Calendar)aCalendar.clone();
+                    return new Calendar[] {firstDateOfPreviousPeriod, lastDateOfPreviousPeriod};
+                }
+            }
+            return null;
+        case HALFYEARLY:
+            // statements are sent in Jan=1, Jul 7,
+            if (month_of_year == Calendar.JANUARY || month_of_year == Calendar.JULY) {
+                if (day_of_month < s_LAST_STATEMENT_SENT_DAYS) {
+                    Calendar aCalendar = (Calendar)today.clone();
+                    aCalendar.add(Calendar.MONTH, -6);
+                    aCalendar.set(Calendar.DATE, 1);
+                    aCalendar.set(Calendar.HOUR, 0);
+                    aCalendar.set(Calendar.MINUTE, 0);
+                    aCalendar.set(Calendar.SECOND, 0);
+                    firstDateOfPreviousPeriod = (Calendar)aCalendar.clone();
+                    aCalendar.add(Calendar.MONTH, 5);
+                    aCalendar.set(Calendar.DATE, aCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) + 1);
+                    lastDateOfPreviousPeriod = (Calendar)aCalendar.clone();
+                    return new Calendar[] {firstDateOfPreviousPeriod, lastDateOfPreviousPeriod};
+                }
+            }
+            return null;
+        case YEARLY:
+            // statements are sent in Jan=1
+            if (month_of_year == Calendar.JANUARY) {
+                if (day_of_month < s_LAST_STATEMENT_SENT_DAYS) {
+                    Calendar aCalendar = (Calendar)today.clone();
+                    aCalendar.add(Calendar.MONTH, -12);
+                    aCalendar.set(Calendar.DATE, 1);
+                    aCalendar.set(Calendar.HOUR, 0);
+                    aCalendar.set(Calendar.MINUTE, 0);
+                    aCalendar.set(Calendar.SECOND, 0);
+                    firstDateOfPreviousPeriod = (Calendar)aCalendar.clone();
+                    aCalendar.add(Calendar.MONTH, 11);
+                    aCalendar.set(Calendar.DATE, aCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) + 1);
+                    lastDateOfPreviousPeriod = (Calendar)aCalendar.clone();
+                    return new Calendar[] {firstDateOfPreviousPeriod, lastDateOfPreviousPeriod};
+                }
+            }
+            return null;
+        default:
+            break;
+        }
+        return null;
+    }
+
+    public static long getDifferenceDays(Date d1, Date d2) {
+        long diff = d2.getTime() - d1.getTime();
+        return TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/987fcbd4/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaConfig.java
----------------------------------------------------------------------
diff --git a/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaConfig.java b/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaConfig.java
new file mode 100644
index 0000000..73c9a80
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaConfig.java
@@ -0,0 +1,57 @@
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements.  See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership.  The ASF 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 org.apache.cloudstack.quota.constant;
+
+import org.apache.cloudstack.framework.config.ConfigKey;
+
+public interface QuotaConfig {
+
+    public static final ConfigKey<Boolean> QuotaPluginEnabled = new ConfigKey<Boolean>("Advanced", Boolean.class, "quota.enable.service", "false",
+            "Indicates whether Quota plugin is enabled or not", true);
+
+    public static final ConfigKey<String> QuotaEnableEnforcement = new ConfigKey<String>("Advanced", String.class, "quota.enable.enforcement", "false",
+            "Enable the usage quota enforcement, i.e. on true when exceeding quota the respective account will be locked.", true);
+
+    public static final ConfigKey<String> QuotaCurrencySymbol = new ConfigKey<String>("Advanced", String.class, "quota.currency.symbol", "$",
+            "The symbol for the currency in use to measure usage.", true);
+
+    public static final ConfigKey<Integer> QuotaStatementPeriod = new ConfigKey<Integer>("Advanced", Integer.class, "quota.statement.period", "1",
+            "This variables define the statement generation interval. Values correspond to bimonthly=0, monthly=1, quarterly=2, half-yearly=3 and yearly=4.", true);
+
+    public static final ConfigKey<String> QuotaSmtpHost = new ConfigKey<String>("Advanced", String.class, "quota.usage.smtp.host", "", "Quota SMTP host for quota related emails",
+            true);
+
+    public static final ConfigKey<String> QuotaSmtpTimeout = new ConfigKey<String>("Advanced", String.class, "quota.usage.smtp.connection.timeout", "60",
+            "Quota SMTP server connection timeout duration", true);
+
+    public static final ConfigKey<String> QuotaSmtpUser = new ConfigKey<String>("Advanced", String.class, "quota.usage.smtp.user", "", "Quota SMTP server username", true);
+
+    public static final ConfigKey<String> QuotaSmtpPassword = new ConfigKey<String>("Advanced", String.class, "quota.usage.smtp.password", "", "Quota SMTP server password", true);
+
+    public static final ConfigKey<String> QuotaSmtpPort = new ConfigKey<String>("Advanced", String.class, "quota.usage.smtp.port", "", "Quota SMTP port", true);
+
+    public static final ConfigKey<String> QuotaSmtpAuthType = new ConfigKey<String>("Advanced", String.class, "quota.usage.smtp.useAuth", "",
+            "If true, use secure SMTP authentication when sending emails.", true);
+
+    public static final ConfigKey<String> QuotaSmtpSender = new ConfigKey<String>("Advanced", String.class, "quota.usage.smtp.sender", "",
+            "Sender of quota alert email (will be in the From header of the email)", true);
+
+    enum QuotaEmailTemplateTypes {
+        QUOTA_LOW, QUOTA_EMPTY, QUOTA_UNLOCK_ACCOUNT, QUOTA_STATEMENT
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/987fcbd4/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaTypes.java
----------------------------------------------------------------------
diff --git a/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaTypes.java b/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaTypes.java
new file mode 100644
index 0000000..36910f4
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaTypes.java
@@ -0,0 +1,103 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF 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 org.apache.cloudstack.quota.constant;
+
+import org.apache.cloudstack.usage.UsageTypes;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+public class QuotaTypes extends UsageTypes {
+    public static final int CPU_CLOCK_RATE = 15;
+    public static final int CPU_NUMBER = 16;
+    public static final int MEMORY = 17;
+
+    private final Integer quotaType;
+    private final String quotaName;
+    private final String quotaUnit;
+    private final String description;
+    private final String discriminator;
+    private final static Map<Integer, QuotaTypes> quotaTypeMap;
+
+    static {
+        final HashMap<Integer, QuotaTypes> quotaTypeList = new HashMap<Integer, QuotaTypes>();
+        quotaTypeList.put(RUNNING_VM, new QuotaTypes(RUNNING_VM, "RUNNING_VM", "Compute-Month", "Running Vm Usage"));
+        quotaTypeList.put(ALLOCATED_VM, new QuotaTypes(ALLOCATED_VM, "ALLOCATED_VM", "Compute-Month", "Allocated Vm Usage"));
+        quotaTypeList.put(IP_ADDRESS, new QuotaTypes(IP_ADDRESS, "IP_ADDRESS", "IP-Month", "IP Address Usage"));
+        quotaTypeList.put(NETWORK_BYTES_SENT, new QuotaTypes(NETWORK_BYTES_SENT, "NETWORK_BYTES_SENT", "GB", "Network Usage (Bytes Sent)"));
+        quotaTypeList.put(NETWORK_BYTES_RECEIVED, new QuotaTypes(NETWORK_BYTES_RECEIVED, "NETWORK_BYTES_RECEIVED", "GB", "Network Usage (Bytes Received)"));
+        quotaTypeList.put(VOLUME, new QuotaTypes(VOLUME, "VOLUME", "GB-Month", "Volume Usage"));
+        quotaTypeList.put(TEMPLATE, new QuotaTypes(TEMPLATE, "TEMPLATE", "GB-Month", "Template Usage"));
+        quotaTypeList.put(ISO, new QuotaTypes(ISO, "ISO", "GB-Month", "ISO Usage"));
+        quotaTypeList.put(SNAPSHOT, new QuotaTypes(SNAPSHOT, "SNAPSHOT", "GB-Month", "Snapshot Usage"));
+        quotaTypeList.put(SECURITY_GROUP, new QuotaTypes(SECURITY_GROUP, "SECURITY_GROUP", "Policy-Month", "Security Group Usage"));
+        quotaTypeList.put(LOAD_BALANCER_POLICY, new QuotaTypes(LOAD_BALANCER_POLICY, "LOAD_BALANCER_POLICY", "Policy-Month", "Load Balancer Usage"));
+        quotaTypeList.put(PORT_FORWARDING_RULE, new QuotaTypes(PORT_FORWARDING_RULE, "PORT_FORWARDING_RULE", "Policy-Month", "Port Forwarding Usage"));
+        quotaTypeList.put(NETWORK_OFFERING, new QuotaTypes(NETWORK_OFFERING, "NETWORK_OFFERING", "Policy-Month", "Network Offering Usage"));
+        quotaTypeList.put(VPN_USERS, new QuotaTypes(VPN_USERS, "VPN_USERS", "Policy-Month", "VPN users usage"));
+        quotaTypeList.put(VM_DISK_IO_READ, new QuotaTypes(VM_DISK_IO_READ, "VM_DISK_IO_READ", "GB", "VM Disk usage(I/O Read)"));
+        quotaTypeList.put(VM_DISK_IO_WRITE, new QuotaTypes(VM_DISK_IO_WRITE, "VM_DISK_IO_WRITE", "GB", "VM Disk usage(I/O Write)"));
+        quotaTypeList.put(VM_DISK_BYTES_READ, new QuotaTypes(VM_DISK_BYTES_READ, "VM_DISK_BYTES_READ", "GB", "VM Disk usage(Bytes Read)"));
+        quotaTypeList.put(VM_DISK_BYTES_WRITE, new QuotaTypes(VM_DISK_BYTES_WRITE, "VPN_USERS", "GB", "VM Disk usage(Bytes Write)"));
+        quotaTypeList.put(VM_SNAPSHOT, new QuotaTypes(VM_SNAPSHOT, "VM_SNAPSHOT", "GB-Month", "VM Snapshot storage usage"));
+        quotaTypeList.put(CPU_CLOCK_RATE, new QuotaTypes(CPU_CLOCK_RATE, "CPU_CLOCK_RATE", "Compute-Month", "Quota tariff for using 1 CPU of clock rate 100MHz"));
+        quotaTypeList.put(CPU_NUMBER, new QuotaTypes(CPU_NUMBER, "CPU_NUMBER", "Compute-Month", "Quota tariff for running VM that has 1vCPU"));
+        quotaTypeList.put(MEMORY, new QuotaTypes(MEMORY, "MEMORY", "Compute-Month", "Quota tariff for using 1MB or RAM for 1 hour"));
+        quotaTypeMap = Collections.unmodifiableMap(quotaTypeList);
+    }
+
+    private QuotaTypes(Integer quotaType, String name, String unit, String description) {
+        this.quotaType = quotaType;
+        this.description = description;
+        this.quotaName = name;
+        this.quotaUnit = unit;
+        this.discriminator = "None";
+    }
+
+    public static Map<Integer, QuotaTypes> listQuotaTypes() {
+        return quotaTypeMap;
+    }
+
+    public String getDiscriminator() {
+        return discriminator;
+    }
+
+    public String getQuotaName() {
+        return quotaName;
+    }
+
+    public String getQuotaUnit() {
+        return quotaUnit;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public Integer getQuotaType() {
+        return quotaType;
+    }
+
+    static public String getDescription(int quotaType) {
+        QuotaTypes t = quotaTypeMap.get(quotaType);
+        if (t != null) {
+            return t.getDescription();
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/987fcbd4/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaAccountDao.java
----------------------------------------------------------------------
diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaAccountDao.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaAccountDao.java
new file mode 100644
index 0000000..d1b441b
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaAccountDao.java
@@ -0,0 +1,35 @@
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements.  See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership.  The ASF 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 org.apache.cloudstack.quota.dao;
+
+import java.util.List;
+
+import org.apache.cloudstack.quota.vo.QuotaAccountVO;
+
+import com.cloud.utils.db.GenericDao;
+
+public interface QuotaAccountDao extends GenericDao<QuotaAccountVO, Long> {
+
+    List<QuotaAccountVO> listAllQuotaAccount();
+
+    QuotaAccountVO findByIdQuotaAccount(Long id);
+
+    QuotaAccountVO persistQuotaAccount(QuotaAccountVO entity);
+
+    boolean updateQuotaAccount(Long id, QuotaAccountVO entity);
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/987fcbd4/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaAccountDaoImpl.java
----------------------------------------------------------------------
diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaAccountDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaAccountDaoImpl.java
new file mode 100644
index 0000000..e3de188
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaAccountDaoImpl.java
@@ -0,0 +1,74 @@
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements.  See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership.  The ASF 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 org.apache.cloudstack.quota.dao;
+
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallback;
+import com.cloud.utils.db.TransactionLegacy;
+import com.cloud.utils.db.TransactionStatus;
+
+import org.apache.cloudstack.quota.vo.QuotaAccountVO;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+import javax.ejb.Local;
+
+import java.util.List;
+
+@Component
+@Local(value = { QuotaAccountDao.class })
+public class QuotaAccountDaoImpl extends GenericDaoBase<QuotaAccountVO, Long> implements QuotaAccountDao {
+    public static final Logger s_logger = Logger.getLogger(QuotaAccountDaoImpl.class);
+
+    public List<QuotaAccountVO> listAllQuotaAccount() {
+        return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaAccountVO>>() {
+            @Override
+            public List<QuotaAccountVO> doInTransaction(final TransactionStatus status) {
+                return listAll();
+            }
+        });
+    }
+
+    public QuotaAccountVO findByIdQuotaAccount(final Long id) {
+        return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaAccountVO>() {
+            @Override
+            public QuotaAccountVO doInTransaction(final TransactionStatus status) {
+                return findById(id);
+            }
+        });
+    }
+
+    public QuotaAccountVO persistQuotaAccount(final QuotaAccountVO entity) {
+        return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaAccountVO>() {
+            @Override
+            public QuotaAccountVO doInTransaction(final TransactionStatus status) {
+                return persist(entity);
+            }
+        });
+    }
+
+    public boolean updateQuotaAccount(final Long id, final QuotaAccountVO entity) {
+        return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<Boolean>() {
+            @Override
+            public Boolean doInTransaction(final TransactionStatus status) {
+                return update(id, entity);
+            }
+        });
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/987fcbd4/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDao.java
----------------------------------------------------------------------
diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDao.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDao.java
new file mode 100644
index 0000000..c694eae
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDao.java
@@ -0,0 +1,43 @@
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements.  See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership.  The ASF 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 org.apache.cloudstack.quota.dao;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
+
+import com.cloud.utils.db.GenericDao;
+
+public interface QuotaBalanceDao extends GenericDao<QuotaBalanceVO, Long> {
+
+    QuotaBalanceVO saveQuotaBalance(QuotaBalanceVO qb);
+
+    List<QuotaBalanceVO> findCreditBalance(Long accountId, Long domainId, Date startDate, Date endDate);
+
+    QuotaBalanceVO findLastBalanceEntry(Long accountId, Long domainId, Date beforeThis);
+
+    QuotaBalanceVO findLaterBalanceEntry(Long accountId, Long domainId, Date afterThis);
+
+    List<QuotaBalanceVO> findQuotaBalance(Long accountId, Long domainId, Date startDate, Date endDate);
+
+    List<QuotaBalanceVO> lastQuotaBalanceVO(Long accountId, Long domainId, Date startDate);
+
+    BigDecimal lastQuotaBalance(Long accountId, Long domainId, Date startDate);
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/987fcbd4/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java
----------------------------------------------------------------------
diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java
new file mode 100644
index 0000000..aa650e1
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java
@@ -0,0 +1,189 @@
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements.  See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership.  The ASF 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 org.apache.cloudstack.quota.dao;
+
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.QueryBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallback;
+import com.cloud.utils.db.TransactionLegacy;
+import com.cloud.utils.db.TransactionStatus;
+
+import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+import javax.ejb.Local;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+@Component
+@Local(value = {QuotaBalanceDao.class})
+public class QuotaBalanceDaoImpl extends GenericDaoBase<QuotaBalanceVO, Long> implements QuotaBalanceDao {
+    private static final Logger s_logger = Logger.getLogger(QuotaBalanceDaoImpl.class.getName());
+
+    public QuotaBalanceVO findLastBalanceEntry(final Long accountId, final Long domainId, final Date beforeThis) {
+        return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaBalanceVO>() {
+            @Override
+            public QuotaBalanceVO doInTransaction(final TransactionStatus status) {
+                List<QuotaBalanceVO> quotaBalanceEntries = new ArrayList<>();
+                Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", false, 0L, 1L);
+                QueryBuilder<QuotaBalanceVO> qb = QueryBuilder.create(QuotaBalanceVO.class);
+                qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
+                qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
+                qb.and(qb.entity().getCreditsId(), SearchCriteria.Op.EQ, 0);
+                qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.LT, beforeThis);
+                quotaBalanceEntries = search(qb.create(), filter);
+                return !quotaBalanceEntries.isEmpty() ? quotaBalanceEntries.get(0) : null;
+            }
+        });
+    }
+
+    public QuotaBalanceVO findLaterBalanceEntry(final Long accountId, final Long domainId, final Date afterThis) {
+        return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaBalanceVO>() {
+            @Override
+            public QuotaBalanceVO doInTransaction(final TransactionStatus status) {
+                List<QuotaBalanceVO> quotaBalanceEntries = new ArrayList<>();
+                Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", true, 0L, 1L);
+                QueryBuilder<QuotaBalanceVO> qb = QueryBuilder.create(QuotaBalanceVO.class);
+                qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
+                qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
+                qb.and(qb.entity().getCreditsId(), SearchCriteria.Op.EQ, 0);
+                qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.GT, afterThis);
+                quotaBalanceEntries = search(qb.create(), filter);
+                return quotaBalanceEntries.size() > 0 ? quotaBalanceEntries.get(0) : null;
+            }
+        });
+    }
+
+    public QuotaBalanceVO saveQuotaBalance(final QuotaBalanceVO qb) {
+        return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaBalanceVO>() {
+            @Override
+            public QuotaBalanceVO doInTransaction(final TransactionStatus status) {
+                return persist(qb);
+            }
+        });
+    }
+
+    public List<QuotaBalanceVO> findCreditBalance(final Long accountId, final Long domainId, final Date lastbalancedate, final Date beforeThis) {
+        return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaBalanceVO>>() {
+            @Override
+            public List<QuotaBalanceVO> doInTransaction(final TransactionStatus status) {
+                if ((lastbalancedate != null) && (beforeThis != null) && lastbalancedate.before(beforeThis)) {
+                    Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", true, 0L, Long.MAX_VALUE);
+                    QueryBuilder<QuotaBalanceVO> qb = QueryBuilder.create(QuotaBalanceVO.class);
+                    qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
+                    qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
+                    qb.and(qb.entity().getCreditsId(), SearchCriteria.Op.GT, 0);
+                    qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.BETWEEN, lastbalancedate, beforeThis);
+                    return search(qb.create(), filter);
+                } else {
+                    return new ArrayList<QuotaBalanceVO>();
+                }
+            }
+        });
+    }
+
+    public List<QuotaBalanceVO> findQuotaBalance(final Long accountId, final Long domainId, final Date startDate, final Date endDate) {
+        return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaBalanceVO>>() {
+            @Override
+            public List<QuotaBalanceVO> doInTransaction(final TransactionStatus status) {
+                List<QuotaBalanceVO> quotaUsageRecords = null;
+                QueryBuilder<QuotaBalanceVO> qb = QueryBuilder.create(QuotaBalanceVO.class);
+                if (accountId != null) {
+                    qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
+                }
+                if (domainId != null) {
+                    qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
+                }
+                if ((startDate != null) && (endDate != null) && startDate.before(endDate)) {
+                    qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.BETWEEN, startDate, endDate);
+                } else {
+                    return Collections.<QuotaBalanceVO> emptyList();
+                }
+                quotaUsageRecords = listBy(qb.create());
+                if (quotaUsageRecords.size() == 0) {
+                    quotaUsageRecords.addAll(lastQuotaBalanceVO(accountId, domainId, startDate));
+                }
+                return quotaUsageRecords;
+
+            }
+        });
+
+    }
+
+    public List<QuotaBalanceVO> lastQuotaBalanceVO(final Long accountId, final Long domainId, final Date pivotDate) {
+        return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaBalanceVO>>() {
+            @Override
+            public List<QuotaBalanceVO> doInTransaction(final TransactionStatus status) {
+                List<QuotaBalanceVO> quotaUsageRecords = null;
+                List<QuotaBalanceVO> trimmedRecords = new ArrayList<QuotaBalanceVO>();
+                Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", false, 0L, 100L);
+                // ASSUMPTION there will be less than 100 continuous credit
+                // transactions
+                QueryBuilder<QuotaBalanceVO> qb = QueryBuilder.create(QuotaBalanceVO.class);
+                if (accountId != null) {
+                    qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
+                }
+                if (domainId != null) {
+                    qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
+                }
+                if ((pivotDate != null)) {
+                    qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.LTEQ, pivotDate);
+                }
+                quotaUsageRecords = search(qb.create(), filter);
+
+                // get records before startDate to find start balance
+                for (QuotaBalanceVO entry : quotaUsageRecords) {
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.debug("FindQuotaBalIance Entry=" + entry);
+                    }
+                    if (entry.getCreditsId() > 0) {
+                        trimmedRecords.add(entry);
+                    } else {
+                        trimmedRecords.add(entry);
+                        break; // add only consecutive credit entries and last balance entry
+                    }
+                }
+                return trimmedRecords;
+            }
+        });
+    }
+
+    public BigDecimal lastQuotaBalance(final Long accountId, final Long domainId, Date startDate) {
+        List<QuotaBalanceVO> quotaBalance = lastQuotaBalanceVO(accountId, domainId, startDate);
+        BigDecimal finalBalance = new BigDecimal(0);
+        if (quotaBalance.isEmpty()) {
+            s_logger.info("There are no balance entries on or before the requested date.");
+            return finalBalance;
+        }
+        for (QuotaBalanceVO entry : quotaBalance) {
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("lastQuotaBalance Entry=" + entry);
+            }
+            finalBalance = finalBalance.add(entry.getCreditBalance());
+        }
+        return finalBalance;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/987fcbd4/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDao.java
----------------------------------------------------------------------
diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDao.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDao.java
new file mode 100644
index 0000000..f08d8f9
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDao.java
@@ -0,0 +1,32 @@
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements.  See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership.  The ASF 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 org.apache.cloudstack.quota.dao;
+
+import java.util.Date;
+import java.util.List;
+
+import org.apache.cloudstack.quota.vo.QuotaCreditsVO;
+
+import com.cloud.utils.db.GenericDao;
+
+public interface QuotaCreditsDao extends GenericDao<QuotaCreditsVO, Long> {
+
+    List<QuotaCreditsVO> findCredits(long accountId, long domainId, Date startDate, Date endDate);
+
+    QuotaCreditsVO saveCredits(QuotaCreditsVO credits);
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/987fcbd4/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDaoImpl.java
----------------------------------------------------------------------
diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDaoImpl.java
new file mode 100644
index 0000000..4b77710
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDaoImpl.java
@@ -0,0 +1,78 @@
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements.  See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership.  The ASF 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 org.apache.cloudstack.quota.dao;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+
+import org.springframework.stereotype.Component;
+import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
+import org.apache.cloudstack.quota.vo.QuotaCreditsVO;
+
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.QueryBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallback;
+import com.cloud.utils.db.TransactionLegacy;
+import com.cloud.utils.db.TransactionStatus;
+
+@Component
+@Local(value = { QuotaCreditsDao.class })
+public class QuotaCreditsDaoImpl extends GenericDaoBase<QuotaCreditsVO, Long> implements QuotaCreditsDao {
+
+    @Inject
+    QuotaBalanceDao _quotaBalanceDao;
+
+    @Override
+    public List<QuotaCreditsVO> findCredits(final long accountId, final long domainId, final Date startDate, final Date endDate) {
+        return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaCreditsVO>>() {
+            @Override
+            public List<QuotaCreditsVO> doInTransaction(final TransactionStatus status) {
+                if ((startDate != null) && (endDate != null) && startDate.before(endDate)) {
+                    Filter filter = new Filter(QuotaCreditsVO.class, "updatedOn", true, 0L, Long.MAX_VALUE);
+                    QueryBuilder<QuotaCreditsVO> qb = QueryBuilder.create(QuotaCreditsVO.class);
+                    qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
+                    qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
+                    qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.BETWEEN, startDate, endDate);
+                    return search(qb.create(), filter);
+                } else {
+                    return Collections.<QuotaCreditsVO> emptyList();
+                }
+            }
+        });
+    }
+
+    @Override
+    public QuotaCreditsVO saveCredits(final QuotaCreditsVO credits) {
+        return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaCreditsVO>() {
+            @Override
+            public QuotaCreditsVO doInTransaction(final TransactionStatus status) {
+                persist(credits);
+                // make an entry in the balance table
+                QuotaBalanceVO bal = new QuotaBalanceVO(credits);
+                _quotaBalanceDao.persist(bal);
+                return credits;
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/987fcbd4/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaEmailTemplatesDao.java
----------------------------------------------------------------------
diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaEmailTemplatesDao.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaEmailTemplatesDao.java
new file mode 100644
index 0000000..573a753
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaEmailTemplatesDao.java
@@ -0,0 +1,27 @@
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements.  See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership.  The ASF 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 org.apache.cloudstack.quota.dao;
+
+import com.cloud.utils.db.GenericDao;
+import org.apache.cloudstack.quota.vo.QuotaEmailTemplatesVO;
+
+import java.util.List;
+
+public interface QuotaEmailTemplatesDao extends GenericDao<QuotaEmailTemplatesVO, Long> {
+    List<QuotaEmailTemplatesVO> listAllQuotaEmailTemplates(String templateName);
+    boolean updateQuotaEmailTemplate(QuotaEmailTemplatesVO template);
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/987fcbd4/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaEmailTemplatesDaoImpl.java
----------------------------------------------------------------------
diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaEmailTemplatesDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaEmailTemplatesDaoImpl.java
new file mode 100644
index 0000000..a971603
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaEmailTemplatesDaoImpl.java
@@ -0,0 +1,74 @@
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements.  See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership.  The ASF 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 org.apache.cloudstack.quota.dao;
+
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallback;
+import com.cloud.utils.db.TransactionLegacy;
+import com.cloud.utils.db.TransactionStatus;
+import com.google.common.base.Strings;
+
+import org.apache.cloudstack.quota.vo.QuotaEmailTemplatesVO;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+import javax.ejb.Local;
+
+import java.util.List;
+
+@Component
+@Local(value = { QuotaEmailTemplatesDao.class })
+public class QuotaEmailTemplatesDaoImpl extends GenericDaoBase<QuotaEmailTemplatesVO, Long> implements QuotaEmailTemplatesDao {
+    private static final Logger s_logger = Logger.getLogger(QuotaEmailTemplatesDaoImpl.class);
+
+    protected SearchBuilder<QuotaEmailTemplatesVO> QuotaEmailTemplateSearch;
+
+    public QuotaEmailTemplatesDaoImpl() {
+        super();
+
+        QuotaEmailTemplateSearch = createSearchBuilder();
+        QuotaEmailTemplateSearch.and("template_name", QuotaEmailTemplateSearch.entity().getTemplateName(), SearchCriteria.Op.EQ);
+        QuotaEmailTemplateSearch.done();
+    }
+
+    @Override
+    public List<QuotaEmailTemplatesVO> listAllQuotaEmailTemplates(final String templateName) {
+        return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaEmailTemplatesVO>>() {
+            @Override
+            public List<QuotaEmailTemplatesVO> doInTransaction(final TransactionStatus status) {
+                SearchCriteria<QuotaEmailTemplatesVO> sc = QuotaEmailTemplateSearch.create();
+                if (!Strings.isNullOrEmpty(templateName)) {
+                    sc.setParameters("template_name", templateName);
+                }
+                return listBy(sc);
+            }
+        });
+    }
+
+    @Override
+    public boolean updateQuotaEmailTemplate(final QuotaEmailTemplatesVO template) {
+        return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<Boolean>() {
+            @Override
+            public Boolean doInTransaction(final TransactionStatus status) {
+                return update(template.getId(), template);
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/987fcbd4/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDao.java
----------------------------------------------------------------------
diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDao.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDao.java
new file mode 100644
index 0000000..fda2cf6
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDao.java
@@ -0,0 +1,37 @@
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements.  See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership.  The ASF 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 org.apache.cloudstack.quota.dao;
+
+import com.cloud.utils.db.GenericDao;
+
+import org.apache.cloudstack.quota.vo.QuotaTariffVO;
+
+import java.util.Date;
+import java.util.List;
+
+public interface QuotaTariffDao extends GenericDao<QuotaTariffVO, Long> {
+
+    QuotaTariffVO findTariffPlanByUsageType(int quotaType, Date onOrBefore);
+
+    List<QuotaTariffVO> listAllTariffPlans();
+
+    List<QuotaTariffVO> listAllTariffPlans(Date onOrBefore);
+
+    Boolean updateQuotaTariff(QuotaTariffVO plan);
+
+    QuotaTariffVO addQuotaTariff(QuotaTariffVO plan);
+}