diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index 2471e0889578..d774c1498ab2 100755
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -269,6 +269,7 @@ public class ApiConstants {
public static final String VIRTUAL_MACHINE_IDS = "virtualmachineids";
public static final String VIRTUAL_MACHINE_ID_IP = "vmidipmap";
public static final String USAGE_ID = "usageid";
+ public static final String USAGE_TYPE = "usagetype";
public static final String VLAN = "vlan";
public static final String VLAN_RANGE = "vlanrange";
diff --git a/api/src/org/apache/cloudstack/api/BaseCmd.java b/api/src/org/apache/cloudstack/api/BaseCmd.java
index 12265665d30f..0f790cac264e 100644
--- a/api/src/org/apache/cloudstack/api/BaseCmd.java
+++ b/api/src/org/apache/cloudstack/api/BaseCmd.java
@@ -97,7 +97,7 @@ public static enum HTTPMethod {
GET, POST, PUT, DELETE
}
public static enum CommandType {
- BOOLEAN, DATE, FLOAT, INTEGER, SHORT, LIST, LONG, OBJECT, MAP, STRING, TZDATE, UUID
+ BOOLEAN, DATE, FLOAT, DOUBLE, INTEGER, SHORT, LIST, LONG, OBJECT, MAP, STRING, TZDATE, UUID
}
private Object _responseObject;
diff --git a/api/src/org/apache/cloudstack/api/command/admin/usage/GetUsageRecordsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/usage/GetUsageRecordsCmd.java
index fd8173d416da..76af050d2ca0 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/usage/GetUsageRecordsCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/usage/GetUsageRecordsCmd.java
@@ -38,6 +38,7 @@
@APICommand(name = "listUsageRecords", description = "Lists usage records for accounts", responseObject = UsageRecordResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class GetUsageRecordsCmd extends BaseListCmd {
+
public static final Logger s_logger = Logger.getLogger(GetUsageRecordsCmd.class.getName());
private static final String s_name = "listusagerecordsresponse";
@@ -111,6 +112,30 @@ public Long getProjectId() {
public String getUsageId() {
return usageId;
}
+ public void setAccountName(String accountName) {
+ this.accountName = accountName;
+ }
+
+ public void setDomainId(Long domainId) {
+ this.domainId = domainId;
+ }
+
+ public void setEndDate(Date endDate) {
+ this.endDate = endDate;
+ }
+
+ public void setStartDate(Date startDate) {
+ this.startDate = startDate;
+ }
+
+ public void setAccountId(Long accountId) {
+ this.accountId = accountId;
+ }
+
+ public void setUsageId(String usageId) {
+ this.usageId = usageId;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
diff --git a/api/src/org/apache/cloudstack/usage/UsageTypes.java b/api/src/org/apache/cloudstack/usage/UsageTypes.java
index 3edfd0b66aad..2163df7efc5d 100644
--- a/api/src/org/apache/cloudstack/usage/UsageTypes.java
+++ b/api/src/org/apache/cloudstack/usage/UsageTypes.java
@@ -22,6 +22,8 @@
import org.apache.cloudstack.api.response.UsageTypeResponse;
public class UsageTypes {
+
+ /* Any changes here should also reflect in cloud_usage.quota_mapping table */
public static final int RUNNING_VM = 1;
public static final int ALLOCATED_VM = 2; // used for tracking how long storage has been allocated for a VM
public static final int IP_ADDRESS = 3;
diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties
index c7f02600ac2a..d4dc46ac7c2d 100644
--- a/client/WEB-INF/classes/resources/messages.properties
+++ b/client/WEB-INF/classes/resources/messages.properties
@@ -1355,6 +1355,13 @@ label.show.advanced.settings=Show advanced settings
label.delete.OpenDaylight.device=Delete OpenDaylight Controller
label.polling.interval.sec=Polling Interval (in sec)
label.quiet.time.sec=Quiet Time (in sec)
+label.usage.type=Usage Type
+label.usage.unit=Unit
+label.quota.value=Quota Value
+label.quota.description=Quota Description
+label.quota.configuration=Quota Configuration
+label.quota.configure=Configure Quota
+label.quota.remove=Remove Quota
label.destroy.vm.graceperiod=Destroy VM Grace Period
label.SNMP.community=SNMP Community
label.SNMP.port=SNMP Port
diff --git a/client/pom.xml b/client/pom.xml
index 13e1411b9719..462af5bfd751 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -246,6 +246,11 @@
cloud-framework-ipc
${project.version}
+
+ org.apache.cloudstack
+ cloud-framework-quota
+ ${project.version}
+
org.apache.cloudstack
cloud-framework-rest
@@ -356,6 +361,11 @@
cloud-plugin-network-globodns
${project.version}
+
+ org.apache.cloudstack
+ cloud-plugin-database-quota
+ ${project.version}
+
diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in
index a66a3dce4863..2801fe38236e 100644
--- a/client/tomcatconf/commands.properties.in
+++ b/client/tomcatconf/commands.properties.in
@@ -781,3 +781,13 @@ listOpenDaylightControllers=1
### GloboDNS commands
addGloboDnsHost=1
+
+### Quota Service
+quotaStatement=15
+quotaBalance=15
+quotaTariffList=15
+quotaTariffUpdate=1
+quotaCredits=1
+quotaEmailTemplateList=1
+quotaEmailTemplateUpdate=1
+
diff --git a/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java
index a3ff45ca3ad3..7263057c6c9c 100644
--- a/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java
+++ b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java
@@ -238,4 +238,5 @@ public ServiceOfferingVO getcomputeOffering(ServiceOfferingVO serviceOffering, M
return dummyoffering;
}
+
}
diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade451to452.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade451to452.java
index 870e534fb7f4..16b8a0dd7993 100644
--- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade451to452.java
+++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade451to452.java
@@ -19,17 +19,20 @@
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.Script;
+
import org.apache.log4j.Logger;
import java.io.File;
import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
public class Upgrade451to452 implements DbUpgrade {
final static Logger s_logger = Logger.getLogger(Upgrade451to452.class);
@Override
public String[] getUpgradableVersionRange() {
- return new String[] {"4.5.1", "4.5.2"};
+ return new String[] { "4.5.1", "4.5.2" };
}
@Override
@@ -48,11 +51,24 @@ public File[] getPrepareScripts() {
if (script == null) {
throw new CloudRuntimeException("Unable to find db/schema-451to452.sql");
}
- return new File[] {new File(script)};
+ return new File[] { new File(script) };
}
@Override
public void performDataMigration(Connection conn) {
+ PreparedStatement pstmt = null;
+ try {
+ pstmt = conn.prepareStatement("ALTER TABLE `cloud_usage`.`cloud_usage` ADD COLUMN `quota_calculated` tinyint(1) DEFAULT 0 NOT NULL COMMENT 'quota calculation status'");
+ pstmt.executeUpdate();
+ pstmt.close();
+ s_logger.debug("Altered usage table and added column quota_calculated");
+ } catch (SQLException e) {
+ if (e.getMessage().contains("quota_calculated")) {
+ s_logger.debug("Usage table already has a column called quota_calculated");
+ } else {
+ throw new CloudRuntimeException("Unable to create column quota_calculated", e);
+ }
+ }
}
@Override
@@ -62,6 +78,7 @@ public File[] getCleanupScripts() {
throw new CloudRuntimeException("Unable to find db/schema-451to452-cleanup.sql");
}
- return new File[] {new File(script)};
+ return new File[] { new File(script) };
}
+
}
diff --git a/engine/schema/src/com/cloud/usage/UsageVO.java b/engine/schema/src/com/cloud/usage/UsageVO.java
index c46abb3a9b5a..bf5f551d2485 100644
--- a/engine/schema/src/com/cloud/usage/UsageVO.java
+++ b/engine/schema/src/com/cloud/usage/UsageVO.java
@@ -103,6 +103,17 @@ public class UsageVO implements Usage, InternalIdentity {
@Temporal(value = TemporalType.TIMESTAMP)
private Date endDate = null;
+ @Column(name = "quota_calculated")
+ private Integer quotaCalculated = null;
+
+ public Integer getQuotaCalculated() {
+ return quotaCalculated;
+ }
+
+ public void setQuotaCalculated(Integer quotaCalculated) {
+ this.quotaCalculated = quotaCalculated;
+ }
+
public UsageVO() {
}
diff --git a/engine/schema/src/com/cloud/usage/dao/UsageDao.java b/engine/schema/src/com/cloud/usage/dao/UsageDao.java
index 334c9d046a51..4062a63a18f7 100644
--- a/engine/schema/src/com/cloud/usage/dao/UsageDao.java
+++ b/engine/schema/src/com/cloud/usage/dao/UsageDao.java
@@ -53,4 +53,6 @@ public interface UsageDao extends GenericDao {
void saveVmDiskStats(List vmDiskStats);
void saveUsageRecords(List usageRecords);
+
+ Pair, Integer> getUsageRecordsPendingQuotaAggregation(long accountId, long domainId);
}
diff --git a/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java
index a2d38e24532a..200e5e8aa51f 100644
--- a/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java
+++ b/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java
@@ -42,35 +42,30 @@
import com.cloud.utils.exception.CloudRuntimeException;
@Component
-@Local(value = {UsageDao.class})
+@Local(value = { UsageDao.class })
public class UsageDaoImpl extends GenericDaoBase implements UsageDao {
public static final Logger s_logger = Logger.getLogger(UsageDaoImpl.class.getName());
private static final String DELETE_ALL = "DELETE FROM cloud_usage";
private static final String DELETE_ALL_BY_ACCOUNTID = "DELETE FROM cloud_usage WHERE account_id = ?";
private static final String INSERT_ACCOUNT = "INSERT INTO cloud_usage.account (id, account_name, type, domain_id, removed, cleanup_needed) VALUES (?,?,?,?,?,?)";
- private static final String INSERT_USER_STATS =
- "INSERT INTO cloud_usage.user_statistics (id, data_center_id, account_id, public_ip_address, device_id, device_type, network_id, net_bytes_received,"
- + " net_bytes_sent, current_bytes_received, current_bytes_sent, agg_bytes_received, agg_bytes_sent) VALUES (?,?,?,?,?,?,?,?,?,?, ?, ?, ?)";
+ private static final String INSERT_USER_STATS = "INSERT INTO cloud_usage.user_statistics (id, data_center_id, account_id, public_ip_address, device_id, device_type, network_id, net_bytes_received,"
+ + " net_bytes_sent, current_bytes_received, current_bytes_sent, agg_bytes_received, agg_bytes_sent) VALUES (?,?,?,?,?,?,?,?,?,?, ?, ?, ?)";
private static final String UPDATE_ACCOUNT = "UPDATE cloud_usage.account SET account_name=?, removed=? WHERE id=?";
- private static final String UPDATE_USER_STATS =
- "UPDATE cloud_usage.user_statistics SET net_bytes_received=?, net_bytes_sent=?, current_bytes_received=?, current_bytes_sent=?, agg_bytes_received=?, agg_bytes_sent=? WHERE id=?";
+ private static final String UPDATE_USER_STATS = "UPDATE cloud_usage.user_statistics SET net_bytes_received=?, net_bytes_sent=?, current_bytes_received=?, current_bytes_sent=?, agg_bytes_received=?, agg_bytes_sent=? WHERE id=?";
private static final String GET_LAST_ACCOUNT = "SELECT id FROM cloud_usage.account ORDER BY id DESC LIMIT 1";
private static final String GET_LAST_USER_STATS = "SELECT id FROM cloud_usage.user_statistics ORDER BY id DESC LIMIT 1";
private static final String GET_PUBLIC_TEMPLATES_BY_ACCOUNTID = "SELECT id FROM cloud.vm_template WHERE account_id = ? AND public = '1' AND removed IS NULL";
private static final String GET_LAST_VM_DISK_STATS = "SELECT id FROM cloud_usage.vm_disk_statistics ORDER BY id DESC LIMIT 1";
- private static final String INSERT_VM_DISK_STATS =
- "INSERT INTO cloud_usage.vm_disk_statistics (id, data_center_id, account_id, vm_id, volume_id, net_io_read, net_io_write, current_io_read, "
- + "current_io_write, agg_io_read, agg_io_write, net_bytes_read, net_bytes_write, current_bytes_read, current_bytes_write, agg_bytes_read, agg_bytes_write) "
- + " VALUES (?,?,?,?,?,?,?,?,?,?, ?, ?, ?, ?,?, ?, ?)";
- private static final String UPDATE_VM_DISK_STATS =
- "UPDATE cloud_usage.vm_disk_statistics SET net_io_read=?, net_io_write=?, current_io_read=?, current_io_write=?, agg_io_read=?, agg_io_write=?, "
- + "net_bytes_read=?, net_bytes_write=?, current_bytes_read=?, current_bytes_write=?, agg_bytes_read=?, agg_bytes_write=? WHERE id=?";
+ private static final String INSERT_VM_DISK_STATS = "INSERT INTO cloud_usage.vm_disk_statistics (id, data_center_id, account_id, vm_id, volume_id, net_io_read, net_io_write, current_io_read, "
+ + "current_io_write, agg_io_read, agg_io_write, net_bytes_read, net_bytes_write, current_bytes_read, current_bytes_write, agg_bytes_read, agg_bytes_write) "
+ + " VALUES (?,?,?,?,?,?,?,?,?,?, ?, ?, ?, ?,?, ?, ?)";
+ private static final String UPDATE_VM_DISK_STATS = "UPDATE cloud_usage.vm_disk_statistics SET net_io_read=?, net_io_write=?, current_io_read=?, current_io_write=?, agg_io_read=?, agg_io_write=?, "
+ + "net_bytes_read=?, net_bytes_write=?, current_bytes_read=?, current_bytes_write=?, agg_bytes_read=?, agg_bytes_write=? WHERE id=?";
private static final String INSERT_USAGE_RECORDS = "INSERT INTO cloud_usage.cloud_usage (zone_id, account_id, domain_id, description, usage_display, "
- +
- "usage_type, raw_usage, vm_instance_id, vm_name, offering_id, template_id, "
+ + "usage_type, raw_usage, vm_instance_id, vm_name, offering_id, template_id, "
+ "usage_id, type, size, network_id, start_date, end_date, virtual_size) VALUES (?,?,?,?,?,?,?,?,?, ?, ?, ?,?,?,?,?,?,?)";
protected final static TimeZone s_gmtTimeZone = TimeZone.getTimeZone("GMT");
@@ -111,7 +106,9 @@ public void saveAccounts(List accounts) {
txn.start();
String sql = INSERT_ACCOUNT;
PreparedStatement pstmt = null;
- pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just want CLOUD_USAGE dataSource connection
+ pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just
+ // want CLOUD_USAGE
+ // dataSource connection
for (AccountVO acct : accounts) {
pstmt.setLong(1, acct.getId());
pstmt.setString(2, acct.getAccountName());
@@ -145,7 +142,9 @@ public void updateAccounts(List accounts) {
txn.start();
String sql = UPDATE_ACCOUNT;
PreparedStatement pstmt = null;
- pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just want CLOUD_USAGE dataSource connection
+ pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just
+ // want CLOUD_USAGE
+ // dataSource connection
for (AccountVO acct : accounts) {
pstmt.setString(1, acct.getAccountName());
@@ -175,7 +174,9 @@ public void saveUserStats(List userStats) {
txn.start();
String sql = INSERT_USER_STATS;
PreparedStatement pstmt = null;
- pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just want CLOUD_USAGE dataSource connection
+ pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just
+ // want CLOUD_USAGE
+ // dataSource connection
for (UserStatisticsVO userStat : userStats) {
pstmt.setLong(1, userStat.getId());
pstmt.setLong(2, userStat.getDataCenterId());
@@ -216,7 +217,9 @@ public void updateUserStats(List userStats) {
txn.start();
String sql = UPDATE_USER_STATS;
PreparedStatement pstmt = null;
- pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just want CLOUD_USAGE dataSource connection
+ pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just
+ // want CLOUD_USAGE
+ // dataSource connection
for (UserStatisticsVO userStat : userStats) {
pstmt.setLong(1, userStat.getNetBytesReceived());
pstmt.setLong(2, userStat.getNetBytesSent());
@@ -313,7 +316,9 @@ public void updateVmDiskStats(List vmDiskStats) {
txn.start();
String sql = UPDATE_VM_DISK_STATS;
PreparedStatement pstmt = null;
- pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just want CLOUD_USAGE dataSource connection
+ pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just
+ // want CLOUD_USAGE
+ // dataSource connection
for (VmDiskStatisticsVO vmDiskStat : vmDiskStats) {
pstmt.setLong(1, vmDiskStat.getNetIORead());
pstmt.setLong(2, vmDiskStat.getNetIOWrite());
@@ -347,7 +352,9 @@ public void saveVmDiskStats(List vmDiskStats) {
txn.start();
String sql = INSERT_VM_DISK_STATS;
PreparedStatement pstmt = null;
- pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just want CLOUD_USAGE dataSource connection
+ pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just
+ // want CLOUD_USAGE
+ // dataSource connection
for (VmDiskStatisticsVO vmDiskStat : vmDiskStats) {
pstmt.setLong(1, vmDiskStat.getId());
pstmt.setLong(2, vmDiskStat.getDataCenterId());
@@ -393,7 +400,9 @@ public void saveUsageRecords(List usageRecords) {
txn.start();
String sql = INSERT_USAGE_RECORDS;
PreparedStatement pstmt = null;
- pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just want CLOUD_USAGE dataSource connection
+ pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just
+ // want CLOUD_USAGE
+ // dataSource connection
for (UsageVO usageRecord : usageRecords) {
pstmt.setLong(1, usageRecord.getZoneId());
pstmt.setLong(2, usageRecord.getAccountId());
@@ -451,4 +460,26 @@ public void saveUsageRecords(List usageRecords) {
throw new CloudRuntimeException(ex.getMessage());
}
}
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public Pair, Integer> getUsageRecordsPendingQuotaAggregation(final long accountId, final long domainId) {
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ TransactionLegacy.open(TransactionLegacy.USAGE_DB).close();
+ s_logger.debug("getting usage records for account: " + accountId + ", domainId: " + domainId);
+ Filter usageFilter = new Filter(UsageVO.class, "startDate", true, 0L, 10000L);
+ SearchCriteria sc = createSearchCriteria();
+ if (accountId != -1) {
+ sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
+ }
+ if (domainId != -1) {
+ sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
+ }
+ sc.addAnd("quotaCalculated", SearchCriteria.Op.NULL);
+ sc.addOr("quotaCalculated", SearchCriteria.Op.EQ, 0);
+ s_logger.debug("Getting usage records" + usageFilter.getOrderBy());
+ Pair, Integer> usageRecords = searchAndCountAllRecords(sc, usageFilter);
+ TransactionLegacy.open(opendb).close();
+ return new Pair, Integer>(usageRecords.first(), usageRecords.second());
+ }
}
diff --git a/framework/pom.xml b/framework/pom.xml
index 84a4469daa7f..546ecf5aa93c 100644
--- a/framework/pom.xml
+++ b/framework/pom.xml
@@ -47,6 +47,7 @@
rest
events
jobs
+ quota
cluster
db
config
diff --git a/framework/quota/pom.xml b/framework/quota/pom.xml
new file mode 100644
index 000000000000..0ed8f8bd5a68
--- /dev/null
+++ b/framework/quota/pom.xml
@@ -0,0 +1,41 @@
+
+
+ 4.0.0
+ cloud-framework-quota
+ Apache CloudStack Framework - Quota
+
+ org.apache.cloudstack
+ cloudstack-framework
+ 4.5.2
+ ../pom.xml
+
+
+
+ org.apache.cloudstack
+ cloud-utils
+ ${project.version}
+
+
+ org.apache.cloudstack
+ cloud-engine-schema
+ ${project.version}
+
+
+
diff --git a/framework/quota/resources/META-INF/cloudstack/quota/spring-framework-quota-context.xml b/framework/quota/resources/META-INF/cloudstack/quota/spring-framework-quota-context.xml
new file mode 100644
index 000000000000..5f3076437687
--- /dev/null
+++ b/framework/quota/resources/META-INF/cloudstack/quota/spring-framework-quota-context.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
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 000000000000..518310ce0ef5
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaConfig.java
@@ -0,0 +1,53 @@
+//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 QuotaPluginEnabled = new ConfigKey("Advanced", Boolean.class, "quota.enable.service", "false", "Indicates whether Quota plugin is enabled or not",
+ true);
+
+ public static final ConfigKey QuotaEnableEnforcement = new ConfigKey("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 QuotaCurrencySymbol = new ConfigKey("Advanced", String.class, "quota.currency.symbol", "R", "The symbol for the currency in use to measure usage.",
+ true);
+
+ public static final ConfigKey QuotaSmtpHost = new ConfigKey("Advanced", String.class, "quota.usage.smtp.host", "", "Quota SMTP host for quota related emails", true);
+
+ public static final ConfigKey QuotaSmtpTimeout = new ConfigKey("Advanced", String.class, "quota.usage.smtp.connection.timeout", "60",
+ "Quota SMTP server connection timeout duration", true);
+
+ public static final ConfigKey QuotaSmtpUser = new ConfigKey("Advanced", String.class, "quota.usage.smtp.user", "", "Quota SMTP server username", true);
+
+ public static final ConfigKey QuotaSmtpPassword = new ConfigKey("Advanced", String.class, "quota.usage.smtp.password", "", "Quota SMTP server password", true);
+
+ public static final ConfigKey QuotaSmtpPort = new ConfigKey("Advanced", String.class, "quota.usage.smtp.port", "", "Quota SMTP port", true);
+
+ public static final ConfigKey QuotaSmtpAuthType = new ConfigKey("Advanced", String.class, "quota.usage.smtp.useAuth", "",
+ "If true, use secure SMTP authentication when sending emails.", true);
+
+ public static final ConfigKey QuotaSmtpSender = new ConfigKey("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
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 000000000000..483ecef278d9
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaTypes.java
@@ -0,0 +1,92 @@
+// 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.HashMap;
+
+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 Integer quotaType;
+ private String quotaName;
+ private String quotaUnit;
+ private String description;
+ private String discriminator;
+
+ public 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 HashMap listQuotaTypes() {
+ final HashMap quotaTypeList = new HashMap();
+ quotaTypeList.put(new Integer(RUNNING_VM), new QuotaTypes(new Integer(RUNNING_VM), "RUNNING_VM", "Compute-Month", "Running Vm Usage"));
+ quotaTypeList.put(new Integer(ALLOCATED_VM), new QuotaTypes(new Integer(ALLOCATED_VM), "ALLOCATED_VM", "Compute-Month", "Allocated Vm Usage"));
+ quotaTypeList.put(new Integer(IP_ADDRESS), new QuotaTypes(new Integer(IP_ADDRESS), "IP_ADDRESS", "IP-Month", "IP Address Usage"));
+ quotaTypeList.put(new Integer(NETWORK_BYTES_SENT), new QuotaTypes(new Integer(NETWORK_BYTES_SENT), "NETWORK_BYTES_SENT", "GB", "Network Usage (Bytes Sent)"));
+ quotaTypeList.put(new Integer(NETWORK_BYTES_RECEIVED), new QuotaTypes(new Integer(NETWORK_BYTES_RECEIVED), "NETWORK_BYTES_RECEIVED", "GB", "Network Usage (Bytes Received)"));
+ quotaTypeList.put(new Integer(VOLUME), new QuotaTypes(new Integer(VOLUME), "VOLUME", "GB-Month", "Volume Usage"));
+ quotaTypeList.put(new Integer(TEMPLATE), new QuotaTypes(new Integer(TEMPLATE), "TEMPLATE", "GB-Month", "Template Usage"));
+ quotaTypeList.put(new Integer(ISO), new QuotaTypes(new Integer(ISO), "ISO", "GB-Month", "ISO Usage"));
+ quotaTypeList.put(new Integer(SNAPSHOT), new QuotaTypes(new Integer(SNAPSHOT), "SNAPSHOT", "GB-Month", "Snapshot Usage"));
+ quotaTypeList.put(new Integer(SECURITY_GROUP), new QuotaTypes(new Integer(SECURITY_GROUP), "SECURITY_GROUP", "Policy-Month", "Security Group Usage"));
+ quotaTypeList.put(new Integer(LOAD_BALANCER_POLICY), new QuotaTypes(new Integer(LOAD_BALANCER_POLICY), "LOAD_BALANCER_POLICY", "Policy-Month", "Load Balancer Usage"));
+ quotaTypeList.put(new Integer(PORT_FORWARDING_RULE), new QuotaTypes(new Integer(PORT_FORWARDING_RULE), "PORT_FORWARDING_RULE", "Policy-Month", "Port Forwarding Usage"));
+ quotaTypeList.put(new Integer(NETWORK_OFFERING), new QuotaTypes(new Integer(NETWORK_OFFERING), "NETWORK_OFFERING", "Policy-Month", "Network Offering Usage"));
+ quotaTypeList.put(new Integer(VPN_USERS), new QuotaTypes(new Integer(VPN_USERS), "VPN_USERS", "Policy-Month", "VPN users usage"));
+ quotaTypeList.put(new Integer(VM_DISK_IO_READ), new QuotaTypes(new Integer(VM_DISK_IO_READ), "VM_DISK_IO_READ", "GB", "VM Disk usage(I/O Read)"));
+ quotaTypeList.put(new Integer(VM_DISK_IO_WRITE), new QuotaTypes(new Integer(VM_DISK_IO_WRITE), "VM_DISK_IO_WRITE", "GB", "VM Disk usage(I/O Write)"));
+ quotaTypeList.put(new Integer(VM_DISK_BYTES_READ), new QuotaTypes(new Integer(VM_DISK_BYTES_READ), "VM_DISK_BYTES_READ", "GB", "VM Disk usage(Bytes Read)"));
+ quotaTypeList.put(new Integer(VM_DISK_BYTES_WRITE), new QuotaTypes(new Integer(VM_DISK_BYTES_WRITE), "VPN_USERS", "GB", "VM Disk usage(Bytes Write)"));
+ quotaTypeList.put(new Integer(VM_SNAPSHOT), new QuotaTypes(new Integer(VM_SNAPSHOT), "VM_SNAPSHOT", "GB-Month", "VM Snapshot storage usage"));
+ quotaTypeList.put(new Integer(CPU_CLOCK_RATE), new QuotaTypes(new Integer(CPU_CLOCK_RATE), "CPU_CLOCK_RATE", "Compute-Month", "Quota tariff for using 1 CPU of clock rate 100MHz"));
+ quotaTypeList.put(new Integer(CPU_NUMBER), new QuotaTypes(new Integer(CPU_NUMBER), "CPU_NUMBER", "Compute-Month", "Quota tariff for running VM that has 1vCPU"));
+ quotaTypeList.put(new Integer(MEMORY), new QuotaTypes(new Integer(MEMORY), "MEMORY", "Compute-Month", "Quota tariff for using 1MB or RAM for 1 hour"));
+ return quotaTypeList;
+ }
+
+ 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) {
+ return listQuotaTypes().get(quotaType).getDescription();
+ }
+}
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 000000000000..06df664cb8ee
--- /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 {
+
+ List listAll();
+
+ QuotaAccountVO findById(Long id);
+
+ QuotaAccountVO persist(QuotaAccountVO entity);
+
+ boolean update(Long id, QuotaAccountVO entity);
+
+}
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 000000000000..e2c5e5acfddd
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaAccountDaoImpl.java
@@ -0,0 +1,73 @@
+//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 javax.ejb.Local;
+
+import org.apache.cloudstack.quota.vo.QuotaAccountVO;
+import org.springframework.stereotype.Component;
+
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.TransactionLegacy;
+
+@Component
+@Local(value = { QuotaAccountDao.class })
+public class QuotaAccountDaoImpl extends GenericDaoBase implements QuotaAccountDao {
+
+ @Override
+ public List listAll() {
+ List result = null;
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ TransactionLegacy.open(TransactionLegacy.USAGE_DB).close();
+ result = super.listAll();
+ TransactionLegacy.open(opendb).close();
+ return result;
+ }
+
+ @Override
+ public QuotaAccountVO findById(Long id) {
+ QuotaAccountVO result = null;
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ TransactionLegacy.open(TransactionLegacy.USAGE_DB).close();
+ result = super.findById(id);
+ TransactionLegacy.open(opendb).close();
+ return result;
+ }
+
+ @Override
+ public QuotaAccountVO persist(QuotaAccountVO entity) {
+ QuotaAccountVO result = null;
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ TransactionLegacy.open(TransactionLegacy.USAGE_DB).close();
+ result = super.persist(entity);
+ TransactionLegacy.open(opendb).close();
+ return result;
+ }
+
+ @Override
+ public boolean update(Long id, QuotaAccountVO entity) {
+ boolean result = false;
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ TransactionLegacy.open(TransactionLegacy.USAGE_DB).close();
+ result = super.update(id, entity);
+ TransactionLegacy.open(opendb).close();
+ return result;
+ }
+
+}
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 000000000000..8bf07ecfe9ea
--- /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 {
+
+ void saveQuotaBalance(List credits);
+
+ List 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 findQuotaBalance(Long accountId, Long domainId, Date startDate, Date endDate);
+
+ List lastQuotaBalanceVO(Long accountId, Long domainId, Date startDate);
+
+ BigDecimal lastQuotaBalance(Long accountId, Long domainId, Date startDate);
+
+}
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 000000000000..628777eda817
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java
@@ -0,0 +1,201 @@
+//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.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.ejb.Local;
+
+import org.springframework.stereotype.Component;
+import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
+import org.apache.log4j.Logger;
+
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.TransactionLegacy;
+
+@Component
+@Local(value = { QuotaBalanceDao.class })
+public class QuotaBalanceDaoImpl extends GenericDaoBase implements QuotaBalanceDao {
+ private static final Logger s_logger = Logger.getLogger(QuotaBalanceDaoImpl.class.getName());
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public QuotaBalanceVO findLastBalanceEntry(final long accountId, final long domainId, final Date beforeThis) {
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ TransactionLegacy.open(TransactionLegacy.USAGE_DB).close();
+ Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", false, 0L, 1L);
+ SearchCriteria sc = createSearchCriteria();
+ sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
+ sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
+ sc.addAnd("creditsId", SearchCriteria.Op.EQ, 0);
+ sc.addAnd("updatedOn", SearchCriteria.Op.LT, beforeThis);
+ List quotab = this.search(sc, filter);
+ TransactionLegacy.open(opendb).close();
+ return quotab.size() > 0 ? quotab.get(0) : null;
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public QuotaBalanceVO findLaterBalanceEntry(final long accountId, final long domainId, final Date afterThis) {
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ TransactionLegacy.open(TransactionLegacy.USAGE_DB).close();
+ Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", true, 0L, 1L);
+ SearchCriteria sc = createSearchCriteria();
+ sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
+ sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
+ sc.addAnd("creditsId", SearchCriteria.Op.EQ, 0);
+ sc.addAnd("updatedOn", SearchCriteria.Op.GT, afterThis);
+ List quotab = this.search(sc, filter);
+ TransactionLegacy.open(opendb).close();
+ return quotab.size() > 0 ? quotab.get(0) : null;
+ }
+
+ @Override
+ public void saveQuotaBalance(final List credits) {
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
+ try {
+ for (QuotaBalanceVO credit : credits) {
+ persist(credit);
+ }
+ } finally {
+ txn.close();
+ }
+ TransactionLegacy.open(opendb).close();
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public List findCreditBalance(final long accountId, final long domainId, final Date lastbalancedate, final Date beforeThis) {
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ TransactionLegacy.open(TransactionLegacy.USAGE_DB).close();
+ Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", true, 0L, Long.MAX_VALUE);
+ SearchCriteria sc = createSearchCriteria();
+ sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
+ sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
+ sc.addAnd("creditsId", SearchCriteria.Op.GT, 0);
+ if ((lastbalancedate != null) && (beforeThis != null) && lastbalancedate.before(beforeThis)) {
+ sc.addAnd("updatedOn", SearchCriteria.Op.BETWEEN, lastbalancedate, beforeThis);
+ } else {
+ return new ArrayList();
+ }
+ List qb = search(sc, filter);
+ TransactionLegacy.open(opendb).close();
+ return qb;
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public List findQuotaBalance(final Long accountId, final Long domainId, final Date startDate, final Date endDate) {
+ // TODO account for series of credits around boundaries
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+
+ TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
+ List quotaUsageRecords = null;
+ try {
+ SearchCriteria sc = createSearchCriteria();
+ if (accountId != null) {
+ sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
+ }
+ if (domainId != null) {
+ sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
+ }
+ if ((startDate != null) && (endDate != null) && startDate.before(endDate)) {
+ sc.addAnd("updatedOn", SearchCriteria.Op.BETWEEN, startDate, endDate);
+ } else {
+ return new ArrayList();
+ }
+ quotaUsageRecords = listBy(sc);
+ if (quotaUsageRecords.size() == 0) {
+ quotaUsageRecords.addAll(lastQuotaBalanceVO(accountId, domainId, startDate));
+ }
+ } finally {
+ txn.close();
+ }
+
+ TransactionLegacy.open(opendb).close();
+ return quotaUsageRecords;
+ }
+
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public List lastQuotaBalanceVO(final Long accountId, final Long domainId, final Date pivotDate) {
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+
+ TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
+ List quotaUsageRecords = null;
+ List trimmedRecords = new ArrayList();
+ try {
+ Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", false, 0L, 100L);
+ // ASSUMPTION there will be less than 100 continuous credit
+ // transactions
+ SearchCriteria sc = createSearchCriteria();
+ if (accountId != null) {
+ sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
+ }
+ if (domainId != null) {
+ sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
+ }
+ if ((pivotDate != null)) {
+ sc.addAnd("updatedOn", SearchCriteria.Op.LTEQ, pivotDate);
+ }
+ quotaUsageRecords = search(sc, filter);
+
+ // get records before startDate to find start balance
+ for (Iterator it = quotaUsageRecords.iterator(); it.hasNext();) {
+ QuotaBalanceVO entry = it.next();
+ s_logger.info("findQuotaBalance Date=" + entry.getUpdatedOn().toGMTString() + " balance=" + entry.getCreditBalance() + " credit=" + entry.getCreditsId());
+ if (entry.getCreditsId() > 0) {
+ trimmedRecords.add(entry);
+ } else {
+ trimmedRecords.add(entry);
+ break; // add only consecutive credit entries and last balance entry
+ }
+ }
+
+ } finally {
+ txn.close();
+ }
+
+ TransactionLegacy.open(opendb).close();
+ return trimmedRecords;
+ }
+
+ @Override
+ public BigDecimal lastQuotaBalance(final Long accountId, final Long domainId, Date startDate) {
+ List quotaBalance = lastQuotaBalanceVO(accountId, domainId, startDate);
+ if (quotaBalance.size() == 0) {
+ new InvalidParameterValueException("There are no balance entries on or before the requested date.");
+ }
+ BigDecimal finalBalance = new BigDecimal(0);
+ for (Iterator it = quotaBalance.iterator(); it.hasNext();) {
+ QuotaBalanceVO entry = it.next();
+ s_logger.info("lastQuotaBalance Date=" + entry.getUpdatedOn().toGMTString() + " balance=" + entry.getCreditBalance() + " credit=" + entry.getCreditsId());
+ finalBalance.add(entry.getCreditBalance());
+ }
+ return finalBalance;
+ }
+
+}
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 000000000000..f08d8f96ca85
--- /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 {
+
+ List findCredits(long accountId, long domainId, Date startDate, Date endDate);
+
+ QuotaCreditsVO saveCredits(QuotaCreditsVO credits);
+
+}
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 000000000000..05e48b0f7487
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDaoImpl.java
@@ -0,0 +1,72 @@
+//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.ArrayList;
+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.SearchCriteria;
+import com.cloud.utils.db.TransactionLegacy;
+
+@Component
+@Local(value = { QuotaCreditsDao.class })
+public class QuotaCreditsDaoImpl extends GenericDaoBase implements QuotaCreditsDao {
+ @Inject
+ QuotaBalanceDao _quotaBalanceDao;
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public List findCredits(final long accountId, final long domainId, final Date startDate, final Date endDate) {
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ TransactionLegacy.open(TransactionLegacy.USAGE_DB);
+ Filter filter = new Filter(QuotaCreditsVO.class, "updatedOn", true, 0L, Long.MAX_VALUE);
+ SearchCriteria sc = createSearchCriteria();
+ sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
+ sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
+ if ((startDate != null) && (endDate != null) && startDate.before(endDate)) {
+ sc.addAnd("updatedOn", SearchCriteria.Op.BETWEEN, startDate, endDate);
+ } else {
+ return new ArrayList();
+ }
+ List qc = search(sc, filter);
+ TransactionLegacy.open(opendb).close();
+ return qc;
+ }
+
+ @Override
+ public QuotaCreditsVO saveCredits(final QuotaCreditsVO credits) {
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ TransactionLegacy.open(TransactionLegacy.USAGE_DB);
+ persist(credits);
+ // make an entry in the balance table
+ QuotaBalanceVO bal = new QuotaBalanceVO(credits);
+ _quotaBalanceDao.persist(bal);
+ TransactionLegacy.open(opendb).close();
+ return credits;
+ }
+
+}
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 000000000000..573a75397442
--- /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 {
+ List listAllQuotaEmailTemplates(String templateName);
+ boolean updateQuotaEmailTemplate(QuotaEmailTemplatesVO template);
+}
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 000000000000..c7b4908a1813
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaEmailTemplatesDaoImpl.java
@@ -0,0 +1,64 @@
+//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.TransactionLegacy;
+import org.apache.cloudstack.quota.vo.QuotaEmailTemplatesVO;
+import org.springframework.stereotype.Component;
+
+import javax.ejb.Local;
+import java.util.List;
+
+@Component
+@Local(value = { QuotaEmailTemplatesDao.class })
+public class QuotaEmailTemplatesDaoImpl extends GenericDaoBase implements QuotaEmailTemplatesDao {
+
+ protected SearchBuilder QuotaEmailTemplateSearch;
+
+ public QuotaEmailTemplatesDaoImpl() {
+ super();
+
+ QuotaEmailTemplateSearch = createSearchBuilder();
+ QuotaEmailTemplateSearch.and("template_name", QuotaEmailTemplateSearch.entity().getTemplateName(), SearchCriteria.Op.EQ);
+ QuotaEmailTemplateSearch.done();
+ }
+
+ @Override
+ public List listAllQuotaEmailTemplates(String templateName) {
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ TransactionLegacy.open(TransactionLegacy.USAGE_DB);
+ SearchCriteria sc = QuotaEmailTemplateSearch.create();
+ if (templateName != null) {
+ sc.setParameters("template_name", templateName);
+ }
+ List result = this.listBy(sc);
+ TransactionLegacy.open(opendb).close();
+ return result;
+ }
+
+ @Override
+ public boolean updateQuotaEmailTemplate(QuotaEmailTemplatesVO template) {
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ TransactionLegacy.open(TransactionLegacy.USAGE_DB);
+ final boolean result = this.update(template.getId(), template);
+ TransactionLegacy.open(opendb).close();
+ return result;
+ }
+}
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 000000000000..7977f28942d7
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDao.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 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 findTariffPlanByUsageType(int quotaType, Date onOrBefore);
+
+ List listAllTariffPlans(Date onOrBefore);
+
+ boolean updateQuotaTariff(QuotaTariffVO plan);
+
+ QuotaTariffVO addQuotaTariff(QuotaTariffVO plan);
+}
diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java
new file mode 100644
index 000000000000..38aad156d0cd
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java
@@ -0,0 +1,138 @@
+//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.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.TransactionLegacy;
+
+import org.apache.cloudstack.quota.constant.QuotaTypes;
+import org.apache.cloudstack.quota.vo.QuotaTariffVO;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+import javax.ejb.Local;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+@Component
+@Local(value = { QuotaTariffDao.class })
+public class QuotaTariffDaoImpl extends GenericDaoBase implements QuotaTariffDao {
+ private static final Logger s_logger = Logger.getLogger(QuotaTariffDaoImpl.class.getName());
+
+ private final SearchBuilder searchUsageType;
+ private final SearchBuilder listAllIncludedUsageType;
+
+ public QuotaTariffDaoImpl() {
+ super();
+ searchUsageType = createSearchBuilder();
+ searchUsageType.and("usage_type", searchUsageType.entity().getUsageType(), SearchCriteria.Op.EQ);
+ searchUsageType.done();
+
+ listAllIncludedUsageType = createSearchBuilder();
+ listAllIncludedUsageType.and("onorbefore", listAllIncludedUsageType.entity().getEffectiveOn(), SearchCriteria.Op.LTEQ);
+ listAllIncludedUsageType.and("quotatype", listAllIncludedUsageType.entity().getUsageType(), SearchCriteria.Op.EQ);
+ listAllIncludedUsageType.done();
+ }
+
+ @Override
+ public QuotaTariffVO findTariffPlanByUsageType(final int quotaType, final Date effectiveDate) {
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ List result = null;
+ TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
+ try {
+ final Filter filter = new Filter(QuotaTariffVO.class, "effectiveOn", false, 0L, 1L);
+ final SearchCriteria sc = listAllIncludedUsageType.create();
+ sc.setParameters("onorbefore", effectiveDate);
+ sc.setParameters("quotatype", quotaType);
+ result = search(sc, filter);
+ } finally {
+ txn.close();
+ }
+ // Switch back
+ TransactionLegacy.open(opendb).close();
+ if (result.size() > 0) {
+ //s_logger.info("findTariffPlanByUsageType: " + effectiveDate + "quota type " + quotaType + " val=" + result.get(0).getCurrencyValue());
+ return result.get(0);
+ } else {
+ //s_logger.info("Missing quota type " + quotaType);
+ return null;
+ }
+ }
+
+ @Override
+ public List listAllTariffPlans(final Date effectiveDate) {
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ List tariffs = new ArrayList();
+ TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
+ try {
+ final Filter filter = new Filter(QuotaTariffVO.class, "effectiveOn", false, 0L, 1L);
+ final SearchCriteria sc = listAllIncludedUsageType.create();
+ sc.setParameters("onorbefore", effectiveDate);
+ for (Integer quotaType : QuotaTypes.listQuotaTypes().keySet()) {
+ sc.setParameters("quotatype", quotaType);
+ List result = search(sc, filter);
+ if (result.size() > 0) {
+ tariffs.add(result.get(0));
+ s_logger.info("listAllTariffPlans onorbefore" + effectiveDate + "quota type " + result.get(0).getDescription() + " , effective Date=" + result.get(0).getEffectiveOn() + " val=" + result.get(0).getCurrencyValue());
+ }
+ }
+ } finally {
+ txn.close();
+ }
+ // Switch back
+ TransactionLegacy.open(opendb).close();
+ return tariffs;
+ }
+
+ @Override
+ public boolean updateQuotaTariff(QuotaTariffVO plan) {
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); // Switch
+ // to
+ boolean result = false;
+ try {
+ // Usage DB
+ result = this.update(plan.getId(), plan);
+ } finally {
+ txn.close();
+ }
+ TransactionLegacy.open(opendb).close(); // Switch back
+ return result;
+ }
+
+ @Override
+ public QuotaTariffVO addQuotaTariff(QuotaTariffVO plan) {
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); // Switch
+ // to
+ QuotaTariffVO result = null;
+ try {
+ // Usage DB
+ plan.setId(null);
+ result = this.persist(plan);
+ } finally {
+ txn.close();
+ }
+ TransactionLegacy.open(opendb).close(); // Switch back
+ return result;
+ }
+}
diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDao.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDao.java
new file mode 100644
index 000000000000..79c55cea23eb
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDao.java
@@ -0,0 +1,40 @@
+//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.QuotaUsageVO;
+
+import com.cloud.utils.Pair;
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.GenericDao;
+import com.cloud.utils.db.SearchCriteria;
+
+public interface QuotaUsageDao extends GenericDao {
+
+ List findQuotaUsage(Long accountId, Long domainId, Integer usageType, Date startDate, Date endDate);
+
+ Pair, Integer> searchAndCountAllRecords(SearchCriteria sc, Filter filter);
+
+ void saveQuotaUsage(List credits);
+
+ BigDecimal findTotalQuotaUsage(Long accountId, Long domainId, Integer usageType, Date startDate, Date endDate);
+
+}
diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDaoImpl.java
new file mode 100644
index 000000000000..bff43d042391
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDaoImpl.java
@@ -0,0 +1,106 @@
+//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.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import javax.ejb.Local;
+
+import org.springframework.stereotype.Component;
+import org.apache.cloudstack.quota.vo.QuotaUsageVO;
+
+import com.cloud.utils.Pair;
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.TransactionLegacy;
+
+@Component
+@Local(value = { QuotaUsageDao.class })
+public class QuotaUsageDaoImpl extends GenericDaoBase implements QuotaUsageDao {
+
+ @Override
+ public Pair, Integer> searchAndCountAllRecords(SearchCriteria sc, Filter filter) {
+ return listAndCountIncludingRemovedBy(sc, filter);
+ }
+
+ @Override
+ public void saveQuotaUsage(List records) {
+ for (QuotaUsageVO usageRecord : records) {
+ persist(usageRecord);
+ }
+ }
+
+ @Override
+ public BigDecimal findTotalQuotaUsage(final Long accountId, final Long domainId, final Integer usageType, final Date startDate, final Date endDate) {
+ List quotaUsage = findQuotaUsage(accountId, domainId, null, startDate, endDate);
+ BigDecimal total = new BigDecimal(0);
+ for (final QuotaUsageVO quotaRecord : quotaUsage) {
+ total = total.add(quotaRecord.getQuotaUsed());
+ }
+ return total;
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public List findQuotaUsage(final Long accountId, final Long domainId, final Integer usageType, final Date startDate, final Date endDate) {
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
+ List quotaUsageRecords = null;
+ try {
+ // TODO instead of max value query with reasonable number and
+ // iterate
+ SearchCriteria sc = createSearchCriteria();
+ if (accountId != null) {
+ sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
+ }
+ /*
+ * if (isDomainAdmin) { SearchCriteria sdc =
+ * _domainDao.createSearchCriteria(); sdc.addOr("path",
+ * SearchCriteria.Op.LIKE,
+ * _domainDao.findById(caller.getDomainId()).getPath() + "%");
+ * List domains = _domainDao.search(sdc, null); List
+ * domainIds = new ArrayList(); for (DomainVO domain :
+ * domains) domainIds.add(domain.getId()); sc.addAnd("domainId",
+ * SearchCriteria.Op.IN, domainIds.toArray());
+ * s_logger.debug("Account ID=" + accountId); }
+ */
+ if (domainId != null) {
+ sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
+ }
+ if (usageType != null) {
+ sc.addAnd("usageType", SearchCriteria.Op.EQ, usageType);
+ }
+ if ((startDate != null) && (endDate != null) && startDate.before(endDate)) {
+ sc.addAnd("startDate", SearchCriteria.Op.BETWEEN, startDate, endDate);
+ sc.addAnd("endDate", SearchCriteria.Op.BETWEEN, startDate, endDate);
+ } else {
+ return new ArrayList();
+ }
+ quotaUsageRecords = listBy(sc);
+ } finally {
+ txn.close();
+ }
+
+ TransactionLegacy.open(opendb).close();
+ return quotaUsageRecords;
+ }
+
+}
diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/ServiceOfferingDao.java b/framework/quota/src/org/apache/cloudstack/quota/dao/ServiceOfferingDao.java
new file mode 100644
index 000000000000..5d340e384f18
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/ServiceOfferingDao.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 org.apache.cloudstack.quota.vo.ServiceOfferingVO;
+
+import com.cloud.utils.db.GenericDao;
+
+public interface ServiceOfferingDao extends GenericDao {
+
+ ServiceOfferingVO findServiceOffering(Long vmId, long serviceOfferingId);
+
+}
diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/ServiceOfferingDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/ServiceOfferingDaoImpl.java
new file mode 100644
index 000000000000..82d4af6b6e81
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/ServiceOfferingDaoImpl.java
@@ -0,0 +1,85 @@
+// 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.Map;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+import org.apache.cloudstack.quota.vo.ServiceOfferingVO;
+
+import com.cloud.event.UsageEventVO;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.TransactionLegacy;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@Component
+@Local(value = { ServiceOfferingDao.class })
+@DB()
+public class ServiceOfferingDaoImpl extends GenericDaoBase implements ServiceOfferingDao {
+ protected static final Logger s_logger = Logger.getLogger(ServiceOfferingDaoImpl.class);
+
+ @Inject
+ UserVmDetailsDao userVmDetailsDao;
+
+ @Override
+ public ServiceOfferingVO findServiceOffering(final Long vmId, final long serviceOfferingId) {
+ final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
+ TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.CLOUD_DB);
+ ServiceOfferingVO result;
+ try {
+ result = findById(vmId, serviceOfferingId);
+ } finally {
+ txn.close();
+ }
+ TransactionLegacy.open(opendb).close();
+ return result;
+ }
+
+ public ServiceOfferingVO findById(Long vmId, long serviceOfferingId) {
+ ServiceOfferingVO offering = super.findById(serviceOfferingId);
+ if (offering.isDynamic()) {
+ offering.setDynamicFlag(true);
+ if (vmId == null) {
+ throw new CloudRuntimeException("missing argument vmId");
+ }
+ Map dynamicOffering = userVmDetailsDao.listDetailsKeyPairs(vmId);
+ return getcomputeOffering(offering, dynamicOffering);
+ }
+ return offering;
+ }
+
+ public ServiceOfferingVO getcomputeOffering(ServiceOfferingVO serviceOffering, Map customParameters) {
+ ServiceOfferingVO dummyoffering = new ServiceOfferingVO(serviceOffering);
+ dummyoffering.setDynamicFlag(true);
+ if (customParameters.containsKey(UsageEventVO.DynamicParameters.cpuNumber.name())) {
+ dummyoffering.setCpu(Integer.parseInt(customParameters.get(UsageEventVO.DynamicParameters.cpuNumber.name())));
+ }
+ if (customParameters.containsKey(UsageEventVO.DynamicParameters.cpuSpeed.name())) {
+ dummyoffering.setSpeed(Integer.parseInt(customParameters.get(UsageEventVO.DynamicParameters.cpuSpeed.name())));
+ }
+ if (customParameters.containsKey(UsageEventVO.DynamicParameters.memory.name())) {
+ dummyoffering.setRamSize(Integer.parseInt(customParameters.get(UsageEventVO.DynamicParameters.memory.name())));
+ }
+ return dummyoffering;
+ }
+
+}
diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/UserVmDetailsDao.java b/framework/quota/src/org/apache/cloudstack/quota/dao/UserVmDetailsDao.java
new file mode 100644
index 000000000000..f14ecf48dfd2
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/UserVmDetailsDao.java
@@ -0,0 +1,31 @@
+// 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.Map;
+
+import com.cloud.utils.db.GenericDao;
+
+import org.apache.cloudstack.quota.vo.UserVmDetailVO;
+
+public interface UserVmDetailsDao extends GenericDao {
+
+ Map listDetailsKeyPairs(long resourceId);
+
+
+}
diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/UserVmDetailsDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/UserVmDetailsDaoImpl.java
new file mode 100644
index 000000000000..7cc42e724355
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/dao/UserVmDetailsDaoImpl.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.quota.dao;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ejb.Local;
+
+import org.springframework.stereotype.Component;
+import org.apache.cloudstack.quota.vo.UserVmDetailVO;
+
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+
+@Component
+@Local(value = UserVmDetailsDao.class)
+public class UserVmDetailsDaoImpl extends GenericDaoBase implements UserVmDetailsDao {
+ private SearchBuilder AllFieldsSearch;
+
+ public UserVmDetailsDaoImpl() {
+ AllFieldsSearch = createSearchBuilder();
+ AllFieldsSearch.and("resourceId", AllFieldsSearch.entity().getResourceId(), SearchCriteria.Op.EQ);
+ AllFieldsSearch.and("name", AllFieldsSearch.entity().getName(), SearchCriteria.Op.EQ);
+ AllFieldsSearch.and("value", AllFieldsSearch.entity().getValue(), SearchCriteria.Op.EQ);
+ // FIXME SnapshotDetailsVO doesn't have a display field
+ if (_allAttributes.containsKey("display")) {
+ AllFieldsSearch.and("display", AllFieldsSearch.entity().isDisplay(), SearchCriteria.Op.EQ);
+ }
+ AllFieldsSearch.done();
+ }
+
+ @Override
+ public Map listDetailsKeyPairs(long resourceId) {
+ SearchCriteria sc = AllFieldsSearch.create();
+ sc.setParameters("resourceId", resourceId);
+
+ List results = search(sc, null);
+ Map details = new HashMap(results.size());
+ for (UserVmDetailVO result : results) {
+ details.put(result.getName(), result.getValue());
+ }
+ return details;
+ }
+
+}
diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaAccountVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaAccountVO.java
new file mode 100644
index 000000000000..eee790d5c1bf
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaAccountVO.java
@@ -0,0 +1,142 @@
+//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.vo;
+
+import org.apache.cloudstack.api.InternalIdentity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Entity
+@Table(name = "quota_account")
+public class QuotaAccountVO implements InternalIdentity {
+
+ private static final long serialVersionUID = -7112846845287653210L;
+
+ @Id
+ @Column(name = "account_id")
+ private Long accountId = null;
+
+ @Column(name = "quota_enforce")
+ private Integer quotaEnforce = null;
+
+ @Column(name = "quota_balance")
+ private BigDecimal quotaBalance;
+
+ @Column(name = "quota_balance_date")
+ @Temporal(value = TemporalType.TIMESTAMP)
+ private Date quotaBalanceDate = null;
+
+ @Column(name = "quota_min_balance")
+ private BigDecimal quotaMinBalance;
+
+ @Column(name = "quota_alert_type")
+ private Integer quotaAlertType = null;
+
+ @Column(name = "quota_alert_date")
+ @Temporal(value = TemporalType.TIMESTAMP)
+ private Date quotaAlertDate = null;
+
+ @Column(name = "last_statement_date")
+ @Temporal(value = TemporalType.TIMESTAMP)
+ private Date lastStatementDate = null;
+
+ public QuotaAccountVO() {
+ }
+
+ public QuotaAccountVO(Long accountId) {
+ super();
+ this.accountId = accountId;
+ }
+
+ @Override
+ public long getId() {
+ return accountId;
+ }
+
+ public Long getAccountId() {
+ return accountId;
+ }
+
+ public void setAccountId(Long accountId) {
+ this.accountId = accountId;
+ }
+
+ public Integer getQuotaEnforce() {
+ return quotaEnforce == null ? 0 : quotaEnforce;
+ }
+
+ public void setQuotaEnforce(Integer quotaEnforce) {
+ this.quotaEnforce = quotaEnforce;
+ }
+
+ public BigDecimal getQuotaBalance() {
+ return quotaBalance;
+ }
+
+ public void setQuotaBalance(BigDecimal quotaBalance) {
+ this.quotaBalance = quotaBalance;
+ }
+
+ public BigDecimal getQuotaMinBalance() {
+ return quotaMinBalance == null ? new BigDecimal(0) : quotaMinBalance;
+ }
+
+ public void setQuotaMinBalance(BigDecimal quotaMinBalance) {
+ this.quotaMinBalance = quotaMinBalance;
+ }
+
+ public Integer getQuotaAlertType() {
+ return quotaAlertType;
+ }
+
+ public void setQuotaAlertType(Integer quotaAlertType) {
+ this.quotaAlertType = quotaAlertType;
+ }
+
+ public Date getQuotaAlertDate() {
+ return quotaAlertDate;
+ }
+
+ public void setQuotaAlertDate(Date quotaAlertDate) {
+ this.quotaAlertDate = quotaAlertDate;
+ }
+
+ public Date getQuotaBalanceDate() {
+ return quotaBalanceDate;
+ }
+
+ public void setQuotaBalanceDate(Date quotaBalanceDate) {
+ this.quotaBalanceDate = quotaBalanceDate;
+ }
+
+ public Date getLastStatementDate() {
+ return lastStatementDate;
+ }
+
+ public void setLastStatementDate(Date lastStatementDate) {
+ this.lastStatementDate = lastStatementDate;
+ }
+
+}
diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaBalanceVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaBalanceVO.java
new file mode 100644
index 000000000000..d46b949f8267
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaBalanceVO.java
@@ -0,0 +1,127 @@
+//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.vo;
+
+import org.apache.cloudstack.api.InternalIdentity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Entity
+@Table(name = "quota_balance")
+public class QuotaBalanceVO implements InternalIdentity {
+
+ private static final long serialVersionUID = -7112846845287653210L;
+
+ @Id
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "account_id")
+ private Long accountId = null;
+
+ @Column(name = "domain_id")
+ private Long domainId = null;
+
+ @Column(name = "credit_balance")
+ private BigDecimal creditBalance;
+
+ @Column(name = "credits_id")
+ private Long creditsId;
+
+ @Column(name = "updated_on")
+ @Temporal(value = TemporalType.TIMESTAMP)
+ private Date updatedOn = null;
+
+ public QuotaBalanceVO() {
+ super();
+ }
+
+ public QuotaBalanceVO(QuotaCreditsVO credit) {
+ super();
+ this.accountId = credit.getAccountId();
+ this.domainId = credit.getDomainId();
+ this.creditBalance = credit.getCredit();
+ this.updatedOn = credit.getUpdatedOn();
+ this.creditsId = credit.getId();
+ }
+
+ public QuotaBalanceVO(Long accountId, Long domainId, BigDecimal creditBalance, Date updatedOn) {
+ super();
+ this.accountId = accountId;
+ this.domainId = domainId;
+ this.creditBalance = creditBalance;
+ this.creditsId=0L;
+ this.updatedOn = updatedOn;
+ }
+
+ @Override
+ public long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Long getAccountId() {
+ return accountId;
+ }
+
+ public void setAccountId(Long accountId) {
+ this.accountId = accountId;
+ }
+
+ public Long getDomainId() {
+ return domainId;
+ }
+
+ public void setDomainId(Long domainId) {
+ this.domainId = domainId;
+ }
+
+ public Long getCreditsId() {
+ return creditsId;
+ }
+
+ public void setCreditsId(Long creditsId) {
+ this.creditsId = creditsId;
+ }
+
+ public BigDecimal getCreditBalance() {
+ return creditBalance;
+ }
+
+ public void setCreditBalance(BigDecimal creditBalance) {
+ this.creditBalance = creditBalance;
+ }
+
+ public Date getUpdatedOn() {
+ return updatedOn;
+ }
+
+ public void setUpdatedOn(Date updatedOn) {
+ this.updatedOn = updatedOn;
+ }
+}
diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaCreditsVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaCreditsVO.java
new file mode 100644
index 000000000000..55205bd2e418
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaCreditsVO.java
@@ -0,0 +1,117 @@
+//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.vo;
+
+import org.apache.cloudstack.api.InternalIdentity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Entity
+@Table(name = "quota_credits")
+public class QuotaCreditsVO implements InternalIdentity {
+
+ private static final long serialVersionUID = -3576833845287653210L;
+
+ @Id
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "account_id")
+ private Long accountId = null;
+
+ @Column(name = "domain_id")
+ private Long domainId = null;
+
+ @Column(name = "credit")
+ private BigDecimal credit;
+
+ @Column(name = "updated_on")
+ @Temporal(value = TemporalType.TIMESTAMP)
+ private Date updatedOn = null;
+
+ public QuotaCreditsVO() {
+ }
+
+ public QuotaCreditsVO(long accountId, long domainId, BigDecimal credit, long updatedBy) {
+ super();
+ this.accountId = accountId;
+ this.domainId = domainId;
+ this.credit = credit;
+ this.updatedBy = updatedBy;
+ }
+
+ public Long getAccountId() {
+ return accountId;
+ }
+
+ public void setAccountId(Long accountId) {
+ this.accountId = accountId;
+ }
+
+ public Long getDomainId() {
+ return domainId;
+ }
+
+ public void setDomainId(Long domainId) {
+ this.domainId = domainId;
+ }
+
+ public BigDecimal getCredit() {
+ return credit;
+ }
+
+ public void setCredit(BigDecimal credit) {
+ this.credit = credit;
+ }
+
+ public Date getUpdatedOn() {
+ return updatedOn;
+ }
+
+ public void setUpdatedOn(Date updatedOn) {
+ this.updatedOn = updatedOn;
+ }
+
+ public Long getUpdatedBy() {
+ return updatedBy;
+ }
+
+ public void setUpdatedBy(Long updatedBy) {
+ this.updatedBy = updatedBy;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ // User ID of the creditor
+ @Column(name = "updated_by")
+ private Long updatedBy = null;
+
+ @Override
+ public long getId() {
+ // TODO Auto-generated method stub
+ return this.id;
+ }
+}
diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaEmailTemplatesVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaEmailTemplatesVO.java
new file mode 100644
index 000000000000..54013fc96ebd
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaEmailTemplatesVO.java
@@ -0,0 +1,109 @@
+//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.vo;
+
+import org.apache.cloudstack.api.InternalIdentity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import java.util.Date;
+
+@Entity
+@Table(name = "quota_email_templates")
+public class QuotaEmailTemplatesVO implements InternalIdentity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "template_name")
+ private String templateName;
+
+ @Column(name = "template_subject")
+ private String templateSubject;
+
+ @Column(name = "template_body")
+ private String templateBody;
+
+ @Column(name = "locale")
+ private String locale;
+
+ @Column(name = "updated")
+ @Temporal(value = TemporalType.TIMESTAMP)
+ private Date lastUpdated = null;
+
+ public QuotaEmailTemplatesVO() {
+ }
+
+ public QuotaEmailTemplatesVO(String templateName, String templateSubject, String templateBody) {
+ super();
+ this.templateName = templateName;
+ this.templateSubject = templateSubject;
+ this.templateBody = templateBody;
+ }
+
+ @Override
+ public long getId() {
+ return id;
+ }
+
+ public String getTemplateName() {
+ return templateName;
+ }
+
+ public void setTemplateName(String templateName) {
+ this.templateName = templateName;
+ }
+
+ public String getTemplateSubject() {
+ return templateSubject;
+ }
+
+ public void setTemplateSubject(String templateSubject) {
+ this.templateSubject = templateSubject;
+ }
+
+ public String getTemplateBody() {
+ return templateBody;
+ }
+
+ public void setTemplateBody(String templateBody) {
+ this.templateBody = templateBody;
+ }
+
+ public Date getLastUpdated() {
+ return lastUpdated;
+ }
+
+ public void setLastUpdated(Date lastUpdated) {
+ this.lastUpdated = lastUpdated;
+ }
+
+ public String getLocale() {
+ return locale;
+ }
+
+ public void setLocale(String locale) {
+ this.locale = locale;
+ }
+}
diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaTariffVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaTariffVO.java
new file mode 100644
index 000000000000..38a26b7c7092
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaTariffVO.java
@@ -0,0 +1,162 @@
+//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.vo;
+
+import org.apache.cloudstack.api.InternalIdentity;
+import org.apache.cloudstack.quota.constant.QuotaTypes;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Entity
+@Table(name = "quota_tariff")
+public class QuotaTariffVO implements InternalIdentity {
+ private static final long serialVersionUID = -7117933766387653203L;
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "usage_type")
+ private int usageType;
+
+ @Column(name = "usage_name")
+ private String usageName;
+
+ @Column(name = "usage_unit")
+ private String usageUnit;
+
+ @Column(name = "usage_discriminator")
+ private String usageDiscriminator;
+
+ @Column(name = "currency_value")
+ private BigDecimal currencyValue;
+
+ @Column(name = "effective_on")
+ @Temporal(value = TemporalType.TIMESTAMP)
+ private Date effectiveOn = null;
+
+ @Column(name = "updated_on")
+ @Temporal(value = TemporalType.TIMESTAMP)
+ private Date updatedOn = null;
+
+ @Column(name = "updated_by")
+ private Long updatedBy = null;
+
+ public QuotaTariffVO() {
+ }
+
+ public QuotaTariffVO(final int usagetype, final String usagename, final String usageunit, final String usagediscriminator, final BigDecimal currencyvalue,
+ final Date effectiveOn, final Date updatedOn, final long updatedBy) {
+ this.usageType = usagetype;
+ this.usageName = usagename;
+ this.usageUnit = usageunit;
+ this.usageDiscriminator = usagediscriminator;
+ this.currencyValue = currencyvalue;
+ this.effectiveOn = effectiveOn;
+ this.updatedOn = updatedOn;
+ this.updatedBy = updatedBy;
+ }
+
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Date getEffectiveOn() {
+ return effectiveOn;
+ }
+
+ public void setEffectiveOn(Date effectiveOn) {
+ this.effectiveOn = effectiveOn;
+ }
+
+ public Date getUpdatedOn() {
+ return updatedOn;
+ }
+
+ public void setUpdatedOn(Date updatedOn) {
+ this.updatedOn = updatedOn;
+ }
+
+ public Long getUpdatedBy() {
+ return updatedBy;
+ }
+
+ public void setUpdatedBy(Long updatedBy) {
+ this.updatedBy = updatedBy;
+ }
+
+ public int getUsageType() {
+ return usageType;
+ }
+
+ public void setUsageType(int usageType) {
+ this.usageType = usageType;
+ }
+
+ public String getUsageName() {
+ return usageName;
+ }
+
+ public void setUsageName(String usageName) {
+ this.usageName = usageName;
+ }
+
+ 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 getCurrencyValue() {
+ return currencyValue;
+ }
+
+ public void setCurrencyValue(BigDecimal currencyValue) {
+ this.currencyValue = currencyValue;
+ }
+
+ public String getDescription() {
+ return QuotaTypes.getDescription(usageType);
+ }
+
+ @Override
+ public long getId() {
+ return this.id;
+ }
+}
\ No newline at end of file
diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaUsageVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaUsageVO.java
new file mode 100644
index 000000000000..a82b309aaa58
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaUsageVO.java
@@ -0,0 +1,172 @@
+//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.vo;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import org.apache.cloudstack.api.InternalIdentity;
+
+@Entity
+@Table(name = "quota_usage")
+public class QuotaUsageVO implements InternalIdentity {
+
+ private static final long serialVersionUID = -7117933845287204781L;
+
+ @Id
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "zone_id")
+ private Long zoneId = null;
+
+ @Column(name = "account_id")
+ private Long accountId = null;
+
+ @Column(name = "domain_id")
+ private Long domainId = null;
+
+ @Column(name = "usage_item_id")
+ private Long usageItemId;
+
+ @Column(name = "usage_type")
+ private int usageType;
+
+ @Column(name = "quota_used")
+ private BigDecimal quotaUsed;
+
+ @Column(name = "start_date")
+ @Temporal(value = TemporalType.TIMESTAMP)
+ private Date startDate = null;
+
+ @Column(name = "end_date")
+ @Temporal(value = TemporalType.TIMESTAMP)
+ private Date endDate = null;
+
+ public QuotaUsageVO() {
+ usageType=-1;
+ quotaUsed = new BigDecimal(0);
+ endDate = new Date();
+ startDate = new Date();
+ }
+
+ public QuotaUsageVO(Long usageItemId, Long zoneId, Long accountId, Long domainId, int usageType, BigDecimal quotaUsed, Date startDate, Date endDate) {
+ super();
+ this.usageItemId = usageItemId;
+ this.zoneId = zoneId;
+ this.accountId = accountId;
+ this.domainId = domainId;
+ this.usageType = usageType;
+ this.quotaUsed = quotaUsed;
+ this.startDate = startDate;
+ this.endDate = endDate;
+ }
+
+ public QuotaUsageVO(QuotaUsageVO toclone) {
+ super();
+ this.usageItemId = toclone.usageItemId;
+ this.zoneId = toclone.zoneId;
+ this.accountId = toclone.accountId;
+ this.domainId = toclone.domainId;
+ this.usageType = toclone.usageType;
+ this.quotaUsed = toclone.quotaUsed;
+ this.startDate = toclone.startDate;
+ this.endDate = toclone.endDate;
+ }
+
+ public Long getZoneId() {
+ return zoneId;
+ }
+
+ public void setZoneId(Long zoneId) {
+ this.zoneId = zoneId;
+ }
+
+ public Long getAccountId() {
+ return accountId;
+ }
+
+ public void setAccountId(Long accountId) {
+ this.accountId = accountId;
+ }
+
+ public Long getDomainId() {
+ return domainId;
+ }
+
+ public void setDomainId(Long domainId) {
+ this.domainId = domainId;
+ }
+
+ @Override
+ public long getId() {
+ // TODO Auto-generated method stub
+ return id;
+ }
+
+ public Long getUsageItemId() {
+ return usageItemId;
+ }
+
+ public void setUsageItemId(Long usageItemId) {
+ this.usageItemId = usageItemId;
+ }
+
+ public int getUsageType() {
+ return usageType;
+ }
+
+ public void setUsageType(int usageType) {
+ this.usageType = usageType;
+ }
+
+ public BigDecimal getQuotaUsed() {
+ return quotaUsed;
+ }
+
+ public void setQuotaUsed(BigDecimal quotaUsed) {
+ this.quotaUsed = quotaUsed;
+ }
+
+ 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 void setId(Long id) {
+ this.id = id;
+ }
+
+}
diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java
new file mode 100644
index 000000000000..6415f24fa670
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java
@@ -0,0 +1,337 @@
+//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.vo;
+
+import java.util.Map;
+
+import javax.persistence.Column;
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+import javax.persistence.PrimaryKeyJoinColumn;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+
+import com.cloud.offering.ServiceOffering;
+import com.cloud.storage.DiskOfferingVO;
+import com.cloud.storage.Storage.ProvisioningType;
+import com.cloud.vm.VirtualMachine;
+
+@Entity
+@Table(name = "service_offering")
+@DiscriminatorValue(value = "Service")
+@PrimaryKeyJoinColumn(name = "id")
+public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering {
+ @Column(name = "cpu")
+ private Integer cpu;
+
+ @Column(name = "speed")
+ private Integer speed;
+
+ @Column(name = "ram_size")
+ private Integer ramSize;
+
+ @Column(name = "nw_rate")
+ private Integer rateMbps;
+
+ @Column(name = "mc_rate")
+ private Integer multicastRateMbps;
+
+ @Column(name = "ha_enabled")
+ private boolean offerHA;
+
+ @Column(name = "limit_cpu_use")
+ private boolean limitCpuUse;
+
+ @Column(name = "is_volatile")
+ private boolean volatileVm;
+
+ @Column(name = "host_tag")
+ private String hostTag;
+
+ @Column(name = "default_use")
+ private boolean defaultUse;
+
+ @Column(name = "vm_type")
+ private String vmType;
+
+ @Column(name = "sort_key")
+ int sortKey;
+
+ @Column(name = "deployment_planner")
+ private String deploymentPlanner = null;
+
+ // This is a delayed load value. If the value is null,
+ // then this field has not been loaded yet.
+ // Call service offering dao to load it.
+ @Transient
+ Map details;
+
+ // This flag is required to tell if the offering is dynamic once the cpu, memory and speed are set.
+ // In some cases cpu, memory and speed are set to non-null values even if the offering is dynamic.
+ @Transient
+ boolean isDynamic;
+
+ protected ServiceOfferingVO() {
+ super();
+ }
+
+ public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, String displayText,
+ ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType, boolean defaultUse) {
+ super(name, displayText, provisioningType, false, tags, recreatable, useLocalStorage, systemUse, true);
+ this.cpu = cpu;
+ this.ramSize = ramSize;
+ this.speed = speed;
+ this.rateMbps = rateMbps;
+ this.multicastRateMbps = multicastRateMbps;
+ this.offerHA = offerHA;
+ limitCpuUse = false;
+ volatileVm = false;
+ this.defaultUse = defaultUse;
+ this.vmType = vmType == null ? null : vmType.toString().toLowerCase();
+ }
+
+ public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitCpuUse,
+ boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType, Long domainId) {
+ super(name, displayText, provisioningType, false, tags, recreatable, useLocalStorage, systemUse, true, domainId);
+ this.cpu = cpu;
+ this.ramSize = ramSize;
+ this.speed = speed;
+ this.rateMbps = rateMbps;
+ this.multicastRateMbps = multicastRateMbps;
+ this.offerHA = offerHA;
+ this.limitCpuUse = limitCpuUse;
+ this.volatileVm = volatileVm;
+ this.vmType = vmType == null ? null : vmType.toString().toLowerCase();
+ }
+
+ public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA,
+ boolean limitResourceUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse,
+ VirtualMachine.Type vmType, Long domainId, String hostTag) {
+ this(name,
+ cpu,
+ ramSize,
+ speed,
+ rateMbps,
+ multicastRateMbps,
+ offerHA,
+ limitResourceUse,
+ volatileVm,
+ displayText,
+ provisioningType,
+ useLocalStorage,
+ recreatable,
+ tags,
+ systemUse,
+ vmType,
+ domainId);
+ this.hostTag = hostTag;
+ }
+
+ public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA,
+ boolean limitResourceUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse,
+ VirtualMachine.Type vmType, Long domainId, String hostTag, String deploymentPlanner) {
+ this(name,
+ cpu,
+ ramSize,
+ speed,
+ rateMbps,
+ multicastRateMbps,
+ offerHA,
+ limitResourceUse,
+ volatileVm,
+ displayText,
+ provisioningType,
+ useLocalStorage,
+ recreatable,
+ tags,
+ systemUse,
+ vmType,
+ domainId,
+ hostTag);
+ this.deploymentPlanner = deploymentPlanner;
+ }
+
+ public ServiceOfferingVO(ServiceOfferingVO offering) {
+ super(offering.getId(),
+ offering.getName(),
+ offering.getDisplayText(),
+ offering.getProvisioningType(),
+ false,
+ offering.getTags(),
+ offering.isRecreatable(),
+ offering.getUseLocalStorage(),
+ offering.getSystemUse(),
+ true,
+ offering.isCustomizedIops()== null ? false:offering.isCustomizedIops(),
+ offering.getDomainId(),
+ offering.getMinIops(),
+ offering.getMaxIops());
+ cpu = offering.getCpu();
+ ramSize = offering.getRamSize();
+ speed = offering.getSpeed();
+ rateMbps = offering.getRateMbps();
+ multicastRateMbps = offering.getMulticastRateMbps();
+ offerHA = offering.getOfferHA();
+ limitCpuUse = offering.getLimitCpuUse();
+ volatileVm = offering.getVolatileVm();
+ hostTag = offering.getHostTag();
+ vmType = offering.getSystemVmType();
+ }
+
+ @Override
+ public boolean getOfferHA() {
+ return offerHA;
+ }
+
+ public void setOfferHA(boolean offerHA) {
+ this.offerHA = offerHA;
+ }
+
+ @Override
+ public boolean getLimitCpuUse() {
+ return limitCpuUse;
+ }
+
+ public void setLimitResourceUse(boolean limitCpuUse) {
+ this.limitCpuUse = limitCpuUse;
+ }
+
+ @Override
+ public boolean getDefaultUse() {
+ return defaultUse;
+ }
+
+ @Override
+ @Transient
+ public String[] getTagsArray() {
+ String tags = getTags();
+ if (tags == null || tags.length() == 0) {
+ return new String[0];
+ }
+
+ return tags.split(",");
+ }
+
+ @Override
+ public Integer getCpu() {
+ return cpu;
+ }
+
+ public void setCpu(int cpu) {
+ this.cpu = cpu;
+ }
+
+ public void setSpeed(int speed) {
+ this.speed = speed;
+ }
+
+ public void setRamSize(int ramSize) {
+ this.ramSize = ramSize;
+ }
+
+ @Override
+ public Integer getSpeed() {
+ return speed;
+ }
+
+ @Override
+ public Integer getRamSize() {
+ return ramSize;
+ }
+
+ public void setRateMbps(Integer rateMbps) {
+ this.rateMbps = rateMbps;
+ }
+
+ @Override
+ public Integer getRateMbps() {
+ return rateMbps;
+ }
+
+ public void setMulticastRateMbps(Integer multicastRateMbps) {
+ this.multicastRateMbps = multicastRateMbps;
+ }
+
+ @Override
+ public Integer getMulticastRateMbps() {
+ return multicastRateMbps;
+ }
+
+ public void setHostTag(String hostTag) {
+ this.hostTag = hostTag;
+ }
+
+ @Override
+ public String getHostTag() {
+ return hostTag;
+ }
+
+ @Override
+ public String getSystemVmType() {
+ return vmType;
+ }
+
+ @Override
+ public void setSortKey(int key) {
+ sortKey = key;
+ }
+
+ @Override
+ public int getSortKey() {
+ return sortKey;
+ }
+
+ @Override
+ public boolean getVolatileVm() {
+ return volatileVm;
+ }
+
+ @Override
+ public String getDeploymentPlanner() {
+ return deploymentPlanner;
+ }
+
+ public Map getDetails() {
+ return details;
+ }
+
+ public String getDetail(String name) {
+ assert (details != null) : "Did you forget to load the details?";
+
+ return details != null ? details.get(name) : null;
+ }
+
+ public void setDetail(String name, String value) {
+ assert (details != null) : "Did you forget to load the details?";
+
+ details.put(name, value);
+ }
+
+ public void setDetails(Map details) {
+ this.details = details;
+ }
+
+ @Override
+ public boolean isDynamic() {
+ return cpu == null || speed == null || ramSize == null || isDynamic;
+ }
+
+ public void setDynamicFlag(boolean isdynamic) {
+ isDynamic = isdynamic;
+ }
+}
+
diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/UserVmDetailVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/UserVmDetailVO.java
new file mode 100644
index 000000000000..daaed90d3224
--- /dev/null
+++ b/framework/quota/src/org/apache/cloudstack/quota/vo/UserVmDetailVO.java
@@ -0,0 +1,84 @@
+//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.vo;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import org.apache.cloudstack.api.ResourceDetail;
+
+@Entity
+@Table(name = "user_vm_details")
+public class UserVmDetailVO implements ResourceDetail {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ private long id;
+
+ @Column(name = "vm_id")
+ private long resourceId;
+
+ @Column(name = "name")
+ private String name;
+
+ @Column(name = "value", length = 5120)
+ private String value;
+
+ @Column(name = "display")
+ private boolean display = true;
+
+ public UserVmDetailVO() {
+ }
+
+ public UserVmDetailVO(long vmId, String name, String value, boolean display) {
+ this.resourceId = vmId;
+ this.name = name;
+ this.value = value;
+ this.display = display;
+ }
+
+ @Override
+ public long getId() {
+ return id;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public long getResourceId() {
+ return resourceId;
+ }
+
+ @Override
+ public boolean isDisplay() {
+ return display;
+ }
+
+}
+
diff --git a/plugins/database/quota/pom.xml b/plugins/database/quota/pom.xml
new file mode 100644
index 000000000000..ae2c85317ddf
--- /dev/null
+++ b/plugins/database/quota/pom.xml
@@ -0,0 +1,58 @@
+
+
+ 4.0.0
+ cloud-plugin-database-quota
+ Apache CloudStack Plugin - Quota Service
+
+ org.apache.cloudstack
+ cloudstack-plugins
+ 4.5.2
+ ../../pom.xml
+
+
+
+ org.apache.cloudstack
+ cloud-api
+ ${project.version}
+
+
+ org.apache.cloudstack
+ cloud-engine-schema
+ ${project.version}
+
+
+ org.apache.cloudstack
+ cloud-utils
+ ${project.version}
+
+
+ org.apache.cloudstack
+ cloud-framework-quota
+ ${project.version}
+
+
+ mysql
+ mysql-connector-java
+ provided
+
+
+ org.apache.commons
+ commons-lang3
+ ${cs.commons-lang3.version}
+
+
+ joda-time
+ joda-time
+ ${cs.joda-time.version}
+
+
+
diff --git a/plugins/database/quota/resources/META-INF/cloudstack/quota/module.properties b/plugins/database/quota/resources/META-INF/cloudstack/quota/module.properties
new file mode 100644
index 000000000000..7332f1518283
--- /dev/null
+++ b/plugins/database/quota/resources/META-INF/cloudstack/quota/module.properties
@@ -0,0 +1,18 @@
+# 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.
+name=quota
+parent=api
diff --git a/plugins/database/quota/resources/META-INF/cloudstack/quota/spring-quota-context.xml b/plugins/database/quota/resources/META-INF/cloudstack/quota/spring-quota-context.xml
new file mode 100644
index 000000000000..15bc144e31a7
--- /dev/null
+++ b/plugins/database/quota/resources/META-INF/cloudstack/quota/spring-quota-context.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaBalanceCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaBalanceCmd.java
new file mode 100644
index 000000000000..ddf6f054a01c
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaBalanceCmd.java
@@ -0,0 +1,136 @@
+//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.command;
+
+import java.util.Date;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.AccountResponse;
+import org.apache.cloudstack.api.response.DomainResponse;
+import org.apache.cloudstack.api.response.QuotaBalanceResponse;
+import org.apache.cloudstack.api.response.QuotaResponseBuilder;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
+import org.apache.cloudstack.api.response.QuotaStatementItemResponse;
+
+import com.cloud.user.Account;
+
+@APICommand(name = "quotaBalance", responseObject = QuotaStatementItemResponse.class, description = "Create a quota balance statement", since = "4.2.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+public class QuotaBalanceCmd extends BaseCmd {
+
+ public static final Logger s_logger = Logger.getLogger(QuotaBalanceCmd.class.getName());
+
+ private static final String s_name = "quotabalanceresponse";
+
+ @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required = true, description = "Optional, Account Id for which statement needs to be generated")
+ private String accountName;
+
+ @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = true, entityType = DomainResponse.class, description = "Optional, If domain Id is given and the caller is domain admin then the statement is generated for domain.")
+ private Long domainId;
+
+ @Parameter(name = ApiConstants.END_DATE, type = CommandType.DATE, description = "End date range for quota query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-03.")
+ private Date endDate;
+
+ @Parameter(name = ApiConstants.START_DATE, type = CommandType.DATE, description = "Start date range quota query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-01.")
+ private Date startDate;
+
+ @Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.UUID, entityType = AccountResponse.class, description = "List usage records for the specified account")
+ private Long accountId;
+
+ @Inject
+ QuotaResponseBuilder _responseBuilder;
+
+ 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 Date getEndDate() {
+ return endDate == null ? null : _responseBuilder.startOfNextDay(endDate);
+ }
+
+ public void setEndDate(Date endDate) {
+ this.endDate = endDate;
+ }
+
+ public Date getStartDate() {
+ return startDate;
+ }
+
+ public void setStartDate(Date startDate) {
+ this.startDate = startDate;
+ }
+
+ public QuotaBalanceCmd() {
+ super();
+ }
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ Long accountId = _accountService.getActiveAccountByName(accountName, domainId).getAccountId();
+ if (accountId == null) {
+ return CallContext.current().getCallingAccount().getId();
+ }
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+ @Override
+ public void execute() {
+ List quotaUsage = _responseBuilder.getQuotaBalance(this);
+
+ QuotaBalanceResponse response;
+ if (getEndDate() == null) {
+ response = _responseBuilder.createQuotaLastBalanceResponse(quotaUsage, startDate);
+ } else {
+ response = _responseBuilder.createQuotaBalanceResponse(quotaUsage, startDate, endDate);
+ }
+ response.setResponseName(getCommandName());
+ setResponseObject(response);
+ }
+
+}
diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaCreditsCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaCreditsCmd.java
new file mode 100644
index 000000000000..1a7db81fce1a
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaCreditsCmd.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.command;
+
+import com.cloud.user.Account;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.DomainResponse;
+import org.apache.cloudstack.api.response.QuotaCreditsResponse;
+import org.apache.cloudstack.api.response.QuotaResponseBuilder;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.quota.QuotaService;
+import org.apache.log4j.Logger;
+
+import javax.inject.Inject;
+
+@APICommand(name = "quotaCredits", responseObject = QuotaCreditsResponse.class, description = "Add +-credits to an account", since = "4.2.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+public class QuotaCreditsCmd extends BaseCmd {
+
+ @Inject
+ QuotaResponseBuilder _responseBuilder;
+
+ @Inject
+ QuotaService _quotaService;
+
+ public static final Logger s_logger = Logger.getLogger(QuotaStatementCmd.class.getName());
+
+ private static final String s_name = "quotacreditsresponse";
+
+ @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required = true, description = "Account Id for which quota credits need to be added")
+ private String accountName;
+
+ @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = true, entityType = DomainResponse.class, description = "Domain for which quota credits need to be added")
+ private Long domainId;
+
+ @Parameter(name = ApiConstants.VALUE, type = CommandType.DOUBLE, required = true, description = "Value of the credits to be added+, subtracted-")
+ private Double value;
+
+ @Parameter(name = "min_balance", type = CommandType.DOUBLE, required = false, description = "Minimum balance threshold of the account")
+ private Double minBalance;
+
+ @Parameter(name = "quota_enforce", type = CommandType.BOOLEAN, required = false, description = "Account for which quota enforce is set to false will not be locked when there is no credit balance")
+ private Boolean quotaEnforce;
+
+ public Double getMinBalance() {
+ return minBalance;
+ }
+
+ public void setMinBalance(Double minBalance) {
+ this.minBalance = minBalance;
+ }
+
+ public Boolean getQuotaEnforce() {
+ return quotaEnforce;
+ }
+
+ public void setQuotaEnforce(Boolean quotaEnforce) {
+ this.quotaEnforce = quotaEnforce;
+ }
+
+ 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 Double getValue() {
+ return value;
+ }
+
+ public void setValue(Double value) {
+ this.value = value;
+ }
+
+ public QuotaCreditsCmd() {
+ super();
+ }
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ @Override
+ public void execute() {
+ Long accountId = _accountService.getActiveAccountByName(accountName, domainId).getAccountId();
+ if (accountId == null) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "The account does not exists or has been removed/disabled");
+ }
+ if (value == null) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Please send a valid non-empty quota value");
+ }
+ if (getQuotaEnforce() != null) {
+ _quotaService.setLockAccount(accountId, getQuotaEnforce());
+ }
+ if (getMinBalance() != null) {
+ _quotaService.setMinBalance(accountId, getMinBalance());
+ }
+ else {
+ _quotaService.setMinBalance(accountId, 0.2 * value);
+ }
+
+ final QuotaCreditsResponse response = _responseBuilder.addQuotaCredits(accountId, domainId, value, CallContext.current().getCallingUserId());
+ response.setResponseName(getCommandName());
+ response.setObjectName("quotacredits");
+ setResponseObject(response);
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+}
diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaEmailTemplateListCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaEmailTemplateListCmd.java
new file mode 100644
index 000000000000..e2985febe21f
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaEmailTemplateListCmd.java
@@ -0,0 +1,56 @@
+//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.command;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.QuotaEmailTemplateResponse;
+import org.apache.cloudstack.api.response.QuotaResponseBuilder;
+import org.apache.log4j.Logger;
+
+import javax.inject.Inject;
+
+@APICommand(name = "quotaEmailTemplateList", responseObject = QuotaEmailTemplateResponse.class, description = "Lists all quota email templates", since = "4.6.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+public class QuotaEmailTemplateListCmd extends BaseListCmd {
+ public static final Logger s_logger = Logger.getLogger(QuotaEmailTemplateListCmd.class.getName());
+ private static final String s_name = "quotaemailtemplatelistresponse";
+
+ @Inject
+ QuotaResponseBuilder _quotaResponseBuilder;
+
+ @Parameter(name = "templatetype", type = CommandType.STRING, description = "List by type of the quota email template, allowed types: QUOTA_LOW, QUOTA_EMPTY")
+ private String templateName;
+
+ public String getTemplateName() {
+ return templateName;
+ }
+
+ @Override
+ public void execute() {
+ final ListResponse response = new ListResponse();
+ response.setResponses(_quotaResponseBuilder.listQuotaEmailTemplates(this));
+ response.setResponseName(getCommandName());
+ setResponseObject(response);
+ }
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+}
diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaEmailTemplateUpdateCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaEmailTemplateUpdateCmd.java
new file mode 100644
index 000000000000..df08d91698b8
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaEmailTemplateUpdateCmd.java
@@ -0,0 +1,111 @@
+//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.command;
+
+import com.cloud.user.Account;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.QuotaResponseBuilder;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.quota.constant.QuotaConfig;
+import org.apache.log4j.Logger;
+
+import javax.inject.Inject;
+import java.util.Arrays;
+
+@APICommand(name = "quotaEmailTemplateUpdate", responseObject = SuccessResponse.class, description = "Updates existing email templates for quota alerts", since = "4.2.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+public class QuotaEmailTemplateUpdateCmd extends BaseCmd {
+ public static final Logger s_logger = Logger.getLogger(QuotaEmailTemplateUpdateCmd.class.getName());
+ private static final String s_name = "quotaemailtemplateupdateresponse";
+
+ @Inject
+ QuotaResponseBuilder _quotaResponseBuilder;
+
+ @Parameter(name = "templatetype", type = CommandType.STRING, required=true, description = "Type of the quota email template, allowed types: QUOTA_LOW, QUOTA_EMPTY")
+ private String templateName;
+
+ @Parameter(name = "templatesubject", type = CommandType.STRING, required=true, description = "The quota email template subject, max: 77 characters", length = 77)
+ private String templateSubject;
+
+ @Parameter(name = "templatebody", type = CommandType.STRING, required=true, description = "The quota email template body, max: 500k characters", length = 512000)
+ private String templateBody;
+
+ @Parameter(name = "locale", type = CommandType.STRING, description = "The locale of the email text")
+ private String locale;
+
+ @Override
+ public void execute() {
+ final String templateName = getTemplateName();
+ if (templateName == null || getTemplateSubject() == null || getTemplateBody() == null) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Failed to update quota email template due to empty or invalid template name or text");
+ }
+
+ boolean isValidTemplateName = false;
+ for (QuotaConfig.QuotaEmailTemplateTypes e: QuotaConfig.QuotaEmailTemplateTypes.values()) {
+ if (e.toString().equalsIgnoreCase(templateName)) {
+ isValidTemplateName = true;
+ setTemplateName(e.toString());
+ break;
+ }
+ }
+ if (!isValidTemplateName) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid quota email template type, allowed values are: " + Arrays.toString(QuotaConfig.QuotaEmailTemplateTypes.values()));
+ }
+
+ if (!_quotaResponseBuilder.updateQuotaEmailTemplate(this)) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Unable to update quota email template due to an internal error");
+ }
+ final SuccessResponse response = new SuccessResponse();
+ response.setResponseName(getCommandName());
+ response.setSuccess(true);
+ setResponseObject(response);
+ }
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+ private void setTemplateName(String templateName) {
+ this.templateName = templateName;
+ }
+
+ public String getTemplateName() {
+ return templateName;
+ }
+
+ public String getTemplateSubject() {
+ return templateSubject;
+ }
+
+ public String getTemplateBody() {
+ return templateBody;
+ }
+
+ public String getLocale() {
+ return locale;
+ }
+
+}
diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaStatementCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaStatementCmd.java
new file mode 100644
index 000000000000..5d38d3dfff7b
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaStatementCmd.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.command;
+
+import java.util.Date;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.AccountResponse;
+import org.apache.cloudstack.api.response.DomainResponse;
+import org.apache.cloudstack.api.response.QuotaResponseBuilder;
+import org.apache.cloudstack.api.response.QuotaStatementResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.quota.vo.QuotaUsageVO;
+import org.apache.cloudstack.api.response.QuotaStatementItemResponse;
+
+import com.cloud.user.Account;
+
+@APICommand(name = "quotaStatement", responseObject = QuotaStatementItemResponse.class, description = "Create a quota statement", since = "4.2.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+public class QuotaStatementCmd extends BaseCmd {
+
+ public static final Logger s_logger = Logger.getLogger(QuotaStatementCmd.class.getName());
+
+ private static final String s_name = "quotastatementresponse";
+
+ @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required = true, description = "Optional, Account Id for which statement needs to be generated")
+ private String accountName;
+
+ @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = true, entityType = DomainResponse.class, description = "Optional, If domain Id is given and the caller is domain admin then the statement is generated for domain.")
+ private Long domainId;
+
+ @Parameter(name = ApiConstants.END_DATE, type = CommandType.DATE, required = true, description = "End date range for quota query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-03.")
+ private Date endDate;
+
+ @Parameter(name = ApiConstants.START_DATE, type = CommandType.DATE, required = true, description = "Start date range quota query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-01.")
+ private Date startDate;
+
+ @Parameter(name = ApiConstants.TYPE, type = CommandType.INTEGER, description = "List quota usage records for the specified usage type")
+ private Integer usageType;
+
+ @Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.UUID, entityType = AccountResponse.class, description = "List usage records for the specified account")
+ private Long accountId;
+
+ @Inject
+ QuotaResponseBuilder _responseBuilder;
+
+ public Long getAccountId() {
+ return accountId;
+ }
+
+ public void setAccountId(Long accountId) {
+ this.accountId = accountId;
+ }
+
+ public Integer getUsageType() {
+ return usageType;
+ }
+
+ public void setUsageType(Integer usageType) {
+ this.usageType = usageType;
+ }
+
+ 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 Date getEndDate() {
+ return _responseBuilder.startOfNextDay(endDate == null ? new Date() : endDate);
+ }
+
+ public void setEndDate(Date endDate) {
+ this.endDate = endDate;
+ }
+
+ public Date getStartDate() {
+ return startDate;
+ }
+
+ public void setStartDate(Date startDate) {
+ this.startDate = startDate;
+ }
+
+ public QuotaStatementCmd() {
+ super();
+ }
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ Long accountId = _accountService.getActiveAccountByName(accountName, domainId).getAccountId();
+ if (accountId == null) {
+ return CallContext.current().getCallingAccount().getId();
+ }
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+ @Override
+ public void execute() {
+ List quotaUsage = _responseBuilder.getQuotaUsage(this);
+
+ QuotaStatementResponse response = _responseBuilder.createQuotaStatementResponse(quotaUsage);
+
+ response.setResponseName(getCommandName());
+ setResponseObject(response);
+ }
+
+}
diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaTariffListCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaTariffListCmd.java
new file mode 100644
index 000000000000..121873f8a007
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaTariffListCmd.java
@@ -0,0 +1,93 @@
+//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.command;
+
+import com.cloud.user.Account;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.QuotaResponseBuilder;
+import org.apache.cloudstack.api.response.QuotaTariffResponse;
+import org.apache.cloudstack.quota.vo.QuotaTariffVO;
+import org.apache.log4j.Logger;
+
+import javax.inject.Inject;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+@APICommand(name = "quotaTariffList", responseObject = QuotaTariffResponse.class, description = "Lists all quota tariff plans", since = "4.6.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+public class QuotaTariffListCmd extends BaseListCmd {
+ public static final Logger s_logger = Logger.getLogger(QuotaTariffListCmd.class.getName());
+ private static final String s_name = "quotatarifflistresponse";
+
+ @Inject
+ QuotaResponseBuilder _responseBuilder;
+
+ @Parameter(name = ApiConstants.USAGE_TYPE, type = CommandType.INTEGER, required = false, description = "Usage type of the resource")
+ private Integer usageType;
+
+ @Parameter(name = ApiConstants.START_DATE, type = CommandType.DATE, required = false, description = "The effective start date on/after which the quota tariff is effective and older tariffs are no longer used for the usage type. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-03.")
+ private Date effectiveDate;
+
+ public QuotaTariffListCmd() {
+ super();
+ }
+
+ @Override
+ public void execute() {
+ final List result = _responseBuilder.listQuotaTariffPlans(this);
+
+ final List responses = new ArrayList();
+ for (final QuotaTariffVO resource : result) {
+ s_logger.info("Result desc=" + resource.getDescription() + " date=" + resource.getEffectiveOn() + " val=" + resource.getCurrencyValue());
+ responses.add(_responseBuilder.createQuotaTariffResponse(resource));
+ }
+
+ final ListResponse response = new ListResponse();
+ response.setResponses(responses);
+ response.setResponseName(getCommandName());
+ setResponseObject(response);
+ }
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+ public Date getEffectiveDate() {
+ return effectiveDate;
+ }
+
+ public Integer getUsageType() {
+ return usageType;
+ }
+
+ public void setUsageType(Integer usageType) {
+ this.usageType = usageType;
+ }
+
+}
diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaTariffUpdateCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaTariffUpdateCmd.java
new file mode 100644
index 000000000000..0af3ab877559
--- /dev/null
+++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaTariffUpdateCmd.java
@@ -0,0 +1,102 @@
+//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.command;
+
+import com.cloud.user.Account;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.QuotaResponseBuilder;
+import org.apache.cloudstack.api.response.QuotaTariffResponse;
+import org.apache.cloudstack.quota.vo.QuotaTariffVO;
+import org.apache.log4j.Logger;
+
+import javax.inject.Inject;
+
+import java.util.Date;
+
+@APICommand(name = "quotaTariffUpdate", responseObject = QuotaTariffResponse.class, description = "Update the tariff plan for a resource", since = "4.6.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+public class QuotaTariffUpdateCmd extends BaseCmd {
+ public static final Logger s_logger = Logger.getLogger(QuotaTariffUpdateCmd.class.getName());
+ private static final String s_name = "quotatariffupdateresponse";
+
+ @Inject
+ QuotaResponseBuilder _responseBuilder;
+
+ @Parameter(name = ApiConstants.USAGE_TYPE, type = CommandType.INTEGER, required = true, description = "Integer value for the usage type of the resource")
+ private Integer usageType;
+
+ @Parameter(name = "value", type = CommandType.DOUBLE, required = true, description = "The quota tariff value of the resource as per the default unit")
+ private Double value;
+
+ @Parameter(name = ApiConstants.START_DATE, type = CommandType.DATE, required = true, description = "The effective start date on/after which the quota tariff is effective and older tariffs are no longer used for the usage type. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-03.")
+ private Date startDate;
+
+ public int getUsageType() {
+ return usageType;
+ }
+
+ public void setUsageType(int usageType) {
+ this.usageType = usageType;
+ }
+
+ public Double getValue() {
+ return value;
+ }
+
+ public void setValue(Double value) {
+ this.value = value;
+ }
+
+ public Date getStartDate() {
+ return startDate;
+ }
+
+ public void setStartDate(Date startDate) {
+ this.startDate = startDate;
+ }
+
+ public QuotaTariffUpdateCmd() {
+ super();
+ }
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ @Override
+ public void execute() {
+ final QuotaTariffVO result = _responseBuilder.updateQuotaTariffPlan(this);
+ if (result == null) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update quota tariff plan");
+ }
+ final QuotaTariffResponse response = _responseBuilder.createQuotaTariffResponse(result);
+ response.setResponseName(getCommandName());
+ setResponseObject(response);
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+}
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 000000000000..2e0c23f21eca
--- /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 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();
+ }
+
+ 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 getCredits() {
+ return credits;
+ }
+
+ public void setCredits(List 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;
+ }
+}
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 000000000000..2c16cf44b7cf
--- /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
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 000000000000..c4a2b7c3a605
--- /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;
+ }
+}
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 000000000000..e9bb61105907
--- /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 listQuotaTariffPlans(QuotaTariffListCmd cmd);
+
+ QuotaTariffResponse createQuotaTariffResponse(QuotaTariffVO configuration);
+
+ QuotaStatementResponse createQuotaStatementResponse(List quotaUsage);
+
+ QuotaBalanceResponse createQuotaBalanceResponse(List quotaUsage, Date startDate, Date endDate);
+
+ QuotaBalanceResponse createQuotaLastBalanceResponse(List quotaBalance, Date startDate);
+
+ QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy, Date despositedOn);
+
+ public List getQuotaUsage(QuotaStatementCmd cmd);
+
+ List getQuotaBalance(QuotaBalanceCmd cmd);
+
+ QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy);
+
+ List listQuotaEmailTemplates(QuotaEmailTemplateListCmd cmd);
+
+ boolean updateQuotaEmailTemplate(QuotaEmailTemplateUpdateCmd cmd);
+
+ Date startOfNextDay(Date dt);
+
+ Date startOfNextDay();
+}
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 000000000000..de082eeaeb49
--- /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 quotaBalance, Date startDate, Date endDate) {
+ if (quotaBalance.size() == 0) {
+ new InvalidParameterValueException("The request period does not contain balance entries.");
+ }
+ Collections.sort(quotaBalance, new Comparator() {
+ 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 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 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 quotaTariffMap = new HashMap();
+ List 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() {
+ public int compare(QuotaUsageVO o1, QuotaUsageVO o2) {
+ if (o1.getUsageType() == o2.getUsageType())
+ return 0;
+ return o1.getUsageType() < o2.getUsageType() ? -1 : 1;
+ }
+ });
+
+ List items = new ArrayList();
+ 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 listQuotaTariffPlans(final QuotaTariffListCmd cmd) {
+ List result = new ArrayList();
+ 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 listQuotaEmailTemplates(QuotaEmailTemplateListCmd cmd) {
+ final String templateName = cmd.getTemplateName();
+ List templates = _quotaEmailTemplateDao.listAllQuotaEmailTemplates(templateName);
+ final List responses = new ArrayList();
+ 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 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 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 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 getQuotaUsage(QuotaStatementCmd cmd) {
+ return _quotaService.getQuotaUsage(cmd.getAccountId(), cmd.getAccountName(), cmd.getDomainId(), cmd.getUsageType(), cmd.getStartDate(), cmd.getEndDate());
+ }
+
+ @Override
+ public List 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;
+ }
+
+}
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 000000000000..e1b0f171e4bc
--- /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;
+ }
+
+}
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 000000000000..7ea5e6cc7ce0
--- /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 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 getLineItem() {
+ return lineItem;
+ }
+
+ public void setLineItem(List 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;
+ }
+}
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 000000000000..48697fd2a822
--- /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;
+ }
+}
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 000000000000..989fba54e7f2
--- /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);
+ }
+
+}
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 000000000000..8ee39b878aff
--- /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 getQuotaUsage(Long accountId, String accountName, Long domainId, Integer usageType, Date startDate, Date endDate);
+
+ List 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);
+
+}
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 000000000000..e13512a9b3ab
--- /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 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> getCommands() {
+ final List> cmdList = new ArrayList>();
+ 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 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 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 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 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 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 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);
+ }
+ }
+
+}
diff --git a/plugins/pom.xml b/plugins/pom.xml
index 6c826600c480..0c7c2fcda9ad 100755
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -90,6 +90,7 @@
network-elements/internal-loadbalancer
network-elements/vxlan
network-elements/globodns
+ database/quota
diff --git a/pom.xml b/pom.xml
index 2a508b50c68d..2dfb9eb14403 100644
--- a/pom.xml
+++ b/pom.xml
@@ -83,6 +83,7 @@
1.3.22
2.6
1.4
+ 3.4
0.9.8
0.10
build/replace.properties
@@ -96,6 +97,7 @@
2.5.3
2.9.1
2.6.1
+ 2.8.1
diff --git a/server/src/com/cloud/api/dispatch/ParamProcessWorker.java b/server/src/com/cloud/api/dispatch/ParamProcessWorker.java
index b990d4aedf4c..f9c9e0f079bd 100644
--- a/server/src/com/cloud/api/dispatch/ParamProcessWorker.java
+++ b/server/src/com/cloud/api/dispatch/ParamProcessWorker.java
@@ -291,6 +291,14 @@ private void setFieldValue(final Field field, final BaseCmd cmdObj, final Object
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
diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java
index 20fcbcb3bd5f..a7d4268bef65 100755
--- a/server/src/com/cloud/user/AccountManagerImpl.java
+++ b/server/src/com/cloud/user/AccountManagerImpl.java
@@ -2179,8 +2179,7 @@ private UserAccount getUserAccount(String username, String password, Long domain
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()))
diff --git a/setup/db/db/schema-451to452.sql b/setup/db/db/schema-451to452.sql
index 5c89008a83ef..90e55271f23e 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";
@@ -33,3 +35,115 @@ CREATE TABLE `cloud`.`saml_token` (
PRIMARY KEY (`id`),
CONSTRAINT `fk_saml_token__domain_id` FOREIGN KEY(`domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- Quota
+
+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}:
Balance = ${quotaBalance}
Total Usage = ${quotaUsage}.');
+UNLOCK TABLES;
+
diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py
index 4fac7ee3790c..e8a930e8dfee 100644
--- a/tools/apidoc/gen_toc.py
+++ b/tools/apidoc/gen_toc.py
@@ -118,6 +118,8 @@
'listIdps': 'Authentication',
'authorizeSamlSso': 'Authentication',
'listSamlAuthorization': 'Authentication',
+ 'quota': 'Quota',
+ 'emailTemplate': 'Quota',
'Capacity': 'System Capacity',
'NetworkDevice': 'Network Device',
'ExternalLoadBalancer': 'Ext Load Balancer',
diff --git a/ui/dictionary.jsp b/ui/dictionary.jsp
index 1f8aa8f875dd..df03367ba1c8 100644
--- a/ui/dictionary.jsp
+++ b/ui/dictionary.jsp
@@ -982,6 +982,13 @@ dictionary = {
'label.purpose': '',
'label.Pxe.server.type': '',
'label.quickview': '',
+'label.usage.type': '',
+'label.usage.unit': '',
+'label.quota.value': '',
+'label.quota.description': '',
+'label.quota.configuration': '',
+'label.quota.configure': '',
+'label.quota.remove': '',
'label.rbd': '',
'label.rbd.monitor': '',
'label.rbd.pool': '',
diff --git a/ui/plugins/plugins.js b/ui/plugins/plugins.js
index 386ec062bb0d..0a6d2e74b4e1 100644
--- a/ui/plugins/plugins.js
+++ b/ui/plugins/plugins.js
@@ -16,6 +16,7 @@
// under the License.
(function($, cloudStack) {
cloudStack.plugins = [
- // 'testPlugin'
+ //'quota',
+ //'testPlugin'
];
}(jQuery, cloudStack));
diff --git a/ui/plugins/quota/config.js b/ui/plugins/quota/config.js
new file mode 100644
index 000000000000..186d50778400
--- /dev/null
+++ b/ui/plugins/quota/config.js
@@ -0,0 +1,25 @@
+// 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.
+(function (cloudStack) {
+ cloudStack.plugins.quota.config = {
+ title: 'Quota',
+ desc: 'CloudStack Quota',
+ externalLink: 'http://www.cloudstack.org/',
+ authorName: 'Apache CloudStack',
+ authorEmail: 'dev@cloudstack.apache.org'
+ };
+}(cloudStack));
diff --git a/ui/plugins/quota/icon.png b/ui/plugins/quota/icon.png
new file mode 100644
index 000000000000..e178ebc32dd9
Binary files /dev/null and b/ui/plugins/quota/icon.png differ
diff --git a/ui/plugins/quota/quota.css b/ui/plugins/quota/quota.css
new file mode 100644
index 000000000000..e9c0d8ff358c
--- /dev/null
+++ b/ui/plugins/quota/quota.css
@@ -0,0 +1,68 @@
+/*
+* 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.
+*/
+
+.quota-tariff-edit {
+ float: right;
+}
+
+.quota-bold {
+ font-size: 12px;
+ font-weight: bold;
+ color: #6D6D6D;
+}
+
+.quota-text {
+ font-size: 11px;
+ color: #282828;
+}
+
+.quota-element {
+ margin: 5px;
+ margin-left: 13px;
+}
+
+.quota-input {
+ background: #F6F6F6;
+ border: 1px solid #AFAFAF;
+ border-radius: 4px;
+}
+
+.quota-button {
+ border:1px solid #0077c7; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px;
+ font-size:11px;
+ padding: 8px;
+ margin-top: 12px;
+ text-shadow: -1px -1px 0 rgba(0,0,0,0.3);font-weight:bold; color: #FFFFFF;
+ background-color: #0099FF; background-image: -webkit-gradient(linear, left top, left bottom, from(#0099FF), to(#004FF7));
+ background-image: -webkit-linear-gradient(top, #0099FF, #004FF7);
+ background-image: -moz-linear-gradient(top, #0099FF, #004FF7);
+ background-image: -ms-linear-gradient(top, #0099FF, #004FF7);
+ background-image: -o-linear-gradient(top, #0099FF, #004FF7);
+ background-image: linear-gradient(to bottom, #0099FF, #004FF7);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#0099FF, endColorstr=#004FF7);
+}
+
+.quota-button:hover {
+ border:1px solid #005c99;
+ background-color: #0039B3; background-image: -webkit-gradient(linear, left top, left bottom, from(#0039B3), to(#004FF7));
+ background-image: -webkit-linear-gradient(top, #0039B3, #004FF7);
+ background-image: -moz-linear-gradient(top, #0039B3, #004FF7);
+ background-image: -ms-linear-gradient(top, #0039B3, #004FF7);
+ background-image: -o-linear-gradient(top, #0039B3, #004FF7);
+ background-image: linear-gradient(to bottom, #0039B3, #004FF7);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#0039B3, endColorstr=#004FF7);
+}
diff --git a/ui/plugins/quota/quota.js b/ui/plugins/quota/quota.js
new file mode 100644
index 000000000000..4e94b2c318c9
--- /dev/null
+++ b/ui/plugins/quota/quota.js
@@ -0,0 +1,726 @@
+// 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.
+
+var g_quotaCurrency = '';
+(function (cloudStack) {
+ cloudStack.plugins.quota = function(plugin) {
+ plugin.ui.addSection({
+ id: 'quota',
+ title: 'Quota',
+ showOnNavigation: true,
+ preFilter: function(args) {
+ return true;
+ },
+ show: function() {
+ var $quotaView = $('');
+ var $toolbar = $('
');
+ var $tabs = $('