@Override
  public Pair<List<? extends VpnUser>, Integer> searchForVpnUsers(ListVpnUsersCmd cmd) {
    String username = cmd.getUsername();
    Long id = cmd.getId();
    Account caller = CallContext.current().getCallingAccount();
    List<Long> permittedAccounts = new ArrayList<Long>();

    Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject =
        new Ternary<Long, Boolean, ListProjectResourcesCriteria>(
            cmd.getDomainId(), cmd.isRecursive(), null);
    _accountMgr.buildACLSearchParameters(
        caller,
        id,
        cmd.getAccountName(),
        cmd.getProjectId(),
        permittedAccounts,
        domainIdRecursiveListProject,
        cmd.listAll(),
        false);
    Long domainId = domainIdRecursiveListProject.first();
    Boolean isRecursive = domainIdRecursiveListProject.second();
    ListProjectResourcesCriteria listProjectResourcesCriteria =
        domainIdRecursiveListProject.third();
    Filter searchFilter =
        new Filter(VpnUserVO.class, "username", true, cmd.getStartIndex(), cmd.getPageSizeVal());
    SearchBuilder<VpnUserVO> sb = _vpnUsersDao.createSearchBuilder();
    _accountMgr.buildACLSearchBuilder(
        sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);

    sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
    sb.and("username", sb.entity().getUsername(), SearchCriteria.Op.EQ);
    sb.and("state", sb.entity().getState(), Op.IN);

    SearchCriteria<VpnUserVO> sc = sb.create();
    _accountMgr.buildACLSearchCriteria(
        sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);

    // list only active users
    sc.setParameters("state", State.Active, State.Add);

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

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

    Pair<List<VpnUserVO>, Integer> result = _vpnUsersDao.searchAndCount(sc, searchFilter);
    return new Pair<List<? extends VpnUser>, Integer>(result.first(), result.second());
  }
  @Override
  public Pair<List<? extends RemoteAccessVpn>, Integer> searchForRemoteAccessVpns(
      ListRemoteAccessVpnsCmd cmd) {
    // do some parameter validation
    Account caller = CallContext.current().getCallingAccount();
    Long ipAddressId = cmd.getPublicIpId();
    List<Long> permittedAccounts = new ArrayList<Long>();

    Long vpnId = cmd.getId();
    Long networkId = cmd.getNetworkId();

    if (ipAddressId != null) {
      PublicIpAddress publicIp = _networkMgr.getPublicIpAddress(ipAddressId);
      if (publicIp == null) {
        throw new InvalidParameterValueException(
            "Unable to list remote access vpns, IP address " + ipAddressId + " not found.");
      } else {
        Long ipAddrAcctId = publicIp.getAccountId();
        if (ipAddrAcctId == null) {
          throw new InvalidParameterValueException(
              "Unable to list remote access vpns, IP address "
                  + ipAddressId
                  + " is not associated with an account.");
        }
      }
      _accountMgr.checkAccess(caller, null, true, publicIp);
    }

    Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject =
        new Ternary<Long, Boolean, ListProjectResourcesCriteria>(
            cmd.getDomainId(), cmd.isRecursive(), null);
    _accountMgr.buildACLSearchParameters(
        caller,
        null,
        cmd.getAccountName(),
        cmd.getProjectId(),
        permittedAccounts,
        domainIdRecursiveListProject,
        cmd.listAll(),
        false);
    Long domainId = domainIdRecursiveListProject.first();
    Boolean isRecursive = domainIdRecursiveListProject.second();
    ListProjectResourcesCriteria listProjectResourcesCriteria =
        domainIdRecursiveListProject.third();

    Filter filter =
        new Filter(
            RemoteAccessVpnVO.class,
            "serverAddressId",
            false,
            cmd.getStartIndex(),
            cmd.getPageSizeVal());
    SearchBuilder<RemoteAccessVpnVO> sb = _remoteAccessVpnDao.createSearchBuilder();
    _accountMgr.buildACLSearchBuilder(
        sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);

    sb.and("serverAddressId", sb.entity().getServerAddressId(), Op.EQ);
    sb.and("id", sb.entity().getId(), Op.EQ);
    sb.and("networkId", sb.entity().getNetworkId(), Op.EQ);
    sb.and("state", sb.entity().getState(), Op.EQ);
    sb.and("display", sb.entity().isDisplay(), Op.EQ);

    SearchCriteria<RemoteAccessVpnVO> sc = sb.create();
    _accountMgr.buildACLSearchCriteria(
        sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);

    sc.setParameters("state", RemoteAccessVpn.State.Running);

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

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

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

    Pair<List<RemoteAccessVpnVO>, Integer> result = _remoteAccessVpnDao.searchAndCount(sc, filter);
    return new Pair<List<? extends RemoteAccessVpn>, Integer>(result.first(), result.second());
  }
  @Override
  public Pair<List<? extends FirewallRule>, Integer> listFirewallRules(ListFirewallRulesCmd cmd) {
    Long ipId = cmd.getIpAddressId();
    Long id = cmd.getId();
    Long networkId = null;
    Map<String, String> tags = cmd.getTags();
    FirewallRule.TrafficType trafficType = cmd.getTrafficType();

    Account caller = CallContext.current().getCallingAccount();
    List<Long> permittedAccounts = new ArrayList<Long>();

    if (ipId != null) {
      IPAddressVO ipAddressVO = _ipAddressDao.findById(ipId);
      if (ipAddressVO == null || !ipAddressVO.readyToUse()) {
        throw new InvalidParameterValueException(
            "Ip address id=" + ipId + " not ready for firewall rules yet");
      }
      _accountMgr.checkAccess(caller, null, true, ipAddressVO);
    }

    Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject =
        new Ternary<Long, Boolean, ListProjectResourcesCriteria>(
            cmd.getDomainId(), cmd.isRecursive(), null);
    _accountMgr.buildACLSearchParameters(
        caller,
        id,
        cmd.getAccountName(),
        cmd.getProjectId(),
        permittedAccounts,
        domainIdRecursiveListProject,
        cmd.listAll(),
        false);
    Long domainId = domainIdRecursiveListProject.first();
    Boolean isRecursive = domainIdRecursiveListProject.second();
    ListProjectResourcesCriteria listProjectResourcesCriteria =
        domainIdRecursiveListProject.third();

    Filter filter =
        new Filter(FirewallRuleVO.class, "id", false, cmd.getStartIndex(), cmd.getPageSizeVal());
    SearchBuilder<FirewallRuleVO> sb = _firewallDao.createSearchBuilder();
    _accountMgr.buildACLSearchBuilder(
        sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);

    sb.and("id", sb.entity().getId(), Op.EQ);
    sb.and("trafficType", sb.entity().getTrafficType(), Op.EQ);
    if (cmd instanceof ListEgressFirewallRulesCmd) {
      networkId = ((ListEgressFirewallRulesCmd) cmd).getNetworkId();
      sb.and("networkId", sb.entity().getNetworkId(), Op.EQ);
    } else {
      sb.and("ip", sb.entity().getSourceIpAddressId(), Op.EQ);
    }
    sb.and("purpose", sb.entity().getPurpose(), Op.EQ);

    if (tags != null && !tags.isEmpty()) {
      SearchBuilder<ResourceTagVO> tagSearch = _resourceTagDao.createSearchBuilder();
      for (int count = 0; count < tags.size(); count++) {
        tagSearch
            .or()
            .op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ);
        tagSearch.and(
            "value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ);
        tagSearch.cp();
      }
      tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ);
      sb.groupBy(sb.entity().getId());
      sb.join(
          "tagSearch",
          tagSearch,
          sb.entity().getId(),
          tagSearch.entity().getResourceId(),
          JoinBuilder.JoinType.INNER);
    }

    SearchCriteria<FirewallRuleVO> sc = sb.create();
    _accountMgr.buildACLSearchCriteria(
        sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);

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

    if (tags != null && !tags.isEmpty()) {
      int count = 0;
      sc.setJoinParameters("tagSearch", "resourceType", TaggedResourceType.FirewallRule.toString());
      for (String key : tags.keySet()) {
        sc.setJoinParameters("tagSearch", "key" + String.valueOf(count), key);
        sc.setJoinParameters("tagSearch", "value" + String.valueOf(count), tags.get(key));
        count++;
      }
    }

    if (ipId != null) {
      sc.setParameters("ip", ipId);
    } else if (cmd instanceof ListEgressFirewallRulesCmd) {
      if (networkId != null) {
        sc.setParameters("networkId", networkId);
      }
    }

    sc.setParameters("purpose", Purpose.Firewall);
    sc.setParameters("trafficType", trafficType);

    Pair<List<FirewallRuleVO>, Integer> result = _firewallDao.searchAndCount(sc, filter);
    return new Pair<List<? extends FirewallRule>, Integer>(result.first(), result.second());
  }