content: package com.ctrip.framework.apollo.biz.service;
  
  import com.google.common.base.Preconditions;
  import com.google.common.collect.Lists;
  
  import com.ctrip.framework.apollo.biz.entity.Instance;
  import com.ctrip.framework.apollo.biz.entity.InstanceConfig;
  import com.ctrip.framework.apollo.biz.repository.InstanceConfigRepository;
  import com.ctrip.framework.apollo.biz.repository.InstanceRepository;
  
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.data.domain.Page;
  import org.springframework.data.domain.PageImpl;
  import org.springframework.data.domain.Pageable;
  import org.springframework.stereotype.Service;
  import org.springframework.transaction.annotation.Transactional;
  import org.springframework.util.CollectionUtils;
  
  import java.math.BigInteger;
  import java.util.Calendar;
  import java.util.Collections;
  import java.util.Date;
  import java.util.List;
  import java.util.Set;
  import java.util.stream.Collectors;
  
  /**
   * @author Jason Song(song_s@ctrip.com)
   */
  @Service
  public class InstanceService {
    @Autowired
    private InstanceRepository instanceRepository;
  
    @Autowired
    private InstanceConfigRepository instanceConfigRepository;
  
    public Instance findInstance(String appId, String clusterName, String dataCenter, String ip) {
      return instanceRepository.findByAppIdAndClusterNameAndDataCenterAndIp(appId, clusterName,
          dataCenter, ip);
    }
  
    public List<Instance> findInstancesByIds(Set<Long> instanceIds) {
      Iterable<Instance> instances = instanceRepository.findAll(instanceIds);
      if (instances == null) {
        return Collections.emptyList();
      }
      return Lists.newArrayList(instances);
    }
  
    @Transactional
    public Instance createInstance(Instance instance) {
      instance.setId(0); //protection
  
      return instanceRepository.save(instance);
    }
  
    public InstanceConfig findInstanceConfig(long instanceId, String configAppId, String
        configNamespaceName) {
      return instanceConfigRepository
          .findByInstanceIdAndConfigAppIdAndConfigNamespaceName(
              instanceId, configAppId, configNamespaceName);
    }
  
    public Page<InstanceConfig> findActiveInstanceConfigsByReleaseKey(String releaseKey, Pageable
        pageable) {
      Page<InstanceConfig> instanceConfigs = instanceConfigRepository
          .findByReleaseKeyAndDataChangeLastModifiedTimeAfter(releaseKey,
              getValidInstanceConfigDate(), pageable);
      return instanceConfigs;
    }
  
    public Page<Instance> findInstancesByNamespace(String appId, String clusterName, String
        namespaceName, Pageable pageable) {
      Page<InstanceConfig> instanceConfigs = instanceConfigRepository.
          findByConfigAppIdAndConfigClusterNameAndConfigNamespaceNameAndDataChangeLastModifiedTimeAfter(appId, clusterName,
              namespaceName, getValidInstanceConfigDate(), pageable);
  
      List<Instance> instances = Collections.emptyList();
      if (instanceConfigs.hasContent()) {
        Set<Long> instanceIds = instanceConfigs.getContent().stream().map
            (InstanceConfig::getInstanceId).collect(Collectors.toSet());
        instances = findInstancesByIds(instanceIds);
      }
  
      return new PageImpl<>(instances, pageable, instanceConfigs.getTotalElements());
    }
  
    public Page<Instance> findInstancesByNamespaceAndInstanceAppId(String instanceAppId, String
        appId, String clusterName, String
                                                                       namespaceName, Pageable
                                                                       pageable) {
      Page<Object[]> instanceIdResult = instanceConfigRepository
          .findInstanceIdsByNamespaceAndInstanceAppId(instanceAppId, appId, clusterName,
              namespaceName, getValidInstanceConfigDate(), pageable);
  
      List<Instance> instances = Collections.emptyList();
      if (instanceIdResult.hasContent()) {
        Set<Long> instanceIds = instanceIdResult.getContent().stream().map((Object o) -> {
          if (o == null) {
            return null;
          }
  
          if (o instanceof Integer) {
            return ((Integer)o).longValue();
          }
  
          if (o instanceof Long) {
            return (Long) o;
          }
  
          //for h2 test
          if (o instanceof BigInteger) {
            return ((BigInteger) o).longValue();
          }
  
          return null;
        }).filter((Long value) -> value != null).collect(Collectors.toSet());
        instances = findInstancesByIds(instanceIds);
      }
  
      return new PageImpl<>(instances, pageable, instanceIdResult.getTotalElements());
    }
  
    public List<InstanceConfig> findInstanceConfigsByNamespaceWithReleaseKeysNotIn(String appId,
                                                                                   String clusterName,
                                                                                   String
                                                                                       namespaceName,
                                                                                   Set<String>
                                                                                       releaseKeysNotIn) {
      List<InstanceConfig> instanceConfigs = instanceConfigRepository.
          findByConfigAppIdAndConfigClusterNameAndConfigNamespaceNameAndDataChangeLastModifiedTimeAfterAndReleaseKeyNotIn(appId, clusterName,
              namespaceName, getValidInstanceConfigDate(), releaseKeysNotIn);
  
      if (CollectionUtils.isEmpty(instanceConfigs)) {
        return Collections.emptyList();
      }
  
      return instanceConfigs;
    }
  
    /**
     * Currently the instance config is expired by 1 day, add one more hour to avoid possible time
     * difference
     */
    private Date getValidInstanceConfigDate() {
      Calendar cal = Calendar.getInstance();
      cal.add(Calendar.DATE, -1);
      cal.add(Calendar.HOUR, -1);
      return cal.getTime();
    }
  
    @Transactional
    public InstanceConfig createInstanceConfig(InstanceConfig instanceConfig) {
      instanceConfig.setId(0); //protection
  
      return instanceConfigRepository.save(instanceConfig);
    }
  
    @Transactional
    public InstanceConfig updateInstanceConfig(InstanceConfig instanceConfig) {
      InstanceConfig existedInstanceConfig = instanceConfigRepository.findOne(instanceConfig.getId());
      Preconditions.checkArgument(existedInstanceConfig != null, String.format(
          "Instance config %d doesn't exist", instanceConfig.getId()));
  
      existedInstanceConfig.setConfigClusterName(instanceConfig.getConfigClusterName());
      existedInstanceConfig.setReleaseKey(instanceConfig.getReleaseKey());
      existedInstanceConfig.setReleaseDeliveryTime(instanceConfig.getReleaseDeliveryTime());
      existedInstanceConfig.setDataChangeLastModifiedTime(instanceConfig
          .getDataChangeLastModifiedTime());
  
      return instanceConfigRepository.save(existedInstanceConfig);
    }
  
    @Transactional
    public int batchDeleteInstanceConfig(String configAppId, String configClusterName, String configNamespaceName){
      return instanceConfigRepository.batchDelete(configAppId, configClusterName, configNamespaceName);
    }
  }
  