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.api.query.dao;
  
  import java.util.ArrayList;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Set;
  
  import javax.inject.Inject;
  
  import org.apache.cloudstack.api.response.ResourceTagResponse;
  import org.apache.cloudstack.api.response.SecurityGroupResponse;
  import org.apache.cloudstack.api.response.SecurityGroupRuleResponse;
  import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
  import org.springframework.stereotype.Component;
  
  import com.cloud.api.ApiDBUtils;
  import com.cloud.api.ApiResponseHelper;
  import com.cloud.api.query.vo.ResourceTagJoinVO;
  import com.cloud.api.query.vo.SecurityGroupJoinVO;
  import com.cloud.network.security.SecurityGroup;
  import com.cloud.network.security.SecurityGroupVMMapVO;
  import com.cloud.network.security.SecurityRule.SecurityRuleType;
  import com.cloud.network.security.dao.SecurityGroupVMMapDao;
  import com.cloud.server.ResourceTag;
  import com.cloud.user.Account;
  import com.cloud.utils.db.GenericDaoBase;
  import com.cloud.utils.db.SearchBuilder;
  import com.cloud.utils.db.SearchCriteria;
  import com.cloud.vm.UserVmVO;
  import com.cloud.vm.dao.UserVmDao;
  
  @Component
  public class SecurityGroupJoinDaoImpl extends GenericDaoBase<SecurityGroupJoinVO, Long> implements SecurityGroupJoinDao {
  
      @Inject
      private ConfigurationDao _configDao;
      @Inject
      private ResourceTagJoinDao _resourceTagJoinDao;
      @Inject
      private SecurityGroupVMMapDao _securityGroupVMMapDao;
      @Inject
      private UserVmDao _userVmDao;
  
      private final SearchBuilder<SecurityGroupJoinVO> sgSearch;
  
      private final SearchBuilder<SecurityGroupJoinVO> sgIdSearch;
  
      protected SecurityGroupJoinDaoImpl() {
  
          sgSearch = createSearchBuilder();
          sgSearch.and("idIN", sgSearch.entity().getId(), SearchCriteria.Op.IN);
          sgSearch.done();
  
          sgIdSearch = createSearchBuilder();
          sgIdSearch.and("id", sgIdSearch.entity().getId(), SearchCriteria.Op.EQ);
          sgIdSearch.done();
  
          this._count = "select count(distinct id) from security_group_view WHERE ";
      }
  
      @Override
      public SecurityGroupResponse newSecurityGroupResponse(SecurityGroupJoinVO vsg, Account caller) {
          SecurityGroupResponse sgResponse = new SecurityGroupResponse();
          sgResponse.setId(vsg.getUuid());
          sgResponse.setName(vsg.getName());
          sgResponse.setDescription(vsg.getDescription());
  
          ApiResponseHelper.populateOwner(sgResponse, vsg);
  
          Long rule_id = vsg.getRuleId();
          if (rule_id != null && rule_id.longValue() > 0) {
              SecurityGroupRuleResponse ruleData = new SecurityGroupRuleResponse();
              ruleData.setRuleId(vsg.getRuleUuid());
              ruleData.setProtocol(vsg.getRuleProtocol());
  
              if ("icmp".equalsIgnoreCase(vsg.getRuleProtocol())) {
                  ruleData.setIcmpType(vsg.getRuleStartPort());
                  ruleData.setIcmpCode(vsg.getRuleEndPort());
              } else {
                  ruleData.setStartPort(vsg.getRuleStartPort());
                  ruleData.setEndPort(vsg.getRuleEndPort());
              }
  
              if (vsg.getRuleAllowedNetworkId() != null) {
                  List<SecurityGroupJoinVO> sgs = this.searchByIds(vsg.getRuleAllowedNetworkId());
                  if (sgs != null && sgs.size() > 0) {
                      SecurityGroupJoinVO sg = sgs.get(0);
                      ruleData.setSecurityGroupName(sg.getName());
                      ruleData.setAccountName(sg.getAccountName());
                  }
              } else {
                  ruleData.setCidr(vsg.getRuleAllowedSourceIpCidr());
              }
  
              // list the tags by rule uuid
              List<ResourceTagJoinVO> tags = _resourceTagJoinDao.listBy(vsg.getRuleUuid(), ResourceTag.ResourceObjectType.SecurityGroupRule);
              Set<ResourceTagResponse> tagResponse = new HashSet<ResourceTagResponse>();
              for (ResourceTagJoinVO tag: tags) {
                  tagResponse.add(ApiDBUtils.newResourceTagResponse(tag, false));
              }
  
              // add the tags to the rule data
              ruleData.setTags(tagResponse);
  
              if (vsg.getRuleType() == SecurityRuleType.IngressRule) {
                  ruleData.setObjectName("ingressrule");
                  sgResponse.addSecurityGroupIngressRule(ruleData);
              } else {
                  ruleData.setObjectName("egressrule");
                  sgResponse.addSecurityGroupEgressRule(ruleData);
              }
          }
  
          List<SecurityGroupVMMapVO> securityGroupVmMap = _securityGroupVMMapDao.listBySecurityGroup(vsg.getId());
          logger.debug("newSecurityGroupResponse() -> virtualmachine count: " + securityGroupVmMap.size());
          sgResponse.setVirtualMachineCount(securityGroupVmMap.size());
  
          for(SecurityGroupVMMapVO securityGroupVMMapVO : securityGroupVmMap) {
              final UserVmVO userVmVO = _userVmDao.findById(securityGroupVMMapVO.getInstanceId());
              if (userVmVO != null) {
                  sgResponse.addVirtualMachineId(userVmVO.getUuid());
              }
          }
  
          // update tag information
          Long tag_id = vsg.getTagId();
          if (tag_id != null && tag_id.longValue() > 0) {
              ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id);
              if (vtag != null) {
                  sgResponse.addTag(ApiDBUtils.newResourceTagResponse(vtag, false));
              }
          }
  
          // set async job
          if (vsg.getJobId() != null) {
              sgResponse.setJobId(vsg.getJobUuid());
              sgResponse.setJobStatus(vsg.getJobStatus());
          }
  
          sgResponse.setObjectName("securitygroup");
  
          return sgResponse;
      }
  
      @Override
      public SecurityGroupResponse setSecurityGroupResponse(SecurityGroupResponse vsgData, SecurityGroupJoinVO vsg) {
          Long rule_id = vsg.getRuleId();
          if (rule_id != null && rule_id.longValue() > 0) {
              SecurityGroupRuleResponse ruleData = new SecurityGroupRuleResponse();
              ruleData.setRuleId(vsg.getRuleUuid());
              ruleData.setProtocol(vsg.getRuleProtocol());
  
              if ("icmp".equalsIgnoreCase(vsg.getRuleProtocol())) {
                  ruleData.setIcmpType(vsg.getRuleStartPort());
                  ruleData.setIcmpCode(vsg.getRuleEndPort());
              } else {
                  ruleData.setStartPort(vsg.getRuleStartPort());
                  ruleData.setEndPort(vsg.getRuleEndPort());
              }
  
              if (vsg.getRuleAllowedNetworkId() != null) {
                  List<SecurityGroupJoinVO> sgs = this.searchByIds(vsg.getRuleAllowedNetworkId());
                  if (sgs != null && sgs.size() > 0) {
                      SecurityGroupJoinVO sg = sgs.get(0);
                      ruleData.setSecurityGroupName(sg.getName());
                      ruleData.setAccountName(sg.getAccountName());
                  }
              } else {
                  ruleData.setCidr(vsg.getRuleAllowedSourceIpCidr());
              }
  
              // add the tags to the rule data
              List<ResourceTagJoinVO> tags = _resourceTagJoinDao.listBy(vsg.getRuleUuid(), ResourceTag.ResourceObjectType.SecurityGroupRule);
              Set<ResourceTagResponse> tagResponse = new HashSet<ResourceTagResponse>();
              for (ResourceTagJoinVO tag: tags) {
                  tagResponse.add(ApiDBUtils.newResourceTagResponse(tag, false));
              }
  
              // add the tags to the rule data
              ruleData.setTags(tagResponse);
  
              if (vsg.getRuleType() == SecurityRuleType.IngressRule) {
                  ruleData.setObjectName("ingressrule");
                  vsgData.addSecurityGroupIngressRule(ruleData);
              } else {
                  ruleData.setObjectName("egressrule");
                  vsgData.addSecurityGroupEgressRule(ruleData);
              }
          }
  
          // update tag information
          Long tag_id = vsg.getTagId();
          if (tag_id != null && tag_id.longValue() > 0) {
              ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id);
              if (vtag != null) {
                  vsgData.addTag(ApiDBUtils.newResourceTagResponse(vtag, false));
              }
          }
          return vsgData;
      }
  
      @Override
      public List<SecurityGroupJoinVO> newSecurityGroupView(SecurityGroup sg) {
  
          SearchCriteria<SecurityGroupJoinVO> sc = sgIdSearch.create();
          sc.setParameters("id", sg.getId());
          return searchIncludingRemoved(sc, null, null, false);
      }
  
      @Override
      public List<SecurityGroupJoinVO> searchByIds(Long... sgIds) {
          // set detail batch query size
          int DETAILS_BATCH_SIZE = 2000;
          String batchCfg = _configDao.getValue("detail.batch.query.size");
          if (batchCfg != null) {
              DETAILS_BATCH_SIZE = Integer.parseInt(batchCfg);
          }
          // query details by batches
          List<SecurityGroupJoinVO> uvList = new ArrayList<SecurityGroupJoinVO>();
          // query details by batches
          int curr_index = 0;
          if (sgIds.length > DETAILS_BATCH_SIZE) {
              while ((curr_index + DETAILS_BATCH_SIZE) <= sgIds.length) {
                  Long[] ids = new Long[DETAILS_BATCH_SIZE];
                  for (int k = 0, j = curr_index; j < curr_index + DETAILS_BATCH_SIZE; j++, k++) {
                      ids[k] = sgIds[j];
                  }
                  SearchCriteria<SecurityGroupJoinVO> sc = sgSearch.create();
                  sc.setParameters("idIN", ids);
                  List<SecurityGroupJoinVO> vms = searchIncludingRemoved(sc, null, null, false);
                  if (vms != null) {
                      uvList.addAll(vms);
                  }
                  curr_index += DETAILS_BATCH_SIZE;
              }
          }
          if (curr_index < sgIds.length) {
              int batch_size = (sgIds.length - curr_index);
              // set the ids value
              Long[] ids = new Long[batch_size];
              for (int k = 0, j = curr_index; j < curr_index + batch_size; j++, k++) {
                  ids[k] = sgIds[j];
              }
              SearchCriteria<SecurityGroupJoinVO> sc = sgSearch.create();
              sc.setParameters("idIN", ids);
              List<SecurityGroupJoinVO> vms = searchIncludingRemoved(sc, null, null, false);
              if (vms != null) {
                  uvList.addAll(vms);
              }
          }
          return uvList;
      }
  }
  