content: // 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 com.cloud.test;
  
  import java.io.File;
  import java.io.IOException;
  import java.net.URISyntaxException;
  import java.security.NoSuchAlgorithmException;
  import java.sql.Date;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.UUID;
  
  import javax.xml.parsers.DocumentBuilder;
  import javax.xml.parsers.DocumentBuilderFactory;
  import javax.xml.parsers.ParserConfigurationException;
  import javax.xml.parsers.SAXParser;
  import javax.xml.parsers.SAXParserFactory;
  
  import org.apache.cloudstack.utils.security.DigestHelper;
  import org.apache.cloudstack.utils.security.ParserUtils;
  import org.apache.logging.log4j.Logger;
  import org.apache.logging.log4j.LogManager;
  import org.apache.logging.log4j.core.config.Configurator;
  import org.w3c.dom.Document;
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  import org.xml.sax.Attributes;
  import org.xml.sax.SAXException;
  import org.xml.sax.helpers.DefaultHandler;
  
  import com.cloud.host.Status;
  import com.cloud.service.ServiceOfferingVO;
  import com.cloud.service.dao.ServiceOfferingDaoImpl;
  import com.cloud.storage.DiskOfferingVO;
  import com.cloud.storage.Storage.ProvisioningType;
  import com.cloud.storage.dao.DiskOfferingDaoImpl;
  import com.cloud.utils.DateUtil;
  import com.cloud.utils.PropertiesUtil;
  import com.cloud.utils.UuidUtils;
  import com.cloud.utils.component.ComponentContext;
  import com.cloud.utils.db.DB;
  import com.cloud.utils.db.Transaction;
  import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn;
  import com.cloud.utils.db.TransactionLegacy;
  import com.cloud.utils.db.TransactionStatus;
  import com.cloud.utils.net.NfsUtils;
  
  public class DatabaseConfig {
      protected static Logger LOGGER = LogManager.getLogger(DatabaseConfig.class);
  
      private String _configFileName = null;
      private String _currentObjectName = null;
      private String _currentFieldName = null;
      private Map<String, String> _currentObjectParams = null;
  
      private static Map<String, String> s_configurationDescriptions = new HashMap<String, String>();
      private static Map<String, String> s_configurationComponents = new HashMap<String, String>();
      private static Map<String, String> s_defaultConfigurationValues = new HashMap<String, String>();
  
      // Change to HashSet
      private static HashSet<String> objectNames = new HashSet<String>();
      private static HashSet<String> fieldNames = new HashSet<String>();
  
      // Maintain an IPRangeConfig object to handle IP related logic
      private final IPRangeConfig iprc = ComponentContext.inject(IPRangeConfig.class);
  
      // Maintain a PodZoneConfig object to handle Pod/Zone related logic
      private final PodZoneConfig pzc = ComponentContext.inject(PodZoneConfig.class);
  
      // Global variables to store network.throttling.rate and multicast.throttling.rate from the configuration table
      // Will be changed from null to a non-null value if the value existed in the configuration table
      private String _networkThrottlingRate = null;
      private String _multicastThrottlingRate = null;
  
      static {
          // initialize the objectNames ArrayList
          objectNames.add("zone");
          objectNames.add("physicalNetwork");
          objectNames.add("vlan");
          objectNames.add("pod");
          objectNames.add("cluster");
          objectNames.add("storagePool");
          objectNames.add("secondaryStorage");
          objectNames.add("serviceOffering");
          objectNames.add("diskOffering");
          objectNames.add("user");
          objectNames.add("pricing");
          objectNames.add("configuration");
          objectNames.add("privateIpAddresses");
          objectNames.add("publicIpAddresses");
          objectNames.add("physicalNetworkServiceProvider");
          objectNames.add("virtualRouterProvider");
  
          // initialize the fieldNames ArrayList
          fieldNames.add("id");
          fieldNames.add("name");
          fieldNames.add("dns1");
          fieldNames.add("dns2");
          fieldNames.add("internalDns1");
          fieldNames.add("internalDns2");
          fieldNames.add("guestNetworkCidr");
          fieldNames.add("gateway");
          fieldNames.add("netmask");
          fieldNames.add("vncConsoleIp");
          fieldNames.add("zoneId");
          fieldNames.add("vlanId");
          fieldNames.add("cpu");
          fieldNames.add("ramSize");
          fieldNames.add("speed");
          fieldNames.add("useLocalStorage");
          fieldNames.add("hypervisorType");
          fieldNames.add("diskSpace");
          fieldNames.add("nwRate");
          fieldNames.add("mcRate");
          fieldNames.add("price");
          fieldNames.add("username");
          fieldNames.add("password");
          fieldNames.add("firstname");
          fieldNames.add("lastname");
          fieldNames.add("email");
          fieldNames.add("priceUnit");
          fieldNames.add("type");
          fieldNames.add("value");
          fieldNames.add("podId");
          fieldNames.add("podName");
          fieldNames.add("ipAddressRange");
          fieldNames.add("vlanType");
          fieldNames.add("vlanName");
          fieldNames.add("cidr");
          fieldNames.add("vnet");
          fieldNames.add("mirrored");
          fieldNames.add("enableHA");
          fieldNames.add("displayText");
          fieldNames.add("domainId");
          fieldNames.add("hostAddress");
          fieldNames.add("hostPath");
          fieldNames.add("guestIpType");
          fieldNames.add("url");
          fieldNames.add("storageType");
          fieldNames.add("category");
          fieldNames.add("tags");
          fieldNames.add("networktype");
          fieldNames.add("clusterId");
          fieldNames.add("physicalNetworkId");
          fieldNames.add("destPhysicalNetworkId");
          fieldNames.add("providerName");
          fieldNames.add("vpn");
          fieldNames.add("dhcp");
          fieldNames.add("dns");
          fieldNames.add("firewall");
          fieldNames.add("sourceNat");
          fieldNames.add("loadBalance");
          fieldNames.add("staticNat");
          fieldNames.add("portForwarding");
          fieldNames.add("userData");
          fieldNames.add("securityGroup");
          fieldNames.add("nspId");
  
          s_configurationDescriptions.put("host.stats.interval", "the interval in milliseconds when host stats are retrieved from agents");
          s_configurationDescriptions.put("storage.stats.interval", "the interval in milliseconds when storage stats (per host) are retrieved from agents");
          s_configurationDescriptions.put("volume.stats.interval", "the interval in milliseconds when volume stats are retrieved from agents");
          s_configurationDescriptions.put("host", "host address to listen on for agent connection");
          s_configurationDescriptions.put("port", "port to listen on for agent connection");
          s_configurationDescriptions.put("guest.domain.suffix", "domain suffix for users");
          s_configurationDescriptions.put("instance.name", "Name of the deployment instance");
          s_configurationDescriptions.put("storage.overprovisioning.factor", "Storage Allocator overprovisioning factor");
          s_configurationDescriptions.put("retries.per.host", "The number of times each command sent to a host should be retried in case of failure.");
          s_configurationDescriptions.put("integration.api.port", "internal port used by the management server for servicing Integration API requests");
          s_configurationDescriptions.put("usage.stats.job.exec.time",
              "the time at which the usage statistics aggregation job will run as an HH24:MM time, e.g. 00:30 to run at 12:30am");
          s_configurationDescriptions.put("usage.stats.job.aggregation.range",
              "the range of time for aggregating the user statistics specified in minutes (e.g. 1440 for daily, 60 for hourly)");
          s_configurationDescriptions.put("consoleproxy.domP.enable", "Obsolete");
          s_configurationDescriptions.put("consoleproxy.port", "Obsolete");
          s_configurationDescriptions.put("consoleproxy.url.port", "Console proxy port for AJAX viewer");
          s_configurationDescriptions.put("consoleproxy.ram.size", "RAM size (in MB) used to create new console proxy VMs");
          s_configurationDescriptions.put("consoleproxy.cmd.port", "Console proxy command port that is used to communicate with management server");
          s_configurationDescriptions.put("consoleproxy.capacityscan.interval",
              "The time interval(in millisecond) to scan whether or not system needs more console proxy to ensure minimal standby capacity");
          s_configurationDescriptions.put("consoleproxy.capacity.standby",
              "The minimal number of console proxy viewer sessions that system is able to serve immediately(standby capacity)");
          s_configurationDescriptions.put("alert.email.addresses", "comma separated list of email addresses used for sending alerts");
          s_configurationDescriptions.put("alert.smtp.host", "SMTP hostname used for sending out email alerts");
          s_configurationDescriptions.put("alert.smtp.port", "port the SMTP server is listening on (default is 25)");
          s_configurationDescriptions.put("alert.smtp.useAuth",
              "If true, use SMTP authentication when sending emails.  If false, do not use SMTP authentication when sending emails.");
          s_configurationDescriptions.put("alert.smtp.username", "username for SMTP authentication (applies only if alert.smtp.useAuth is true)");
          s_configurationDescriptions.put("alert.smtp.password", "password for SMTP authentication (applies only if alert.smtp.useAuth is true)");
          s_configurationDescriptions.put("alert.email.sender", "sender of alert email (will be in the From header of the email)");
          s_configurationDescriptions.put("memory.capacity.threshold",
              "percentage (as a value between 0 and 1) of memory utilization above which alerts will be sent about low memory available");
          s_configurationDescriptions.put("cpu.capacity.threshold",
              "percentage (as a value between 0 and 1) of cpu utilization above which alerts will be sent about low cpu available");
          s_configurationDescriptions.put("storage.capacity.threshold",
              "percentage (as a value between 0 and 1) of storage utilization above which alerts will be sent about low storage available");
          s_configurationDescriptions.put("public.ip.capacity.threshold",
              "percentage (as a value between 0 and 1) of public IP address space utilization above which alerts will be sent");
          s_configurationDescriptions.put("private.ip.capacity.threshold",
              "percentage (as a value between 0 and 1) of private IP address space utilization above which alerts will be sent");
          s_configurationDescriptions.put("expunge.interval", "the interval to wait before running the expunge thread");
          s_configurationDescriptions.put("network.throttling.rate", "default data transfer rate in megabits per second allowed per user");
          s_configurationDescriptions.put("multicast.throttling.rate", "default multicast rate in megabits per second allowed");
          s_configurationDescriptions.put("system.vm.use.local.storage", "Indicates whether to use local storage pools or shared storage pools for system VMs.");
          s_configurationDescriptions.put("snapshot.poll.interval", "The time interval in seconds when the management server polls for snapshots to be scheduled.");
          s_configurationDescriptions.put("snapshot.max.hourly", "Maximum hourly snapshots for a volume");
          s_configurationDescriptions.put("snapshot.max.daily", "Maximum daily snapshots for a volume");
          s_configurationDescriptions.put("snapshot.max.weekly", "Maximum weekly snapshots for a volume");
          s_configurationDescriptions.put("snapshot.max.monthly", "Maximum monthly snapshots for a volume");
          s_configurationDescriptions.put("snapshot.recurring.test", "Flag for testing recurring snapshots");
          s_configurationDescriptions.put("snapshot.test.minutes.per.hour", "Set it to a smaller value to take more recurring snapshots");
          s_configurationDescriptions.put("snapshot.test.hours.per.day", "Set it to a smaller value to take more recurring snapshots");
          s_configurationDescriptions.put("snapshot.test.days.per.week", "Set it to a smaller value to take more recurring snapshots");
          s_configurationDescriptions.put("snapshot.test.days.per.month", "Set it to a smaller value to take more recurring snapshots");
          s_configurationDescriptions.put("snapshot.test.weeks.per.month", "Set it to a smaller value to take more recurring snapshots");
          s_configurationDescriptions.put("snapshot.test.months.per.year", "Set it to a smaller value to take more recurring snapshots");
          s_configurationDescriptions.put("hypervisor.type", "The type of hypervisor that this deployment will use.");
          s_configurationDescriptions.put("publish.action.events", "enable or disable to control the publishing of action events on the event bus");
          s_configurationDescriptions.put("publish.alert.events", "enable or disable to control the publishing of alert events on the event bus");
          s_configurationDescriptions.put("publish.resource.state.events", "enable or disable to control the publishing of resource state events on the event bus");
          s_configurationDescriptions.put("publish.usage.events", "enable or disable to control the publishing of usage events on the event bus");
          s_configurationDescriptions.put("publish.async.job.events", "enable or disable to control the publishing of async job events on the event bus");
  
          s_configurationComponents.put("host.stats.interval", "management-server");
          s_configurationComponents.put("storage.stats.interval", "management-server");
          s_configurationComponents.put("volume.stats.interval", "management-server");
          s_configurationComponents.put("integration.api.port", "management-server");
          s_configurationComponents.put("usage.stats.job.exec.time", "management-server");
          s_configurationComponents.put("usage.stats.job.aggregation.range", "management-server");
          s_configurationComponents.put("consoleproxy.domP.enable", "management-server");
          s_configurationComponents.put("consoleproxy.port", "management-server");
          s_configurationComponents.put("consoleproxy.url.port", "management-server");
          s_configurationComponents.put("alert.email.addresses", "management-server");
          s_configurationComponents.put("alert.smtp.host", "management-server");
          s_configurationComponents.put("alert.smtp.port", "management-server");
          s_configurationComponents.put("alert.smtp.useAuth", "management-server");
          s_configurationComponents.put("alert.smtp.username", "management-server");
          s_configurationComponents.put("alert.smtp.password", "management-server");
          s_configurationComponents.put("alert.email.sender", "management-server");
          s_configurationComponents.put("memory.capacity.threshold", "management-server");
          s_configurationComponents.put("cpu.capacity.threshold", "management-server");
          s_configurationComponents.put("storage.capacity.threshold", "management-server");
          s_configurationComponents.put("public.ip.capacity.threshold", "management-server");
          s_configurationComponents.put("private.ip.capacity.threshold", "management-server");
          s_configurationComponents.put("capacity.check.period", "management-server");
          s_configurationComponents.put("network.throttling.rate", "management-server");
          s_configurationComponents.put("multicast.throttling.rate", "management-server");
          s_configurationComponents.put("event.purge.interval", "management-server");
          s_configurationComponents.put("account.cleanup.interval", "management-server");
          s_configurationComponents.put("expunge.delay", "UserVmManager");
          s_configurationComponents.put("expunge.interval", "UserVmManager");
          s_configurationComponents.put("host", "AgentManager");
          s_configurationComponents.put("port", "AgentManager");
          s_configurationComponents.put("domain", "AgentManager");
          s_configurationComponents.put("instance.name", "AgentManager");
          s_configurationComponents.put("storage.overprovisioning.factor", "StorageAllocator");
          s_configurationComponents.put("retries.per.host", "AgentManager");
          s_configurationComponents.put("start.retry", "AgentManager");
          s_configurationComponents.put("wait", "AgentManager");
          s_configurationComponents.put("ping.timeout", "AgentManager");
          s_configurationComponents.put("ping.interval", "AgentManager");
          s_configurationComponents.put("alert.wait", "AgentManager");
          s_configurationComponents.put("update.wait", "AgentManager");
          s_configurationComponents.put("guest.domain.suffix", "AgentManager");
          s_configurationComponents.put("consoleproxy.ram.size", "AgentManager");
          s_configurationComponents.put("consoleproxy.cmd.port", "AgentManager");
          s_configurationComponents.put("consoleproxy.capacityscan.interval", "AgentManager");
          s_configurationComponents.put("consoleproxy.capacity.standby", "AgentManager");
          s_configurationComponents.put("consoleproxy.session.max", "AgentManager");
          s_configurationComponents.put("consoleproxy.session.timeout", "AgentManager");
          s_configurationComponents.put("expunge.workers", "UserVmManager");
          s_configurationComponents.put("extract.url.cleanup.interval", "management-server");
          s_configurationComponents.put("storage.overwrite.provisioning", "UserVmManager");
          s_configurationComponents.put("init", "none");
          s_configurationComponents.put("system.vm.use.local.storage", "ManagementServer");
          s_configurationComponents.put("snapshot.poll.interval", "SnapshotManager");
          s_configurationComponents.put("snapshot.max.hourly", "SnapshotManager");
          s_configurationComponents.put("snapshot.max.daily", "SnapshotManager");
          s_configurationComponents.put("snapshot.max.weekly", "SnapshotManager");
          s_configurationComponents.put("snapshot.max.monthly", "SnapshotManager");
          s_configurationComponents.put("snapshot.recurring.test", "SnapshotManager");
          s_configurationComponents.put("snapshot.test.minutes.per.hour", "SnapshotManager");
          s_configurationComponents.put("snapshot.test.hours.per.day", "SnapshotManager");
          s_configurationComponents.put("snapshot.test.days.per.week", "SnapshotManager");
          s_configurationComponents.put("snapshot.test.days.per.month", "SnapshotManager");
          s_configurationComponents.put("snapshot.test.weeks.per.month", "SnapshotManager");
          s_configurationComponents.put("snapshot.test.months.per.year", "SnapshotManager");
          s_configurationComponents.put("hypervisor.type", "ManagementServer");
          s_configurationComponents.put("publish.action.events", "management-server");
          s_configurationComponents.put("publish.alert.events", "management-server");
          s_configurationComponents.put("publish.resource.state.events", "management-server");
          s_configurationComponents.put("publish.usage.events", "management-server");
          s_configurationComponents.put("publish.async.job.events", "management-server");
  
          s_defaultConfigurationValues.put("host.stats.interval", "60000");
          s_defaultConfigurationValues.put("storage.stats.interval", "60000");
          s_defaultConfigurationValues.put("volume.stats.interval", "60000");
          s_defaultConfigurationValues.put("port", "8250");
          s_defaultConfigurationValues.put("integration.api.port", "8096");
          s_defaultConfigurationValues.put("usage.stats.job.exec.time", "00:15"); // run at 12:15am
          s_defaultConfigurationValues.put("usage.stats.job.aggregation.range", "1440"); // do a daily aggregation
          s_defaultConfigurationValues.put("storage.overprovisioning.factor", "2");
          s_defaultConfigurationValues.put("retries.per.host", "2");
          s_defaultConfigurationValues.put("ping.timeout", "2.5");
          s_defaultConfigurationValues.put("ping.interval", "60");
          s_defaultConfigurationValues.put("snapshot.poll.interval", "300");
          s_defaultConfigurationValues.put("snapshot.max.hourly", "8");
          s_defaultConfigurationValues.put("snapshot.max.daily", "8");
          s_defaultConfigurationValues.put("snapshot.max.weekly", "8");
          s_defaultConfigurationValues.put("snapshot.max.monthly", "8");
          s_defaultConfigurationValues.put("snapshot.recurring.test", "false");
          s_defaultConfigurationValues.put("snapshot.test.minutes.per.hour", "60");
          s_defaultConfigurationValues.put("snapshot.test.hours.per.day", "24");
          s_defaultConfigurationValues.put("snapshot.test.days.per.week", "7");
          s_defaultConfigurationValues.put("snapshot.test.days.per.month", "30");
          s_defaultConfigurationValues.put("snapshot.test.weeks.per.month", "4");
          s_defaultConfigurationValues.put("snapshot.test.months.per.year", "12");
          s_defaultConfigurationValues.put("alert.wait", "1800");
          s_defaultConfigurationValues.put("update.wait", "600");
          s_defaultConfigurationValues.put("expunge.interval", "86400");
          s_defaultConfigurationValues.put("extract.url.cleanup.interval", "120");
          s_defaultConfigurationValues.put("instance.name", "VM");
          s_defaultConfigurationValues.put("expunge.workers", "1");
          s_defaultConfigurationValues.put("event.purge.interval", "86400");
          s_defaultConfigurationValues.put("account.cleanup.interval", "86400");
          s_defaultConfigurationValues.put("system.vm.use.local.storage", "false");
          s_defaultConfigurationValues.put("init", "false");
          s_defaultConfigurationValues.put("cpu.overprovisioning.factor", "1");
          s_defaultConfigurationValues.put("mem.overprovisioning.factor", "1");
          s_defaultConfigurationValues.put("publish.action.events", "true");
          s_defaultConfigurationValues.put("publish.alert.events", "true");
          s_defaultConfigurationValues.put("publish.resource.state.events", "true");
          s_defaultConfigurationValues.put("publish.usage.events", "true");
          s_defaultConfigurationValues.put("publish.async.job.events", "true");
      }
  
      protected DatabaseConfig() {
      }
  
      /**
       * @param args - name of server-setup.xml file which contains the bootstrap data
       */
      public static void main(String[] args) {
          System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");
          System.setProperty("javax.xml.parsers.SAXParserFactory", "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl");
  
          File file = PropertiesUtil.findConfigFile("log4j-cloud.xml");
          if (file != null) {
              System.out.println("Log4j configuration from : " + file.getAbsolutePath());
              Configurator.initialize(null, file.getAbsolutePath());
          } else {
              System.out.println("Configure log4j with default properties");
          }
  
          if (args.length < 1) {
              LOGGER.error("error starting database config, missing initial data file");
          } else {
              try {
                  DatabaseConfig config = ComponentContext.inject(DatabaseConfig.class);
                  config.doVersionCheck();
                  config.doConfig();
                  System.exit(0);
              } catch (Exception ex) {
                  System.out.print("Error Caught");
                  ex.printStackTrace();
                  LOGGER.error("error", ex);
              }
          }
      }
  
      public DatabaseConfig(String configFileName) {
          _configFileName = configFileName;
      }
  
      private void doVersionCheck() {
          try {
              String warningMsg = "\nYou are using an outdated format for server-setup.xml. Please switch to the new format.\n";
              DocumentBuilderFactory dbf = ParserUtils.getSaferDocumentBuilderFactory();
              DocumentBuilder dbuilder = dbf.newDocumentBuilder();
              File configFile = new File(_configFileName);
              Document d = dbuilder.parse(configFile);
              NodeList nodeList = d.getElementsByTagName("version");
  
              if (nodeList.getLength() == 0) {
                  System.out.println(warningMsg);
                  return;
              }
  
              Node firstNode = nodeList.item(0);
              String version = firstNode.getTextContent();
  
              if (!version.equals("2.0")) {
                  System.out.println(warningMsg);
              }
  
          } catch (ParserConfigurationException parserException) {
              parserException.printStackTrace();
          } catch (IOException ioException) {
              ioException.printStackTrace();
          } catch (SAXException saxException) {
              saxException.printStackTrace();
          }
      }
  
      @DB
      protected void doConfig() {
          try {
              final File configFile = new File(_configFileName);
  
              SAXParserFactory spfactory = SAXParserFactory.newInstance();
              final SAXParser saxParser = spfactory.newSAXParser();
              final DbConfigXMLHandler handler = new DbConfigXMLHandler();
              handler.setParent(this);
  
              Transaction.execute(new TransactionCallbackWithExceptionNoReturn<Exception>() {
                  @Override
                  public void doInTransactionWithoutResult(TransactionStatus status) throws Exception {
                      // Save user configured values for all fields
                      saxParser.parse(configFile, handler);
  
                      // Save default values for configuration fields
                      saveVMTemplate();
                      saveRootDomain();
                      saveDefaultConfiguations();
                  }
              });
  
              // Check pod CIDRs against each other, and against the guest ip network/netmask
              pzc.checkAllPodCidrSubnets();
          } catch (Exception ex) {
              System.out.print("ERROR IS" + ex);
              LOGGER.error("error", ex);
          }
      }
  
      private void setCurrentObjectName(String name) {
          _currentObjectName = name;
      }
  
      private void saveCurrentObject() {
          if ("zone".equals(_currentObjectName)) {
              saveZone();
          } else if ("physicalNetwork".equals(_currentObjectName)) {
              savePhysicalNetwork();
          } else if ("vlan".equals(_currentObjectName)) {
              saveVlan();
          } else if ("pod".equals(_currentObjectName)) {
              savePod();
          } else if ("serviceOffering".equals(_currentObjectName)) {
              saveServiceOffering();
          } else if ("diskOffering".equals(_currentObjectName)) {
              saveDiskOffering();
          } else if ("user".equals(_currentObjectName)) {
              saveUser();
          } else if ("configuration".equals(_currentObjectName)) {
              saveConfiguration();
          } else if ("storagePool".equals(_currentObjectName)) {
              saveStoragePool();
          } else if ("secondaryStorage".equals(_currentObjectName)) {
              saveSecondaryStorage();
          } else if ("cluster".equals(_currentObjectName)) {
              saveCluster();
          } else if ("physicalNetworkServiceProvider".equals(_currentObjectName)) {
              savePhysicalNetworkServiceProvider();
          } else if ("virtualRouterProvider".equals(_currentObjectName)) {
              saveVirtualRouterProvider();
          }
          _currentObjectParams = null;
      }
  
      @DB
      public void saveSecondaryStorage() {
          long dataCenterId = Long.parseLong(_currentObjectParams.get("zoneId"));
          String url = _currentObjectParams.get("url");
          String mountPoint;
          try {
              mountPoint = NfsUtils.url2Mount(url);
          } catch (URISyntaxException e1) {
              return;
          }
          String insertSql1 =
              "INSERT INTO `host` (`id`, `name`, `status` , `type` , `private_ip_address`, `private_netmask` ,`private_mac_address` , `storage_ip_address` ,`storage_netmask`, `storage_mac_address`, `data_center_id`, `version`, `dom0_memory`, `last_ping`, `resource`, `guid`, `hypervisor_type`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
          String insertSqlHostDetails = "INSERT INTO `host_details` (`id`, `host_id`, `name`, `value`) VALUES(?,?,?,?)";
          String insertSql2 = "INSERT INTO `op_host` (`id`, `sequence`) VALUES(?, ?)";
          TransactionLegacy txn = TransactionLegacy.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql1);
              stmt.setLong(1, 0);
              stmt.setString(2, url);
              stmt.setString(3, "UP");
              stmt.setString(4, "SecondaryStorage");
              stmt.setString(5, "192.168.122.1");
              stmt.setString(6, "255.255.255.0");
              stmt.setString(7, "92:ff:f5:ad:23:e1");
              stmt.setString(8, "192.168.122.1");
              stmt.setString(9, "255.255.255.0");
              stmt.setString(10, "92:ff:f5:ad:23:e1");
              stmt.setLong(11, dataCenterId);
              stmt.setString(12, "2.2.4");
              stmt.setLong(13, 0);
              stmt.setLong(14, 1238425896);
  
              boolean nfs = false;
              if (url.startsWith("nfs") || url.startsWith("cifs")) {
                  nfs = true;
              }
              if (nfs) {
                  stmt.setString(15, "com.cloud.storage.resource.NfsSecondaryStorageResource");
              } else {
                  stmt.setString(15, "com.cloud.storage.secondary.LocalSecondaryStorageResource");
              }
              stmt.setString(16, url);
              stmt.setString(17, "None");
              stmt.executeUpdate();
  
              stmt = txn.prepareAutoCloseStatement(insertSqlHostDetails);
              stmt.setLong(1, 1);
              stmt.setLong(2, 1);
              stmt.setString(3, "mount.parent");
              if (nfs) {
                  stmt.setString(4, "/mnt");
              } else {
                  stmt.setString(4, "/");
              }
              stmt.executeUpdate();
  
              stmt.setLong(1, 2);
              stmt.setLong(2, 1);
              stmt.setString(3, "mount.path");
              if (nfs) {
                  stmt.setString(4, mountPoint);
              } else {
                  stmt.setString(4, url.replaceFirst("file:/", ""));
              }
              stmt.executeUpdate();
  
              stmt.setLong(1, 3);
              stmt.setLong(2, 1);
              stmt.setString(3, "orig.url");
              stmt.setString(4, url);
              stmt.executeUpdate();
  
              stmt = txn.prepareAutoCloseStatement(insertSql2);
              stmt.setLong(1, 1);
              stmt.setLong(2, 1);
              stmt.executeUpdate();
          } catch (SQLException ex) {
              System.out.println("Error creating secondary storage: " + ex.getMessage());
              return;
          }
      }
  
      @DB
      public void saveCluster() {
          String name = _currentObjectParams.get("name");
          long id = Long.parseLong(_currentObjectParams.get("id"));
          long dataCenterId = Long.parseLong(_currentObjectParams.get("zoneId"));
          long podId = Long.parseLong(_currentObjectParams.get("podId"));
          String hypervisor = _currentObjectParams.get("hypervisorType");
          String insertSql1 =
              "INSERT INTO `cluster` (`id`, `name`, `data_center_id` , `pod_id`, `hypervisor_type` , `cluster_type`, `allocation_state`) VALUES (?,?,?,?,?,?,?)";
  
          TransactionLegacy txn = TransactionLegacy.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql1);
              stmt.setLong(1, id);
              stmt.setString(2, name);
              stmt.setLong(3, dataCenterId);
              stmt.setLong(4, podId);
              stmt.setString(5, hypervisor);
              stmt.setString(6, "CloudManaged");
              stmt.setString(7, "Enabled");
              stmt.executeUpdate();
  
          } catch (SQLException ex) {
              System.out.println("Error creating cluster: " + ex.getMessage());
              LOGGER.error("error creating cluster", ex);
              return;
          }
  
      }
  
      @DB
      public void saveStoragePool() {
          String name = _currentObjectParams.get("name");
          long id = Long.parseLong(_currentObjectParams.get("id"));
          long dataCenterId = Long.parseLong(_currentObjectParams.get("zoneId"));
          long podId = Long.parseLong(_currentObjectParams.get("podId"));
          long clusterId = Long.parseLong(_currentObjectParams.get("clusterId"));
          String hostAddress = _currentObjectParams.get("hostAddress");
          String hostPath = _currentObjectParams.get("hostPath");
          String storageType = _currentObjectParams.get("storageType");
          String uuid = UuidUtils.nameUUIDFromBytes(new String(hostAddress + hostPath).getBytes()).toString();
  
          String insertSql1 =
              "INSERT INTO `storage_pool` (`id`, `name`, `uuid` , `pool_type` , `port`, `data_center_id` ,`available_bytes` , `capacity_bytes` ,`host_address`, `path`, `created`, `pod_id`,`status` , `cluster_id`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
          // String insertSql2 = "INSERT INTO `netfs_storage_pool` VALUES (?,?,?)";
  
          TransactionLegacy txn = TransactionLegacy.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql1);
              stmt.setLong(1, id);
              stmt.setString(2, name);
              stmt.setString(3, uuid);
              if (storageType == null) {
                  stmt.setString(4, "NetworkFileSystem");
              } else {
                  stmt.setString(4, storageType);
              }
              stmt.setLong(5, 111);
              stmt.setLong(6, dataCenterId);
              stmt.setLong(7, 0);
              stmt.setLong(8, 0);
              stmt.setString(9, hostAddress);
              stmt.setString(10, hostPath);
              stmt.setDate(11, new Date(DateUtil.currentGMTTime().getTime()));
              stmt.setLong(12, podId);
              stmt.setString(13, Status.Up.toString());
              stmt.setLong(14, clusterId);
              stmt.executeUpdate();
  
          } catch (SQLException ex) {
              System.out.println("Error creating storage pool: " + ex.getMessage());
              LOGGER.error("error creating storage pool ", ex);
              return;
          }
  
      }
  
      private void saveZone() {
          long id = Long.parseLong(_currentObjectParams.get("id"));
          String name = _currentObjectParams.get("name");
          //String description = _currentObjectParams.get("description");
          String dns1 = _currentObjectParams.get("dns1");
          String dns2 = _currentObjectParams.get("dns2");
          String internalDns1 = _currentObjectParams.get("internalDns1");
          String internalDns2 = _currentObjectParams.get("internalDns2");
          //String vnetRange = _currentObjectParams.get("vnet");
          String guestNetworkCidr = _currentObjectParams.get("guestNetworkCidr");
          String networkType = _currentObjectParams.get("networktype");
  
          // Check that all IPs are valid
          String ipError = "Please enter a valid IP address for the field: ";
          if (!IPRangeConfig.validOrBlankIP(dns1)) {
              printError(ipError + "dns1");
          }
          if (!IPRangeConfig.validOrBlankIP(dns2)) {
              printError(ipError + "dns2");
          }
          if (!IPRangeConfig.validOrBlankIP(internalDns1)) {
              printError(ipError + "internalDns1");
          }
          if (!IPRangeConfig.validOrBlankIP(internalDns2)) {
              printError(ipError + "internalDns2");
          }
          if (!IPRangeConfig.validCIDR(guestNetworkCidr)) {
              printError("Please enter a valid value for guestNetworkCidr");
          }
  
          pzc.saveZone(false, id, name, dns1, dns2, internalDns1, internalDns2, guestNetworkCidr, networkType);
      }
  
      private void savePhysicalNetwork() {
          long id = Long.parseLong(_currentObjectParams.get("id"));
          String zoneId = _currentObjectParams.get("zoneId");
          String vnetRange = _currentObjectParams.get("vnet");
  
          int vnetStart = -1;
          int vnetEnd = -1;
          if (vnetRange != null) {
              String[] tokens = vnetRange.split("-");
              vnetStart = Integer.parseInt(tokens[0]);
              vnetEnd = Integer.parseInt(tokens[1]);
          }
          long zoneDbId = Long.parseLong(zoneId);
          pzc.savePhysicalNetwork(false, id, zoneDbId, vnetStart, vnetEnd);
  
      }
  
      private void savePhysicalNetworkServiceProvider() {
          long id = Long.parseLong(_currentObjectParams.get("id"));
          long physicalNetworkId = Long.parseLong(_currentObjectParams.get("physicalNetworkId"));
          String providerName = _currentObjectParams.get("providerName");
          long destPhysicalNetworkId = Long.parseLong(_currentObjectParams.get("destPhysicalNetworkId"));
          String uuid = UUID.randomUUID().toString();
  
          int vpn = Integer.parseInt(_currentObjectParams.get("vpn"));
          int dhcp = Integer.parseInt(_currentObjectParams.get("dhcp"));
          int dns = Integer.parseInt(_currentObjectParams.get("dns"));
          int gateway = Integer.parseInt(_currentObjectParams.get("gateway"));
          int firewall = Integer.parseInt(_currentObjectParams.get("firewall"));
          int sourceNat = Integer.parseInt(_currentObjectParams.get("sourceNat"));
          int lb = Integer.parseInt(_currentObjectParams.get("loadBalance"));
          int staticNat = Integer.parseInt(_currentObjectParams.get("staticNat"));
          int pf = Integer.parseInt(_currentObjectParams.get("portForwarding"));
          int userData = Integer.parseInt(_currentObjectParams.get("userData"));
          int securityGroup = Integer.parseInt(_currentObjectParams.get("securityGroup"));
  
          String insertSql1 =
              "INSERT INTO `physical_network_service_providers` (`id`, `uuid`, `physical_network_id` , `provider_name`, `state` ,"
                  + "`destination_physical_network_id`, `vpn_service_provided`, `dhcp_service_provided`, `dns_service_provided`, `gateway_service_provided`,"
                  + "`firewall_service_provided`, `source_nat_service_provided`, `load_balance_service_provided`, `static_nat_service_provided`,"
                  + "`port_forwarding_service_provided`, `user_data_service_provided`, `security_group_service_provided`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
  
          TransactionLegacy txn = TransactionLegacy.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql1);
              stmt.setLong(1, id);
              stmt.setString(2, uuid);
              stmt.setLong(3, physicalNetworkId);
              stmt.setString(4, providerName);
              stmt.setString(5, "Enabled");
              stmt.setLong(6, destPhysicalNetworkId);
              stmt.setInt(7, vpn);
              stmt.setInt(8, dhcp);
              stmt.setInt(9, dns);
              stmt.setInt(10, gateway);
              stmt.setInt(11, firewall);
              stmt.setInt(12, sourceNat);
              stmt.setInt(13, lb);
              stmt.setInt(14, staticNat);
              stmt.setInt(15, pf);
              stmt.setInt(16, userData);
              stmt.setInt(17, securityGroup);
              stmt.executeUpdate();
          } catch (SQLException ex) {
              System.out.println("Error creating physical network service provider: " + ex.getMessage());
              LOGGER.error("error creating physical network service provider", ex);
              return;
          }
  
      }
  
      private void saveVirtualRouterProvider() {
          long id = Long.parseLong(_currentObjectParams.get("id"));
          long nspId = Long.parseLong(_currentObjectParams.get("nspId"));
          String uuid = UUID.randomUUID().toString();
          String type = _currentObjectParams.get("type");
  
          String insertSql1 = "INSERT INTO `virtual_router_providers` (`id`, `nsp_id`, `uuid` , `type` , `enabled`) " + "VALUES (?,?,?,?,?)";
  
          TransactionLegacy txn = TransactionLegacy.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql1);
              stmt.setLong(1, id);
              stmt.setLong(2, nspId);
              stmt.setString(3, uuid);
              stmt.setString(4, type);
              stmt.setInt(5, 1);
              stmt.executeUpdate();
          } catch (SQLException ex) {
              System.out.println("Error creating virtual router provider: " + ex.getMessage());
              LOGGER.error("error creating virtual router provider ", ex);
              return;
          }
  
      }
  
      private void saveVlan() {
          String zoneId = _currentObjectParams.get("zoneId");
          String physicalNetworkIdStr = _currentObjectParams.get("physicalNetworkId");
          String vlanId = _currentObjectParams.get("vlanId");
          String gateway = _currentObjectParams.get("gateway");
          String netmask = _currentObjectParams.get("netmask");
          String publicIpRange = _currentObjectParams.get("ipAddressRange");
          String vlanType = _currentObjectParams.get("vlanType");
          String vlanPodName = _currentObjectParams.get("podName");
  
          String ipError = "Please enter a valid IP address for the field: ";
          if (!IPRangeConfig.validOrBlankIP(gateway)) {
              printError(ipError + "gateway");
          }
          if (!IPRangeConfig.validOrBlankIP(netmask)) {
              printError(ipError + "netmask");
          }
  
          // Check that the given IP address range was valid
          if (!checkIpAddressRange(publicIpRange)) {
              printError("Please enter a valid public IP range.");
          }
  
          // Split the IP address range
          String[] ipAddressRangeArray = publicIpRange.split("\\-");
          String startIP = ipAddressRangeArray[0];
          String endIP = null;
          if (ipAddressRangeArray.length > 1) {
              endIP = ipAddressRangeArray[1];
          }
  
          // If a netmask was provided, check that the startIP, endIP, and gateway all belong to the same subnet
          if (netmask != null && !netmask.equals("")) {
              if (endIP != null) {
                  if (!IPRangeConfig.sameSubnet(startIP, endIP, netmask)) {
                      printError("Start and end IPs for the public IP range must be in the same subnet, as per the provided netmask.");
                  }
              }
  
              if (gateway != null && !gateway.equals("")) {
                  if (!IPRangeConfig.sameSubnet(startIP, gateway, netmask)) {
                      printError("The start IP for the public IP range must be in the same subnet as the gateway, as per the provided netmask.");
                  }
                  if (endIP != null) {
                      if (!IPRangeConfig.sameSubnet(endIP, gateway, netmask)) {
                          printError("The end IP for the public IP range must be in the same subnet as the gateway, as per the provided netmask.");
                      }
                  }
              }
          }
  
          long zoneDbId = Long.parseLong(zoneId);
          String zoneName = PodZoneConfig.getZoneName(zoneDbId);
  
          long physicalNetworkId = Long.parseLong(physicalNetworkIdStr);
  
          //Set networkId to be 0, the value will be updated after management server starts up
          pzc.modifyVlan(zoneName, true, vlanId, gateway, netmask, vlanPodName, vlanType, publicIpRange, 0, physicalNetworkId);
  
          long vlanDbId = pzc.getVlanDbId(zoneName, vlanId);
          iprc.saveIPRange("public", -1, zoneDbId, vlanDbId, startIP, endIP, null, physicalNetworkId);
  
      }
  
      private void savePod() {
          long id = Long.parseLong(_currentObjectParams.get("id"));
          String name = _currentObjectParams.get("name");
          long dataCenterId = Long.parseLong(_currentObjectParams.get("zoneId"));
          String privateIpRange = _currentObjectParams.get("ipAddressRange");
          String gateway = _currentObjectParams.get("gateway");
          String cidr = _currentObjectParams.get("cidr");
          String zoneName = PodZoneConfig.getZoneName(dataCenterId);
          String startIP = null;
          String endIP = null;
          String vlanRange = _currentObjectParams.get("vnet");
  
          int vlanStart = -1;
          int vlanEnd = -1;
          if (vlanRange != null) {
              String[] tokens = vlanRange.split("-");
              vlanStart = Integer.parseInt(tokens[0]);
              vlanEnd = Integer.parseInt(tokens[1]);
          }
  
          // Get the individual cidrAddress and cidrSize values
          String[] cidrPair = cidr.split("\\/");
          String cidrAddress = cidrPair[0];
          String cidrSize = cidrPair[1];
          long cidrSizeNum = Long.parseLong(cidrSize);
  
          // Check that the gateway is in the same subnet as the CIDR
          if (!IPRangeConfig.sameSubnetCIDR(gateway, cidrAddress, cidrSizeNum)) {
              printError("For pod " + name + " in zone " + zoneName + " , please ensure that your gateway is in the same subnet as the  pod's CIDR address.");
          }
  
          pzc.savePod(false, id, name, dataCenterId, gateway, cidr, vlanStart, vlanEnd);
  
          if (privateIpRange != null) {
              // Check that the given IP address range was valid
              if (!checkIpAddressRange(privateIpRange)) {
                  printError("Please enter a valid private IP range.");
              }
  
              String[] ipAddressRangeArray = privateIpRange.split("\\-");
              startIP = ipAddressRangeArray[0];
              endIP = null;
              if (ipAddressRangeArray.length > 1) {
                  endIP = ipAddressRangeArray[1];
              }
          }
  
          // Check that the start IP and end IP match up with the CIDR
          if (!IPRangeConfig.sameSubnetCIDR(startIP, endIP, cidrSizeNum)) {
              printError("For pod " + name + " in zone " + zoneName + ", please ensure that your start IP and end IP are in the same subnet, as per the pod's CIDR size.");
          }
  
          if (!IPRangeConfig.sameSubnetCIDR(startIP, cidrAddress, cidrSizeNum)) {
              printError("For pod " + name + " in zone " + zoneName + ", please ensure that your start IP is in the same subnet as the pod's CIDR address.");
          }
  
          if (!IPRangeConfig.sameSubnetCIDR(endIP, cidrAddress, cidrSizeNum)) {
              printError("For pod " + name + " in zone " + zoneName + ", please ensure that your end IP is in the same subnet as the pod's CIDR address.");
          }
  
          if (privateIpRange != null) {
              // Save the IP address range
              iprc.saveIPRange("private", id, dataCenterId, -1, startIP, endIP, null, -1);
          }
  
      }
  
      @DB
      protected void saveServiceOffering() {
          long id = Long.parseLong(_currentObjectParams.get("id"));
          String name = _currentObjectParams.get("name");
          String displayText = _currentObjectParams.get("displayText");
          ProvisioningType provisioningType = ProvisioningType.valueOf(_currentObjectParams.get("provisioningType"));
          int cpu = Integer.parseInt(_currentObjectParams.get("cpu"));
          int ramSize = Integer.parseInt(_currentObjectParams.get("ramSize"));
          int speed = Integer.parseInt(_currentObjectParams.get("speed"));
          String useLocalStorageValue = _currentObjectParams.get("useLocalStorage");
  
  //        int nwRate = Integer.parseInt(_currentObjectParams.get("nwRate"));
  //        int mcRate = Integer.parseInt(_currentObjectParams.get("mcRate"));
          boolean ha = Boolean.parseBoolean(_currentObjectParams.get("enableHA"));
          boolean mirroring = Boolean.parseBoolean(_currentObjectParams.get("mirrored"));
  
          boolean useLocalStorage;
          if (useLocalStorageValue != null) {
              if (Boolean.parseBoolean(useLocalStorageValue)) {
                  useLocalStorage = true;
              } else {
                  useLocalStorage = false;
              }
          } else {
              useLocalStorage = false;
          }
          DiskOfferingVO diskOfferingVO = new DiskOfferingVO(name, displayText, provisioningType, false, null, false, false, true);
  
          ServiceOfferingVO serviceOffering =
              new ServiceOfferingVO(name, cpu, ramSize, speed, null, null, ha, displayText,
                      false, null, false);
  
          Long bytesReadRate = Long.parseLong(_currentObjectParams.get("bytesReadRate"));
          if ((bytesReadRate != null) && (bytesReadRate > 0))
              diskOfferingVO.setBytesReadRate(bytesReadRate);
          Long bytesWriteRate = Long.parseLong(_currentObjectParams.get("bytesWriteRate"));
          if ((bytesWriteRate != null) && (bytesWriteRate > 0))
              diskOfferingVO.setBytesWriteRate(bytesWriteRate);
          Long iopsReadRate = Long.parseLong(_currentObjectParams.get("iopsReadRate"));
          if ((iopsReadRate != null) && (iopsReadRate > 0))
              diskOfferingVO.setIopsReadRate(iopsReadRate);
          Long iopsWriteRate = Long.parseLong(_currentObjectParams.get("iopsWriteRate"));
          if ((iopsWriteRate != null) && (iopsWriteRate > 0))
              diskOfferingVO.setIopsWriteRate(iopsWriteRate);
  
          DiskOfferingDaoImpl DiskOfferinDao = ComponentContext.inject(DiskOfferingDaoImpl.class);
          try {
              DiskOfferinDao.persist(diskOfferingVO);
          } catch (Exception e) {
              LOGGER.error("error creating disk offering", e);
          }
  
          serviceOffering.setDiskOfferingId(diskOfferingVO.getId());
          ServiceOfferingDaoImpl serviceOfferingDao = ComponentContext.inject(ServiceOfferingDaoImpl.class);
          try {
              serviceOfferingDao.persist(serviceOffering);
          } catch (Exception e) {
              LOGGER.error("error creating service offering", e);
          }
          /*
          String insertSql = "INSERT INTO `cloud`.`service_offering` (id, name, cpu, ram_size, speed, nw_rate, mc_rate, created, ha_enabled, mirrored, display_text, guest_ip_type, use_local_storage) " +
                  "VALUES (" + id + ",'" + name + "'," + cpu + "," + ramSize + "," + speed + "," + nwRate + "," + mcRate + ",now()," + ha + "," + mirroring + ",'" + displayText + "','" + guestIpType + "','" + useLocalStorage + "')";
  
          Transaction txn = Transaction.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
              stmt.executeUpdate();
          } catch (SQLException ex) {
              LOGGER.error("error creating service offering", ex);
              return;
          }
           */
      }
  
      @DB
      protected void saveDiskOffering() {
          long id = Long.parseLong(_currentObjectParams.get("id"));
          String name = _currentObjectParams.get("name");
          String displayText = _currentObjectParams.get("displayText");
          ProvisioningType provisioningType = ProvisioningType.valueOf(_currentObjectParams.get("provisioningtype"));
          long diskSpace = Long.parseLong(_currentObjectParams.get("diskSpace"));
          diskSpace = diskSpace * 1024 * 1024;
  //        boolean mirroring = Boolean.parseBoolean(_currentObjectParams.get("mirrored"));
          String tags = _currentObjectParams.get("tags");
          String useLocal = _currentObjectParams.get("useLocal");
          boolean local = false;
          if (useLocal != null) {
              local = Boolean.parseBoolean(useLocal);
          }
  
          if (tags != null && tags.length() > 0) {
              String[] tokens = tags.split(",");
              StringBuilder newTags = new StringBuilder();
              for (String token : tokens) {
                  newTags.append(token.trim()).append(",");
              }
              newTags.delete(newTags.length() - 1, newTags.length());
              tags = newTags.toString();
          }
          DiskOfferingVO diskOffering = new DiskOfferingVO(name, displayText, provisioningType, diskSpace, tags, false, null, null, null);
          diskOffering.setUseLocalStorage(local);
  
          Long bytesReadRate = Long.parseLong(_currentObjectParams.get("bytesReadRate"));
          if (bytesReadRate != null && (bytesReadRate > 0))
              diskOffering.setBytesReadRate(bytesReadRate);
          Long bytesWriteRate = Long.parseLong(_currentObjectParams.get("bytesWriteRate"));
          if (bytesWriteRate != null && (bytesWriteRate > 0))
              diskOffering.setBytesWriteRate(bytesWriteRate);
          Long iopsReadRate = Long.parseLong(_currentObjectParams.get("iopsReadRate"));
          if (iopsReadRate != null && (iopsReadRate > 0))
              diskOffering.setIopsReadRate(iopsReadRate);
          Long iopsWriteRate = Long.parseLong(_currentObjectParams.get("iopsWriteRate"));
          if (iopsWriteRate != null && (iopsWriteRate > 0))
              diskOffering.setIopsWriteRate(iopsWriteRate);
  
          DiskOfferingDaoImpl offering = ComponentContext.inject(DiskOfferingDaoImpl.class);
          try {
              offering.persist(diskOffering);
          } catch (Exception e) {
              LOGGER.error("error creating disk offering", e);
  
          }
          /*
          String insertSql = "INSERT INTO `cloud`.`disk_offering` (id, domain_id, name, display_text, disk_size, mirrored, tags) " +
                  "VALUES (" + id + "," + domainId + ",'" + name + "','" + displayText + "'," + diskSpace + "," + mirroring + ", ? )";
  
          Transaction txn = Transaction.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
              stmt.setString(1, tags);
              stmt.executeUpdate();
          } catch (SQLException ex) {
              LOGGER.error("error creating disk offering", ex);
              return;
          }
           */
      }
  
      @DB
      protected void saveThrottlingRates() {
          boolean saveNetworkThrottlingRate = (_networkThrottlingRate != null);
          boolean saveMulticastThrottlingRate = (_multicastThrottlingRate != null);
  
          if (!saveNetworkThrottlingRate && !saveMulticastThrottlingRate) {
              return;
          }
  
          String insertNWRateSql = "UPDATE `cloud`.`service_offering` SET `nw_rate` = ?";
          String insertMCRateSql = "UPDATE `cloud`.`service_offering` SET `mc_rate` = ?";
  
          TransactionLegacy txn = TransactionLegacy.currentTxn();
          try {
              PreparedStatement stmt;
  
              if (saveNetworkThrottlingRate) {
                  stmt = txn.prepareAutoCloseStatement(insertNWRateSql);
                  stmt.setString(1, _networkThrottlingRate);
                  stmt.executeUpdate();
              }
  
              if (saveMulticastThrottlingRate) {
                  stmt = txn.prepareAutoCloseStatement(insertMCRateSql);
                  stmt.setString(1, _multicastThrottlingRate);
                  stmt.executeUpdate();
              }
  
          } catch (SQLException ex) {
              LOGGER.error("error saving network and multicast throttling rates to all service offerings", ex);
              return;
          }
      }
  
      // no configurable values for VM Template, hard-code the defaults for now
      private void saveVMTemplate() {
          /*
          long id = 1;
          String uniqueName = "routing";
          String name = "DomR Template";
          int isPublic = 0;
          String path = "template/private/u000000/os/routing";
          String type = "ext3";
          int requiresHvm = 0;
          int bits = 64;
          long createdByUserId = 1;
          int isReady = 1;
  
          String insertSql = "INSERT INTO `cloud`.`vm_template` (id, unique_name, name, public, path, created, type, hvm, bits, created_by, ready) " +
                  "VALUES (" + id + ",'" + uniqueName + "','" + name + "'," + isPublic + ",'" + path + "',now(),'" + type + "'," +
                  requiresHvm + "," + bits + "," + createdByUserId + "," + isReady + ")";
  
          Transaction txn = Transaction.open();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
              stmt.executeUpdate();
          } catch (SQLException ex) {
              LOGGER.error("error creating vm template: " + ex);
          } finally {
              txn.close();
          }
           */
          /*
          // do it again for console proxy template
          id = 2;
          uniqueName = "consoleproxy";
          name = "Console Proxy Template";
          isPublic = 0;
          path = "template/private/u000000/os/consoleproxy";
          type = "ext3";
  
          insertSql = "INSERT INTO `cloud`.`vm_template` (id, unique_name, name, public, path, created, type, hvm, bits, created_by, ready) " +
          "VALUES (" + id + ",'" + uniqueName + "','" + name + "'," + isPublic + ",'" + path + "',now(),'" + type + "'," +
          requiresHvm + "," + bits + "," + createdByUserId + "," + isReady + ")";
  
          Transaction txn = Transaction.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
              stmt.executeUpdate();
          } catch (SQLException ex) {
              LOGGER.error("error creating vm template: " + ex);
          } finally {
              txn.close();
          }
           */
      }
  
      @DB
      protected void saveUser() {
          // insert system account
          final String insertSystemAccount = "INSERT INTO `cloud`.`account` (id, account_name, type, domain_id) VALUES (1, 'system', '1', '1')";
          TransactionLegacy txn = TransactionLegacy.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSystemAccount);
              stmt.executeUpdate();
          } catch (SQLException ex) {
              LOGGER.error("error creating system account", ex);
          }
  
          // insert system user
          final String insertSystemUser =
              "INSERT INTO `cloud`.`user` (id, username, password, account_id, firstname, lastname, created)"
                  + " VALUES (1, 'system', RAND(), 1, 'system', 'cloud', now())";
          txn = TransactionLegacy.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSystemUser);
              stmt.executeUpdate();
          } catch (SQLException ex) {
              LOGGER.error("error creating system user", ex);
          }
  
          // insert admin user
          long id = Long.parseLong(_currentObjectParams.get("id"));
          String username = _currentObjectParams.get("username");
          String firstname = _currentObjectParams.get("firstname");
          String lastname = _currentObjectParams.get("lastname");
          String password = _currentObjectParams.get("password");
          String email = _currentObjectParams.get("email");
  
          if (email == null || email.equals("")) {
              printError("An email address for each user is required.");
          }
  
          String algorithm = "MD5";
          String pwDigest;
          try {
              pwDigest = DigestHelper.getPaddedDigest(algorithm, password);
          } catch (NoSuchAlgorithmException e) {
              LOGGER.error("error saving user", e);
              return;
          }
  
          // create an account for the admin user first
          final String insertAdminAccount = "INSERT INTO `cloud`.`account` (id, account_name, type, domain_id) VALUES (?, ?, '1', '1')";
          txn = TransactionLegacy.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(insertAdminAccount);
              stmt.setLong(1, id);
              stmt.setString(2, username);
              stmt.executeUpdate();
          } catch (SQLException ex) {
              LOGGER.error("error creating account", ex);
          }
  
          // now insert the user
          final String insertUser =
                  "INSERT INTO `cloud`.`user` (id, username, password, account_id, firstname, lastname, email, created) " + "VALUES (?,?,?, 2, ?,?,?,now())";
          txn = TransactionLegacy.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(insertUser);
              stmt.setLong(1, id);
              stmt.setString(2, username);
              stmt.setString(3, pwDigest);
              stmt.setString(4, firstname);
              stmt.setString(5, lastname);
              stmt.setString(6, email);
              stmt.executeUpdate();
          } catch (SQLException ex) {
              LOGGER.error("error creating user", ex);
          }
      }
  
      private void saveDefaultConfiguations() {
          for (String name : s_defaultConfigurationValues.keySet()) {
              String value = s_defaultConfigurationValues.get(name);
              saveConfiguration(name, value, null);
          }
      }
  
      private void saveConfiguration() {
          String name = _currentObjectParams.get("name");
          String value = _currentObjectParams.get("value");
          String category = _currentObjectParams.get("category");
          saveConfiguration(name, value, category);
      }
  
      @DB
      protected void saveConfiguration(String name, String value, String category) {
          String instance = "DEFAULT";
          String description = s_configurationDescriptions.get(name);
          String component = s_configurationComponents.get(name);
          if (category == null) {
              category = "Advanced";
          }
  
          String instanceNameError = "Please enter a non-blank value for the field: ";
          if (name.equals("instance.name")) {
              if (value == null || value.isEmpty() || !value.matches("^[A-Za-z0-9]{1,8}$")) {
                  printError(instanceNameError + "configuration: instance.name can not be empty and can only contain numbers and alphabets up to 8 characters long");
              }
          }
  
          if (name.equals("network.throttling.rate")) {
              if (value != null && !value.isEmpty()) {
                  _networkThrottlingRate = value;
              }
          }
  
          if (name.equals("multicast.throttling.rate")) {
              if (value != null && !value.isEmpty()) {
                  _multicastThrottlingRate = value;
              }
          }
  
          String insertSql =
                  "INSERT INTO `cloud`.`configuration` (instance, component, name, value, description, category) " +
                  "VALUES (?,?,?,?,?,?)";
          String selectSql = "SELECT name FROM cloud.configuration WHERE name = ?";
  
          TransactionLegacy txn = TransactionLegacy.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(selectSql);
              stmt.setString(1, name);
              ResultSet result = stmt.executeQuery();
              Boolean hasRow = result.next();
              if (!hasRow) {
                  stmt = txn.prepareAutoCloseStatement(insertSql);
                  stmt.setString(1, instance);
                  stmt.setString(2, component);
                  stmt.setString(3, name);
                  stmt.setString(4, value);
                  stmt.setString(5, description);
                  stmt.setString(6, category);
                  stmt.executeUpdate();
              }
          } catch (SQLException ex) {
              LOGGER.error("error creating configuration", ex);
          }
      }
  
      private boolean checkIpAddressRange(String ipAddressRange) {
          String[] ipAddressRangeArray = ipAddressRange.split("\\-");
          String startIP = ipAddressRangeArray[0];
          String endIP = null;
          if (ipAddressRangeArray.length > 1) {
              endIP = ipAddressRangeArray[1];
          }
  
          if (!IPRangeConfig.validIP(startIP)) {
              LOGGER.error("The private IP address: " + startIP + " is invalid.");
              return false;
          }
  
          if (!IPRangeConfig.validOrBlankIP(endIP)) {
              LOGGER.error("The private IP address: " + endIP + " is invalid.");
              return false;
          }
  
          if (!IPRangeConfig.validIPRange(startIP, endIP)) {
              LOGGER.error("The  IP range " + startIP + " -> " + endIP + " is invalid.");
              return false;
          }
  
          return true;
      }
  
      @DB
      protected void saveRootDomain() {
          String insertSql = "insert into `cloud`.`domain` (id, name, parent, owner, path, level) values (1, 'ROOT', NULL, 2, '/', 0)";
          TransactionLegacy txn = TransactionLegacy.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
              stmt.executeUpdate();
          } catch (SQLException ex) {
              LOGGER.error("error creating ROOT domain", ex);
          }
  
          /*
          String updateSql = "update account set domain_id = 1 where id = 2";
          Transaction txn = Transaction.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareStatement(updateSql);
              stmt.executeUpdate();
          } catch (SQLException ex) {
              LOGGER.error("error updating admin user", ex);
          } finally {
              txn.close();
          }
  
          updateSql = "update account set domain_id = 1 where id = 1";
          Transaction txn = Transaction.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareStatement(updateSql);
              stmt.executeUpdate();
          } catch (SQLException ex) {
              LOGGER.error("error updating system user", ex);
          } finally {
              txn.close();
          }
           */
      }
  
      class DbConfigXMLHandler extends DefaultHandler {
          private DatabaseConfig _parent = null;
  
          public void setParent(DatabaseConfig parent) {
              _parent = parent;
          }
  
          @Override
          public void endElement(String s, String s1, String s2) throws SAXException {
              if (DatabaseConfig.objectNames.contains(s2) || "object".equals(s2)) {
                  _parent.saveCurrentObject();
              } else if (DatabaseConfig.fieldNames.contains(s2) || "field".equals(s2)) {
                  _currentFieldName = null;
              }
          }
  
          @Override
          public void startElement(String s, String s1, String s2, Attributes attributes) throws SAXException {
              if ("object".equals(s2)) {
                  _parent.setCurrentObjectName(convertName(attributes.getValue("name")));
              } else if ("field".equals(s2)) {
                  if (_currentObjectParams == null) {
                      _currentObjectParams = new HashMap<String, String>();
                  }
                  _currentFieldName = convertName(attributes.getValue("name"));
              } else if (DatabaseConfig.objectNames.contains(s2)) {
                  _parent.setCurrentObjectName(s2);
              } else if (DatabaseConfig.fieldNames.contains(s2)) {
                  if (_currentObjectParams == null) {
                      _currentObjectParams = new HashMap<String, String>();
                  }
                  _currentFieldName = s2;
              }
          }
  
          @Override
          public void characters(char[] ch, int start, int length) throws SAXException {
              if ((_currentObjectParams != null) && (_currentFieldName != null)) {
                  String currentFieldVal = new String(ch, start, length);
                  _currentObjectParams.put(_currentFieldName, currentFieldVal);
              }
          }
  
          private String convertName(String name) {
              if (name.contains(".")) {
                  String[] nameArray = name.split("\\.");
                  for (int i = 1; i < nameArray.length; i++) {
                      String word = nameArray[i];
                      nameArray[i] = word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase();
                  }
                  name = "";
                  for (int i = 0; i < nameArray.length; i++) {
                      name = name.concat(nameArray[i]);
                  }
              }
              return name;
          }
      }
  
      public static List<String> genReturnList(String success, String message) {
          List<String> returnList = new ArrayList<String>(2);
          returnList.add(0, success);
          returnList.add(1, message);
          return returnList;
      }
  
      public static void printError(String message) {
          System.out.println(message);
          System.exit(1);
      }
  
      public static String getDatabaseValueString(String selectSql, String name, String errorMsg) {
          TransactionLegacy txn = TransactionLegacy.open("getDatabaseValueString");
          PreparedStatement stmt = null;
  
          try {
              stmt = txn.prepareAutoCloseStatement(selectSql);
              ResultSet rs = stmt.executeQuery();
              if (rs.next()) {
                  String value = rs.getString(name);
                  return value;
              } else {
                  return null;
              }
          } catch (SQLException e) {
              System.out.println("Exception: " + e.getMessage());
              printError(errorMsg);
          } finally {
              txn.close();
          }
          return null;
      }
  
      public static long getDatabaseValueLong(String selectSql, String name, String errorMsg) {
          TransactionLegacy txn = TransactionLegacy.open("getDatabaseValueLong");
          PreparedStatement stmt = null;
  
          try {
              stmt = txn.prepareAutoCloseStatement(selectSql);
              ResultSet rs = stmt.executeQuery();
              if (rs.next()) {
                  return rs.getLong(name);
              } else {
                  return -1;
              }
          } catch (SQLException e) {
              System.out.println("Exception: " + e.getMessage());
              printError(errorMsg);
          } finally {
              txn.close();
          }
          return -1;
      }
  
      public static void saveSQL(String sql, String errorMsg) {
          TransactionLegacy txn = TransactionLegacy.open("saveSQL");
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(sql);
              stmt.executeUpdate();
          } catch (SQLException ex) {
              System.out.println("SQL Exception: " + ex.getMessage());
              printError(errorMsg);
          } finally {
              txn.close();
          }
      }
  
  }
  