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