Commit 91e56acf by Yiming Liu

Merge pull request #226 from nobodyiam/config-load-policy-change-merge

Use new strategy to load config.
parents 4ef524e0 f2ddfc6d
*.class
.DS_Store
application.pid
# Mobile Tools for Java (J2ME)
.mtj.tmp/
......
......@@ -178,9 +178,13 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
logger.debug("Config server responds with 304 HTTP status code.");
return m_configCache.get();
}
logger.debug("Loaded config: {}", response.getBody());
return response.getBody();
ApolloConfig result = response.getBody();
Cat.logEvent("Apollo.Client.ConfigLoaded." + result.getNamespaceName(), result.getReleaseKey());
logger.debug("Loaded config for {}: {}", m_namespace, result);
return result;
} catch (Throwable ex) {
Cat.logError(ex);
transaction.setStatus(ex);
......
......@@ -25,6 +25,7 @@ public class ConfigUtil {
/**
* Get the app id for the current application.
*
* @return the app id
* @throws IllegalStateException if app id is not set
*/
......@@ -36,18 +37,30 @@ public class ConfigUtil {
/**
* Get the data center info for the current application.
*
* @return the current data center, null if there is no such info.
*/
public String getDataCenter() {
return Foundation.server().getDataCenter();
String dataCenter = Foundation.server().getDataCenter();
//TODO use sub env from framework foundation if data center is null
return dataCenter;
}
/**
* Get the cluster name for the current application.
*
* @return the cluster name, or "default" if not specified
*/
public String getCluster() {
//Load data center from system property
String cluster = System.getProperty("apollo.cluster");
//Use data center as cluster
if (cluster == null) {
cluster = getDataCenter();
}
//Use default cluster
if (cluster == null) {
cluster = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
......@@ -56,6 +69,7 @@ public class ConfigUtil {
/**
* Get the current environment.
*
* @return the env
* @throws IllegalStateException if env is set
*/
......
......@@ -65,15 +65,18 @@ public class ConfigController {
HttpServletResponse response) throws IOException {
List<Release> releases = Lists.newLinkedList();
Release currentAppRelease = configService.findRelease(appId, clusterName, namespace);
Release currentAppRelease = loadConfig(appId, clusterName, namespace, dataCenter);
String appClusterNameLoaded = clusterName;
if (currentAppRelease != null) {
releases.add(currentAppRelease);
//we have cluster search process, so the cluster name might be overridden
appClusterNameLoaded = currentAppRelease.getClusterName();
}
//if namespace is not 'application', should check if it's a public configuration
if (!Objects.equals(ConfigConsts.NAMESPACE_DEFAULT, namespace)) {
Release publicRelease = this.findPublicConfig(appId, namespace, dataCenter);
Release publicRelease = this.findPublicConfig(appId, clusterName, namespace, dataCenter);
if (!Objects.isNull(publicRelease)) {
releases.add(publicRelease);
}
......@@ -96,14 +99,14 @@ public class ConfigController {
// Client side configuration is the same with server side, return 304
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
Cat.logEvent("Apollo.Config.NotModified",
assembleKey(appId, clusterName, namespace, dataCenter));
assembleKey(appId, appClusterNameLoaded, namespace, dataCenter));
return null;
}
ApolloConfig apolloConfig = new ApolloConfig(appId, clusterName, namespace, mergedReleaseKey);
ApolloConfig apolloConfig = new ApolloConfig(appId, appClusterNameLoaded, namespace, mergedReleaseKey);
apolloConfig.setConfigurations(mergeReleaseConfigurations(releases));
Cat.logEvent("Apollo.Config.Found", assembleKey(appId, clusterName, namespace, dataCenter));
Cat.logEvent("Apollo.Config.Found", assembleKey(appId, appClusterNameLoaded, namespace, dataCenter));
return apolloConfig;
}
......@@ -112,7 +115,7 @@ public class ConfigController {
* @param namespace the namespace
* @param dataCenter the datacenter
*/
private Release findPublicConfig(String applicationId, String namespace, String dataCenter) {
private Release findPublicConfig(String applicationId, String clusterName, String namespace, String dataCenter) {
AppNamespace appNamespace = appNamespaceService.findByNamespaceName(namespace);
//check whether the namespace's appId equals to current one
......@@ -122,10 +125,24 @@ public class ConfigController {
String publicConfigAppId = appNamespace.getAppId();
return loadConfig(publicConfigAppId, clusterName, namespace, dataCenter);
}
private Release loadConfig(String appId, String clusterName, String namespace, String dataCenter) {
//load from specified cluster fist
if (!Objects.equals(ConfigConsts.CLUSTER_NAME_DEFAULT, clusterName)) {
Release clusterRelease =
configService.findRelease(appId, clusterName, namespace);
if (!Objects.isNull(clusterRelease)) {
return clusterRelease;
}
}
//try to load via data center
if (!Objects.isNull(dataCenter)) {
if (!Objects.isNull(dataCenter) && !Objects.equals(dataCenter, clusterName)) {
Release dataCenterRelease =
configService.findRelease(publicConfigAppId, dataCenter, namespace);
configService.findRelease(appId, dataCenter, namespace);
if (!Objects.isNull(dataCenterRelease)) {
return dataCenterRelease;
}
......@@ -133,7 +150,7 @@ public class ConfigController {
//fallback to default release
return configService
.findRelease(publicConfigAppId, ConfigConsts.CLUSTER_NAME_DEFAULT, namespace);
.findRelease(appId, ConfigConsts.CLUSTER_NAME_DEFAULT, namespace);
}
/**
......
......@@ -7,6 +7,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.common.collect.Sets;
import com.ctrip.framework.apollo.biz.entity.AppNamespace;
import com.ctrip.framework.apollo.biz.message.MessageListener;
......@@ -30,6 +31,7 @@ import org.springframework.web.context.request.async.DeferredResult;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
* @author Jason Song(song_s@ctrip.com)
......@@ -59,11 +61,11 @@ public class NotificationController implements MessageListener {
@RequestParam(value = "cluster") String cluster,
@RequestParam(value = "namespace", defaultValue = ConfigConsts.NAMESPACE_DEFAULT) String namespace,
@RequestParam(value = "dataCenter", required = false) String dataCenter) {
List<String> watchedKeys = Lists.newArrayList(assembleKey(appId, cluster, namespace));
Set<String> watchedKeys = assembleWatchKeys(appId, cluster, namespace, dataCenter);
//Listen on more namespaces, since it's not the default namespace
if (!Objects.equals(ConfigConsts.NAMESPACE_DEFAULT, namespace)) {
watchedKeys.addAll(this.findPublicConfigWatchKey(appId, namespace, dataCenter));
watchedKeys.addAll(this.findPublicConfigWatchKey(appId, cluster, namespace, dataCenter));
}
DeferredResult<ResponseEntity<ApolloConfigNotification>> deferredResult =
......@@ -94,9 +96,9 @@ public class NotificationController implements MessageListener {
return STRING_JOINER.join(appId, cluster, namespace);
}
private List<String> findPublicConfigWatchKey(String applicationId, String namespace,
String dataCenter) {
List<String> publicWatchedKeys = Lists.newArrayList();
private Set<String> findPublicConfigWatchKey(String applicationId, String clusterName,
String namespace,
String dataCenter) {
AppNamespace appNamespace = appNamespaceService.findByNamespaceName(namespace);
/**
* Manually close the entity manager.
......@@ -108,21 +110,32 @@ public class NotificationController implements MessageListener {
//check whether the namespace's appId equals to current one
if (Objects.isNull(appNamespace) || Objects.equals(applicationId, appNamespace.getAppId())) {
return publicWatchedKeys;
return Sets.newHashSet();
}
String publicConfigAppId = appNamespace.getAppId();
return assembleWatchKeys(publicConfigAppId, clusterName, namespace, dataCenter);
}
private Set<String> assembleWatchKeys(String appId, String clusterName, String namespace,
String dataCenter) {
Set<String> watchedKeys = Sets.newHashSet();
//watch specified cluster config change
if (!Objects.equals(ConfigConsts.CLUSTER_NAME_DEFAULT, clusterName)) {
watchedKeys.add(assembleKey(appId, clusterName, namespace));
}
//watch data center config change
if (!Objects.isNull(dataCenter)) {
publicWatchedKeys.add(assembleKey(publicConfigAppId, dataCenter, namespace));
if (!Objects.isNull(dataCenter) && !Objects.equals(dataCenter, clusterName)) {
watchedKeys.add(assembleKey(appId, dataCenter, namespace));
}
//watch default cluster config change
publicWatchedKeys
.add(assembleKey(publicConfigAppId, ConfigConsts.CLUSTER_NAME_DEFAULT, namespace));
watchedKeys.add(assembleKey(appId, ConfigConsts.CLUSTER_NAME_DEFAULT, namespace));
return publicWatchedKeys;
return watchedKeys;
}
@Override
......@@ -154,7 +167,7 @@ public class NotificationController implements MessageListener {
logger.info("Notification completed");
}
private void logWatchedKeysToCat(List<String> watchedKeys, String eventName) {
private void logWatchedKeysToCat(Set<String> watchedKeys, String eventName) {
for (String watchedKey : watchedKeys) {
Cat.logEvent(eventName, watchedKey);
}
......
......@@ -45,6 +45,7 @@ public class ConfigControllerTest {
private AppNamespaceService appNamespaceService;
private String someAppId;
private String someClusterName;
private String defaultClusterName;
private String defaultNamespaceName;
private String somePublicNamespaceName;
private String someDataCenter;
......@@ -61,12 +62,14 @@ public class ConfigControllerTest {
someAppId = "1";
someClusterName = "someClusterName";
defaultClusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
defaultNamespaceName = ConfigConsts.NAMESPACE_DEFAULT;
somePublicNamespaceName = "somePublicNamespace";
someDataCenter = "someDC";
String someValidConfiguration = "{\"apollo.bar\": \"foo\"}";
String somePublicConfiguration = "{\"apollo.public.bar\": \"foo\"}";
when(someRelease.getClusterName()).thenReturn(someClusterName);
when(someRelease.getConfigurations()).thenReturn(someValidConfiguration);
when(somePublicRelease.getConfigurations()).thenReturn(somePublicConfiguration);
}
......@@ -129,6 +132,55 @@ public class ConfigControllerTest {
}
@Test
public void testQueryConfigWithDefaultClusterWithDataCenterRelease() throws Exception {
String someClientSideReleaseKey = "1";
String someServerSideNewReleaseKey = "2";
HttpServletResponse someResponse = mock(HttpServletResponse.class);
when(configService.findRelease(someAppId, someDataCenter, defaultNamespaceName))
.thenReturn(someRelease);
when(someRelease.getReleaseKey()).thenReturn(someServerSideNewReleaseKey);
when(someRelease.getClusterName()).thenReturn(someDataCenter);
ApolloConfig result = configController.queryConfig(someAppId, defaultClusterName,
defaultNamespaceName, someDataCenter, someClientSideReleaseKey,
someResponse);
verify(configService, times(1)).findRelease(someAppId, someDataCenter, defaultNamespaceName);
assertEquals(someAppId, result.getAppId());
assertEquals(someDataCenter, result.getCluster());
assertEquals(defaultNamespaceName, result.getNamespaceName());
assertEquals(someServerSideNewReleaseKey, result.getReleaseKey());
}
@Test
public void testQueryConfigWithDefaultClusterWithNoDataCenterRelease() throws Exception {
String someClientSideReleaseKey = "1";
String someServerSideNewReleaseKey = "2";
HttpServletResponse someResponse = mock(HttpServletResponse.class);
when(configService.findRelease(someAppId, someDataCenter, defaultNamespaceName))
.thenReturn(null);
when(configService.findRelease(someAppId, defaultClusterName, defaultNamespaceName))
.thenReturn(someRelease);
when(someRelease.getReleaseKey()).thenReturn(someServerSideNewReleaseKey);
when(someRelease.getClusterName()).thenReturn(defaultClusterName);
ApolloConfig result = configController.queryConfig(someAppId, defaultClusterName,
defaultNamespaceName, someDataCenter, someClientSideReleaseKey,
someResponse);
verify(configService, times(1)).findRelease(someAppId, someDataCenter, defaultNamespaceName);
verify(configService, times(1)).findRelease(someAppId, defaultClusterName, defaultNamespaceName);
assertEquals(someAppId, result.getAppId());
assertEquals(defaultClusterName, result.getCluster());
assertEquals(defaultNamespaceName, result.getNamespaceName());
assertEquals(someServerSideNewReleaseKey, result.getReleaseKey());
}
@Test
public void testQueryConfigWithAppOwnNamespace() throws Exception {
String someClientSideReleaseKey = "1";
String someServerSideReleaseKey = "2";
......
......@@ -35,6 +35,7 @@ public class NotificationControllerTest {
private NotificationController controller;
private String someAppId;
private String someCluster;
private String defaultCluster;
private String defaultNamespace;
private String somePublicNamespace;
private String someDataCenter;
......@@ -53,6 +54,7 @@ public class NotificationControllerTest {
someAppId = "someAppId";
someCluster = "someCluster";
defaultCluster = ConfigConsts.CLUSTER_NAME_DEFAULT;
defaultNamespace = ConfigConsts.NAMESPACE_DEFAULT;
somePublicNamespace = "somePublicNamespace";
someDataCenter = "someDC";
......@@ -68,11 +70,58 @@ public class NotificationControllerTest {
deferredResult = controller
.pollNotification(someAppId, someCluster, defaultNamespace, someDataCenter);
String key =
Joiner.on(ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR)
.join(someAppId, someCluster, defaultNamespace);
assertEquals(1, deferredResults.size());
assertTrue(deferredResults.get(key).contains(deferredResult));
List<String> clusters =
Lists.newArrayList(someCluster, someDataCenter, ConfigConsts.CLUSTER_NAME_DEFAULT);
assertEquals(clusters.size(), deferredResults.size());
for (String cluster : clusters) {
String key =
Joiner.on(ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR)
.join(someAppId, cluster, defaultNamespace);
assertTrue(deferredResults.get(key).contains(deferredResult));
}
}
@Test
public void testPollNotificationWithDefaultNamespaceWithDefaultClusterWithDataCenter()
throws Exception {
DeferredResult<ResponseEntity<ApolloConfigNotification>>
deferredResult = controller
.pollNotification(someAppId, defaultCluster, defaultNamespace, someDataCenter);
List<String> clusters =
Lists.newArrayList(someDataCenter, defaultCluster);
assertEquals(clusters.size(), deferredResults.size());
for (String cluster : clusters) {
String key =
Joiner.on(ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR)
.join(someAppId, cluster, defaultNamespace);
assertTrue(deferredResults.get(key).contains(deferredResult));
}
}
@Test
public void testPollNotificationWithDefaultNamespaceWithDefaultClusterWithNoDataCenter()
throws Exception {
DeferredResult<ResponseEntity<ApolloConfigNotification>>
deferredResult = controller
.pollNotification(someAppId, defaultCluster, defaultNamespace, null);
List<String> clusters =
Lists.newArrayList(defaultCluster);
assertEquals(clusters.size(), deferredResults.size());
for (String cluster : clusters) {
String key =
Joiner.on(ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR)
.join(someAppId, cluster, defaultNamespace);
assertTrue(deferredResults.get(key).contains(deferredResult));
}
}
@Test
......@@ -88,16 +137,19 @@ public class NotificationControllerTest {
deferredResult = controller
.pollNotification(someAppId, someCluster, somePublicNamespace, someDataCenter);
List<String> publicClusters =
Lists.newArrayList(someDataCenter, ConfigConsts.CLUSTER_NAME_DEFAULT);
List<String> clusters =
Lists.newArrayList(someCluster, someDataCenter, ConfigConsts.CLUSTER_NAME_DEFAULT);
assertEquals(3, deferredResults.size());
String key =
Joiner.on(ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR)
.join(someAppId, someCluster, somePublicNamespace);
assertTrue(deferredResults.get(key).contains(deferredResult));
assertEquals(clusters.size() * 2, deferredResults.size());
for (String cluster : clusters) {
String publicKey =
Joiner.on(ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR)
.join(someAppId, cluster, somePublicNamespace);
assertTrue(deferredResults.get(publicKey).contains(deferredResult));
}
for (String cluster : publicClusters) {
for (String cluster : clusters) {
String publicKey =
Joiner.on(ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR)
.join(somePublicAppId, cluster, somePublicNamespace);
......
......@@ -110,6 +110,7 @@ public class ConfigControllerIntegrationTest extends AbstractBaseIntegrationTest
@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 testQueryPublicConfigWithDataCenterFoundAndOverride() throws Exception {
ResponseEntity<ApolloConfig> response = restTemplate
......@@ -118,11 +119,13 @@ public class ConfigControllerIntegrationTest extends AbstractBaseIntegrationTest
getHostUrl(), someAppId, someDefaultCluster, somePublicNamespace, someDC);
ApolloConfig result = response.getBody();
assertEquals("TEST-RELEASE-KEY5" + ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR + "TEST-RELEASE-KEY4", result.getReleaseKey());
assertEquals(
"TEST-RELEASE-KEY6" + ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR + "TEST-RELEASE-KEY4",
result.getReleaseKey());
assertEquals(someAppId, result.getAppId());
assertEquals(someDefaultCluster, result.getCluster());
assertEquals(someDC, result.getCluster());
assertEquals(somePublicNamespace, result.getNamespaceName());
assertEquals("override-v1", result.getConfigurations().get("k1"));
assertEquals("override-someDC-v1", result.getConfigurations().get("k1"));
assertEquals("someDC-v2", result.getConfigurations().get("k2"));
}
......@@ -147,6 +150,7 @@ public class ConfigControllerIntegrationTest extends AbstractBaseIntegrationTest
@Test
@Sql(scripts = "/integration-test/test-release.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql(scripts = "/integration-test/test-release-public-default-override.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql(scripts = "/integration-test/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
public void testQueryPublicConfigWithDataCenterNotFoundAndOverride() throws Exception {
String someDCNotFound = "someDCNotFound";
......@@ -156,7 +160,9 @@ public class ConfigControllerIntegrationTest extends AbstractBaseIntegrationTest
getHostUrl(), someAppId, someDefaultCluster, somePublicNamespace, someDCNotFound);
ApolloConfig result = response.getBody();
assertEquals("TEST-RELEASE-KEY5" + ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR + "TEST-RELEASE-KEY3", result.getReleaseKey());
assertEquals(
"TEST-RELEASE-KEY5" + ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR + "TEST-RELEASE-KEY3",
result.getReleaseKey());
assertEquals(someAppId, result.getAppId());
assertEquals(someDefaultCluster, result.getCluster());
assertEquals(somePublicNamespace, result.getNamespaceName());
......
INSERT INTO RELEASE (id, ReleaseKey, Name, Comment, AppId, ClusterName, NamespaceName, Configurations)
VALUES (995, 'TEST-RELEASE-KEY6', 'INTEGRATION-TEST-DEFAULT-OVERRIDE-PUBLIC-DC','First Release','someAppId', 'someDC', 'somePublicNamespace', '{"k1":"override-someDC-v1"}');
INSERT INTO RELEASE (id, ReleaseKey, Name, Comment, AppId, ClusterName, NamespaceName, Configurations)
VALUES (994, 'TEST-RELEASE-KEY5', 'INTEGRATION-TEST-DEFAULT-OVERRIDE-PUBLIC','First Release','someAppId', 'default', 'somePublicNamespace', '{"k1":"override-v1"}');
......@@ -25,5 +25,3 @@ INSERT INTO RELEASE (id, ReleaseKey, Name, Comment, AppId, ClusterName, Namespac
VALUES (992, 'TEST-RELEASE-KEY3', 'INTEGRATION-TEST-PUBLIC-DEFAULT','First Release','somePublicAppId', 'default', 'somePublicNamespace', '{"k1":"default-v1", "k2":"default-v2"}');
INSERT INTO RELEASE (id, ReleaseKey, Name, Comment, AppId, ClusterName, NamespaceName, Configurations)
VALUES (993, 'TEST-RELEASE-KEY4', 'INTEGRATION-TEST-PUBLIC-NAMESPACE','First Release','somePublicAppId', 'someDC', 'somePublicNamespace', '{"k1":"someDC-v1", "k2":"someDC-v2"}');
INSERT INTO RELEASE (id, ReleaseKey, Name, Comment, AppId, ClusterName, NamespaceName, Configurations)
VALUES (994, 'TEST-RELEASE-KEY5', 'INTEGRATION-TEST-DEFAULT-OVERRIDE-PUBLIC','First Release','someAppId', 'default', 'somePublicNamespace', '{"k1":"override-v1"}');
19575
\ No newline at end of file
......@@ -139,7 +139,7 @@
<dependency>
<groupId>com.ctrip.framework</groupId>
<artifactId>framework-foundation</artifactId>
<version>1.1.5</version>
<version>1.1.6</version>
</dependency>
<dependency>
<groupId>com.dianping.cat</groupId>
......
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