Commit 18bd2a73 by Yiming Liu

Merge pull request #74 from nobodyiam/client-refactor-dependency

Use HttpURLConnection and gson to remove Spring and Jackson dependencies
parents 76528a11 f5d513fb
package com.ctrip.apollo.biz.service;
import java.io.IOException;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.ctrip.apollo.biz.entity.Release;
import com.ctrip.apollo.biz.repository.ReleaseRepository;
import com.ctrip.apollo.core.dto.ApolloConfig;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.lang.reflect.Type;
import java.util.Map;
/**
* Config Service
......@@ -24,10 +25,9 @@ public class ConfigService {
@Autowired
private ReleaseRepository releaseRepository;
private ObjectMapper objectMapper = new ObjectMapper();
private Gson gson = new Gson();
private TypeReference<Map<String, String>> configurationTypeReference =
new TypeReference<Map<String, String>>() {};
private Type configurationTypeReference = new TypeToken<Map<String, String>>(){}.getType();
public Release findRelease(String appId, String clusterName, String namespaceName) {
Release release = releaseRepository.findLatest(appId, clusterName, namespaceName);
......@@ -49,8 +49,8 @@ public class ConfigService {
Map<String, String> transformConfigurationToMap(String configurations) {
try {
return objectMapper.readValue(configurations, configurationTypeReference);
} catch (IOException e) {
return gson.fromJson(configurations, configurationTypeReference);
} catch (Throwable e) {
e.printStackTrace();
return Maps.newHashMap();
}
......
package com.ctrip.apollo.biz.service;
import com.google.common.collect.Maps;
import com.ctrip.apollo.biz.entity.Release;
import com.ctrip.apollo.biz.repository.ReleaseRepository;
import com.ctrip.apollo.biz.service.ConfigService;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Before;
import org.junit.Test;
......@@ -14,16 +12,10 @@ import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import java.io.IOException;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.anyObject;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* @author Jason Song(song_s@ctrip.com)
......@@ -32,8 +24,6 @@ import static org.mockito.Mockito.when;
public class ConfigServiceTest {
@Mock
private ReleaseRepository releaseRepository;
@Mock
private ObjectMapper objectMapper;
private ConfigService configService;
@Before
......@@ -41,7 +31,6 @@ public class ConfigServiceTest {
configService = new ConfigService();
ReflectionTestUtils
.setField(configService, "releaseRepository", releaseRepository);
ReflectionTestUtils.setField(configService, "objectMapper", objectMapper);
}
// @Test
......@@ -131,21 +120,16 @@ public class ConfigServiceTest {
public void testTransformConfigurationToMapSuccessful() throws Exception {
String someValidConfiguration = "{\"apollo.bar\": \"foo\"}";
Map<String, String> someMap = Maps.newHashMap();
when(objectMapper.readValue(eq(someValidConfiguration), (TypeReference) anyObject()))
.thenReturn(someMap);
someMap.put("apollo.bar", "foo");
Map<String, String> result = configService.transformConfigurationToMap(someValidConfiguration);
assertEquals(someMap, result);
verify(objectMapper, times(1))
.readValue(eq(someValidConfiguration), (TypeReference) anyObject());
}
@Test
public void testTransformConfigurationToMapFailed() throws Exception {
String someInvalidConfiguration = "xxx";
when(objectMapper.readValue(eq(someInvalidConfiguration), (TypeReference) anyObject()))
.thenThrow(IOException.class);
Map<String, String>
result =
......
......@@ -24,38 +24,29 @@
<groupId>com.dianping.cat</groupId>
<artifactId>cat-client</artifactId>
</dependency>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<!-- end of spring -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<!-- end of util -->
<!-- test -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<scope>test</scope>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<scope>test</scope>
<artifactId>log4j-slf4j-impl</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</exclusion>
</exclusions>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<scope>test</scope>
<artifactId>log4j-core</artifactId>
<scope>provided</scope>
</dependency>
<!-- end of test -->
</dependencies>
</project>
package com.ctrip.apollo.build;
import com.ctrip.apollo.internals.ConfigServiceLocator;
import com.ctrip.apollo.internals.DefaultConfigManager;
import com.ctrip.apollo.spi.DefaultConfigFactory;
import com.ctrip.apollo.spi.DefaultConfigFactoryManager;
import com.ctrip.apollo.spi.DefaultConfigRegistry;
import com.ctrip.apollo.util.ConfigUtil;
import com.ctrip.apollo.util.http.HttpUtil;
import org.unidal.lookup.configuration.AbstractResourceConfigurator;
import org.unidal.lookup.configuration.Component;
......@@ -27,6 +30,9 @@ public class ComponentConfigurator extends AbstractResourceConfigurator {
all.add(A(DefaultConfigFactory.class));
all.add(A(DefaultConfigRegistry.class));
all.add(A(DefaultConfigFactoryManager.class));
all.add(A(ConfigUtil.class));
all.add(A(ConfigServiceLocator.class));
all.add(A(HttpUtil.class));
return all;
}
......
......@@ -2,38 +2,46 @@ package com.ctrip.apollo.internals;
import com.ctrip.apollo.core.dto.ServiceDTO;
import com.ctrip.apollo.env.ClientEnvironment;
import com.ctrip.apollo.util.http.HttpRequest;
import com.ctrip.apollo.util.http.HttpResponse;
import com.ctrip.apollo.util.http.HttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.client.RestTemplate;
import org.unidal.lookup.annotation.Inject;
import org.unidal.lookup.annotation.Named;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
@Named(type = ConfigServiceLocator.class)
public class ConfigServiceLocator {
private static final Logger logger = LoggerFactory.getLogger(ConfigServiceLocator.class);
private RestTemplate restTemplate = new RestTemplate();
@Inject
private HttpUtil m_httpUtil;
private List<ServiceDTO> serviceCaches = new ArrayList<>();
public List<ServiceDTO> getConfigServices() {
ClientEnvironment env = ClientEnvironment.getInstance();
String domainName = env.getMetaServerDomainName();
String url = domainName + "/services/config";
HttpRequest request = new HttpRequest(url);
try {
ServiceDTO[] services = restTemplate.getForObject(new URI(url), ServiceDTO[].class);
HttpResponse<ServiceDTO[]> response = m_httpUtil.doGet(request, ServiceDTO[].class);
ServiceDTO[] services = response.getBody();
if (services != null && services.length > 0) {
serviceCaches.clear();
for (ServiceDTO service : services) {
serviceCaches.add(service);
}
}
} catch (Exception ex) {
logger.warn(ex.getMessage());
} catch (Throwable t) {
logger.error("Get config services failed", t);
throw new RuntimeException("Get config services failed", t);
}
return serviceCaches;
}
}
......@@ -4,6 +4,9 @@ import com.ctrip.apollo.Config;
import com.ctrip.apollo.core.utils.ClassLoaderUtil;
import com.dianping.cat.Cat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
......@@ -12,6 +15,7 @@ import java.util.Properties;
* @author Jason Song(song_s@ctrip.com)
*/
public class DefaultConfig implements Config {
private static final Logger logger = LoggerFactory.getLogger(DefaultConfig.class);
private final String m_namespace;
private Properties m_resourceProperties;
private Properties m_configProperties;
......@@ -28,9 +32,10 @@ public class DefaultConfig implements Config {
try {
m_configProperties = m_configRepository.loadConfig();
} catch (Throwable ex) {
throw new RuntimeException(
String.format("Init Apollo Local Config failed - namespace: %s",
m_namespace), ex);
String message = String.format("Init Apollo Local Config failed - namespace: %s",
m_namespace);
logger.error(message, ex);
throw new RuntimeException(message, ex);
}
}
......@@ -74,6 +79,7 @@ public class DefaultConfig implements Config {
try {
properties.load(in);
} catch (IOException e) {
logger.error("Load resource config for namespace {} failed", namespace, e);
Cat.logError(e);
} finally {
try {
......
......@@ -5,9 +5,14 @@ import com.google.common.base.Preconditions;
import com.ctrip.apollo.util.ConfigUtil;
import com.dianping.cat.Cat;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.unidal.lookup.ContainerLoader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
......@@ -18,16 +23,23 @@ import java.util.Properties;
* @author Jason Song(song_s@ctrip.com)
*/
public class LocalFileConfigRepository implements ConfigRepository {
private static final Logger logger = LoggerFactory.getLogger(LocalFileConfigRepository.class);
private PlexusContainer m_container;
private final String m_namespace;
private final File m_baseDir;
private final ConfigUtil m_configUtil;
private Properties m_fileProperties;
private ConfigRepository m_fallback;
public LocalFileConfigRepository(File baseDir, String namespace, ConfigUtil configUtil) {
public LocalFileConfigRepository(File baseDir, String namespace) {
m_baseDir = baseDir;
m_namespace = namespace;
m_configUtil = configUtil;
m_container = ContainerLoader.getDefaultContainer();
try {
m_configUtil = m_container.lookup(ConfigUtil.class);
} catch (ComponentLookupException e) {
throw new IllegalStateException("Unable to load component!", e);
}
}
@Override
......@@ -53,6 +65,7 @@ public class LocalFileConfigRepository implements ConfigRepository {
persistLocalCacheFile(m_baseDir, m_namespace);
return;
} catch (Throwable ex) {
logger.error("Load config from fallback loader failed", ex);
Cat.logError(ex);
}
}
......@@ -79,6 +92,7 @@ public class LocalFileConfigRepository implements ConfigRepository {
properties = new Properties();
properties.load(in);
} catch (IOException e) {
logger.error("Loading config from local cache file {} failed", file.getAbsolutePath(), e);
Cat.logError(e);
throw e;
} finally {
......@@ -91,7 +105,10 @@ public class LocalFileConfigRepository implements ConfigRepository {
}
}
} else {
//TODO error handling
String message =
String.format("Cannot read from local cache file %s", file.getAbsolutePath());
logger.error(message);
throw new RuntimeException(message);
}
return properties;
......@@ -108,9 +125,8 @@ public class LocalFileConfigRepository implements ConfigRepository {
try {
out = new FileOutputStream(file);
m_fileProperties.store(out, "Persisted by DefaultConfig");
} catch (FileNotFoundException ex) {
Cat.logError(ex);
} catch (IOException ex) {
logger.error("Persist local cache file {} failed", file.getAbsolutePath(), ex);
Cat.logError(ex);
} finally {
if (out != null) {
......
package com.ctrip.apollo.internals;
import com.google.common.collect.Maps;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.ctrip.apollo.core.dto.ApolloConfig;
import com.ctrip.apollo.core.dto.ServiceDTO;
import com.ctrip.apollo.util.ConfigUtil;
import com.ctrip.apollo.util.http.HttpRequest;
import com.ctrip.apollo.util.http.HttpResponse;
import com.ctrip.apollo.util.http.HttpUtil;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import org.unidal.lookup.ContainerLoader;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class RemoteConfigRepository implements ConfigRepository {
private static final Logger logger = LoggerFactory.getLogger(RemoteConfigRepository.class);
private RestTemplate m_restTemplate;
private PlexusContainer m_container;
private ConfigServiceLocator m_serviceLocator;
private HttpUtil m_httpUtil;
private ConfigUtil m_configUtil;
private Properties m_remoteProperties;
private AtomicReference<ApolloConfig> m_configCache;
private String m_namespace;
public RemoteConfigRepository(RestTemplate restTemplate,
ConfigServiceLocator serviceLocator,
ConfigUtil configUtil, String namespace) {
m_restTemplate = restTemplate;
m_serviceLocator = serviceLocator;
m_configUtil = configUtil;
public RemoteConfigRepository(String namespace) {
m_namespace = namespace;
m_configCache = new AtomicReference<>();
m_container = ContainerLoader.getDefaultContainer();
try {
m_configUtil = m_container.lookup(ConfigUtil.class);
m_httpUtil = m_container.lookup(HttpUtil.class);
m_serviceLocator = m_container.lookup(ConfigServiceLocator.class);
} catch (ComponentLookupException e) {
throw new IllegalStateException("Unable to load component!", e);
}
}
@Override
public Properties loadConfig() {
if (m_remoteProperties == null) {
if (m_configCache.get() == null) {
initRemoteConfig();
}
Properties result = new Properties();
result.putAll(m_remoteProperties);
return result;
return transformApolloConfigToProperties(m_configCache.get());
}
@Override
......@@ -55,79 +59,60 @@ public class RemoteConfigRepository implements ConfigRepository {
}
private void initRemoteConfig() {
ApolloConfig apolloConfig = this.loadApolloConfig();
m_remoteProperties = new Properties();
m_remoteProperties.putAll(apolloConfig.getConfigurations());
m_configCache.set(this.loadApolloConfig());
}
private Properties transformApolloConfigToProperties(ApolloConfig apolloConfig) {
Properties result = new Properties();
result.putAll(apolloConfig.getConfigurations());
return result;
}
private ApolloConfig loadApolloConfig() {
String appId = m_configUtil.getAppId();
String cluster = m_configUtil.getCluster();
String uri = getConfigServiceUrl();
logger.info("Loading config from {}, appId={}, cluster={}, namespace={}", uri, appId, cluster,
m_namespace);
HttpRequest request =
new HttpRequest(assembleUrl(uri, appId, cluster, m_namespace, m_configCache.get()));
try {
ApolloConfig result =
this.getRemoteConfig(m_restTemplate, getConfigServiceUrl(),
appId, cluster,
m_namespace,
null);
if (result == null) {
return null;
HttpResponse<ApolloConfig> response = m_httpUtil.doGet(request, ApolloConfig.class);
if (response.getStatusCode() == 304) {
return m_configCache.get();
}
logger.info("Loaded config: {}", result);
return result;
} catch (Throwable ex) {
throw new RuntimeException(
logger.info("Loaded config: {}", response.getBody());
return response.getBody();
} catch (Throwable t) {
String message =
String.format("Load Apollo Config failed - appId: %s, cluster: %s, namespace: %s", appId,
cluster, m_namespace), ex);
cluster, m_namespace);
logger.error(message, t);
throw new RuntimeException(message, t);
}
}
private String assembleUrl(String uri, String appId, String cluster, String namespace,
ApolloConfig previousConfig) {
String path = "/config/%s/%s";
List<String> params = Lists.newArrayList(appId, cluster);
private ApolloConfig getRemoteConfig(RestTemplate restTemplate, String uri,
String appId, String cluster, String namespace,
ApolloConfig previousConfig) {
logger.info("Loading config from {}, appId={}, cluster={}, namespace={}", uri, appId, cluster,
namespace);
String path = "/config/{appId}/{cluster}";
Map<String, Object> paramMap = Maps.newHashMap();
paramMap.put("appId", appId);
paramMap.put("cluster", cluster);
if (StringUtils.hasText(namespace)) {
path = path + "/{namespace}";
paramMap.put("namespace", namespace);
if (!Strings.isNullOrEmpty(namespace)) {
path = path + "/%s";
params.add(namespace);
}
if (previousConfig != null) {
path = path + "?releaseId={releaseId}";
paramMap.put("releaseId", previousConfig.getReleaseId());
path = path + "?releaseId=%s";
params.add(String.valueOf(previousConfig.getReleaseId()));
}
ResponseEntity<ApolloConfig> response;
try {
// TODO retry
response = restTemplate.exchange(uri
+ path, HttpMethod.GET, new HttpEntity<Void>((Void) null), ApolloConfig.class, paramMap);
} catch (Throwable ex) {
throw ex;
}
if (response == null) {
throw new RuntimeException("Load apollo config failed, response is null");
}
if (response.getStatusCode() == HttpStatus.NOT_MODIFIED) {
return null;
}
if (response.getStatusCode() != HttpStatus.OK) {
throw new RuntimeException(
String.format("Load apollo config failed, response status %s", response.getStatusCode()));
}
ApolloConfig result = response.getBody();
return result;
String pathExpanded = String.format(path, params.toArray());
return uri + pathExpanded;
}
private String getConfigServiceUrl() {
......
......@@ -2,12 +2,16 @@ package com.ctrip.apollo.internals;
import com.ctrip.apollo.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Properties;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class SimpleConfig implements Config {
private static final Logger logger = LoggerFactory.getLogger(SimpleConfig.class);
private String m_namespace;
private ConfigRepository m_configRepository;
private Properties m_configProperties;
......@@ -22,9 +26,10 @@ public class SimpleConfig implements Config {
try {
m_configProperties = m_configRepository.loadConfig();
} catch (Throwable ex) {
throw new RuntimeException(
String.format("Init Apollo Remote Config failed - namespace: %s",
m_namespace), ex);
String message = String.format("Init Apollo Remote Config failed - namespace: %s",
m_namespace);
logger.error(message, ex);
throw new RuntimeException(message, ex);
}
}
......
......@@ -2,11 +2,10 @@ package com.ctrip.apollo.spi;
import com.ctrip.apollo.Config;
import com.ctrip.apollo.core.utils.ClassLoaderUtil;
import com.ctrip.apollo.internals.*;
import com.ctrip.apollo.internals.DefaultConfig;
import com.ctrip.apollo.internals.LocalFileConfigRepository;
import com.ctrip.apollo.internals.RemoteConfigRepository;
import com.ctrip.apollo.util.ConfigUtil;
import org.springframework.web.client.RestTemplate;
import org.unidal.lookup.annotation.Named;
import java.io.File;
......@@ -28,20 +27,20 @@ public class DefaultConfigFactory implements ConfigFactory {
@Override
public Config create(String namespace) {
DefaultConfig defaultConfig = new DefaultConfig(namespace, createLocalConfigRepository(namespace));
DefaultConfig defaultConfig =
new DefaultConfig(namespace, createLocalConfigRepository(namespace));
return defaultConfig;
}
LocalFileConfigRepository createLocalConfigRepository(String namespace) {
LocalFileConfigRepository
localFileConfigLoader =
new LocalFileConfigRepository(m_baseDir, namespace, ConfigUtil.getInstance());
new LocalFileConfigRepository(m_baseDir, namespace);
localFileConfigLoader.setFallback(createRemoteConfigRepository(namespace));
return localFileConfigLoader;
}
RemoteConfigRepository createRemoteConfigRepository(String namespace) {
return new RemoteConfigRepository(new RestTemplate(), new ConfigServiceLocator(),
ConfigUtil.getInstance(), namespace);
return new RemoteConfigRepository(namespace);
}
}
package com.ctrip.apollo.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.unidal.lookup.annotation.Named;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Named(type = ConfigUtil.class)
public class ConfigUtil {
//TODO read from config?
private static final int refreshInterval = 5;
private static final TimeUnit refreshIntervalTimeUnit = TimeUnit.MINUTES;
private static ConfigUtil configUtil = new ConfigUtil();
private ConfigUtil() {
}
public static ConfigUtil getInstance() {
return configUtil;
}
private static final int connectTimeout = 5000; //5 seconds
private static final int readTimeout = 10000; //10 seconds
public String getAppId() {
// TODO return the actual app id
......@@ -36,6 +25,14 @@ public class ConfigUtil {
return "default";
}
public int getConnectTimeout() {
return connectTimeout;
}
public int getReadTimeout() {
return readTimeout;
}
public int getRefreshInterval() {
return refreshInterval;
}
......
package com.ctrip.apollo.util.http;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class HttpRequest {
private String m_url;
private int m_connectTimeout;
private int m_readTimeout;
public HttpRequest(String url) {
this.m_url = url;
m_connectTimeout = -1;
m_readTimeout = -1;
}
public String getUrl() {
return m_url;
}
public int getConnectTimeout() {
return m_connectTimeout;
}
public void setConnectTimeout(int connectTimeout) {
this.m_connectTimeout = connectTimeout;
}
public int getReadTimeout() {
return m_readTimeout;
}
public void setReadTimeout(int readTimeout) {
this.m_readTimeout = readTimeout;
}
}
package com.ctrip.apollo.util.http;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class HttpResponse<T> {
private final int m_statusCode;
private final T m_body;
public HttpResponse(int statusCode, T body) {
this.m_statusCode = statusCode;
this.m_body = body;
}
public int getStatusCode() {
return m_statusCode;
}
public T getBody() {
return m_body;
}
}
package com.ctrip.apollo.util.http;
import com.google.common.base.Charsets;
import com.google.gson.Gson;
import com.ctrip.apollo.util.ConfigUtil;
import org.unidal.helper.Files;
import org.unidal.lookup.annotation.Inject;
import org.unidal.lookup.annotation.Named;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Named(type = HttpUtil.class)
public class HttpUtil {
@Inject
private ConfigUtil m_configUtil;
private Gson gson;
public HttpUtil() {
gson = new Gson();
}
/**
* Do get operation for the http request
*
* @throws RuntimeException if any error happened or response code is neither 200 nor 304
*/
public <T> HttpResponse<T> doGet(HttpRequest httpRequest, Class<T> responseType) {
InputStream is = null;
try {
HttpURLConnection conn = (HttpURLConnection) new URL(httpRequest.getUrl()).openConnection();
conn.setRequestMethod("GET");
if (httpRequest.getConnectTimeout() < 0) {
conn.setConnectTimeout(m_configUtil.getConnectTimeout());
} else {
conn.setConnectTimeout(httpRequest.getConnectTimeout());
}
if (httpRequest.getReadTimeout() < 0) {
conn.setReadTimeout(m_configUtil.getReadTimeout());
} else {
conn.setReadTimeout(httpRequest.getReadTimeout());
}
conn.connect();
int statusCode = conn.getResponseCode();
if (statusCode == 200) {
is = conn.getInputStream();
String content = Files.IO.INSTANCE.readFrom(is, Charsets.UTF_8.name());
return new HttpResponse<>(statusCode, gson.fromJson(content, responseType));
}
if (statusCode == 304) {
return new HttpResponse<>(statusCode, null);
}
throw new RuntimeException(
String.format("Get operation failed, status code - %d", statusCode));
} catch (Throwable ex) {
throw new RuntimeException("Could not complete get operation", ex);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
//ignore
}
}
}
}
}
......@@ -26,5 +26,27 @@
</requirement>
</requirements>
</component>
<component>
<role>com.ctrip.apollo.util.ConfigUtil</role>
<implementation>com.ctrip.apollo.util.ConfigUtil</implementation>
</component>
<component>
<role>com.ctrip.apollo.internals.ConfigServiceLocator</role>
<implementation>com.ctrip.apollo.internals.ConfigServiceLocator</implementation>
<requirements>
<requirement>
<role>com.ctrip.apollo.util.http.HttpUtil</role>
</requirement>
</requirements>
</component>
<component>
<role>com.ctrip.apollo.util.http.HttpUtil</role>
<implementation>com.ctrip.apollo.util.http.HttpUtil</implementation>
<requirements>
<requirement>
<role>com.ctrip.apollo.util.ConfigUtil</role>
</requirement>
</requirements>
</component>
</components>
</plexus>
......@@ -28,7 +28,7 @@ public class DefaultConfigTest {
@Before
public void setUp() throws Exception {
someResourceDir = new File(ClassLoaderUtil.getClassPath() + "/META-INF/config");
someResourceDir.mkdir();
someResourceDir.mkdirs();
someNamespace = "someName";
configRepository = mock(ConfigRepository.class);
}
......
......@@ -8,6 +8,7 @@ import com.ctrip.apollo.util.ConfigUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.unidal.lookup.ComponentTestCase;
import java.io.File;
import java.util.Properties;
......@@ -21,15 +22,17 @@ import static org.mockito.Mockito.when;
/**
* Created by Jason on 4/9/16.
*/
public class LocalFileConfigRepositoryTest {
public class LocalFileConfigRepositoryTest extends ComponentTestCase {
private File someBaseDir;
private String someNamespace;
private ConfigRepository fallbackRepo;
private Properties someProperties;
private ConfigUtil someConfigUtil;
private static String someAppId = "someApp";
private static String someCluster = "someCluster";
@Before
public void setUp() throws Exception {
super.setUp();
someBaseDir = new File("src/test/resources/config-cache");
someBaseDir.mkdir();
......@@ -39,12 +42,7 @@ public class LocalFileConfigRepositoryTest {
fallbackRepo = mock(ConfigRepository.class);
when(fallbackRepo.loadConfig()).thenReturn(someProperties);
String someAppId = "someApp";
String someCluster = "someCluster";
someConfigUtil = mock(ConfigUtil.class);
when(someConfigUtil.getAppId()).thenReturn(someAppId);
when(someConfigUtil.getCluster()).thenReturn(someCluster);
defineComponent(ConfigUtil.class, MockConfigUtil.class);
}
@After
......@@ -66,8 +64,8 @@ public class LocalFileConfigRepositoryTest {
}
private String assembleLocalCacheFileName() {
return String.format("%s-%s-%s.properties", someConfigUtil.getAppId(),
someConfigUtil.getCluster(), someNamespace);
return String.format("%s-%s-%s.properties", someAppId,
someCluster, someNamespace);
}
@Test
......@@ -84,7 +82,7 @@ public class LocalFileConfigRepositoryTest {
Files.write(someKey + "=" + someValue, file, Charsets.UTF_8);
LocalFileConfigRepository localRepo = new LocalFileConfigRepository(someBaseDir, someNamespace, someConfigUtil);
LocalFileConfigRepository localRepo = new LocalFileConfigRepository(someBaseDir, someNamespace);
Properties properties = localRepo.loadConfig();
assertEquals(someValue, properties.getProperty(someKey));
......@@ -95,7 +93,7 @@ public class LocalFileConfigRepositoryTest {
public void testLoadConfigWithNoLocalFile() throws Exception {
LocalFileConfigRepository
localFileConfigRepository =
new LocalFileConfigRepository(someBaseDir, someNamespace, someConfigUtil);
new LocalFileConfigRepository(someBaseDir, someNamespace);
localFileConfigRepository.setFallback(fallbackRepo);
......@@ -109,7 +107,7 @@ public class LocalFileConfigRepositoryTest {
@Test
public void testLoadConfigWithNoLocalFileMultipleTimes() throws Exception {
LocalFileConfigRepository localRepo =
new LocalFileConfigRepository(someBaseDir, someNamespace, someConfigUtil);
new LocalFileConfigRepository(someBaseDir, someNamespace);
localRepo.setFallback(fallbackRepo);
......@@ -117,7 +115,7 @@ public class LocalFileConfigRepositoryTest {
LocalFileConfigRepository
anotherLocalRepoWithNoFallback =
new LocalFileConfigRepository(someBaseDir, someNamespace, someConfigUtil);
new LocalFileConfigRepository(someBaseDir, someNamespace);
Properties anotherProperties = anotherLocalRepoWithNoFallback.loadConfig();
......@@ -127,4 +125,16 @@ public class LocalFileConfigRepositoryTest {
}
}
\ No newline at end of file
public static class MockConfigUtil extends ConfigUtil {
@Override
public String getAppId() {
return someAppId;
}
@Override
public String getCluster() {
return someCluster;
}
}
}
......@@ -6,26 +6,22 @@ import com.google.common.collect.Maps;
import com.ctrip.apollo.core.dto.ApolloConfig;
import com.ctrip.apollo.core.dto.ServiceDTO;
import com.ctrip.apollo.util.ConfigUtil;
import com.ctrip.apollo.util.http.HttpRequest;
import com.ctrip.apollo.util.http.HttpResponse;
import com.ctrip.apollo.util.http.HttpUtil;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import org.unidal.lookup.ComponentTestCase;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyMap;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
......@@ -33,27 +29,23 @@ import static org.mockito.Mockito.when;
* Created by Jason on 4/9/16.
*/
@RunWith(MockitoJUnitRunner.class)
public class RemoteConfigRepositoryTest {
@Mock
private RestTemplate restTemplate;
public class RemoteConfigRepositoryTest extends ComponentTestCase {
@Mock
private ConfigServiceLocator configServiceLocator;
private String someNamespace;
@Mock
private ResponseEntity<ApolloConfig> someResponse;
private static HttpResponse<ApolloConfig> someResponse;
@Mock
private ConfigUtil someConfigUtil;
@Before
public void setUp() throws Exception {
super.setUp();
someNamespace = "someName";
String someServerUrl = "http://someServer";
mockConfigServiceLocator(someServerUrl);
String someAppId = "someApp";
String someCluster = "someCluster";
when(someConfigUtil.getAppId()).thenReturn(someAppId);
when(someConfigUtil.getCluster()).thenReturn(someCluster);
defineComponent(ConfigUtil.class, MockConfigUtil.class);
defineComponent(ConfigServiceLocator.class, MockConfigServiceLocator.class);
defineComponent(HttpUtil.class, MockHttpUtil.class);
}
@Test
......@@ -64,13 +56,10 @@ public class RemoteConfigRepositoryTest {
configurations.put(someKey, someValue);
ApolloConfig someApolloConfig = assembleApolloConfig(configurations);
when(someResponse.getStatusCode()).thenReturn(HttpStatus.OK);
when(someResponse.getStatusCode()).thenReturn(200);
when(someResponse.getBody()).thenReturn(someApolloConfig);
when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class),
eq(ApolloConfig.class), anyMap())).thenReturn(someResponse);
RemoteConfigRepository remoteConfigRepository = new RemoteConfigRepository(restTemplate, configServiceLocator, someConfigUtil, someNamespace);
RemoteConfigRepository remoteConfigRepository = new RemoteConfigRepository(someNamespace);
Properties config = remoteConfigRepository.loadConfig();
assertEquals(configurations, config);
......@@ -79,11 +68,9 @@ public class RemoteConfigRepositoryTest {
@Test(expected = RuntimeException.class)
public void testGetRemoteConfigWithServerError() throws Exception {
when(someResponse.getStatusCode()).thenReturn(HttpStatus.INTERNAL_SERVER_ERROR);
when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class),
eq(ApolloConfig.class), anyMap())).thenReturn(someResponse);
when(someResponse.getStatusCode()).thenReturn(500);
RemoteConfigRepository remoteConfigRepository = new RemoteConfigRepository(restTemplate, configServiceLocator, someConfigUtil, someNamespace);
RemoteConfigRepository remoteConfigRepository = new RemoteConfigRepository(someNamespace);
remoteConfigRepository.loadConfig();
}
......@@ -99,10 +86,35 @@ public class RemoteConfigRepositoryTest {
return apolloConfig;
}
private void mockConfigServiceLocator(String serverUrl) {
ServiceDTO serviceDTO = mock(ServiceDTO.class);
public static class MockConfigUtil extends ConfigUtil {
@Override
public String getAppId() {
return "someApp";
}
when(serviceDTO.getHomepageUrl()).thenReturn(serverUrl);
when(configServiceLocator.getConfigServices()).thenReturn(Lists.newArrayList(serviceDTO));
@Override
public String getCluster() {
return "someCluster";
}
}
public static class MockConfigServiceLocator extends ConfigServiceLocator {
@Override
public List<ServiceDTO> getConfigServices() {
String someServerUrl = "http://someServer";
ServiceDTO serviceDTO = mock(ServiceDTO.class);
when(serviceDTO.getHomepageUrl()).thenReturn(someServerUrl);
return Lists.newArrayList(serviceDTO);
}
}
public static class MockHttpUtil extends HttpUtil {
@Override
public <T> HttpResponse<T> doGet(HttpRequest httpRequest, Class<T> responseType) {
return (HttpResponse<T>) someResponse;
}
}
}
......@@ -15,12 +15,8 @@
<dependencies>
<!-- json -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<!-- end of json -->
<!-- util -->
......
......@@ -2,9 +2,6 @@ package com.ctrip.apollo.core.dto;
import com.google.common.base.MoreObjects;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Map;
/**
......@@ -22,11 +19,10 @@ public class ApolloConfig {
private long releaseId;
@JsonCreator
public ApolloConfig(@JsonProperty("appId") String appId,
@JsonProperty("cluster") String cluster,
@JsonProperty("namespace") String namespace,
@JsonProperty("releaseId") long releaseId) {
public ApolloConfig(String appId,
String cluster,
String namespace,
long releaseId) {
super();
this.appId = appId;
this.cluster = cluster;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment