content: package com.ctrip.framework.apollo.adminservice.controller;
  
  import com.google.common.base.Splitter;
  import com.google.common.base.Strings;
  import com.google.common.collect.HashMultimap;
  import com.google.common.collect.Maps;
  import com.google.common.collect.Multimap;
  import com.google.common.collect.Sets;
  
  import com.ctrip.framework.apollo.biz.entity.Instance;
  import com.ctrip.framework.apollo.biz.entity.InstanceConfig;
  import com.ctrip.framework.apollo.biz.entity.Release;
  import com.ctrip.framework.apollo.biz.service.InstanceService;
  import com.ctrip.framework.apollo.biz.service.ReleaseService;
  import com.ctrip.framework.apollo.common.dto.InstanceConfigDTO;
  import com.ctrip.framework.apollo.common.dto.InstanceDTO;
  import com.ctrip.framework.apollo.common.dto.PageDTO;
  import com.ctrip.framework.apollo.common.dto.ReleaseDTO;
  import com.ctrip.framework.apollo.common.exception.NotFoundException;
  import com.ctrip.framework.apollo.common.utils.BeanUtils;
  
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.data.domain.Page;
  import org.springframework.data.domain.PageRequest;
  import org.springframework.data.domain.Pageable;
  import org.springframework.util.CollectionUtils;
  import org.springframework.web.bind.annotation.RequestMapping;
  import org.springframework.web.bind.annotation.RequestMethod;
  import org.springframework.web.bind.annotation.RequestParam;
  import org.springframework.web.bind.annotation.RestController;
  
  import java.util.Collection;
  import java.util.Collections;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.stream.Collectors;
  
  /**
   * @author Jason Song(song_s@ctrip.com)
   */
  @RestController
  @RequestMapping("/instances")
  public class InstanceConfigController {
    private static final Splitter RELEASES_SPLITTER = Splitter.on(",").omitEmptyStrings()
        .trimResults();
    @Autowired
    private ReleaseService releaseService;
    @Autowired
    private InstanceService instanceService;
  
    @RequestMapping(value = "/by-release", method = RequestMethod.GET)
    public PageDTO<InstanceDTO> getByRelease(@RequestParam("releaseId") long releaseId,
                                             Pageable pageable) {
      Release release = releaseService.findOne(releaseId);
      if (release == null) {
        throw new NotFoundException(String.format("release not found for %s", releaseId));
      }
      Page<InstanceConfig> instanceConfigsPage = instanceService.findActiveInstanceConfigsByReleaseKey
          (release.getReleaseKey(), pageable);
  
      List<InstanceDTO> instanceDTOs = Collections.emptyList();
  
      if (instanceConfigsPage.hasContent()) {
        Multimap<Long, InstanceConfig> instanceConfigMap = HashMultimap.create();
        Set<String> otherReleaseKeys = Sets.newHashSet();
  
        for (InstanceConfig instanceConfig : instanceConfigsPage.getContent()) {
          instanceConfigMap.put(instanceConfig.getInstanceId(), instanceConfig);
          otherReleaseKeys.add(instanceConfig.getReleaseKey());
        }
  
        Set<Long> instanceIds = instanceConfigMap.keySet();
  
        List<Instance> instances = instanceService.findInstancesByIds(instanceIds);
  
        if (!CollectionUtils.isEmpty(instances)) {
          instanceDTOs = BeanUtils.batchTransform(InstanceDTO.class, instances);
        }
  
        for (InstanceDTO instanceDTO : instanceDTOs) {
          Collection<InstanceConfig> configs = instanceConfigMap.get(instanceDTO.getId());
          List<InstanceConfigDTO> configDTOs = configs.stream().map(instanceConfig -> {
            InstanceConfigDTO instanceConfigDTO = new InstanceConfigDTO();
            //to save some space
            instanceConfigDTO.setRelease(null);
            instanceConfigDTO.setReleaseDeliveryTime(instanceConfig.getReleaseDeliveryTime());
            instanceConfigDTO.setDataChangeLastModifiedTime(instanceConfig
                .getDataChangeLastModifiedTime());
            return instanceConfigDTO;
          }).collect(Collectors.toList());
          instanceDTO.setConfigs(configDTOs);
        }
      }
  
      return new PageDTO<>(instanceDTOs, pageable, instanceConfigsPage.getTotalElements());
    }
  
    @RequestMapping(value = "/by-namespace-and-releases-not-in", method = RequestMethod.GET)
    public List<InstanceDTO> getByReleasesNotIn(@RequestParam("appId") String appId,
                                                @RequestParam("clusterName") String clusterName,
                                                @RequestParam("namespaceName") String namespaceName,
                                                @RequestParam("releaseIds") String releaseIds) {
      Set<Long> releaseIdSet = RELEASES_SPLITTER.splitToList(releaseIds).stream().map(Long::parseLong)
          .collect(Collectors.toSet());
  
      List<Release> releases = releaseService.findByReleaseIds(releaseIdSet);
  
      if (CollectionUtils.isEmpty(releases)) {
        throw new NotFoundException(String.format("releases not found for %s", releaseIds));
      }
  
      Set<String> releaseKeys = releases.stream().map(Release::getReleaseKey).collect(Collectors
          .toSet());
  
      List<InstanceConfig> instanceConfigs = instanceService
          .findInstanceConfigsByNamespaceWithReleaseKeysNotIn(appId, clusterName, namespaceName,
              releaseKeys);
  
      Multimap<Long, InstanceConfig> instanceConfigMap = HashMultimap.create();
      Set<String> otherReleaseKeys = Sets.newHashSet();
  
      for (InstanceConfig instanceConfig : instanceConfigs) {
        instanceConfigMap.put(instanceConfig.getInstanceId(), instanceConfig);
        otherReleaseKeys.add(instanceConfig.getReleaseKey());
      }
  
      List<Instance> instances = instanceService.findInstancesByIds(instanceConfigMap.keySet());
  
      if (CollectionUtils.isEmpty(instances)) {
        return Collections.emptyList();
      }
  
      List<InstanceDTO> instanceDTOs = BeanUtils.batchTransform(InstanceDTO.class, instances);
  
      List<Release> otherReleases = releaseService.findByReleaseKeys(otherReleaseKeys);
      Map<String, ReleaseDTO> releaseMap = Maps.newHashMap();
  
      for (Release release : otherReleases) {
        //unset configurations to save space
        release.setConfigurations(null);
        ReleaseDTO releaseDTO = BeanUtils.transfrom(ReleaseDTO.class, release);
        releaseMap.put(release.getReleaseKey(), releaseDTO);
      }
  
      for (InstanceDTO instanceDTO : instanceDTOs) {
        Collection<InstanceConfig> configs = instanceConfigMap.get(instanceDTO.getId());
        List<InstanceConfigDTO> configDTOs = configs.stream().map(instanceConfig -> {
          InstanceConfigDTO instanceConfigDTO = new InstanceConfigDTO();
          instanceConfigDTO.setRelease(releaseMap.get(instanceConfig.getReleaseKey()));
          instanceConfigDTO.setReleaseDeliveryTime(instanceConfig.getReleaseDeliveryTime());
          instanceConfigDTO.setDataChangeLastModifiedTime(instanceConfig
              .getDataChangeLastModifiedTime());
          return instanceConfigDTO;
        }).collect(Collectors.toList());
        instanceDTO.setConfigs(configDTOs);
      }
  
      return instanceDTOs;
    }
  
    @RequestMapping(value = "/by-namespace", method = RequestMethod.GET)
    public PageDTO<InstanceDTO> getInstancesByNamespace(
        @RequestParam("appId") String appId, @RequestParam("clusterName") String clusterName,
        @RequestParam("namespaceName") String namespaceName,
        @RequestParam(value = "instanceAppId", required = false) String instanceAppId,
        Pageable pageable) {
      Page<Instance> instances;
      if (Strings.isNullOrEmpty(instanceAppId)) {
        instances = instanceService.findInstancesByNamespace(appId, clusterName,
            namespaceName, pageable);
      } else {
        instances = instanceService.findInstancesByNamespaceAndInstanceAppId(instanceAppId, appId,
            clusterName, namespaceName, pageable);
      }
  
      List<InstanceDTO> instanceDTOs = BeanUtils.batchTransform(InstanceDTO.class, instances.getContent());
      return new PageDTO<>(instanceDTOs, pageable, instances.getTotalElements());
    }
  
    @RequestMapping(value = "/by-namespace/count", method = RequestMethod.GET)
    public long getInstancesCountByNamespace(@RequestParam("appId") String appId,
                                            @RequestParam("clusterName") String clusterName,
                                            @RequestParam("namespaceName") String namespaceName) {
      Page<Instance> instances = instanceService.findInstancesByNamespace(appId, clusterName,
          namespaceName, new PageRequest(0, 1));
      return instances.getTotalElements();
    }
  }
  