Coverage Report - com.ctrip.framework.apollo.portal.service.ServiceLocator
 
Classes in this File Line Coverage Branch Coverage Complexity
ServiceLocator
71%
27/38
31%
5/16
3.8
 
 1  
 package com.ctrip.framework.apollo.portal.service;
 2  
 
 3  
 import java.net.URI;
 4  
 import java.util.Map;
 5  
 import java.util.concurrent.ConcurrentHashMap;
 6  
 import java.util.concurrent.atomic.AtomicInteger;
 7  
 
 8  
 import javax.annotation.PostConstruct;
 9  
 
 10  
 import org.slf4j.Logger;
 11  
 import org.slf4j.LoggerFactory;
 12  
 import org.springframework.beans.factory.annotation.Autowired;
 13  
 import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
 14  
 import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
 15  
 import org.springframework.http.client.SimpleClientHttpRequestFactory;
 16  
 import org.springframework.stereotype.Service;
 17  
 import org.springframework.web.client.RestTemplate;
 18  
 
 19  
 import com.ctrip.framework.apollo.core.MetaDomainConsts;
 20  
 import com.ctrip.framework.apollo.core.dto.ServiceDTO;
 21  
 import com.ctrip.framework.apollo.core.enums.Env;
 22  
 import com.ctrip.framework.apollo.core.exception.ServiceException;
 23  
 
 24  
 /**
 25  
  * @author liuym
 26  
  */
 27  
 @Service
 28  1
 public class ServiceLocator {
 29  
 
 30  1
   private static final Logger logger = LoggerFactory.getLogger(ServiceLocator.class);
 31  
 
 32  
   private static final int DEFAULT_TIMEOUT_MS = 1000;
 33  
 
 34  
   private static final int RETRY_TIMES = 3;
 35  
 
 36  
   private static final int CALL_META_SERVER_THRESHOLD = 2;
 37  
 
 38  
   private static final String ADMIN_SERVICE_URL_PATH = "/services/admin";
 39  
 
 40  
   private RestTemplate restTemplate;
 41  
 
 42  
   @Autowired
 43  
   private HttpMessageConverters httpMessageConverters;
 44  
 
 45  1
   private Map<Env, ServiceDTO[]> serviceAddressCache = new ConcurrentHashMap<>();
 46  
 
 47  1
   private final AtomicInteger adminCallCounts = new AtomicInteger(0);
 48  
 
 49  
   @PostConstruct
 50  
   private void postConstruct() {
 51  1
     restTemplate = new RestTemplate(httpMessageConverters.getConverters());
 52  1
     if (restTemplate.getRequestFactory() instanceof SimpleClientHttpRequestFactory) {
 53  1
       SimpleClientHttpRequestFactory rf =
 54  1
           (SimpleClientHttpRequestFactory) restTemplate.getRequestFactory();
 55  1
       rf.setReadTimeout(DEFAULT_TIMEOUT_MS);
 56  1
       rf.setConnectTimeout(DEFAULT_TIMEOUT_MS);
 57  1
     } else if (restTemplate.getRequestFactory() instanceof HttpComponentsClientHttpRequestFactory) {
 58  0
       HttpComponentsClientHttpRequestFactory rf =
 59  0
           (HttpComponentsClientHttpRequestFactory) restTemplate.getRequestFactory();
 60  0
       rf.setReadTimeout(DEFAULT_TIMEOUT_MS);
 61  0
       rf.setConnectTimeout(DEFAULT_TIMEOUT_MS);
 62  
     }
 63  1
   }
 64  
 
 65  
 
 66  
   public ServiceDTO getServiceAddress(Env env) throws ServiceException {
 67  
 
 68  12
     if (adminCallCounts.get() % CALL_META_SERVER_THRESHOLD == 0) {
 69  12
       return getServiceAddressFromMetaServer(env);
 70  
     } else {
 71  
       //if cached then return from cache
 72  0
       ServiceDTO[] serviceDTOs = serviceAddressCache.get(env);
 73  0
       if (serviceDTOs != null && serviceDTOs.length > 0){
 74  0
         return randomServiceAddress(serviceDTOs);
 75  
       }else {//return from meta server
 76  0
         return getServiceAddressFromMetaServer(env);
 77  
       }
 78  
     }
 79  
 
 80  
 
 81  
   }
 82  
 
 83  
   public ServiceDTO getServiceAddressFromMetaServer(Env env) {
 84  
     //retry
 85  48
     for (int i = 0; i < RETRY_TIMES; i++) {
 86  36
       ServiceDTO[] services = getServices(env);
 87  36
       if (services != null && services.length > 0) {
 88  0
         serviceAddressCache.put(env, services);
 89  0
         return randomServiceAddress(services);
 90  
       } else {
 91  36
         logger.warn(String.format("can not get %s admin service address at %d time", env, i));
 92  
       }
 93  
     }
 94  
     //clear cache
 95  12
     serviceAddressCache.remove(env);
 96  12
     logger.error(String.format("can not get %s admin service address", env));
 97  12
     throw new ServiceException("No available admin service");
 98  
   }
 99  
 
 100  
 
 101  
   private ServiceDTO[] getServices(Env env) {
 102  36
     String domainName = MetaDomainConsts.getDomain(env);
 103  36
     String url = domainName + ADMIN_SERVICE_URL_PATH;
 104  
 
 105  
     try {
 106  36
       return restTemplate.getForObject(new URI(url), ServiceDTO[].class);
 107  36
     } catch (Exception ex) {
 108  36
       logger.warn(ex.getMessage());
 109  36
       return null;
 110  
     }
 111  
   }
 112  
 
 113  
   private ServiceDTO randomServiceAddress(ServiceDTO[] services){
 114  0
     return services[Math.abs(adminCallCounts.getAndIncrement()) % services.length];
 115  
   }
 116  
 
 117  
 }