@Override
  public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
    Map<String, String> configs = _configDao.getConfiguration(params);

    _userLimit = NumbersUtil.parseInt(configs.get(Config.RemoteAccessVpnUserLimit.key()), 8);

    _clientIpRange = configs.get(Config.RemoteAccessVpnClientIpRange.key());

    _pskLength = NumbersUtil.parseInt(configs.get(Config.RemoteAccessVpnPskLength.key()), 24);

    validateRemoteAccessVpnConfiguration();

    VpnSearch = _remoteAccessVpnDao.createSearchBuilder();
    VpnSearch.and("accountId", VpnSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
    SearchBuilder<DomainVO> domainSearch = _domainDao.createSearchBuilder();
    domainSearch.and("path", domainSearch.entity().getPath(), SearchCriteria.Op.LIKE);
    VpnSearch.join(
        "domainSearch",
        domainSearch,
        VpnSearch.entity().getDomainId(),
        domainSearch.entity().getId(),
        JoinBuilder.JoinType.INNER);
    VpnSearch.done();

    return true;
  }
  private Long accountAndUserValidation(
      Account account, Long userId, UserVmVO vmInstanceCheck, VMTemplateVO template, String msg)
      throws PermissionDeniedException {

    if (account != null) {
      if (!isAdmin(account.getType())) {
        if ((vmInstanceCheck != null) && (account.getId() != vmInstanceCheck.getAccountId())) {
          throw new PermissionDeniedException(msg + ". Permission denied.");
        }

        if ((template != null)
            && (!template.isPublicTemplate()
                && (account.getId() != template.getAccountId())
                && (template.getTemplateType() != TemplateType.PERHOST))) {
          throw new PermissionDeniedException(msg + ". Permission denied.");
        }

      } else {
        if ((vmInstanceCheck != null)
            && !_domainDao.isChildDomain(account.getDomainId(), vmInstanceCheck.getDomainId())) {
          throw new PermissionDeniedException(msg + ". Permission denied.");
        }
        // FIXME: if template/ISO owner is null we probably need to
        // throw some kind of exception

        if (template != null) {
          Account templateOwner = _accountDao.findById(template.getAccountId());
          if ((templateOwner != null)
              && !_domainDao.isChildDomain(account.getDomainId(), templateOwner.getDomainId())) {
            throw new PermissionDeniedException(msg + ". Permission denied.");
          }
        }
      }
    }
    // If command is executed via 8096 port, set userId to the id of System
    // account (1)
    if (userId == null) {
      userId = new Long(1);
    }

    return userId;
  }
  @Override
  public List<SecurityGroupRulesVO> searchForSecurityGroupRules(ListSecurityGroupsCmd cmd)
      throws PermissionDeniedException, InvalidParameterValueException {
    Account caller = UserContext.current().getCaller();
    Long domainId = cmd.getDomainId();
    String accountName = cmd.getAccountName();
    Long instanceId = cmd.getVirtualMachineId();
    String securityGroup = cmd.getSecurityGroupName();
    Long id = cmd.getId();
    Long accountId = null;

    if (instanceId != null) {
      UserVmVO userVM = _userVMDao.findById(instanceId);
      if (userVM == null) {
        throw new InvalidParameterValueException(
            "Unable to list network groups for virtual machine instance "
                + instanceId
                + "; instance not found.");
      }
      _accountMgr.checkAccess(caller, null, userVM);
      return listSecurityGroupRulesByVM(instanceId.longValue());
    }

    if (_accountMgr.isAdmin(caller.getType())) {
      if (domainId != null) {
        Domain domain = _domainMgr.getDomain(domainId);
        if (domain == null) {
          throw new InvalidParameterValueException("Unable to find domain by id " + domainId);
        }
        _accountMgr.checkAccess(caller, domain);
        if (accountName != null) {
          Account account = _accountMgr.getActiveAccountByName(accountName, domainId);
          if (account == null) {
            throw new InvalidParameterValueException(
                "Unable to find account " + accountName + " in domain " + domainId);
          }
          _accountMgr.checkAccess(caller, null, account);
          accountId = account.getId();
        }
      }
    } else {
      // regular user can see only his own security groups
      accountId = caller.getId();
    }

    List<SecurityGroupRulesVO> securityRulesList = new ArrayList<SecurityGroupRulesVO>();
    Filter searchFilter =
        new Filter(SecurityGroupVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal());
    Object keyword = cmd.getKeyword();

    SearchBuilder<SecurityGroupVO> sb = _securityGroupDao.createSearchBuilder();
    sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
    sb.and("accountId", sb.entity().getAccountId(), SearchCriteria.Op.EQ);
    sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ);
    sb.and("domainId", sb.entity().getDomainId(), SearchCriteria.Op.EQ);

    // only do a recursive domain search if the search is not limited by account or instance
    if ((accountId == null)
        && (instanceId == null)
        && (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN)) {
      SearchBuilder<DomainVO> domainSearch = _domainDao.createSearchBuilder();
      domainSearch.and("path", domainSearch.entity().getPath(), SearchCriteria.Op.LIKE);
      sb.join(
          "domainSearch",
          domainSearch,
          sb.entity().getDomainId(),
          domainSearch.entity().getId(),
          JoinBuilder.JoinType.INNER);
    }

    SearchCriteria<SecurityGroupVO> sc = sb.create();

    if (id != null) {
      sc.setParameters("id", id);
    }

    if (securityGroup != null) {
      sc.setParameters("name", securityGroup);
    }

    if (accountId != null) {
      sc.setParameters("accountId", accountId);
    }

    // only do a recursive domain search if the search is not limited by account or instance
    if ((accountId == null)
        && (instanceId == null)
        && (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN)) {
      DomainVO domain = _domainDao.findById(caller.getDomainId());
      sc.setJoinParameters("domainSearch", "path", domain.getPath() + "%");
    }

    if (keyword != null) {
      SearchCriteria<SecurityGroupRulesVO> ssc = _securityGroupRulesDao.createSearchCriteria();
      ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
      ssc.addOr("description", SearchCriteria.Op.LIKE, "%" + keyword + "%");
      sc.addAnd("name", SearchCriteria.Op.SC, ssc);
    }

    List<SecurityGroupVO> securityGroups = _securityGroupDao.search(sc, searchFilter);
    for (SecurityGroupVO group : securityGroups) {
      securityRulesList.addAll(_securityGroupRulesDao.listSecurityRulesByGroupId(group.getId()));
    }

    return securityRulesList;
  }
  @Override
  public Set<Pair<Long, Long>> searchTemplates(
      String name,
      String keyword,
      TemplateFilter templateFilter,
      boolean isIso,
      List<HypervisorType> hypers,
      Boolean bootable,
      DomainVO domain,
      Long pageSize,
      Long startIndex,
      Long zoneId,
      HypervisorType hyperType,
      boolean onlyReady,
      boolean showDomr,
      List<Account> permittedAccounts,
      Account caller,
      ListProjectResourcesCriteria listProjectResourcesCriteria) {
    StringBuilder builder = new StringBuilder();
    if (!permittedAccounts.isEmpty()) {
      for (Account permittedAccount : permittedAccounts) {
        builder.append(permittedAccount.getAccountId() + ",");
      }
    }

    String permittedAccountsStr = builder.toString();

    if (permittedAccountsStr.length() > 0) {
      // chop the "," off
      permittedAccountsStr = permittedAccountsStr.substring(0, permittedAccountsStr.length() - 1);
    }

    Transaction txn = Transaction.currentTxn();
    txn.start();

    /* Use LinkedHashSet here to guarantee iteration order */
    Set<Pair<Long, Long>> templateZonePairList = new LinkedHashSet<Pair<Long, Long>>();
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    StringBuilder relatedDomainIds = new StringBuilder();
    String sql = SELECT_TEMPLATE_ZONE_REF;
    String groupByClause = "";
    try {
      // short accountType;
      // String accountId = null;
      String guestOSJoin = "";
      StringBuilder templateHostRefJoin = new StringBuilder();
      String dataCenterJoin = "";

      if (isIso && !hyperType.equals(HypervisorType.None)) {
        guestOSJoin =
            " INNER JOIN guest_os guestOS on (guestOS.id = t.guest_os_id) INNER JOIN guest_os_hypervisor goh on ( goh.guest_os_id = guestOS.id) ";
      }
      if (onlyReady) {
        templateHostRefJoin.append(
            " INNER JOIN  template_host_ref thr on (t.id = thr.template_id) INNER JOIN host h on (thr.host_id = h.id)");
        sql = SELECT_TEMPLATE_HOST_REF;
        groupByClause = " GROUP BY t.id, h.data_center_id ";
      }
      if ((templateFilter == TemplateFilter.featured)
          || (templateFilter == TemplateFilter.community)) {
        dataCenterJoin = " INNER JOIN data_center dc on (h.data_center_id = dc.id)";
      }

      sql += guestOSJoin + templateHostRefJoin + dataCenterJoin;
      String whereClause = "";

      // All joins have to be made before we start setting the condition settings
      if ((listProjectResourcesCriteria == ListProjectResourcesCriteria.SkipProjectResources
              || (!permittedAccounts.isEmpty()
                  && !(templateFilter == TemplateFilter.community
                      || templateFilter == TemplateFilter.featured)))
          && !(caller.getType() != Account.ACCOUNT_TYPE_NORMAL
              && templateFilter == TemplateFilter.all)) {
        whereClause += " INNER JOIN account a on (t.account_id = a.id)";
        if ((templateFilter == TemplateFilter.self
                || templateFilter == TemplateFilter.selfexecutable)
            && (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN
                || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN)) {
          whereClause +=
              " INNER JOIN domain d on (a.domain_id = d.id) WHERE d.path LIKE '"
                  + domain.getPath()
                  + "%'";
          if (listProjectResourcesCriteria == ListProjectResourcesCriteria.SkipProjectResources) {
            whereClause += " AND a.type != " + Account.ACCOUNT_TYPE_PROJECT;
          }
        } else if (listProjectResourcesCriteria
            == ListProjectResourcesCriteria.SkipProjectResources) {
          whereClause += " WHERE a.type != " + Account.ACCOUNT_TYPE_PROJECT;
        }
      }

      if (!permittedAccounts.isEmpty()) {
        for (Account account : permittedAccounts) {
          // accountType = account.getType();
          // accountId = Long.toString(account.getId());
          DomainVO accountDomain = _domainDao.findById(account.getDomainId());

          // get all parent domain ID's all the way till root domain
          DomainVO domainTreeNode = accountDomain;
          while (true) {
            relatedDomainIds.append(domainTreeNode.getId());
            relatedDomainIds.append(",");
            if (domainTreeNode.getParent() != null) {
              domainTreeNode = _domainDao.findById(domainTreeNode.getParent());
            } else {
              break;
            }
          }

          // get all child domain ID's
          if (isAdmin(account.getType())) {
            List<DomainVO> allChildDomains =
                _domainDao.findAllChildren(accountDomain.getPath(), accountDomain.getId());
            for (DomainVO childDomain : allChildDomains) {
              relatedDomainIds.append(childDomain.getId());
              relatedDomainIds.append(",");
            }
          }
          relatedDomainIds.setLength(relatedDomainIds.length() - 1);
        }
      }

      String attr = " AND ";
      if (whereClause.endsWith(" WHERE ")) {
        attr += " WHERE ";
      }

      if (!isIso) {
        if (hypers.isEmpty()) {
          return templateZonePairList;
        } else {
          StringBuilder relatedHypers = new StringBuilder();
          for (HypervisorType hyper : hypers) {
            relatedHypers.append("'");
            relatedHypers.append(hyper.toString());
            relatedHypers.append("'");
            relatedHypers.append(",");
          }
          relatedHypers.setLength(relatedHypers.length() - 1);
          whereClause += attr + " t.hypervisor_type IN (" + relatedHypers + ")";
        }
      }

      if (!permittedAccounts.isEmpty()
          && !(templateFilter == TemplateFilter.featured
              || templateFilter == TemplateFilter.community)
          && !isAdmin(caller.getType())) {
        whereClause += attr + "t.account_id IN (" + permittedAccountsStr + ")";
      }

      if (templateFilter == TemplateFilter.featured) {
        whereClause += attr + "t.public = 1 AND t.featured = 1";
        if (!permittedAccounts.isEmpty()) {
          whereClause +=
              attr + "(dc.domain_id IN (" + relatedDomainIds + ") OR dc.domain_id is NULL)";
        }
      } else if (templateFilter == TemplateFilter.self
          || templateFilter == TemplateFilter.selfexecutable) {
        whereClause += " AND t.account_id IN (" + permittedAccountsStr + ")";
      } else if (templateFilter == TemplateFilter.sharedexecutable) {
        whereClause +=
            " LEFT JOIN launch_permission lp ON t.id = lp.template_id WHERE"
                + " (t.account_id IN ("
                + permittedAccountsStr
                + ") OR"
                + " lp.account_id IN ("
                + permittedAccountsStr
                + "))";
      } else if (templateFilter == TemplateFilter.executable && !permittedAccounts.isEmpty()) {
        whereClause += attr + "(t.public = 1 OR t.account_id IN (" + permittedAccountsStr + "))";
      } else if (templateFilter == TemplateFilter.community) {
        whereClause += attr + "t.public = 1 AND t.featured = 0";
        if (!permittedAccounts.isEmpty()) {
          whereClause +=
              attr + "(dc.domain_id IN (" + relatedDomainIds + ") OR dc.domain_id is NULL)";
        }
      } else if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && !isIso) {
        return templateZonePairList;
      }

      if (whereClause.equals("")) {
        whereClause += " WHERE ";
      } else if (!whereClause.equals(" WHERE ")) {
        whereClause += " AND ";
      }

      sql +=
          whereClause
              + getExtrasWhere(
                  templateFilter,
                  name,
                  keyword,
                  isIso,
                  bootable,
                  hyperType,
                  zoneId,
                  onlyReady,
                  showDomr)
              + groupByClause
              + getOrderByLimit(pageSize, startIndex);

      pstmt = txn.prepareStatement(sql);
      rs = pstmt.executeQuery();
      while (rs.next()) {
        Pair<Long, Long> templateZonePair = new Pair<Long, Long>(rs.getLong(1), rs.getLong(2));
        templateZonePairList.add(templateZonePair);
      }

      // for now, defaulting pageSize to a large val if null; may need to revisit post 2.2RC2
      if (isIso
          && templateZonePairList.size() < (pageSize != null ? pageSize : 500)
          && templateFilter != TemplateFilter.community
          && !(templateFilter == TemplateFilter.self
              && !BaseCmd.isRootAdmin(
                  caller.getType()))) { // evaluates to true If root admin and filter=self
        List<VMTemplateVO> publicIsos = publicIsoSearch(bootable, false);
        for (int i = 0; i < publicIsos.size(); i++) {
          if (keyword != null && publicIsos.get(i).getName().contains(keyword)) {
            templateZonePairList.add(new Pair<Long, Long>(publicIsos.get(i).getId(), null));
            continue;
          } else if (name != null && publicIsos.get(i).getName().contains(name)) {
            templateZonePairList.add(new Pair<Long, Long>(publicIsos.get(i).getId(), null));
            continue;
          } else if (keyword == null && name == null) {
            templateZonePairList.add(new Pair<Long, Long>(publicIsos.get(i).getId(), null));
          }
        }
      }
    } catch (Exception e) {
      s_logger.warn("Error listing templates", e);
    } finally {
      try {
        if (rs != null) {
          rs.close();
        }
        if (pstmt != null) {
          pstmt.close();
        }
        txn.commit();
      } catch (SQLException sqle) {
        s_logger.warn("Error in cleaning up", sqle);
      }
    }

    return templateZonePairList;
  }
  @Override
  public List<LoadBalancerVO> searchForLoadBalancers(ListLoadBalancerRulesCmd cmd) {
    Account caller = UserContext.current().getCaller();
    Long ipId = cmd.getPublicIpId();
    Long zoneId = cmd.getZoneId();
    String path = null;

    Pair<String, Long> accountDomainPair =
        _accountMgr.finalizeAccountDomainForList(caller, cmd.getAccountName(), cmd.getDomainId());
    String accountName = accountDomainPair.first();
    Long domainId = accountDomainPair.second();

    if (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN
        || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) {
      Domain domain = _domainMgr.getDomain(caller.getDomainId());
      path = domain.getPath();
    }

    Filter searchFilter =
        new Filter(LoadBalancerVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal());

    Object id = cmd.getId();
    Object name = cmd.getLoadBalancerRuleName();
    Object keyword = cmd.getKeyword();
    Object instanceId = cmd.getVirtualMachineId();

    SearchBuilder<LoadBalancerVO> sb = _lbDao.createSearchBuilder();
    sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
    sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE);
    sb.and("sourceIpAddress", sb.entity().getSourceIpAddressId(), SearchCriteria.Op.EQ);
    sb.and("accountId", sb.entity().getAccountId(), SearchCriteria.Op.EQ);
    sb.and("domainId", sb.entity().getDomainId(), SearchCriteria.Op.EQ);

    if (instanceId != null) {
      SearchBuilder<LoadBalancerVMMapVO> lbVMSearch = _lb2VmMapDao.createSearchBuilder();
      lbVMSearch.and("instanceId", lbVMSearch.entity().getInstanceId(), SearchCriteria.Op.EQ);
      sb.join(
          "lbVMSearch",
          lbVMSearch,
          sb.entity().getId(),
          lbVMSearch.entity().getLoadBalancerId(),
          JoinBuilder.JoinType.INNER);
    }

    if (path != null) {
      // for domain admin we should show only subdomains information
      SearchBuilder<DomainVO> domainSearch = _domainDao.createSearchBuilder();
      domainSearch.and("path", domainSearch.entity().getPath(), SearchCriteria.Op.LIKE);
      sb.join(
          "domainSearch",
          domainSearch,
          sb.entity().getDomainId(),
          domainSearch.entity().getId(),
          JoinBuilder.JoinType.INNER);
    }

    if (zoneId != null) {
      SearchBuilder<IPAddressVO> ipSearch = _ipAddressDao.createSearchBuilder();
      ipSearch.and("zoneId", ipSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ);
      sb.join(
          "ipSearch",
          ipSearch,
          sb.entity().getSourceIpAddressId(),
          ipSearch.entity().getId(),
          JoinBuilder.JoinType.INNER);
    }

    SearchCriteria<LoadBalancerVO> sc = sb.create();
    if (keyword != null) {
      SearchCriteria<LoadBalancerVO> ssc = _lbDao.createSearchCriteria();
      ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
      ssc.addOr("description", SearchCriteria.Op.LIKE, "%" + keyword + "%");

      sc.addAnd("name", SearchCriteria.Op.SC, ssc);
    }

    if (name != null) {
      sc.setParameters("name", "%" + name + "%");
    }

    if (id != null) {
      sc.setParameters("id", id);
    }

    if (ipId != null) {
      sc.setParameters("sourceIpAddress", ipId);
    }

    if (instanceId != null) {
      sc.setJoinParameters("lbVMSearch", "instanceId", instanceId);
    }

    if (domainId != null) {
      sc.setParameters("domainId", domainId);
      if (accountName != null) {
        Account account = _accountMgr.getActiveAccountByName(accountName, domainId);
        sc.setParameters("accountId", account.getId());
      }
    }

    if (path != null) {
      sc.setJoinParameters("domainSearch", "path", path + "%");
    }

    if (zoneId != null) {
      sc.setJoinParameters("ipSearch", "zoneId", zoneId);
    }

    return _lbDao.search(sc, searchFilter);
  }