cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From raj...@apache.org
Subject [4/6] git commit: updated refs/heads/pr/689-review to af28a82
Date Mon, 31 Aug 2015 10:34:38 GMT
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaBalanceResponse.java
----------------------------------------------------------------------
diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaBalanceResponse.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaBalanceResponse.java
new file mode 100644
index 0000000..2e0c23f
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaBalanceResponse.java
@@ -0,0 +1,153 @@
+//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.api.response;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import com.google.gson.annotations.SerializedName;
+
+import org.apache.cloudstack.api.BaseResponse;
+import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
+
+import com.cloud.serializer.Param;
+
+public class QuotaBalanceResponse extends BaseResponse {
+
+    @SerializedName("accountid")
+    @Param(description = "account id")
+    private Long accountId;
+
+    @SerializedName("account")
+    @Param(description = "account name")
+    private String accountName;
+
+    @SerializedName("domain")
+    @Param(description = "domain id")
+    private Long domainId;
+
+    @SerializedName("startquota")
+    @Param(description = "quota started with")
+    private BigDecimal startQuota;
+
+    @SerializedName("endquota")
+    @Param(description = "quota by end of this period")
+    private BigDecimal endQuota;
+
+    @SerializedName("credits")
+    @Param(description = "list of credits made during this period")
+    private List<QuotaCreditsResponse> credits = null;
+
+    @SerializedName("startdate")
+    @Param(description = "start date")
+    private Date startDate = null;
+
+    @SerializedName("enddate")
+    @Param(description = "end date")
+    private Date endDate = null;
+
+    @SerializedName("currency")
+    @Param(description = "currency")
+    private String currency;
+
+    public QuotaBalanceResponse() {
+        super();
+        credits = new ArrayList<QuotaCreditsResponse>();
+    }
+
+    public Long getAccountId() {
+        return accountId;
+    }
+
+    public void setAccountId(Long accountId) {
+        this.accountId = accountId;
+    }
+
+    public String getAccountName() {
+        return accountName;
+    }
+
+    public void setAccountName(String accountName) {
+        this.accountName = accountName;
+    }
+
+    public Long getDomainId() {
+        return domainId;
+    }
+
+    public void setDomainId(Long domainId) {
+        this.domainId = domainId;
+    }
+
+    public BigDecimal getStartQuota() {
+        return startQuota;
+    }
+
+    public void setStartQuota(BigDecimal startQuota) {
+        this.startQuota = startQuota.setScale(2, RoundingMode.HALF_EVEN);
+    }
+
+    public BigDecimal getEndQuota() {
+        return endQuota;
+    }
+
+    public void setEndQuota(BigDecimal endQuota) {
+        this.endQuota = endQuota.setScale(2, RoundingMode.HALF_EVEN);
+    }
+
+    public List<QuotaCreditsResponse> getCredits() {
+        return credits;
+    }
+
+    public void setCredits(List<QuotaCreditsResponse> credits) {
+        this.credits = credits;
+    }
+
+    public void addCredits(QuotaBalanceVO credit) {
+        QuotaCreditsResponse cr = new QuotaCreditsResponse();
+        cr.setCredits(credit.getCreditBalance());
+        cr.setUpdatedOn(credit.getUpdatedOn());
+        credits.add(0, cr);
+    }
+
+    public Date getStartDate() {
+        return startDate;
+    }
+
+    public void setStartDate(Date startDate) {
+        this.startDate = startDate;
+    }
+
+    public Date getEndDate() {
+        return endDate;
+    }
+
+    public void setEndDate(Date endDate) {
+        this.endDate = endDate;
+    }
+
+    public String getCurrency() {
+        return currency;
+    }
+
+    public void setCurrency(String currency) {
+        this.currency = currency;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaCreditsResponse.java
----------------------------------------------------------------------
diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaCreditsResponse.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaCreditsResponse.java
new file mode 100644
index 0000000..2c16cf4
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaCreditsResponse.java
@@ -0,0 +1,91 @@
+//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.api.response;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+
+import org.apache.cloudstack.api.BaseResponse;
+import org.apache.cloudstack.quota.vo.QuotaCreditsVO;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Date;
+
+public class QuotaCreditsResponse extends BaseResponse {
+
+    @SerializedName("credits")
+    @Param(description = "the credit deposited")
+    private BigDecimal credits;
+
+    @SerializedName("updated_by")
+    @Param(description = "the user name of the admin who updated the credits")
+    private String updatedBy;
+
+    @SerializedName("updated_on")
+    @Param(description = "the account name of the admin who updated the credits")
+    private Date updatedOn;
+
+    @SerializedName("currency")
+    @Param(description = "currency")
+    private String currency;
+
+    public QuotaCreditsResponse() {
+        super();
+    }
+
+    public QuotaCreditsResponse(QuotaCreditsVO result, String updatedBy) {
+        super();
+        if (result != null) {
+            setCredits(result.getCredit());
+            setUpdatedBy(updatedBy);
+            setUpdatedOn(new Date());
+        }
+    }
+
+    public BigDecimal getCredits() {
+        return credits;
+    }
+
+    public void setCredits(BigDecimal credits) {
+        this.credits = credits.setScale(2, RoundingMode.HALF_EVEN);
+    }
+
+    public String getUpdatedBy() {
+        return updatedBy;
+    }
+
+    public void setUpdatedBy(String updatedBy) {
+        this.updatedBy = updatedBy;
+    }
+
+    public Date getUpdatedOn() {
+        return updatedOn;
+    }
+
+    public void setUpdatedOn(Date updatedOn) {
+        this.updatedOn = updatedOn;
+    }
+
+    public String getCurrency() {
+        return currency;
+    }
+
+    public void setCurrency(String currency) {
+        this.currency = currency;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaEmailTemplateResponse.java
----------------------------------------------------------------------
diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaEmailTemplateResponse.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaEmailTemplateResponse.java
new file mode 100644
index 0000000..c4a2b7c
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaEmailTemplateResponse.java
@@ -0,0 +1,90 @@
+//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.api.response;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+import org.apache.cloudstack.api.BaseResponse;
+
+import java.util.Date;
+
+public class QuotaEmailTemplateResponse extends BaseResponse {
+    @SerializedName("templatetype")
+    @Param(description = "Template type")
+    private String templateType;
+
+    @SerializedName("templatesubject")
+    @Param(description = "The quota email template subject")
+    private String templateSubject;
+
+    @SerializedName("templatebody")
+    @Param(description = "The quota email template content")
+    private String templateText;
+
+    @SerializedName("locale")
+    @Param(description = "The quota email template locale")
+    private String locale;
+
+    @SerializedName("last_updated")
+    @Param(description = "Last date/time when template was updated")
+    private Date lastUpdatedOn;
+
+    public QuotaEmailTemplateResponse() {
+        super();
+        this.setObjectName("quotaemailtemplate");
+    }
+
+    public String getTemplateType() {
+        return templateType;
+    }
+
+    public void setTemplateType(String templateType) {
+        this.templateType = templateType;
+    }
+
+    public String getTemplateSubject() {
+        return templateSubject;
+    }
+
+    public void setTemplateSubject(String templateSubject) {
+        this.templateSubject = templateSubject;
+    }
+
+    public String getTemplateText() {
+        return templateText;
+    }
+
+    public void setTemplateText(String templateText) {
+        this.templateText = templateText;
+    }
+
+    public String getLocale() {
+        return locale;
+    }
+
+    public void setLocale(String locale) {
+        this.locale = locale;
+    }
+
+    public Date getLastUpdatedOn() {
+        return lastUpdatedOn;
+    }
+
+    public void setLastUpdatedOn(Date lastUpdatedOn) {
+        this.lastUpdatedOn = lastUpdatedOn;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilder.java
----------------------------------------------------------------------
diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilder.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilder.java
new file mode 100644
index 0000000..e9bb611
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilder.java
@@ -0,0 +1,62 @@
+//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.api.response;
+
+
+import org.apache.cloudstack.api.command.QuotaBalanceCmd;
+import org.apache.cloudstack.api.command.QuotaEmailTemplateListCmd;
+import org.apache.cloudstack.api.command.QuotaEmailTemplateUpdateCmd;
+import org.apache.cloudstack.api.command.QuotaStatementCmd;
+import org.apache.cloudstack.api.command.QuotaTariffListCmd;
+import org.apache.cloudstack.api.command.QuotaTariffUpdateCmd;
+import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
+import org.apache.cloudstack.quota.vo.QuotaTariffVO;
+import org.apache.cloudstack.quota.vo.QuotaUsageVO;
+
+import java.util.Date;
+import java.util.List;
+
+public interface QuotaResponseBuilder {
+
+    QuotaTariffVO updateQuotaTariffPlan(QuotaTariffUpdateCmd cmd);
+
+    List<QuotaTariffVO> listQuotaTariffPlans(QuotaTariffListCmd cmd);
+
+    QuotaTariffResponse createQuotaTariffResponse(QuotaTariffVO configuration);
+
+    QuotaStatementResponse createQuotaStatementResponse(List<QuotaUsageVO> quotaUsage);
+
+    QuotaBalanceResponse createQuotaBalanceResponse(List<QuotaBalanceVO> quotaUsage, Date startDate, Date endDate);
+
+    QuotaBalanceResponse createQuotaLastBalanceResponse(List<QuotaBalanceVO> quotaBalance, Date startDate);
+
+    QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy, Date despositedOn);
+
+    public List<QuotaUsageVO> getQuotaUsage(QuotaStatementCmd cmd);
+
+    List<QuotaBalanceVO> getQuotaBalance(QuotaBalanceCmd cmd);
+
+    QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy);
+
+    List<QuotaEmailTemplateResponse> listQuotaEmailTemplates(QuotaEmailTemplateListCmd cmd);
+
+    boolean updateQuotaEmailTemplate(QuotaEmailTemplateUpdateCmd cmd);
+
+    Date startOfNextDay(Date dt);
+
+    Date startOfNextDay();
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java
----------------------------------------------------------------------
diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java
new file mode 100644
index 0000000..de082ee
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java
@@ -0,0 +1,412 @@
+//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.api.response;
+
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.user.Account;
+import com.cloud.user.AccountVO;
+import com.cloud.user.User;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.user.dao.UserDao;
+import com.cloud.utils.db.TransactionLegacy;
+
+import org.apache.cloudstack.api.command.QuotaBalanceCmd;
+import org.apache.cloudstack.api.command.QuotaEmailTemplateListCmd;
+import org.apache.cloudstack.api.command.QuotaEmailTemplateUpdateCmd;
+import org.apache.cloudstack.api.command.QuotaStatementCmd;
+import org.apache.cloudstack.api.command.QuotaTariffListCmd;
+import org.apache.cloudstack.api.command.QuotaTariffUpdateCmd;
+import org.apache.cloudstack.quota.QuotaService;
+import org.apache.cloudstack.quota.constant.QuotaConfig;
+import org.apache.cloudstack.quota.constant.QuotaTypes;
+import org.apache.cloudstack.quota.dao.QuotaBalanceDao;
+import org.apache.cloudstack.quota.dao.QuotaCreditsDao;
+import org.apache.cloudstack.quota.dao.QuotaEmailTemplatesDao;
+import org.apache.cloudstack.quota.dao.QuotaTariffDao;
+import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
+import org.apache.cloudstack.quota.vo.QuotaCreditsVO;
+import org.apache.cloudstack.quota.vo.QuotaEmailTemplatesVO;
+import org.apache.cloudstack.quota.vo.QuotaTariffVO;
+import org.apache.cloudstack.quota.vo.QuotaUsageVO;
+import org.apache.cloudstack.region.RegionManager;
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+@Component
+@Local(value = QuotaResponseBuilderImpl.class)
+public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
+    private static final Logger s_logger = Logger.getLogger(QuotaResponseBuilderImpl.class.getName());
+
+    @Inject
+    private QuotaTariffDao _quotaTariffDao;
+    @Inject
+    private QuotaBalanceDao _quotaBalanceDao;
+    @Inject
+    private QuotaCreditsDao _quotaCreditsDao;
+    @Inject
+    private QuotaEmailTemplatesDao _quotaEmailTemplateDao;
+
+    @Inject
+    private UserDao _userDao;
+    @Inject
+    private QuotaService _quotaService;
+    @Inject
+    AccountDao _accountDao;
+    @Inject
+    private RegionManager _regionMgr;
+
+    @Override
+    public QuotaTariffResponse createQuotaTariffResponse(QuotaTariffVO tariff) {
+        final QuotaTariffResponse response = new QuotaTariffResponse();
+        response.setUsageType(tariff.getUsageType());
+        response.setUsageName(tariff.getUsageName());
+        response.setUsageUnit(tariff.getUsageUnit());
+        response.setUsageDiscriminator(tariff.getUsageDiscriminator());
+        response.setTariffValue(tariff.getCurrencyValue());
+        response.setEffectiveOn(tariff.getEffectiveOn());
+        response.setDescription(tariff.getDescription());
+        response.setCurrency(QuotaConfig.QuotaCurrencySymbol.value());
+        return response;
+    }
+
+    @Override
+    public QuotaBalanceResponse createQuotaBalanceResponse(List<QuotaBalanceVO> quotaBalance, Date startDate, Date endDate) {
+        if (quotaBalance.size() == 0) {
+            new InvalidParameterValueException("The request period does not contain balance entries.");
+        }
+        Collections.sort(quotaBalance, new Comparator<QuotaBalanceVO>() {
+            public int compare(QuotaBalanceVO o1, QuotaBalanceVO o2) {
+                return o2.getUpdatedOn().compareTo(o1.getUpdatedOn()); // desc
+            }
+        });
+
+        QuotaBalanceResponse resp = new QuotaBalanceResponse();
+        BigDecimal lastCredits = new BigDecimal(0);
+        boolean consecutive = true;
+        for (Iterator<QuotaBalanceVO> it = quotaBalance.iterator(); it.hasNext();) {
+            QuotaBalanceVO entry = it.next();
+            s_logger.info("createQuotaBalanceResponse: Date=" + entry.getUpdatedOn().toGMTString() + " balance=" + entry.getCreditBalance() + " credit=" + entry.getCreditsId());
+            if (entry.getCreditsId() > 0) {
+                if (consecutive) {
+                    lastCredits = lastCredits.add(entry.getCreditBalance());
+                }
+                resp.addCredits(entry);
+                it.remove();
+            } else {
+                consecutive = false;
+            }
+        }
+
+        if (quotaBalance.size() > 0) {
+            // order is desc last item is the start item
+            QuotaBalanceVO startItem = quotaBalance.get(quotaBalance.size() - 1);
+            QuotaBalanceVO endItem = quotaBalance.get(0);
+            resp.setStartDate(startDate);
+            resp.setStartQuota(startItem.getCreditBalance());
+            resp.setEndDate(endDate);
+            resp.setEndQuota(endItem.getCreditBalance().add(lastCredits));
+        } else {
+            resp.setStartQuota(new BigDecimal(0));
+            resp.setEndQuota(new BigDecimal(0));
+        }
+        resp.setCurrency(QuotaConfig.QuotaCurrencySymbol.value());
+        resp.setObjectName("balance");
+        return resp;
+    }
+
+    @Override
+    public QuotaStatementResponse createQuotaStatementResponse(final List<QuotaUsageVO> quotaUsage) {
+        if (quotaUsage == null || quotaUsage.size() == 0) {
+            throw new InvalidParameterValueException("There is no usage data found for period mentioned.");
+        }
+        final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+        TransactionLegacy.open(TransactionLegacy.USAGE_DB).close();
+        QuotaStatementResponse statement = new QuotaStatementResponse();
+
+        HashMap<Integer, QuotaTariffVO> quotaTariffMap = new HashMap<Integer, QuotaTariffVO>();
+        List<QuotaTariffVO> result = _quotaTariffDao.listAll();
+
+        for (QuotaTariffVO quotaTariff : result) {
+            quotaTariffMap.put(quotaTariff.getUsageType(), quotaTariff);
+            // add dummy record for each usage type
+            QuotaUsageVO dummy = new QuotaUsageVO(quotaUsage.get(0));
+            dummy.setUsageType(quotaTariff.getUsageType());
+            dummy.setQuotaUsed(new BigDecimal(0));
+            quotaUsage.add(dummy);
+        }
+
+        Collections.sort(quotaUsage, new Comparator<QuotaUsageVO>() {
+            public int compare(QuotaUsageVO o1, QuotaUsageVO o2) {
+                if (o1.getUsageType() == o2.getUsageType())
+                    return 0;
+                return o1.getUsageType() < o2.getUsageType() ? -1 : 1;
+            }
+        });
+
+        List<QuotaStatementItemResponse> items = new ArrayList<QuotaStatementItemResponse>();
+        QuotaStatementItemResponse lineitem;
+        int type = -1;
+        BigDecimal usage = new BigDecimal(0);
+        BigDecimal totalUsage = new BigDecimal(0);
+        quotaUsage.add(new QuotaUsageVO());// boundary
+        QuotaUsageVO prev = quotaUsage.get(0);
+        //s_logger.info("createQuotaStatementResponse record count=" + quotaUsage.size());
+        for (final QuotaUsageVO quotaRecord : quotaUsage) {
+            //s_logger.info("createQuotaStatementResponse Type=" + quotaRecord.getUsageType() + " usage=" + usage + " name" + quotaRecord.getUsageItemId());
+            if (type != quotaRecord.getUsageType()) {
+                if (type != -1) {
+                    lineitem = new QuotaStatementItemResponse();
+                    lineitem.setUsageType(type);
+                    lineitem.setQuotaUsed(usage);
+                    lineitem.setAccountId(prev.getAccountId());
+                    lineitem.setDomainId(prev.getDomainId());
+                    lineitem.setStartDate(prev.getStartDate());
+                    lineitem.setEndDate(prev.getEndDate());
+                    lineitem.setUsageUnit(quotaTariffMap.get(type).getUsageUnit());
+                    lineitem.setUsageName(quotaTariffMap.get(type).getUsageName());
+                    lineitem.setObjectName("quotausage");
+                    items.add(lineitem);
+                    totalUsage = totalUsage.add(usage);
+                    usage = new BigDecimal(0);
+                }
+                type = quotaRecord.getUsageType();
+            }
+            prev = quotaRecord;
+            usage = usage.add(quotaRecord.getQuotaUsed());
+        }
+        TransactionLegacy.open(opendb).close();
+
+        statement.setLineItem(items);
+        statement.setTotalQuota(totalUsage);
+        statement.setCurrency(QuotaConfig.QuotaCurrencySymbol.value());
+        statement.setObjectName("statement");
+        return statement;
+    }
+
+    @Override
+    public List<QuotaTariffVO> listQuotaTariffPlans(final QuotaTariffListCmd cmd) {
+        List<QuotaTariffVO> result = new ArrayList<QuotaTariffVO>();
+        Date effectiveDate = cmd.getEffectiveDate() == null ? new Date() : cmd.getEffectiveDate();
+        Date adjustedEffectiveDate = _quotaService.computeAdjustedTime(effectiveDate);
+        s_logger.info("Effective datec=" + effectiveDate + " quotatype=" + cmd.getUsageType() + " Adjusted date=" + adjustedEffectiveDate);
+        if (cmd.getUsageType() != null) {
+            QuotaTariffVO tariffPlan = _quotaTariffDao.findTariffPlanByUsageType(cmd.getUsageType(), adjustedEffectiveDate);
+            if (tariffPlan != null) {
+                result.add(tariffPlan);
+            }
+        } else {
+            result = _quotaTariffDao.listAllTariffPlans(adjustedEffectiveDate);
+        }
+        return result;
+    }
+
+    @Override
+    public QuotaTariffVO updateQuotaTariffPlan(QuotaTariffUpdateCmd cmd) {
+        final int quotaType = cmd.getUsageType();
+        final BigDecimal quotaCost = new BigDecimal(cmd.getValue());
+        final Date effectiveDate = _quotaService.computeAdjustedTime(cmd.getStartDate());
+        final Date now = _quotaService.computeAdjustedTime(new Date());
+        // if effective date is in the past return error
+        if (effectiveDate.compareTo(now) < 0) {
+            throw new InvalidParameterValueException("Incorrect effective date for tariff " + effectiveDate + " is less than now " + now);
+        }
+        QuotaTypes quotaConstant = QuotaTypes.listQuotaTypes().get(quotaType);
+        if (quotaConstant == null) {
+            throw new InvalidParameterValueException("Quota type does not exists " + quotaType);
+        }
+        final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+        TransactionLegacy.open(TransactionLegacy.USAGE_DB).close();
+        QuotaTariffVO result = null;
+        try {
+            result = new QuotaTariffVO();
+            result.setUsageType(quotaType);
+            result.setUsageName(quotaConstant.getQuotaName());
+            result.setUsageUnit(quotaConstant.getQuotaUnit());
+            result.setUsageDiscriminator(quotaConstant.getDiscriminator());
+            result.setCurrencyValue(quotaCost);
+            result.setEffectiveOn(effectiveDate);
+            result.setUpdatedOn(now);
+            result.setUpdatedBy(cmd.getEntityOwnerId());
+
+            s_logger.debug(String.format("Updating Quota Tariff Plan: New value=%s for resource type=%d effective on date=%s", quotaCost, quotaType, effectiveDate));
+            _quotaTariffDao.addQuotaTariff(result);
+        } catch (Exception pokemon) {
+            s_logger.error("Error in update quota tariff plan: " + pokemon);
+        } finally {
+            TransactionLegacy.open(opendb).close();
+        }
+        return result;
+    }
+
+    @Override
+    public QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy) {
+        Date depositDate = new Date();
+        Date adjustedStartDate = _quotaService.computeAdjustedTime(depositDate);
+        QuotaBalanceVO qb = _quotaBalanceDao.findLaterBalanceEntry(accountId, domainId, adjustedStartDate);
+
+        if (qb != null) {
+            throw new InvalidParameterValueException("Incorrect deposit date: " + adjustedStartDate + " there are balance entries after this date");
+        }
+
+        return addQuotaCredits(accountId, domainId, amount, updatedBy, adjustedStartDate);
+    }
+
+    @Override
+    public QuotaCreditsResponse addQuotaCredits(final Long accountId, final Long domainId, final Double amount, final Long updatedBy, final Date despositedOn) {
+        final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+        QuotaCreditsVO result = null;
+        TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
+        try {
+            QuotaCreditsVO credits = new QuotaCreditsVO(accountId, domainId, new BigDecimal(amount), updatedBy);
+            s_logger.info("addQuotaCredits: Depositing " + amount + " on adjusted date " + despositedOn);
+            credits.setUpdatedOn(despositedOn);
+            result = _quotaCreditsDao.saveCredits(credits);
+        } finally {
+            txn.close();
+        }
+        TransactionLegacy.open(TransactionLegacy.CLOUD_DB).close();
+        final AccountVO account = _accountDao.findById(accountId);
+        final boolean lockAccountEnforcement = QuotaConfig.QuotaEnableEnforcement.value().equalsIgnoreCase("true");
+        final BigDecimal currentAccountBalance = _quotaBalanceDao.lastQuotaBalance(accountId, domainId, startOfNextDay(despositedOn));
+        if (lockAccountEnforcement && (currentAccountBalance.compareTo(new BigDecimal(0)) >= 0)) {
+            if (account.getState() == Account.State.locked) {
+                try {
+                    _regionMgr.enableAccount(account.getAccountName(), domainId, accountId);
+                    //_quotaMgr.sendQuotaAlert(account, currentAccountBalance, QuotaConfig.QuotaEmailTemplateTypes.QUOTA_UNLOCK_ACCOUNT);
+                } catch (Exception e) {
+                    s_logger.error(String.format("Unable to unlock account %s after getting enough quota credits", account.getAccountName()));
+                }
+            }
+        }
+
+        String creditor = String.valueOf(Account.ACCOUNT_ID_SYSTEM);
+        User creditorUser = _userDao.getUser(updatedBy);
+        if (creditorUser != null) {
+            creditor = creditorUser.getUsername();
+        }
+        TransactionLegacy.open(opendb).close();
+        QuotaCreditsResponse response = new QuotaCreditsResponse(result, creditor);
+        response.setCurrency(QuotaConfig.QuotaCurrencySymbol.value());
+        return response;
+    }
+
+    private QuotaEmailTemplateResponse createQuotaEmailResponse(QuotaEmailTemplatesVO template) {
+        QuotaEmailTemplateResponse response = new QuotaEmailTemplateResponse();
+        response.setTemplateType(template.getTemplateName());
+        response.setTemplateSubject(template.getTemplateSubject());
+        response.setTemplateText(template.getTemplateBody());
+        response.setLocale(template.getLocale());
+        response.setLastUpdatedOn(template.getLastUpdated());
+        return response;
+    }
+
+    @Override
+    public List<QuotaEmailTemplateResponse> listQuotaEmailTemplates(QuotaEmailTemplateListCmd cmd) {
+        final String templateName = cmd.getTemplateName();
+        List<QuotaEmailTemplatesVO> templates = _quotaEmailTemplateDao.listAllQuotaEmailTemplates(templateName);
+        final List<QuotaEmailTemplateResponse> responses = new ArrayList<QuotaEmailTemplateResponse>();
+        for (final QuotaEmailTemplatesVO template : templates) {
+            responses.add(createQuotaEmailResponse(template));
+        }
+        return responses;
+    }
+
+    @Override
+    public boolean updateQuotaEmailTemplate(QuotaEmailTemplateUpdateCmd cmd) {
+        final String templateName = cmd.getTemplateName();
+        final String templateSubject = StringEscapeUtils.escapeJavaScript(cmd.getTemplateSubject());
+        final String templateBody = StringEscapeUtils.escapeJavaScript(cmd.getTemplateBody());
+        final String locale = cmd.getLocale();
+
+        final List<QuotaEmailTemplatesVO> templates = _quotaEmailTemplateDao.listAllQuotaEmailTemplates(templateName);
+        if (templates.size() == 1) {
+            final QuotaEmailTemplatesVO template = templates.get(0);
+            template.setTemplateSubject(templateSubject);
+            template.setTemplateBody(templateBody);
+            if (locale != null) {
+                template.setLocale(locale);
+            }
+            return _quotaEmailTemplateDao.updateQuotaEmailTemplate(template);
+        }
+        return false;
+    }
+
+    @Override
+    public QuotaBalanceResponse createQuotaLastBalanceResponse(List<QuotaBalanceVO> quotaBalance, Date startDate) {
+        if (quotaBalance.size() == 0) {
+            new InvalidParameterValueException("There are no balance entries on or before the requested date.");
+        }
+        if (startDate == null) {
+            startDate = new Date();
+        }
+        QuotaBalanceResponse resp = new QuotaBalanceResponse();
+        BigDecimal lastCredits = new BigDecimal(0);
+        for (Iterator<QuotaBalanceVO> it = quotaBalance.iterator(); it.hasNext();) {
+            QuotaBalanceVO entry = it.next();
+            s_logger.info("createQuotaLastBalanceResponse Date=" + entry.getUpdatedOn() + " balance=" + entry.getCreditBalance() + " credit=" + entry.getCreditsId());
+            lastCredits = lastCredits.add(entry.getCreditBalance());
+        }
+        resp.setStartQuota(lastCredits);
+        resp.setStartDate(_quotaService.computeAdjustedTime(startDate));
+        resp.setCurrency(QuotaConfig.QuotaCurrencySymbol.value());
+        resp.setObjectName("balance");
+        return resp;
+    }
+
+    @Override
+    public List<QuotaUsageVO> getQuotaUsage(QuotaStatementCmd cmd) {
+        return _quotaService.getQuotaUsage(cmd.getAccountId(), cmd.getAccountName(), cmd.getDomainId(), cmd.getUsageType(), cmd.getStartDate(), cmd.getEndDate());
+    }
+
+    @Override
+    public List<QuotaBalanceVO> getQuotaBalance(QuotaBalanceCmd cmd) {
+        return _quotaService.findQuotaBalanceVO(cmd.getAccountId(), cmd.getAccountName(), cmd.getDomainId(), cmd.getStartDate(), cmd.getEndDate());
+    }
+
+    @Override
+    public Date startOfNextDay(Date dt) {
+        Calendar c = Calendar.getInstance();
+        c.setTime(dt);
+        c.add(Calendar.DATE, 1);
+        dt = c.getTime();
+        return dt;
+    }
+
+    @Override
+    public Date startOfNextDay() {
+        Calendar c = Calendar.getInstance();
+        c.setTime(new Date());
+        c.add(Calendar.DATE, 1);
+        Date dt = c.getTime();
+        return dt;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementItemResponse.java
----------------------------------------------------------------------
diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementItemResponse.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementItemResponse.java
new file mode 100644
index 0000000..e1b0f17
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementItemResponse.java
@@ -0,0 +1,143 @@
+//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.api.response;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Date;
+
+import com.google.gson.annotations.SerializedName;
+
+import org.apache.cloudstack.api.BaseResponse;
+
+import com.cloud.serializer.Param;
+
+public class QuotaStatementItemResponse extends BaseResponse {
+
+    @SerializedName("type")
+    @Param(description = "usage type")
+    private int usageType;
+
+    @SerializedName("accountid")
+    @Param(description = "account id")
+    private Long accountId;
+
+    @SerializedName("account")
+    @Param(description = "account name")
+    private String accountName;
+
+    @SerializedName("domain")
+    @Param(description = "domain id")
+    private Long domainId;
+
+    @SerializedName("name")
+    @Param(description = "usage type name")
+    private String usageName;
+
+    @SerializedName("unit")
+    @Param(description = "usage unit")
+    private String usageUnit;
+
+    @SerializedName("quota")
+    @Param(description = "quota consumed")
+    private BigDecimal quotaUsed;
+
+    @SerializedName("startdate")
+    @Param(description = "start date")
+    private Date startDate = null;
+
+    @SerializedName("enddate")
+    @Param(description = "end date")
+    private Date endDate = null;
+
+    public QuotaStatementItemResponse() {
+        super();
+    }
+
+    public Long getAccountId() {
+        return accountId;
+    }
+
+    public void setAccountId(Long accountId) {
+        this.accountId = accountId;
+    }
+
+    public String getAccountName() {
+        return accountName;
+    }
+
+    public void setAccountName(String accountName) {
+        this.accountName = accountName;
+    }
+
+    public Long getDomainId() {
+        return domainId;
+    }
+
+    public void setDomainId(Long domainId) {
+        this.domainId = domainId;
+    }
+
+    public String getUsageName() {
+        return usageName;
+    }
+
+    public void setUsageName(String usageName) {
+        this.usageName = usageName;
+    }
+
+    public int getUsageType() {
+        return usageType;
+    }
+
+    public void setUsageType(int usageType) {
+        this.usageType = usageType;
+    }
+
+    public String getUsageUnit() {
+        return usageUnit;
+    }
+
+    public void setUsageUnit(String usageUnit) {
+        this.usageUnit = usageUnit;
+    }
+
+    public BigDecimal getQuotaUsed() {
+        return quotaUsed;
+    }
+
+    public void setQuotaUsed(BigDecimal quotaUsed) {
+        this.quotaUsed = quotaUsed.setScale(2, RoundingMode.HALF_EVEN);
+    }
+
+    public Date getStartDate() {
+        return startDate;
+    }
+
+    public void setStartDate(Date startDate) {
+        this.startDate = startDate;
+    }
+
+    public Date getEndDate() {
+        return endDate;
+    }
+
+    public void setEndDate(Date endDate) {
+        this.endDate = endDate;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementResponse.java
----------------------------------------------------------------------
diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementResponse.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementResponse.java
new file mode 100644
index 0000000..7ea5e6c
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementResponse.java
@@ -0,0 +1,130 @@
+//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.api.response;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+import org.apache.cloudstack.api.BaseResponse;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Date;
+import java.util.List;
+
+public class QuotaStatementResponse  extends BaseResponse {
+
+    @SerializedName("accountid")
+    @Param(description = "account id")
+    private Long accountId;
+
+    @SerializedName("account")
+    @Param(description = "account name")
+    private String accountName;
+
+    @SerializedName("domain")
+    @Param(description = "domain id")
+    private Long domainId;
+
+    @SerializedName("quotausage")
+    @Param(description = "list of quota usage under various types", responseObject = QuotaStatementItemResponse.class)
+    private List<QuotaStatementItemResponse> lineItem;
+
+    @SerializedName("totalquota")
+    @Param(description = "total quota used during this period")
+    private BigDecimal totalQuota;
+
+    @SerializedName("startdate")
+    @Param(description = "start date")
+    private Date startDate = null;
+
+    @SerializedName("enddate")
+    @Param(description = "end date")
+    private Date endDate = null;
+
+    @SerializedName("currency")
+    @Param(description = "currency")
+    private String currency;
+
+    public QuotaStatementResponse() {
+        super();
+    }
+
+    public Long getAccountId() {
+        return accountId;
+    }
+
+    public void setAccountId(Long accountId) {
+        this.accountId = accountId;
+    }
+
+    public String getAccountName() {
+        return accountName;
+    }
+
+    public void setAccountName(String accountName) {
+        this.accountName = accountName;
+    }
+
+    public Long getDomainId() {
+        return domainId;
+    }
+
+    public void setDomainId(Long domainId) {
+        this.domainId = domainId;
+    }
+
+    public List<QuotaStatementItemResponse> getLineItem() {
+        return lineItem;
+    }
+
+    public void setLineItem(List<QuotaStatementItemResponse> lineItem) {
+        this.lineItem = lineItem;
+    }
+
+    public Date getStartDate() {
+        return startDate;
+    }
+
+    public void setStartDate(Date startDate) {
+        this.startDate = startDate;
+    }
+
+    public Date getEndDate() {
+        return endDate;
+    }
+
+    public void setEndDate(Date endDate) {
+        this.endDate = endDate;
+    }
+
+
+    public BigDecimal getTotalQuota() {
+        return totalQuota;
+    }
+
+    public void setTotalQuota(BigDecimal totalQuota) {
+        this.totalQuota = totalQuota.setScale(2, RoundingMode.HALF_EVEN);
+    }
+
+    public String getCurrency() {
+        return currency;
+    }
+
+    public void setCurrency(String currency) {
+        this.currency = currency;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaTariffResponse.java
----------------------------------------------------------------------
diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaTariffResponse.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaTariffResponse.java
new file mode 100644
index 0000000..48697fd
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaTariffResponse.java
@@ -0,0 +1,134 @@
+//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.api.response;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+
+import org.apache.cloudstack.api.BaseResponse;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+public class QuotaTariffResponse extends BaseResponse {
+
+    @SerializedName("usageType")
+    @Param(description = "usageType")
+    private int usageType;
+
+    @SerializedName("usageName")
+    @Param(description = "usageName")
+    private String usageName;
+
+    @SerializedName("usageUnit")
+    @Param(description = "usageUnit")
+    private String usageUnit;
+
+    @SerializedName("usageDiscriminator")
+    @Param(description = "usageDiscriminator")
+    private String usageDiscriminator;
+
+    @SerializedName("tariffValue")
+    @Param(description = "tariffValue")
+    private BigDecimal tariffValue;
+
+    @SerializedName("effectiveDate")
+    @Param(description = "the date on/after which this quota value will be effective")
+    private Date effectiveOn = null;
+
+    @SerializedName("description")
+    @Param(description = "description")
+    private String description;
+
+    @SerializedName("currency")
+    @Param(description = "currency")
+    private String currency;
+
+    public QuotaTariffResponse() {
+        super();
+        this.setObjectName("quotatariff");
+    }
+
+    public QuotaTariffResponse(final int usageType) {
+        super();
+        this.usageType = usageType;
+    }
+
+    public String getUsageName() {
+        return usageName;
+    }
+
+    public void setUsageName(String usageName) {
+        this.usageName = usageName;
+    }
+
+    public int getUsageType() {
+        return usageType;
+    }
+
+    public void setUsageType(int usageType) {
+        this.usageType = usageType;
+    }
+
+    public String getUsageUnit() {
+        return usageUnit;
+    }
+
+    public void setUsageUnit(String usageUnit) {
+        this.usageUnit = usageUnit;
+    }
+
+    public String getUsageDiscriminator() {
+        return usageDiscriminator;
+    }
+
+    public void setUsageDiscriminator(String usageDiscriminator) {
+        this.usageDiscriminator = usageDiscriminator;
+    }
+
+    public BigDecimal getTariffValue() {
+        return tariffValue;
+    }
+
+    public void setTariffValue(BigDecimal tariffValue) {
+        this.tariffValue = tariffValue;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Date getEffectiveOn() {
+        return effectiveOn;
+    }
+
+    public void setEffectiveOn(Date effectiveOn) {
+        this.effectiveOn = effectiveOn;
+    }
+
+    public String getCurrency() {
+        return currency;
+    }
+
+    public void setCurrency(String currency) {
+        this.currency = currency;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaTypeResponse.java
----------------------------------------------------------------------
diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaTypeResponse.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaTypeResponse.java
new file mode 100644
index 0000000..989fba5
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaTypeResponse.java
@@ -0,0 +1,58 @@
+// 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.api.response;
+
+import com.google.gson.annotations.SerializedName;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+
+import com.cloud.serializer.Param;
+
+public class QuotaTypeResponse extends BaseResponse {
+
+    @SerializedName("quotatypeid")
+    @Param(description = "quota type")
+    private Integer quotaType;
+
+    @SerializedName(ApiConstants.DESCRIPTION)
+    @Param(description = "description of usage type")
+    private String description;
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Integer getQuotaType() {
+        return quotaType;
+    }
+
+    public void setQuotaType(Integer quotaType) {
+        this.quotaType = quotaType;
+    }
+
+    public QuotaTypeResponse(Integer quotaType, String description) {
+        this.quotaType = quotaType;
+        this.description = description;
+        setObjectName(ApiConstants.USAGE_TYPE);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaService.java
----------------------------------------------------------------------
diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaService.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaService.java
new file mode 100644
index 0000000..8ee39b8
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaService.java
@@ -0,0 +1,39 @@
+//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.utils.component.PluggableService;
+
+import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
+import org.apache.cloudstack.quota.vo.QuotaUsageVO;
+
+import java.util.Date;
+import java.util.List;
+
+public interface QuotaService extends PluggableService {
+
+    List<QuotaUsageVO> getQuotaUsage(Long accountId, String accountName, Long domainId, Integer usageType, Date startDate, Date endDate);
+
+    List<QuotaBalanceVO> findQuotaBalanceVO(Long accountId, String accountName, Long domainId, Date startDate, Date endDate);
+
+    Date computeAdjustedTime(Date date);
+
+    void setLockAccount(Long accountId, Boolean state);
+
+    void setMinBalance(Long accountId, Double balance);
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java
----------------------------------------------------------------------
diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java
new file mode 100644
index 0000000..e13512a
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java
@@ -0,0 +1,296 @@
+//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.configuration.Config;
+import com.cloud.domain.dao.DomainDao;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.PermissionDeniedException;
+import com.cloud.user.Account;
+import com.cloud.user.AccountVO;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.component.ManagerBase;
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.TransactionLegacy;
+
+import org.apache.cloudstack.api.command.QuotaBalanceCmd;
+import org.apache.cloudstack.api.command.QuotaCreditsCmd;
+import org.apache.cloudstack.api.command.QuotaEmailTemplateUpdateCmd;
+import org.apache.cloudstack.api.command.QuotaEmailTemplateListCmd;
+import org.apache.cloudstack.api.command.QuotaStatementCmd;
+import org.apache.cloudstack.api.command.QuotaTariffListCmd;
+import org.apache.cloudstack.api.command.QuotaTariffUpdateCmd;
+import org.apache.cloudstack.api.response.QuotaResponseBuilder;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.framework.config.Configurable;
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.quota.constant.QuotaConfig;
+import org.apache.cloudstack.quota.dao.QuotaAccountDao;
+import org.apache.cloudstack.quota.dao.QuotaBalanceDao;
+import org.apache.cloudstack.quota.dao.QuotaUsageDao;
+import org.apache.cloudstack.quota.vo.QuotaAccountVO;
+import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
+import org.apache.cloudstack.quota.vo.QuotaUsageVO;
+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.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+
+@Component
+@Local(value = QuotaService.class)
+public class QuotaServiceImpl extends ManagerBase implements QuotaService, Configurable, QuotaConfig {
+    private static final Logger s_logger = Logger.getLogger(QuotaServiceImpl.class.getName());
+
+    @Inject
+    private AccountDao _accountDao;
+    @Inject
+    private QuotaAccountDao _quotaAcc;
+    @Inject
+    private QuotaUsageDao _quotaUsageDao;
+    @Inject
+    private DomainDao _domainDao;
+    @Inject
+    private ConfigurationDao _configDao;
+    @Inject
+    private QuotaBalanceDao _quotaBalanceDao;
+    @Inject
+    private QuotaResponseBuilder _respBldr;
+
+    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 QuotaServiceImpl() {
+        super();
+    }
+
+    @Override
+    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+        super.configure(name, params);
+        String timeZoneStr = _configDao.getValue(Config.UsageAggregationTimezone.toString());
+        String aggregationRange = _configDao.getValue(Config.UsageStatsJobAggregationRange.toString());
+        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 List<Class<?>> getCommands() {
+        final List<Class<?>> cmdList = new ArrayList<Class<?>>();
+        if (!isQuotaServiceEnabled()) {
+            return cmdList;
+        }
+        cmdList.add(QuotaStatementCmd.class);
+        cmdList.add(QuotaBalanceCmd.class);
+        cmdList.add(QuotaTariffListCmd.class);
+        cmdList.add(QuotaTariffUpdateCmd.class);
+        cmdList.add(QuotaCreditsCmd.class);
+        cmdList.add(QuotaEmailTemplateListCmd.class);
+        cmdList.add(QuotaEmailTemplateUpdateCmd.class);
+        return cmdList;
+    }
+
+    @Override
+    public String getConfigComponentName() {
+        return "QUOTA-PLUGIN";
+    }
+
+    @Override
+    public ConfigKey<?>[] getConfigKeys() {
+        return new ConfigKey<?>[] { QuotaPluginEnabled, QuotaEnableEnforcement, QuotaCurrencySymbol, QuotaSmtpHost, QuotaSmtpPort, QuotaSmtpTimeout, QuotaSmtpUser,
+                QuotaSmtpPassword, QuotaSmtpAuthType, QuotaSmtpSender };
+    }
+
+    public Boolean isQuotaServiceEnabled() {
+        return QuotaPluginEnabled.value();
+    }
+
+    @Override
+    public List<QuotaBalanceVO> findQuotaBalanceVO(Long accountId, String accountName, Long domainId, Date startDate, Date endDate) {
+        final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+        TransactionLegacy.open(TransactionLegacy.CLOUD_DB).close();
+
+        Account userAccount = null;
+        Account caller = CallContext.current().getCallingAccount();
+
+        // if accountId is not specified, use accountName and domainId
+        if ((accountId == null) && (accountName != null) && (domainId != null)) {
+            if (_domainDao.isChildDomain(caller.getDomainId(), domainId)) {
+                Filter filter = new Filter(AccountVO.class, "id", Boolean.FALSE, null, null);
+                List<AccountVO> accounts = _accountDao.listAccounts(accountName, domainId, filter);
+                if (accounts.size() > 0) {
+                    userAccount = accounts.get(0);
+                }
+                if (userAccount != null) {
+                    accountId = userAccount.getId();
+                } else {
+                    throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId);
+                }
+            } else {
+                throw new PermissionDeniedException("Invalid Domain Id or Account");
+            }
+        }
+        TransactionLegacy.open(opendb).close();
+
+        startDate = startDate == null ? new Date() : startDate;
+
+        if (endDate == null) {
+            // adjust start date to end of day as there is no end date
+            Date adjustedStartDate = computeAdjustedTime(_respBldr.startOfNextDay(startDate));
+            s_logger.debug("getQuotaBalance1: Getting quota balance records for account: " + accountId + ", domainId: " + domainId + ", on or before " + adjustedStartDate);
+            List<QuotaBalanceVO> qbrecords = _quotaBalanceDao.lastQuotaBalanceVO(accountId, domainId, adjustedStartDate);
+            s_logger.info("Found records size=" + qbrecords.size());
+            if (qbrecords.size() == 0) {
+                throw new InvalidParameterValueException("Incorrect Date there are no quota records before this date " + adjustedStartDate);
+            } else {
+                return qbrecords;
+            }
+        } else {
+            Date adjustedStartDate = computeAdjustedTime(startDate);
+            if (endDate.after(_respBldr.startOfNextDay())) {
+                throw new InvalidParameterValueException("Incorrect Date Range. End date:" + endDate + " should not be in future. ");
+            } else if (startDate.before(endDate)) {
+                Date adjustedEndDate = computeAdjustedTime(endDate);
+                s_logger.debug("getQuotaBalance2: Getting quota balance records for account: " + accountId + ", domainId: " + domainId + ", between " + adjustedStartDate + " and " + adjustedEndDate);
+                List<QuotaBalanceVO> qbrecords = _quotaBalanceDao.findQuotaBalance(accountId, domainId, adjustedStartDate, adjustedEndDate);
+                s_logger.info("getQuotaBalance3: Found records size=" + qbrecords.size());
+                if (qbrecords.size() == 0) {
+                    throw new InvalidParameterValueException("Incorrect Date range there are no quota records between these dates start date " + adjustedStartDate + " and end date:" + endDate);
+                } else {
+                    return qbrecords;
+                }
+            } else {
+                throw new InvalidParameterValueException("Incorrect Date Range. Start date: " + startDate + " is after end date:" + endDate);
+            }
+        }
+
+    }
+
+    @Override
+    public List<QuotaUsageVO> getQuotaUsage(Long accountId, String accountName, Long domainId, Integer usageType, Date startDate, Date endDate) {
+        final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+        TransactionLegacy.open(TransactionLegacy.CLOUD_DB).close();
+        Account userAccount = null;
+        Account caller = CallContext.current().getCallingAccount();
+
+        // if accountId is not specified, use accountName and domainId
+        if ((accountId == null) && (accountName != null) && (domainId != null)) {
+            if (_domainDao.isChildDomain(caller.getDomainId(), domainId)) {
+                Filter filter = new Filter(AccountVO.class, "id", Boolean.FALSE, null, null);
+                List<AccountVO> accounts = _accountDao.listAccounts(accountName, domainId, filter);
+                if (accounts.size() > 0) {
+                    userAccount = accounts.get(0);
+                }
+                if (userAccount != null) {
+                    accountId = userAccount.getId();
+                } else {
+                    throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId);
+                }
+            } else {
+                throw new PermissionDeniedException("Invalid Domain Id or Account");
+            }
+        }
+        TransactionLegacy.open(opendb).close();
+
+        if (startDate.after(endDate)) {
+            throw new InvalidParameterValueException("Incorrect Date Range. Start date: " + startDate + " is after end date:" + endDate);
+        }
+        if (endDate.after(_respBldr.startOfNextDay())) {
+            throw new InvalidParameterValueException("Incorrect Date Range. End date:" + endDate + " should not be in future. ");
+        }
+        Date adjustedEndDate = computeAdjustedTime(endDate);
+        Date adjustedStartDate = computeAdjustedTime(startDate);
+        s_logger.debug("Getting quota records for account: " + accountId + ", domainId: " + domainId + ", between " + startDate + " and " + endDate);
+        return _quotaUsageDao.findQuotaUsage(accountId, domainId, usageType, adjustedStartDate, adjustedEndDate);
+    }
+
+    @Override
+    public Date computeAdjustedTime(final Date date) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(date);
+        TimeZone localTZ = cal.getTimeZone();
+        int timezoneOffset = cal.get(Calendar.ZONE_OFFSET);
+        if (localTZ.inDaylightTime(date)) {
+            timezoneOffset += (60 * 60 * 1000);
+        }
+        cal.add(Calendar.MILLISECOND, timezoneOffset);
+
+        Date newTime = cal.getTime();
+
+        Calendar calTS = Calendar.getInstance(_usageTimezone);
+        calTS.setTime(newTime);
+        timezoneOffset = calTS.get(Calendar.ZONE_OFFSET);
+        if (_usageTimezone.inDaylightTime(date)) {
+            timezoneOffset += (60 * 60 * 1000);
+        }
+
+        calTS.add(Calendar.MILLISECOND, -1 * timezoneOffset);
+
+        return calTS.getTime();
+    }
+
+    @Override
+    public void setLockAccount(Long accountId, Boolean state) {
+        QuotaAccountVO acc = _quotaAcc.findById(accountId);
+        if (acc == null) {
+            acc = new QuotaAccountVO(accountId);
+            acc.setQuotaEnforce(state ? 1 : 0);
+            _quotaAcc.persist(acc);
+        } else {
+            acc.setQuotaEnforce(state ? 1 : 0);
+            _quotaAcc.update(accountId, acc);
+        }
+    }
+
+    @Override
+    public void setMinBalance(Long accountId, Double balance) {
+        QuotaAccountVO acc = _quotaAcc.findById(accountId);
+        if (acc == null) {
+            acc = new QuotaAccountVO(accountId);
+            acc.setQuotaMinBalance(new BigDecimal(balance));
+            _quotaAcc.persist(acc);
+        } else {
+            acc.setQuotaMinBalance(new BigDecimal(balance));
+            _quotaAcc.update(accountId, acc);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/plugins/hypervisors/ovm3/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/ovm3/pom.xml b/plugins/hypervisors/ovm3/pom.xml
index 82b6e46..34fc411 100644
--- a/plugins/hypervisors/ovm3/pom.xml
+++ b/plugins/hypervisors/ovm3/pom.xml
@@ -45,7 +45,7 @@
     <dependency>
 	<groupId>org.apache.commons</groupId>
 	<artifactId>commons-lang3</artifactId>
-	<version>${cs.lang3.version}</version>
+	<version>${cs.commons-lang3.version}</version>
     </dependency>
     <dependency>
 	<groupId>log4j</groupId>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/plugins/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/pom.xml b/plugins/pom.xml
index 7368d20..2237b2f 100755
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -101,6 +101,7 @@
     <module>network-elements/internal-loadbalancer</module>
     <module>network-elements/vxlan</module>
     <module>network-elements/globodns</module>
+    <module>database/quota</module>
   </modules>
 
   <dependencies>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 219402c..3d02d48 100644
--- a/pom.xml
+++ b/pom.xml
@@ -98,7 +98,7 @@
     <cs.powermock.version>1.5.3</cs.powermock.version>
     <cs.aws.sdk.version>1.3.22</cs.aws.sdk.version>
     <cs.lang.version>2.6</cs.lang.version>
-    <cs.lang3.version>3.4</cs.lang3.version>
+    <cs.commons-lang3.version>3.4</cs.commons-lang3.version>
     <cs.commons-io.version>2.4</cs.commons-io.version>
     <cs.commons-validator.version>1.4.0</cs.commons-validator.version>
     <cs.reflections.version>0.9.9</cs.reflections.version>
@@ -115,6 +115,7 @@
     <cs.javadoc.version>2.10.1</cs.javadoc.version>
     <cs.opensaml.version>2.6.1</cs.opensaml.version>
     <cs.xml-apis.version>1.4.01</cs.xml-apis.version>
+    <cs.joda-time.version>2.8.1</cs.joda-time.version>
   </properties>
 
   <distributionManagement>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/server/src/com/cloud/api/dispatch/ParamProcessWorker.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/dispatch/ParamProcessWorker.java b/server/src/com/cloud/api/dispatch/ParamProcessWorker.java
index eb3b77a..6d9707d 100644
--- a/server/src/com/cloud/api/dispatch/ParamProcessWorker.java
+++ b/server/src/com/cloud/api/dispatch/ParamProcessWorker.java
@@ -294,6 +294,14 @@ public class ParamProcessWorker implements DispatchWorker {
                     field.set(cmdObj, Float.valueOf(paramObj.toString()));
                 }
                 break;
+            case DOUBLE:
+                // Assuming that the parameters have been checked for required before now,
+                // we ignore blank or null values and defer to the command to set a default
+                // value for optional parameters ...
+                if (paramObj != null && isNotBlank(paramObj.toString())) {
+                    field.set(cmdObj, Double.valueOf(paramObj.toString()));
+                }
+                break;
             case INTEGER:
                 // Assuming that the parameters have been checked for required before now,
                 // we ignore blank or null values and defer to the command to set a default

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/server/src/com/cloud/user/AccountManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java
index 2d07e84..5d32356 100644
--- a/server/src/com/cloud/user/AccountManagerImpl.java
+++ b/server/src/com/cloud/user/AccountManagerImpl.java
@@ -2183,8 +2183,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
                 if (s_logger.isInfoEnabled()) {
                     s_logger.info("User " + username + " in domain " + domainName + " is disabled/locked (or account is disabled/locked)");
                 }
-                throw new CloudAuthenticationException("User " + username + " in domain " + domainName + " is disabled/locked (or account is disabled/locked)");
-                // return null;
+                throw new CloudAuthenticationException("User " + username + " (or their account) in domain " + domainName + " is disabled/locked. Please contact the administrator.");
             }
             // Whenever the user is able to log in successfully, reset the login attempts to zero
             if (!isInternalAccount(userAccount.getId()))

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/setup/db/db/schema-451to452.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-451to452.sql b/setup/db/db/schema-451to452.sql
index d0aeabf..b54a4c3 100644
--- a/setup/db/db/schema-451to452.sql
+++ b/setup/db/db/schema-451to452.sql
@@ -19,7 +19,9 @@
 -- Schema upgrade from 4.5.1 to 4.5.2;
 --;
 
-DELETE FROM `cloud`.`configuration` WHERE name like 'saml%';
+-- SAML
+
+DELETE FROM `cloud`.`configuration` WHERE name like 'saml%' and component='management-server';
 
 ALTER TABLE `cloud`.`user` ADD COLUMN `external_entity` text DEFAULT NULL COMMENT "reference to external federation entity";
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/setup/db/db/schema-452to460.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-452to460.sql b/setup/db/db/schema-452to460.sql
index e013b2b..b704f40 100644
--- a/setup/db/db/schema-452to460.sql
+++ b/setup/db/db/schema-452to460.sql
@@ -399,3 +399,115 @@ CREATE TABLE `cloud`.`external_bigswitch_bcf_devices` (
   CONSTRAINT `fk_external_bigswitch_bcf_devices__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
+-- Quota start
+
+CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_account` (
+      `account_id` int(11) NOT NULL,
+      `quota_balance` decimal(15,2) NULL,
+      `quota_balance_date` datetime NULL,
+      `quota_enforce` int(1) DEFAULT NULL,
+      `quota_min_balance` decimal(15,2) DEFAULT NULL,
+      `quota_alert_date` datetime DEFAULT NULL,
+      `quota_alert_type` int(11) DEFAULT NULL,
+      `last_statement_date` datetime DEFAULT NULL,
+      PRIMARY KEY (`account_id`),
+  CONSTRAINT `account_id` FOREIGN KEY (`account_id`) REFERENCES `cloud_usage`.`account` (`quota_enforce`)
+  ON DELETE NO ACTION
+  ON UPDATE NO ACTION
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_tariff` (
+  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
+  `usage_type` int(2) unsigned DEFAULT NULL,
+  `usage_name` varchar(255) NOT NULL COMMENT 'usage type',
+  `usage_unit` varchar(255) NOT NULL COMMENT 'usage type',
+  `usage_discriminator` varchar(255) NOT NULL COMMENT 'usage type',
+  `currency_value` decimal(15,2) NOT NULL COMMENT 'usage type',
+  `effective_on` datetime NOT NULL COMMENT 'date time on which this quota values will become effective',
+  `updated_on` datetime NOT NULL COMMENT 'date this entry was updated on',
+  `updated_by` bigint unsigned NOT NULL,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+LOCK TABLES `cloud_usage`.`quota_tariff` WRITE;
+INSERT IGNORE INTO `cloud_usage`.`quota_tariff` (`usage_type`, `usage_name`, `usage_unit`, `usage_discriminator`, `currency_value`, `effective_on`,  `updated_on`, `updated_by`) VALUES
+ (1,'RUNNING_VM','Compute-Month','',0.00,'2010-05-04', '2010-05-04',1),
+ (2,'ALLOCATED_VM','Compute-Month','',0.00,'2010-05-04', '2010-05-04',1),
+ (3,'IP_ADDRESS','IP-Month','',0.00,'2010-05-04', '2010-05-04',1),
+ (4,'NETWORK_BYTES_SENT','GB','',0.00,'2010-05-04', '2010-05-04',1),
+ (5,'NETWORK_BYTES_RECEIVED','GB','',0.00,'2010-05-04', '2010-05-04',1),
+ (6,'VOLUME','GB-Month','',0.00,'2010-05-04', '2010-05-04',1),
+ (7,'TEMPLATE','GB-Month','',0.00,'2010-05-04', '2010-05-04',1),
+ (8,'ISO','GB-Month','',0.00,'2010-05-04', '2010-05-04',1),
+ (9,'SNAPSHOT','GB-Month','',0.00,'2010-05-04', '2010-05-04',1),
+ (10,'SECURITY_GROUP','Policy-Month','',0.00,'2010-05-04', '2010-05-04',1),
+ (11,'LOAD_BALANCER_POLICY','Policy-Month','',0.00,'2010-05-04', '2010-05-04',1),
+ (12,'PORT_FORWARDING_RULE','Policy-Month','',0.00,'2010-05-04', '2010-05-04',1),
+ (13,'NETWORK_OFFERING','Policy-Month','',0.00,'2010-05-04', '2010-05-04',1),
+ (14,'VPN_USERS','Policy-Month','',0.00,'2010-05-04', '2010-05-04',1),
+ (15,'CPU_SPEED','Compute-Month','100MHz',0.00,'2010-05-04', '2010-05-04',1),
+ (16,'vCPU','Compute-Month','1VCPU',0.00,'2010-05-04', '2010-05-04',1),
+ (17,'MEMORY','Compute-Month','1MB',0.00,'2010-05-04', '2010-05-04',1),
+ (21,'VM_DISK_IO_READ','GB','1',0.00,'2010-05-04', '2010-05-04',1),
+ (22,'VM_DISK_IO_WRITE','GB','1',0.00,'2010-05-04', '2010-05-04',1),
+ (23,'VM_DISK_BYTES_READ','GB','1',0.00,'2010-05-04', '2010-05-04',1),
+ (24,'VM_DISK_BYTES_WRITE','GB','1',0.00,'2010-05-04', '2010-05-04',1),
+ (25,'VM_SNAPSHOT','GB-Month','',0.00,'2010-05-04', '2010-05-04',1);
+UNLOCK TABLES;
+
+CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_credits` (
+  `id` bigint unsigned NOT NULL auto_increment COMMENT 'id',
+  `account_id` bigint unsigned NOT NULL,
+  `domain_id` bigint(20) unsigned NOT NULL,
+  `credit` decimal(15,4) COMMENT 'amount credited',
+  `updated_on` datetime NOT NULL COMMENT 'date created',
+  `updated_by` bigint unsigned NOT NULL,
+  PRIMARY KEY  (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_usage` (
+  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
+  `usage_item_id` bigint(20) unsigned NOT NULL,
+  `zone_id` bigint(20) unsigned NOT NULL,
+  `account_id` bigint(20) unsigned NOT NULL,
+  `domain_id` bigint(20) unsigned NOT NULL,
+  `usage_type` varchar(64) DEFAULT NULL,
+  `quota_used` decimal(15,8) unsigned NOT NULL,
+  `start_date` datetime NOT NULL COMMENT 'start time for this usage item',
+  `end_date` datetime NOT NULL COMMENT 'end time for this usage item',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_balance` (
+  `id` bigint unsigned NOT NULL auto_increment COMMENT 'id',
+  `account_id` bigint unsigned NOT NULL,
+  `domain_id` bigint(20) unsigned NOT NULL,
+  `credit_balance` decimal(15,8) COMMENT 'amount of credits remaining',
+  `credits_id`  bigint unsigned COMMENT 'if not null then this entry corresponds to credit change quota_credits',
+  `updated_on` datetime NOT NULL COMMENT 'date updated on',
+  PRIMARY KEY  (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_email_templates` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT,
+  `template_name` varchar(64) NOT NULL UNIQUE,
+  `template_subject` longtext,
+  `template_body` longtext,
+  `locale` varchar(25) DEFAULT 'en_US',
+  `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+LOCK TABLES `cloud_usage`.`quota_email_templates` WRITE;
+INSERT IGNORE INTO `cloud_usage`.`quota_email_templates` (`template_name`, `template_subject`, `template_body`) VALUES
+ ('QUOTA_LOW', 'Quota Usage Threshold crossed by your account ${accountName}', 'Your account ${accountName} in the domain ${domainName} has reached quota usage threshold, your current quota balance is ${quotaBalance}.'),
+ ('QUOTA_EMPTY', 'Quota Exhausted, account ${accountName} is locked now', 'Your account ${accountName} in the domain ${domainName} has exhausted allocated quota and has been locked now, please contact the administrator.'),
+ ('QUOTA_UNLOCK_ACCOUNT', 'Quota credits added, account ${accountName} is unlocked now', 'Your account ${accountName} in the domain ${domainName} has enough quota credits now with the current balance of ${quotaBalance}. Your account has been unlocked now.'),
+ ('QUOTA_STATEMENT', 'Quota Statement for your account ${accountName}', 'Monthly quota statement of your account ${accountName} in the domain ${domainName}:<br>Balance = ${quotaBalance}<br>Total Usage = ${quotaUsage}.');
+UNLOCK TABLES;
+
+-- Quota end

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/tools/apidoc/gen_toc.py
----------------------------------------------------------------------
diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py
index cb26e2b..2f147c7 100644
--- a/tools/apidoc/gen_toc.py
+++ b/tools/apidoc/gen_toc.py
@@ -118,6 +118,8 @@ known_categories = {
     'listIdps': 'Authentication',
     'authorizeSamlSso': 'Authentication',
     'listSamlAuthorization': 'Authentication',
+    'quota': 'Quota',
+    'emailTemplate': 'Quota',
     'Capacity': 'System Capacity',
     'NetworkDevice': 'Network Device',
     'ExternalLoadBalancer': 'Ext Load Balancer',

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/usage/pom.xml
----------------------------------------------------------------------
diff --git a/usage/pom.xml b/usage/pom.xml
index c1cbb92..2c172b1 100644
--- a/usage/pom.xml
+++ b/usage/pom.xml
@@ -36,6 +36,11 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
+        <groupId>org.apache.cloudstack</groupId>
+        <artifactId>cloud-framework-quota</artifactId>
+        <version>${project.version}</version>
+    </dependency>
+    <dependency>
       <groupId>commons-daemon</groupId>
       <artifactId>commons-daemon</artifactId>
     </dependency>
@@ -65,6 +70,11 @@
       <version>2.4.9</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+      <version>${cs.commons-lang3.version}</version>
+    </dependency>
   </dependencies>
   <build>
     <resources>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/usage/resources/usageApplicationContext.xml
----------------------------------------------------------------------
diff --git a/usage/resources/usageApplicationContext.xml b/usage/resources/usageApplicationContext.xml
index 85936c7..b1d57c4 100644
--- a/usage/resources/usageApplicationContext.xml
+++ b/usage/resources/usageApplicationContext.xml
@@ -17,36 +17,38 @@
   under the License.
 -->
 <beans xmlns="http://www.springframework.org/schema/beans"
-  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
-  xmlns:context="http://www.springframework.org/schema/context"
-  xmlns:tx="http://www.springframework.org/schema/tx" 
-  xmlns:aop="http://www.springframework.org/schema/aop"
-  xsi:schemaLocation="http://www.springframework.org/schema/beans
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
+	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
                       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                       http://www.springframework.org/schema/tx 
                       http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                       http://www.springframework.org/schema/aop
                       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
                       http://www.springframework.org/schema/context
-                      http://www.springframework.org/schema/context/spring-context-3.0.xsd">                     
-
-  <context:annotation-config />
-  <context:component-scan base-package="com.cloud.usage, com.cloud.event.dao, com.cloud.user.dao, com.cloud.configuration.dao, com.cloud.alert.dao, com.cloud.domain.dao, org.apache.cloudstack.framework.config.dao">
-  </context:component-scan>
-  
-  <!--
-    @DB support
-  -->
-  <bean id="transactionContextBuilder" class="com.cloud.utils.db.TransactionContextBuilder" />
-
-  <bean id="instantiatePostProcessor" class="com.cloud.utils.component.ComponentInstantiationPostProcessor">
-    <property name="Interceptors">
-        <list>
-            <ref bean="transactionContextBuilder" />
-        </list>
-    </property>
-  </bean>
-  
-  <bean id="ComponentContext" class="com.cloud.utils.component.ComponentContext" />
- 
+                      http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+
+	<context:annotation-config />
+	<context:component-scan
+		base-package="com.cloud.usage, com.cloud.event.dao, com.cloud.user.dao, com.cloud.configuration.dao, com.cloud.alert.dao, com.cloud.domain.dao, org.apache.cloudstack.framework.config.dao,
+      org.apache.cloudstack.quota.constant, org.apache.cloudstack.quota.dao, org.apache.cloudstack.quota.vo">
+	</context:component-scan>
+
+	<bean id="QuotaManager" class="org.apache.cloudstack.quota.QuotaManagerImpl" />
+    <bean id="QuotaAlertManager" class="org.apache.cloudstack.quota.QuotaAlertManagerImpl" />
+
+	<!-- @DB support -->
+	<bean id="transactionContextBuilder" class="com.cloud.utils.db.TransactionContextBuilder" />
+
+	<bean id="instantiatePostProcessor"
+		class="com.cloud.utils.component.ComponentInstantiationPostProcessor">
+		<property name="Interceptors">
+			<list>
+				<ref bean="transactionContextBuilder" />
+			</list>
+		</property>
+	</bean>
+
+	<bean id="ComponentContext" class="com.cloud.utils.component.ComponentContext" />
+
 </beans>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/usage/src/com/cloud/usage/UsageManagerImpl.java
----------------------------------------------------------------------
diff --git a/usage/src/com/cloud/usage/UsageManagerImpl.java b/usage/src/com/cloud/usage/UsageManagerImpl.java
index c1e26b3..043b19d 100644
--- a/usage/src/com/cloud/usage/UsageManagerImpl.java
+++ b/usage/src/com/cloud/usage/UsageManagerImpl.java
@@ -34,10 +34,11 @@ import javax.ejb.Local;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import org.apache.cloudstack.quota.QuotaAlertManager;
+import org.apache.cloudstack.quota.QuotaManager;
 import org.apache.cloudstack.utils.usage.UsageUtils;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
-
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.managed.context.ManagedContextRunnable;
 import org.apache.cloudstack.usage.UsageTypes;
@@ -144,11 +145,16 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
     ConfigurationDao _configDao;
     @Inject
     private UsageVMSnapshotDao _usageVMSnapshotDao;
+    @Inject
+    private QuotaManager _quotaManager;
+    @Inject
+    private QuotaAlertManager _alertManager;
 
     private String _version = null;
     private final Calendar _jobExecTime = Calendar.getInstance();
     private int _aggregationDuration = 0;
     private int _sanityCheckInterval = 0;
+    private boolean _runQuota=false;
     String _hostname = null;
     int _pid = 0;
     TimeZone _usageTimezone = TimeZone.getTimeZone("GMT");;
@@ -199,6 +205,8 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
         String execTimeZone = configs.get("usage.execution.timezone");
         String aggreagationTimeZone = configs.get("usage.aggregation.timezone");
         String sanityCheckInterval = configs.get("usage.sanity.check.interval");
+        String quotaEnable = configs.get("quota.enable.service");
+        _runQuota = Boolean.valueOf(quotaEnable == null ? "false" : quotaEnable );
         if (sanityCheckInterval != null) {
             _sanityCheckInterval = Integer.parseInt(sanityCheckInterval);
         }
@@ -373,6 +381,26 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
             }
 
             parse(job, startDate, endDate);
+            if (_runQuota){
+                try {
+                    _quotaManager.calculateQuotaUsage();
+                }
+                catch (Exception e){
+                    s_logger.fatal("Exception received while calculating quota " + e.getMessage());
+                    if (s_logger.isDebugEnabled()){
+                        e.printStackTrace();
+                    }
+                }
+                try {
+                    _alertManager.checkAndSendQuotaAlertEmails();
+                    _alertManager.sendMonthlyStatement();
+                } catch (Exception e) {
+                    s_logger.fatal("Exception received while sending alerts " + e.getMessage());
+                    if (s_logger.isDebugEnabled()) {
+                        e.printStackTrace();
+                    }
+                }
+            }
         } else {
             if (s_logger.isDebugEnabled()) {
                 s_logger.debug("Not owner of usage job, skipping...");

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dedb351f/usage/src/org/apache/cloudstack/quota/QuotaAlertManager.java
----------------------------------------------------------------------
diff --git a/usage/src/org/apache/cloudstack/quota/QuotaAlertManager.java b/usage/src/org/apache/cloudstack/quota/QuotaAlertManager.java
new file mode 100644
index 0000000..c07e015
--- /dev/null
+++ b/usage/src/org/apache/cloudstack/quota/QuotaAlertManager.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
+//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.utils.component.Manager;
+
+public interface QuotaAlertManager extends Manager {
+
+    public void checkAndSendQuotaAlertEmails();
+
+    void sendMonthlyStatement();
+
+}


Mime
View raw message