diff --git a/apollo-adminservice/pom.xml b/apollo-adminservice/pom.xml index cd89c245d3272e4cbab2373f2fdaba5d0eb2e25a..4d47c7ccd348b574477a0a8ea7ce2b50cc88c0c9 100644 --- a/apollo-adminservice/pom.xml +++ b/apollo-adminservice/pom.xml @@ -4,7 +4,7 @@ com.ctrip.framework.apollo apollo - 0.0.6 + 0.0.7-SNAPSHOT ../pom.xml 4.0.0 diff --git a/apollo-assembly/pom.xml b/apollo-assembly/pom.xml index ff5af3603497ae7c78f2c4557f4869ea114b0fe1..07c2dd1d68dbaaf6b3a53517965a220863101dbb 100644 --- a/apollo-assembly/pom.xml +++ b/apollo-assembly/pom.xml @@ -4,7 +4,7 @@ com.ctrip.framework.apollo apollo - 0.0.6 + 0.0.7-SNAPSHOT ../pom.xml 4.0.0 diff --git a/apollo-biz/pom.xml b/apollo-biz/pom.xml index cc7e8bc9714cb3045b169d683d407776182a39c3..2a716c2634e1a7e2468da84f361a82b5ea468849 100644 --- a/apollo-biz/pom.xml +++ b/apollo-biz/pom.xml @@ -4,7 +4,7 @@ apollo com.ctrip.framework.apollo - 0.0.6 + 0.0.7-SNAPSHOT 4.0.0 apollo-biz diff --git a/apollo-buildtools/pom.xml b/apollo-buildtools/pom.xml index 4caf191bd46e8fbdc4456f75a30662e80c1ae6f5..3977717a56e9769d3917f97af96c50d1918045a9 100644 --- a/apollo-buildtools/pom.xml +++ b/apollo-buildtools/pom.xml @@ -4,7 +4,7 @@ com.ctrip.framework.apollo apollo - 0.0.6 + 0.0.7-SNAPSHOT ../pom.xml 4.0.0 diff --git a/apollo-client/pom.xml b/apollo-client/pom.xml index 278e4c10d10b469f3ff7a44f9accb67a1dad974f..d3da41f061a8d6976fa0a4d9cb7d35c6fd472353 100644 --- a/apollo-client/pom.xml +++ b/apollo-client/pom.xml @@ -4,7 +4,7 @@ com.ctrip.framework.apollo apollo - 0.0.6 + 0.0.7-SNAPSHOT ../pom.xml 4.0.0 diff --git a/apollo-common/pom.xml b/apollo-common/pom.xml index a4f81fa596df812f088ad61da925a299c7c4975f..7c7ac462281c5808d6569ad6c6c4e5afe7dd3a4f 100644 --- a/apollo-common/pom.xml +++ b/apollo-common/pom.xml @@ -4,7 +4,7 @@ com.ctrip.framework.apollo apollo - 0.0.6 + 0.0.7-SNAPSHOT ../pom.xml 4.0.0 diff --git a/apollo-configservice/pom.xml b/apollo-configservice/pom.xml index 28d38a6f11a4b8d6e491127ece1d6717d5cfd07d..57aaaacf2abfcbbd9044aae1a26984a36522641a 100644 --- a/apollo-configservice/pom.xml +++ b/apollo-configservice/pom.xml @@ -4,7 +4,7 @@ com.ctrip.framework.apollo apollo - 0.0.6 + 0.0.7-SNAPSHOT ../pom.xml 4.0.0 diff --git a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/ConfigFileController.java b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/ConfigFileController.java index 3ab6c48d1c5b1943fe8902413213c71606f12e53..6577d4f28e082ae18faaf916bf5804a2f8c4dfe9 100644 --- a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/ConfigFileController.java +++ b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/ConfigFileController.java @@ -11,6 +11,7 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; +import com.google.gson.Gson; import com.ctrip.framework.apollo.biz.entity.ReleaseMessage; import com.ctrip.framework.apollo.biz.message.ReleaseMessageListener; @@ -19,11 +20,9 @@ import com.ctrip.framework.apollo.configservice.util.NamespaceUtil; import com.ctrip.framework.apollo.configservice.util.WatchKeysUtil; import com.ctrip.framework.apollo.core.ConfigConsts; import com.ctrip.framework.apollo.core.dto.ApolloConfig; -import com.ctrip.framework.apollo.core.dto.ApolloConfigNotification; import com.ctrip.framework.apollo.core.utils.PropertiesUtil; import com.dianping.cat.Cat; -import org.hibernate.cache.spi.CacheKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -35,12 +34,9 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.context.request.async.DeferredResult; import java.io.IOException; -import java.io.StringWriter; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Properties; import java.util.Set; @@ -53,18 +49,20 @@ import javax.servlet.http.HttpServletResponse; */ @RestController @RequestMapping("/configfiles") -public class ConfigFileController implements ReleaseMessageListener{ +public class ConfigFileController implements ReleaseMessageListener { private static final Logger logger = LoggerFactory.getLogger(ConfigFileController.class); private static final Joiner STRING_JOINER = Joiner.on(ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR); private static final long MAX_CACHE_SIZE = 50 * 1024 * 1024; // 50MB - private static final long EXPIRE_AFTER_WRITE = 10; - private final HttpHeaders responseHeaders; + private static final long EXPIRE_AFTER_WRITE = 30; + private final HttpHeaders propertiesResponseHeaders; + private final HttpHeaders jsonResponseHeaders; private final ResponseEntity NOT_FOUND_RESPONSE; private Cache localCache; private final Multimap watchedKeys2CacheKey = Multimaps.synchronizedSetMultimap(HashMultimap.create()); private final Multimap cacheKey2WatchedKeys = Multimaps.synchronizedSetMultimap(HashMultimap.create()); + private static final Gson gson = new Gson(); @Autowired private ConfigController configController; @@ -103,23 +101,60 @@ public class ConfigFileController implements ReleaseMessageListener{ } }) .build(); - responseHeaders = new HttpHeaders(); - responseHeaders.add("Content-Type", "text/plain;charset=UTF-8"); + propertiesResponseHeaders = new HttpHeaders(); + propertiesResponseHeaders.add("Content-Type", "text/plain;charset=UTF-8"); + jsonResponseHeaders = new HttpHeaders(); + jsonResponseHeaders.add("Content-Type", "application/json;charset=UTF-8"); NOT_FOUND_RESPONSE = new ResponseEntity<>(HttpStatus.NOT_FOUND); } @RequestMapping(value = "/{appId}/{clusterName}/{namespace:.+}", method = RequestMethod.GET) - public ResponseEntity queryConfigAsFile(@PathVariable String appId, + public ResponseEntity queryConfigAsProperties(@PathVariable String appId, + @PathVariable String clusterName, + @PathVariable String namespace, + @RequestParam(value = "dataCenter", required = false) String dataCenter, + @RequestParam(value = "ip", required = false) String clientIp, + HttpServletResponse response) + throws IOException { + + String result = + queryConfig(ConfigFileOutputFormat.PROPERTIES, appId, clusterName, namespace, dataCenter, + clientIp, response); + + if (result == null) { + return NOT_FOUND_RESPONSE; + } + + return new ResponseEntity<>(result, propertiesResponseHeaders, HttpStatus.OK); + } + + @RequestMapping(value = "/json/{appId}/{clusterName}/{namespace:.+}", method = RequestMethod.GET) + public ResponseEntity queryConfigAsJson(@PathVariable String appId, @PathVariable String clusterName, @PathVariable String namespace, @RequestParam(value = "dataCenter", required = false) String dataCenter, @RequestParam(value = "ip", required = false) String clientIp, HttpServletResponse response) throws IOException { + + String result = + queryConfig(ConfigFileOutputFormat.JSON, appId, clusterName, namespace, dataCenter, + clientIp, response); + + if (result == null) { + return NOT_FOUND_RESPONSE; + } + + return new ResponseEntity<>(result, jsonResponseHeaders, HttpStatus.OK); + } + + String queryConfig(ConfigFileOutputFormat outputFormat, String appId, String clusterName, + String namespace, String dataCenter, String clientIp, + HttpServletResponse response) throws IOException { //strip out .properties suffix namespace = namespaceUtil.filterNamespaceName(namespace); //TODO add clientIp as key parts? - String cacheKey = assembleCacheKey(appId, clusterName, namespace, dataCenter); + String cacheKey = assembleCacheKey(outputFormat, appId, clusterName, namespace, dataCenter); String result = localCache.getIfPresent(cacheKey); @@ -131,11 +166,19 @@ public class ConfigFileController implements ReleaseMessageListener{ response); if (apolloConfig == null || apolloConfig.getConfigurations() == null) { - return NOT_FOUND_RESPONSE; + return null; + } + + switch (outputFormat) { + case PROPERTIES: + Properties properties = new Properties(); + properties.putAll(apolloConfig.getConfigurations()); + result = PropertiesUtil.toString(properties); + break; + case JSON: + result = gson.toJson(apolloConfig.getConfigurations()); + break; } - Properties properties = new Properties(); - properties.putAll(apolloConfig.getConfigurations()); - result = PropertiesUtil.toString(properties); localCache.put(cacheKey, result); logger.debug("adding cache for key: {}", cacheKey); @@ -153,13 +196,14 @@ public class ConfigFileController implements ReleaseMessageListener{ Cat.logEvent("ConfigFile-Cache-Hit", cacheKey); } - return new ResponseEntity<>(result, responseHeaders, - HttpStatus.OK); + return result; } - String assembleCacheKey(String appId, String clusterName, String namespace, - String dataCenter) { - List keyParts = Lists.newArrayList(appId, clusterName, namespace); + String assembleCacheKey(ConfigFileOutputFormat outputFormat, String appId, String clusterName, + String namespace, + String dataCenter) { + List keyParts = + Lists.newArrayList(outputFormat.getValue(), appId, clusterName, namespace); if (!Strings.isNullOrEmpty(dataCenter)) { keyParts.add(dataCenter); } @@ -187,4 +231,18 @@ public class ConfigFileController implements ReleaseMessageListener{ localCache.invalidate(cacheKey); } } + + enum ConfigFileOutputFormat { + PROPERTIES("properties"), JSON("json"); + + private String value; + + ConfigFileOutputFormat(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + } } diff --git a/apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/controller/ConfigFileControllerTest.java b/apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/controller/ConfigFileControllerTest.java index 08d1f190ef6f6e4de890e78cfb3ce46e7f44a50a..3387632d82a353489417cc21455f4956155baa37 100644 --- a/apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/controller/ConfigFileControllerTest.java +++ b/apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/controller/ConfigFileControllerTest.java @@ -5,6 +5,8 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; import com.ctrip.framework.apollo.biz.entity.ReleaseMessage; import com.ctrip.framework.apollo.biz.message.Topics; @@ -21,7 +23,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.util.ReflectionTestUtils; -import java.util.List; +import java.lang.reflect.Type; import java.util.Map; import java.util.Set; @@ -81,7 +83,7 @@ public class ConfigFileControllerTest { } @Test - public void testQueryConfigAsFile() throws Exception { + public void testQueryConfigAsProperties() throws Exception { String someKey = "someKey"; String someValue = "someValue"; String anotherKey = "anotherKey"; @@ -93,7 +95,7 @@ public class ConfigFileControllerTest { String cacheKey = configFileController - .assembleCacheKey(someAppId, someClusterName, someNamespace, someDataCenter); + .assembleCacheKey(ConfigFileController.ConfigFileOutputFormat.PROPERTIES, someAppId, someClusterName, someNamespace, someDataCenter); Map configurations = ImmutableMap.of(someKey, someValue, anotherKey, anotherValue); @@ -108,7 +110,7 @@ public class ConfigFileControllerTest { ResponseEntity response = configFileController - .queryConfigAsFile(someAppId, someClusterName, someNamespace, someDataCenter, + .queryConfigAsProperties(someAppId, someClusterName, someNamespace, someDataCenter, someClientIp, someResponse); assertEquals(2, watchedKeys2CacheKey.size()); @@ -124,7 +126,7 @@ public class ConfigFileControllerTest { ResponseEntity anotherResponse = configFileController - .queryConfigAsFile(someAppId, someClusterName, someNamespace, someDataCenter, + .queryConfigAsProperties(someAppId, someClusterName, someNamespace, someDataCenter, someClientIp, someResponse); assertEquals(response, anotherResponse); @@ -134,6 +136,36 @@ public class ConfigFileControllerTest { someResponse); } + @Test + public void testQueryConfigAsJson() throws Exception { + String someKey = "someKey"; + String someValue = "someValue"; + Gson gson = new Gson(); + Type responseType = new TypeToken>(){}.getType(); + + String someWatchKey = "someWatchKey"; + Set watchKeys = Sets.newHashSet(someWatchKey); + + Map configurations = + ImmutableMap.of(someKey, someValue); + ApolloConfig someApolloConfig = mock(ApolloConfig.class); + when(configController + .queryConfig(someAppId, someClusterName, someNamespace, someDataCenter, "-1", someClientIp, + someResponse)).thenReturn(someApolloConfig); + when(someApolloConfig.getConfigurations()).thenReturn(configurations); + when(watchKeysUtil + .assembleAllWatchKeys(someAppId, someClusterName, someNamespace, someDataCenter)) + .thenReturn(watchKeys); + + ResponseEntity response = + configFileController + .queryConfigAsJson(someAppId, someClusterName, someNamespace, someDataCenter, + someClientIp, someResponse); + + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertEquals(configurations, gson.fromJson(response.getBody(), responseType)); + } + @Test public void testHandleMessage() throws Exception { String someWatchKey = "someWatchKey"; diff --git a/apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/ConfigFileControllerIntegrationTest.java b/apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/ConfigFileControllerIntegrationTest.java index 96cfd72c87daf8bf99df2796d832e3166f507944..6de3da25e45b30d7da7e14e6014876ff6a68c13e 100644 --- a/apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/ConfigFileControllerIntegrationTest.java +++ b/apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/ConfigFileControllerIntegrationTest.java @@ -2,6 +2,8 @@ package com.ctrip.framework.apollo.configservice.integration; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; import com.ctrip.framework.apollo.biz.entity.Namespace; import com.ctrip.framework.apollo.core.ConfigConsts; @@ -13,6 +15,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.context.jdbc.Sql; +import java.lang.reflect.Type; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -30,6 +33,8 @@ public class ConfigFileControllerIntegrationTest extends AbstractBaseIntegration private String somePublicNamespace; private String someDC; private String someDefaultCluster; + private Gson gson = new Gson(); + private Type mapResponseType = new TypeToken>(){}.getType(); @Before public void setUp() throws Exception { @@ -44,7 +49,7 @@ public class ConfigFileControllerIntegrationTest extends AbstractBaseIntegration @Test @Sql(scripts = "/integration-test/test-release.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/integration-test/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) - public void testQueryConfigAsFile() throws Exception { + public void testQueryConfigAsProperties() throws Exception { ResponseEntity response = restTemplate .getForEntity("{baseurl}/configfiles/{appId}/{clusterName}/{namespace}", String.class, @@ -60,7 +65,7 @@ public class ConfigFileControllerIntegrationTest extends AbstractBaseIntegration @Sql(scripts = "/integration-test/test-release.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/integration-test/test-release-public-dc-override.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/integration-test/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) - public void testQueryPublicConfigAsFile() throws Exception { + public void testQueryPublicConfigAsProperties() throws Exception { ResponseEntity response = restTemplate .getForEntity( @@ -75,6 +80,42 @@ public class ConfigFileControllerIntegrationTest extends AbstractBaseIntegration assertTrue(result.contains("k2=someDC-v2")); } + @Test + @Sql(scripts = "/integration-test/test-release.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + @Sql(scripts = "/integration-test/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) + public void testQueryConfigAsJson() throws Exception { + ResponseEntity response = + restTemplate + .getForEntity("{baseurl}/configfiles/json/{appId}/{clusterName}/{namespace}", String.class, + getHostUrl(), someAppId, someCluster, someNamespace); + + String result = response.getBody(); + Map configs = gson.fromJson(response.getBody(), mapResponseType); + + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertEquals("v2", configs.get("k2")); + } + + @Test + @Sql(scripts = "/integration-test/test-release.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + @Sql(scripts = "/integration-test/test-release-public-dc-override.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + @Sql(scripts = "/integration-test/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) + public void testQueryPublicConfigAsJson() throws Exception { + ResponseEntity response = + restTemplate + .getForEntity( + "{baseurl}/configfiles/json/{appId}/{clusterName}/{namespace}?dataCenter={dateCenter}", + String.class, + getHostUrl(), someAppId, someDefaultCluster, somePublicNamespace, someDC); + + String result = response.getBody(); + Map configs = gson.fromJson(response.getBody(), mapResponseType); + + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertEquals("override-someDC-v1", configs.get("k1")); + assertEquals("someDC-v2", configs.get("k2")); + } + @Test @Sql(scripts = "/integration-test/test-release.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/integration-test/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) diff --git a/apollo-core/pom.xml b/apollo-core/pom.xml index 7cffe8fb0141ab990b7f5191b4a6e59b75d07963..6459ede6fa7ef60cdf1cad5e076c8d1e5cdb7ebe 100644 --- a/apollo-core/pom.xml +++ b/apollo-core/pom.xml @@ -4,7 +4,7 @@ com.ctrip.framework.apollo apollo - 0.0.6 + 0.0.7-SNAPSHOT ../pom.xml 4.0.0 diff --git a/apollo-demo/pom.xml b/apollo-demo/pom.xml index 38c04ccedbe4bbf82a1c400785fbf09c94347602..6e94e5bbb894d1cc540da80cfc74bc2acdfc72aa 100644 --- a/apollo-demo/pom.xml +++ b/apollo-demo/pom.xml @@ -4,7 +4,7 @@ apollo com.ctrip.framework.apollo - 0.0.6 + 0.0.7-SNAPSHOT 4.0.0 apollo-demo diff --git a/apollo-portal/pom.xml b/apollo-portal/pom.xml index aa7fb39371e6ad2feedac079fcc3b62d116823ae..7b7d9f660ebd79567fa77bc1aef6c746c2347a45 100644 --- a/apollo-portal/pom.xml +++ b/apollo-portal/pom.xml @@ -4,7 +4,7 @@ com.ctrip.framework.apollo apollo - 0.0.6 + 0.0.7-SNAPSHOT ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 745f4f5271a909edbe7962ef1221048d6828ea9a..da106c9aa0979c203e8e93f8237546b040f1003f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.ctrip.framework.apollo apollo - 0.0.6 + 0.0.7-SNAPSHOT Apollo pom Ctrip Configuration Center