Coverage Report - com.ctrip.framework.apollo.internals.ConfigServiceLocator
 
Classes in this File Line Coverage Branch Coverage Complexity
ConfigServiceLocator
89%
59/66
58%
7/12
2.2
ConfigServiceLocator$1
100%
1/1
N/A
2.2
ConfigServiceLocator$2
100%
5/5
N/A
2.2
 
 1  
 package com.ctrip.framework.apollo.internals;
 2  
 
 3  
 import com.google.common.base.Joiner;
 4  
 import com.google.common.base.Strings;
 5  
 import com.google.common.collect.Lists;
 6  
 import com.google.common.collect.Maps;
 7  
 import com.google.common.escape.Escaper;
 8  
 import com.google.common.net.UrlEscapers;
 9  
 import com.google.gson.reflect.TypeToken;
 10  
 
 11  
 import com.ctrip.framework.apollo.core.dto.ServiceDTO;
 12  
 import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory;
 13  
 import com.ctrip.framework.apollo.exceptions.ApolloConfigException;
 14  
 import com.ctrip.framework.apollo.util.ConfigUtil;
 15  
 import com.ctrip.framework.apollo.util.http.HttpRequest;
 16  
 import com.ctrip.framework.apollo.util.http.HttpResponse;
 17  
 import com.ctrip.framework.apollo.util.http.HttpUtil;
 18  
 import com.dianping.cat.Cat;
 19  
 import com.dianping.cat.message.Message;
 20  
 import com.dianping.cat.message.Transaction;
 21  
 
 22  
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
 23  
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
 24  
 import org.slf4j.Logger;
 25  
 import org.slf4j.LoggerFactory;
 26  
 import org.unidal.lookup.annotation.Inject;
 27  
 import org.unidal.lookup.annotation.Named;
 28  
 
 29  
 import java.lang.reflect.Type;
 30  
 import java.util.List;
 31  
 import java.util.Map;
 32  
 import java.util.concurrent.Executors;
 33  
 import java.util.concurrent.ScheduledExecutorService;
 34  
 import java.util.concurrent.TimeUnit;
 35  
 import java.util.concurrent.atomic.AtomicReference;
 36  
 
 37  
 @Named(type = ConfigServiceLocator.class)
 38  48
 public class ConfigServiceLocator implements Initializable {
 39  1
   private static final Logger logger = LoggerFactory.getLogger(ConfigServiceLocator.class);
 40  
   @Inject
 41  
   private HttpUtil m_httpUtil;
 42  
   @Inject
 43  
   private ConfigUtil m_configUtil;
 44  
   private AtomicReference<List<ServiceDTO>> m_configServices;
 45  
   private Type m_responseType;
 46  
   private ScheduledExecutorService m_executorService;
 47  1
   private static final Joiner.MapJoiner MAP_JOINER = Joiner.on("&").withKeyValueSeparator("=");
 48  1
   private static final Escaper queryParamEscaper = UrlEscapers.urlFormParameterEscaper();
 49  
 
 50  
   /**
 51  
    * Create a config service locator.
 52  
    */
 53  14
   public ConfigServiceLocator() {
 54  14
     List<ServiceDTO> initial = Lists.newArrayList();
 55  14
     m_configServices = new AtomicReference<>(initial);
 56  14
     m_responseType = new TypeToken<List<ServiceDTO>>() {
 57  14
     }.getType();
 58  28
     this.m_executorService = Executors.newScheduledThreadPool(1,
 59  14
         ApolloThreadFactory.create("ConfigServiceLocator", true));
 60  14
   }
 61  
 
 62  
   @Override
 63  
   public void initialize() throws InitializationException {
 64  8
     this.tryUpdateConfigServices();
 65  8
     this.schedulePeriodicRefresh();
 66  8
   }
 67  
 
 68  
   /**
 69  
    * Get the config service info from remote meta server.
 70  
    *
 71  
    * @return the services dto
 72  
    */
 73  
   public List<ServiceDTO> getConfigServices() {
 74  56
     if (m_configServices.get().isEmpty()) {
 75  0
       updateConfigServices();
 76  
     }
 77  
 
 78  56
     return m_configServices.get();
 79  
   }
 80  
 
 81  
   private boolean tryUpdateConfigServices() {
 82  
     try {
 83  32
       updateConfigServices();
 84  31
       return true;
 85  0
     } catch (Throwable ex) {
 86  
       //ignore
 87  
     }
 88  0
     return false;
 89  
   }
 90  
 
 91  
   private void schedulePeriodicRefresh() {
 92  16
     this.m_executorService.scheduleAtFixedRate(
 93  8
         new Runnable() {
 94  
           @Override
 95  
           public void run() {
 96  24
             logger.debug("refresh config services");
 97  24
             Cat.logEvent("Apollo.MetaService", "periodicRefresh");
 98  24
             tryUpdateConfigServices();
 99  23
           }
 100  8
         }, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(),
 101  8
         m_configUtil.getRefreshIntervalTimeUnit());
 102  8
   }
 103  
 
 104  
   private synchronized void updateConfigServices() {
 105  32
     String url = assembleMetaServiceUrl();
 106  
 
 107  32
     HttpRequest request = new HttpRequest(url);
 108  32
     int maxRetries = 5;
 109  32
     Throwable exception = null;
 110  
 
 111  33
     for (int i = 0; i < maxRetries; i++) {
 112  33
       Transaction transaction = Cat.newTransaction("Apollo.MetaService", "getConfigService");
 113  33
       transaction.addData("Url", url);
 114  
       try {
 115  33
         HttpResponse<List<ServiceDTO>> response = m_httpUtil.doGet(request, m_responseType);
 116  31
         transaction.setStatus(Message.SUCCESS);
 117  31
         List<ServiceDTO> services = response.getBody();
 118  31
         if (services == null || services.isEmpty()) {
 119  0
           logConfigServiceToCat("Empty response!");
 120  
           continue;
 121  
         }
 122  31
         m_configServices.set(services);
 123  31
         logConfigServicesToCat(services);
 124  31
         return;
 125  2
       } catch (Throwable ex) {
 126  2
         Cat.logError(ex);
 127  2
         transaction.setStatus(ex);
 128  2
         exception = ex;
 129  
       } finally {
 130  33
         transaction.complete();
 131  2
       }
 132  
 
 133  
       try {
 134  2
         TimeUnit.SECONDS.sleep(1);
 135  0
       } catch (InterruptedException ex) {
 136  
         //ignore
 137  1
       }
 138  
     }
 139  
 
 140  0
     throw new ApolloConfigException(
 141  0
         String.format("Get config services failed from %s", url), exception);
 142  
   }
 143  
 
 144  
   private String assembleMetaServiceUrl() {
 145  32
     String domainName = m_configUtil.getMetaServerDomainName();
 146  32
     String appId = m_configUtil.getAppId();
 147  32
     String localIp = m_configUtil.getLocalIp();
 148  
 
 149  32
     Map<String, String> queryParams = Maps.newHashMap();
 150  32
     queryParams.put("appId", queryParamEscaper.escape(appId));
 151  32
     if (!Strings.isNullOrEmpty(localIp)) {
 152  32
       queryParams.put("ip", queryParamEscaper.escape(localIp));
 153  
     }
 154  
 
 155  32
     return domainName + "/services/config?" + MAP_JOINER.join(queryParams);
 156  
   }
 157  
 
 158  
   private void logConfigServicesToCat(List<ServiceDTO> serviceDtos) {
 159  31
     for (ServiceDTO serviceDto : serviceDtos) {
 160  31
       logConfigServiceToCat(serviceDto.getHomepageUrl());
 161  31
     }
 162  31
   }
 163  
 
 164  
   private void logConfigServiceToCat(String serviceUrl) {
 165  31
     Cat.logEvent("Apollo.Config.Services", serviceUrl);
 166  31
   }
 167  
 }