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);
+}