提交 3d0186e1 编写于 作者: Y Yiming Liu

Merge pull request #141 from nobodyiam/client-refactor-service-integration

Client refactor, Config service integration test.
......@@ -13,6 +13,81 @@ public interface Config {
*/
public String getProperty(String key, String defaultValue);
/**
* Return the integer property value with the given key, or
* {@code defaultValue} if the key doesn't exist.
* @param key the property name
* @param defaultValue the default value is key is not found
* @return the property value as integer
*
* @throws NumberFormatException if the property value is invalid
*/
public Integer getIntProperty(String key, Integer defaultValue);
/**
* Return the long property value with the given key, or
* {@code defaultValue} if the key doesn't exist.
* @param key the property name
* @param defaultValue the default value is key is not found
* @return the property value as long
*
* @throws NumberFormatException if the property value is invalid
*/
public Long getLongProperty(String key, Long defaultValue);
/**
* Return the short property value with the given key, or
* {@code defaultValue} if the key doesn't exist.
* @param key the property name
* @param defaultValue the default value is key is not found
* @return the property value as short
*
* @throws NumberFormatException if the property value is invalid
*/
public Short getShortProperty(String key, Short defaultValue);
/**
* Return the float property value with the given key, or
* {@code defaultValue} if the key doesn't exist.
* @param key the property name
* @param defaultValue the default value is key is not found
* @return the property value as float
*
* @throws NumberFormatException if the property value is invalid
*/
public Float getFloatProperty(String key, Float defaultValue);
/**
* Return the double property value with the given key, or
* {@code defaultValue} if the key doesn't exist.
* @param key the property name
* @param defaultValue the default value is key is not found
* @return the property value as double
*
* @throws NumberFormatException if the property value is invalid
*/
public Double getDoubleProperty(String key, Double defaultValue);
/**
* Return the byte property value with the given key, or
* {@code defaultValue} if the key doesn't exist.
* @param key the property name
* @param defaultValue the default value is key is not found
* @return the property value as byte
*
* @throws NumberFormatException if the property value is invalid
*/
public Byte getByteProperty(String key, Byte defaultValue);
/**
* Return the boolean property value with the given key, or
* {@code defaultValue} if the key doesn't exist.
* @param key the property name
* @param defaultValue the default value is key is not found
* @return the property value as boolean
*/
public Boolean getBooleanProperty(String key, Boolean defaultValue);
/**
* Add change listener to this config instance.
* @param listener the config change listener
......
package com.ctrip.apollo;
import com.ctrip.apollo.core.ConfigConsts;
import com.ctrip.apollo.internals.ConfigManager;
import com.ctrip.apollo.spi.ConfigFactory;
import com.ctrip.apollo.spi.ConfigRegistry;
......@@ -24,11 +25,11 @@ public class ConfigService {
}
/**
* Get the config instance with default namespace.
* Get Application's config instance.
* @return config instance
*/
public static Config getConfig() {
return getConfig(getDefaultNamespace());
public static Config getAppConfig() {
return getConfig(ConfigConsts.NAMESPACE_DEFAULT);
}
/**
......@@ -59,17 +60,8 @@ public class ConfigService {
}
}
private static String getDefaultNamespace() {
try {
return s_instance.m_container.lookup(ConfigUtil.class).getAppId();
} catch (ComponentLookupException ex) {
Cat.logError(ex);
throw new IllegalStateException("Unable to load ConfigUtil!", ex);
}
}
public static void setConfig(Config config) {
setConfig(getDefaultNamespace(), config);
static void setConfig(Config config) {
setConfig(ConfigConsts.NAMESPACE_DEFAULT, config);
}
/**
......@@ -77,7 +69,7 @@ public class ConfigService {
* @param namespace the namespace
* @param config the config instance
*/
public static void setConfig(String namespace, final Config config) {
static void setConfig(String namespace, final Config config) {
getRegistry().register(namespace, new ConfigFactory() {
@Override
public Config create(String namespace) {
......@@ -86,8 +78,8 @@ public class ConfigService {
});
}
public static void setConfigFactory(ConfigFactory factory) {
setConfigFactory(getDefaultNamespace(), factory);
static void setConfigFactory(ConfigFactory factory) {
setConfigFactory(ConfigConsts.NAMESPACE_DEFAULT, factory);
}
/**
......@@ -95,12 +87,12 @@ public class ConfigService {
* @param namespace the namespace
* @param factory the factory instance
*/
public static void setConfigFactory(String namespace, ConfigFactory factory) {
static void setConfigFactory(String namespace, ConfigFactory factory) {
getRegistry().register(namespace, factory);
}
// for test only
public static void setContainer(PlexusContainer m_container) {
static void setContainer(PlexusContainer m_container) {
s_instance.m_container = m_container;
}
}
......@@ -5,5 +5,5 @@ package com.ctrip.apollo.enums;
* @author Jason Song(song_s@ctrip.com)
*/
public enum PropertyChangeType {
NEW, MODIFIED, DELETED
ADDED, MODIFIED, DELETED
}
package com.ctrip.apollo.env;
import com.google.common.base.Strings;
import com.ctrip.apollo.core.enums.Env;
import com.ctrip.framework.foundation.Foundation;
public class ClientEnvironment {
private static Env s_env;
private static String s_appId;
private static String s_cluster;
static {
setEnv(Foundation.server().getEnvType());
s_appId = Foundation.app().getAppId();
s_cluster = System.getProperty("apollo.cluster");
}
public static String getAppId() {
return s_appId;
}
public static Env getEnv() {
return s_env;
}
public static String getCluster() {
return s_cluster;
}
private static void setEnv(String envName) {
if (Strings.isNullOrEmpty(envName)) {
return;
}
switch (envName.toUpperCase()) {
case "LPT":
s_env = Env.LPT;
break;
case "FAT":
case "FWS":
s_env = Env.FAT;
break;
case "UAT":
s_env = Env.UAT;
break;
case "PRO":
s_env = Env.PRO;
break;
case "DEV":
s_env = Env.DEV;
break;
case "LOCAL":
s_env = Env.LOCAL;
break;
default:
//do nothing
break;
}
}
}
......@@ -32,6 +32,48 @@ public abstract class AbstractConfig implements Config {
}
}
@Override
public Integer getIntProperty(String key, Integer defaultValue) {
String value = getProperty(key, null);
return value == null ? defaultValue : Integer.parseInt(value);
}
@Override
public Long getLongProperty(String key, Long defaultValue) {
String value = getProperty(key, null);
return value == null ? defaultValue : Long.parseLong(value);
}
@Override
public Short getShortProperty(String key, Short defaultValue) {
String value = getProperty(key, null);
return value == null ? defaultValue : Short.parseShort(value);
}
@Override
public Float getFloatProperty(String key, Float defaultValue) {
String value = getProperty(key, null);
return value == null ? defaultValue : Float.parseFloat(value);
}
@Override
public Double getDoubleProperty(String key, Double defaultValue) {
String value = getProperty(key, null);
return value == null ? defaultValue : Double.parseDouble(value);
}
@Override
public Byte getByteProperty(String key, Byte defaultValue) {
String value = getProperty(key, null);
return value == null ? defaultValue : Byte.parseByte(value);
}
@Override
public Boolean getBooleanProperty(String key, Boolean defaultValue) {
String value = getProperty(key, null);
return value == null ? defaultValue : Boolean.parseBoolean(value);
}
protected void fireConfigChange(ConfigChangeEvent changeEvent) {
for (ConfigChangeListener listener : m_listeners) {
try {
......@@ -43,7 +85,8 @@ public abstract class AbstractConfig implements Config {
}
}
List<ConfigChange> calcPropertyChanges(Properties previous,
List<ConfigChange> calcPropertyChanges(String namespace,
Properties previous,
Properties current) {
if (previous == null) {
previous = new Properties();
......@@ -64,11 +107,12 @@ public abstract class AbstractConfig implements Config {
for (String newKey : newKeys) {
changes
.add(new ConfigChange(newKey, null, current.getProperty(newKey), PropertyChangeType.NEW));
.add(new ConfigChange(namespace, newKey, null, current.getProperty(newKey),
PropertyChangeType.ADDED));
}
for (String removedKey : removedKeys) {
changes.add(new ConfigChange(removedKey, previous.getProperty(removedKey), null,
changes.add(new ConfigChange(namespace, removedKey, previous.getProperty(removedKey), null,
PropertyChangeType.DELETED));
}
......@@ -78,7 +122,7 @@ public abstract class AbstractConfig implements Config {
if (Objects.equal(previousValue, currentValue)) {
continue;
}
changes.add(new ConfigChange(commonKey, previousValue,
changes.add(new ConfigChange(namespace, commonKey, previousValue,
currentValue, PropertyChangeType.MODIFIED));
}
......
......@@ -18,15 +18,17 @@ public abstract class AbstractConfigRepository implements ConfigRepository {
private static final Logger logger = LoggerFactory.getLogger(AbstractConfigRepository.class);
private List<RepositoryChangeListener> m_listeners = Lists.newCopyOnWriteArrayList();
protected void trySync() {
protected boolean trySync() {
try {
sync();
return true;
} catch (Throwable ex) {
Cat.logError(ex);
logger
.warn("Sync config failed with repository {}, reason: {}", this.getClass(), ExceptionUtil
.getDetailMessage(ex));
}
return false;
}
protected abstract void sync();
......
......@@ -28,7 +28,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
@Named(type = ConfigServiceLocator.class)
public class ConfigServiceLocator implements Initializable{
public class ConfigServiceLocator implements Initializable {
private static final Logger logger = LoggerFactory.getLogger(ConfigServiceLocator.class);
@Inject
private HttpUtil m_httpUtil;
......@@ -69,12 +69,14 @@ public class ConfigServiceLocator implements Initializable{
return m_configServices.get();
}
private void tryUpdateConfigServices() {
private boolean tryUpdateConfigServices() {
try {
updateConfigServices();
return true;
} catch (Throwable ex) {
//ignore
}
return false;
}
private void schedulePeriodicRefresh() {
......@@ -84,8 +86,9 @@ public class ConfigServiceLocator implements Initializable{
public void run() {
logger.debug("refresh config services");
Transaction transaction = Cat.newTransaction("Apollo.MetaService", "periodicRefresh");
tryUpdateConfigServices();
transaction.setStatus(Message.SUCCESS);
boolean syncResult = tryUpdateConfigServices();
String status = syncResult ? Message.SUCCESS : "-1";
transaction.setStatus(status);
transaction.complete();
}
}, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(),
......@@ -129,8 +132,8 @@ public class ConfigServiceLocator implements Initializable{
}
private void logConfigServicesToCat(List<ServiceDTO> serviceDtos) {
for (ServiceDTO serviceDTO : serviceDtos) {
Cat.logEvent("Apollo.Config.Services", serviceDTO.getHomepageUrl());
for (ServiceDTO serviceDto : serviceDtos) {
Cat.logEvent("Apollo.Config.Services", serviceDto.getHomepageUrl());
}
}
}
......@@ -47,11 +47,14 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
private void initialize() {
try {
m_configProperties.set(m_configRepository.getConfig());
m_configRepository.addChangeListener(this);
} catch (Throwable ex) {
Cat.logError(ex);
logger.warn("Init Apollo Local Config failed - namespace: {}, reason: {}.",
m_namespace, ExceptionUtil.getDetailMessage(ex));
} finally {
//register the change listener no matter config repository is working or not
//so that whenever config repository is recovered, config could get changed
m_configRepository.addChangeListener(this);
}
}
......@@ -108,7 +111,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
private Map<String, ConfigChange> updateAndCalcConfigChanges(Properties newConfigProperties) {
List<ConfigChange> configChanges =
calcPropertyChanges(m_configProperties.get(), newConfigProperties);
calcPropertyChanges(m_namespace, m_configProperties.get(), newConfigProperties);
ImmutableMap.Builder<String, ConfigChange> actualChanges =
new ImmutableMap.Builder<>();
......@@ -127,7 +130,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
for (ConfigChange change : configChanges) {
change.setNewValue(this.getProperty(change.getPropertyName(), change.getNewValue()));
switch (change.getChangeType()) {
case NEW:
case ADDED:
if (Objects.equals(change.getOldValue(), change.getNewValue())) {
break;
}
......
......@@ -99,8 +99,9 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
public void run() {
logger.debug("refresh config for namespace: {}", m_namespace);
Transaction transaction = Cat.newTransaction("Apollo.ConfigService", "periodicRefresh");
trySync();
transaction.setStatus(Message.SUCCESS);
boolean syncSuccess = trySync();
String status = syncSuccess ? Message.SUCCESS : "-1";
transaction.setStatus(status);
transaction.complete();
}
}, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(),
......
......@@ -39,11 +39,14 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList
private void initialize() {
try {
m_configProperties = m_configRepository.getConfig();
m_configRepository.addChangeListener(this);
} catch (Throwable ex) {
Cat.logError(ex);
logger.warn("Init Apollo Simple Config failed - namespace: {}, reason: {}", m_namespace,
ExceptionUtil.getDetailMessage(ex));
} finally {
//register the change listener no matter config repository is working or not
//so that whenever config repository is recovered, config could get changed
m_configRepository.addChangeListener(this);
}
}
......@@ -64,7 +67,9 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList
Properties newConfigProperties = new Properties();
newConfigProperties.putAll(newProperties);
List<ConfigChange> changes = calcPropertyChanges(m_configProperties, newConfigProperties);
List<ConfigChange>
changes =
calcPropertyChanges(namespace, m_configProperties, newConfigProperties);
Map<String, ConfigChange> changeMap = Maps.uniqueIndex(changes,
new Function<ConfigChange, String>() {
@Override
......
......@@ -10,6 +10,7 @@ import com.ctrip.apollo.enums.PropertyChangeType;
* @author Jason Song(song_s@ctrip.com)
*/
public class ConfigChange {
private final String namespace;
private final String propertyName;
private String oldValue;
private String newValue;
......@@ -17,13 +18,15 @@ public class ConfigChange {
/**
* Constructor.
* @param namespace the namespace of the key
* @param propertyName the key whose value is changed
* @param oldValue the value before change
* @param newValue the value after change
* @param changeType the change type
*/
public ConfigChange(String propertyName, String oldValue, String newValue,
public ConfigChange(String namespace, String propertyName, String oldValue, String newValue,
PropertyChangeType changeType) {
this.namespace = namespace;
this.propertyName = propertyName;
this.oldValue = oldValue;
this.newValue = newValue;
......@@ -58,10 +61,15 @@ public class ConfigChange {
this.changeType = changeType;
}
public String getNamespace() {
return namespace;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.omitNullValues()
.add("namespace", namespace)
.add("propertyName", propertyName)
.add("oldValue", oldValue)
.add("newValue", newValue)
......
......@@ -9,7 +9,7 @@ import java.util.Set;
*/
public class ConfigChangeEvent {
private final String m_namespace;
private final Map<String, ConfigChange> changes;
private final Map<String, ConfigChange> m_changes;
/**
* Constructor.
......@@ -19,7 +19,7 @@ public class ConfigChangeEvent {
public ConfigChangeEvent(String namespace,
Map<String, ConfigChange> changes) {
this.m_namespace = namespace;
this.changes = changes;
this.m_changes = changes;
}
/**
......@@ -27,7 +27,7 @@ public class ConfigChangeEvent {
* @return the list of the keys
*/
public Set<String> changedKeys() {
return changes.keySet();
return m_changes.keySet();
}
/**
......@@ -36,16 +36,16 @@ public class ConfigChangeEvent {
* @return the change instance
*/
public ConfigChange getChange(String key) {
return changes.get(key);
return m_changes.get(key);
}
/**
* Get the changes as <Key, Change> map.
* Please note that the returned Map is immutable.
* @return changes
* Check whether the specified key is changed
* @param key the key
* @return true if the key is changed, false otherwise.
*/
public Map<String, ConfigChange> getChanges() {
return changes;
public boolean isChanged(String key) {
return m_changes.containsKey(key);
}
/**
......
package com.ctrip.apollo.util;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.ctrip.apollo.core.ConfigConsts;
import com.ctrip.apollo.core.MetaDomainConsts;
import com.ctrip.apollo.core.enums.Env;
import com.ctrip.apollo.env.ClientEnvironment;
import com.ctrip.framework.foundation.Foundation;
import org.unidal.lookup.annotation.Named;
......@@ -28,7 +29,7 @@ public class ConfigUtil {
* @throws IllegalStateException if app id is not set
*/
public String getAppId() {
String appId = ClientEnvironment.getAppId();
String appId = Foundation.app().getAppId();
Preconditions.checkState(appId != null, "app.id is not set");
return appId;
}
......@@ -38,7 +39,7 @@ public class ConfigUtil {
* @return the cluster name, or "default" if not specified
*/
public String getCluster() {
String cluster = ClientEnvironment.getCluster();
String cluster = System.getProperty("apollo.cluster");
if (cluster == null) {
cluster = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
......@@ -51,11 +52,34 @@ public class ConfigUtil {
* @throws IllegalStateException if env is set
*/
public Env getApolloEnv() {
Env env = ClientEnvironment.getEnv();
Env env = transformEnv(Foundation.server().getEnvType());
Preconditions.checkState(env != null, "env is not set");
return env;
}
private Env transformEnv(String envName) {
if (Strings.isNullOrEmpty(envName)) {
return null;
}
switch (envName.toUpperCase()) {
case "LPT":
return Env.LPT;
case "FAT":
case "FWS":
return Env.FAT;
case "UAT":
return Env.UAT;
case "PRO":
return Env.PRO;
case "DEV":
return Env.DEV;
case "LOCAL":
return Env.LOCAL;
default:
return null;
}
}
public String getMetaServerDomainName() {
return MetaDomainConsts.getDomain(getApolloEnv());
}
......
......@@ -9,6 +9,11 @@ import java.util.List;
* @author Jason Song(song_s@ctrip.com)
*/
public class ExceptionUtil {
/**
* Assemble the detail message for the throwable with all of its cause included (at most 10 causes).
* @param ex the exception
* @return the message along with its causes
*/
public static String getDetailMessage(Throwable ex) {
if (ex == null || Strings.isNullOrEmpty(ex.getMessage())) {
return "";
......
package com.ctrip.apollo.integration;
package com.ctrip.apollo;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
......@@ -34,7 +34,7 @@ import javax.servlet.http.HttpServletResponse;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class BaseIntegrationTest extends ComponentTestCase {
public abstract class BaseIntegrationTest extends ComponentTestCase {
private static final int PORT = findFreePort();
private static final String metaServiceUrl = "http://localhost:" + PORT;
private static final String someAppName = "someAppName";
......
package com.ctrip.apollo;
import com.ctrip.apollo.core.ConfigConsts;
import com.ctrip.apollo.internals.AbstractConfig;
import com.ctrip.apollo.spi.ConfigFactory;
import com.ctrip.apollo.util.ConfigUtil;
......@@ -31,7 +33,7 @@ public class ConfigServiceTest extends ComponentTestCase {
String someKey = "first";
ConfigService.setConfig(new MockConfig(someNamespace));
Config config = ConfigService.getConfig();
Config config = ConfigService.getAppConfig();
assertEquals(someNamespace + ":" + someKey, config.getProperty(someKey, null));
assertEquals(null, config.getProperty("unknown", null));
......@@ -42,9 +44,9 @@ public class ConfigServiceTest extends ComponentTestCase {
String someKey = "someKey";
ConfigService.setConfigFactory(new MockConfigFactory());
Config config = ConfigService.getConfig();
Config config = ConfigService.getAppConfig();
assertEquals(someAppId + ":" + someKey,
assertEquals(ConfigConsts.NAMESPACE_DEFAULT + ":" + someKey,
config.getProperty(someKey, null));
}
......@@ -60,7 +62,7 @@ public class ConfigServiceTest extends ComponentTestCase {
assertEquals(null, config.getProperty("unknown", null));
}
private static class MockConfig implements Config {
private static class MockConfig extends AbstractConfig {
private final String m_namespace;
public MockConfig(String namespace) {
......@@ -75,11 +77,6 @@ public class ConfigServiceTest extends ComponentTestCase {
return m_namespace + ":" + key;
}
@Override
public void addChangeListener(ConfigChangeListener listener) {
}
}
public static class MockConfigFactory implements ConfigFactory {
......
......@@ -5,9 +5,11 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.SettableFuture;
import com.ctrip.apollo.BaseIntegrationTest;
import com.ctrip.apollo.Config;
import com.ctrip.apollo.ConfigChangeListener;
import com.ctrip.apollo.ConfigService;
import com.ctrip.apollo.core.ConfigConsts;
import com.ctrip.apollo.core.dto.ApolloConfig;
import com.ctrip.apollo.core.dto.ApolloConfigNotification;
import com.ctrip.apollo.core.utils.ClassLoaderUtil;
......@@ -37,6 +39,7 @@ import javax.servlet.http.HttpServletResponse;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
* @author Jason Song(song_s@ctrip.com)
......@@ -50,7 +53,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
public void setUp() throws Exception {
super.setUp();
defaultNamespace = someAppId;
defaultNamespace = ConfigConsts.NAMESPACE_DEFAULT;
someReleaseId = "1";
configDir = new File(ClassLoaderUtil.getClassPath() + "config-cache");
configDir.mkdirs();
......@@ -90,7 +93,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
ContextHandler handler = mockConfigServerHandler(HttpServletResponse.SC_OK, apolloConfig);
startServerWithHandlers(handler);
Config config = ConfigService.getConfig();
Config config = ConfigService.getAppConfig();
assertEquals(someValue, config.getProperty(someKey, null));
assertEquals(someDefaultValue, config.getProperty(someNonExistedKey, someDefaultValue));
......@@ -109,7 +112,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
ContextHandler handler = mockConfigServerHandler(HttpServletResponse.SC_OK, apolloConfig);
startServerWithHandlers(handler);
Config config = ConfigService.getConfig();
Config config = ConfigService.getAppConfig();
assertEquals(anotherValue, config.getProperty(someKey, null));
}
......@@ -120,7 +123,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
mockConfigServerHandler(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null);
startServerWithHandlers(handler);
Config config = ConfigService.getConfig();
Config config = ConfigService.getAppConfig();
String someKey = "someKey";
String someDefaultValue = "defaultValue" + Math.random();
......@@ -140,7 +143,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
mockConfigServerHandler(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null);
startServerWithHandlers(handler);
Config config = ConfigService.getConfig();
Config config = ConfigService.getAppConfig();
assertEquals(someValue, config.getProperty(someKey, null));
}
......@@ -154,7 +157,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
ContextHandler metaServerHandler = mockMetaServerHandler(failAtFirstTime);
startServerWithHandlers(metaServerHandler, configHandler);
Config config = ConfigService.getConfig();
Config config = ConfigService.getAppConfig();
assertEquals(someValue, config.getProperty(someKey, null));
}
......@@ -169,7 +172,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
mockConfigServerHandler(HttpServletResponse.SC_OK, apolloConfig, failedAtFirstTime);
startServerWithHandlers(handler);
Config config = ConfigService.getConfig();
Config config = ConfigService.getAppConfig();
assertEquals(someValue, config.getProperty(someKey, null));
}
......@@ -192,7 +195,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
ContextHandler handler = mockConfigServerHandler(HttpServletResponse.SC_OK, apolloConfig);
startServerWithHandlers(handler);
Config config = ConfigService.getConfig();
Config config = ConfigService.getAppConfig();
final List<ConfigChangeEvent> changeEvents = Lists.newArrayList();
final SettableFuture<Boolean> refreshFinished = SettableFuture.create();
......@@ -205,7 +208,8 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
if (counter.incrementAndGet() > 1) {
return;
}
assertEquals(1, changeEvent.getChanges().size());
assertEquals(1, changeEvent.changedKeys().size());
assertTrue(changeEvent.isChanged(someKey));
assertEquals(someValue, changeEvent.getChange(someKey).getOldValue());
assertEquals(anotherValue, changeEvent.getChange(someKey).getNewValue());
// if there is any assertion failed above, this line won't be executed
......@@ -242,7 +246,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
startServerWithHandlers(configHandler, pollHandler);
Config config = ConfigService.getConfig();
Config config = ConfigService.getAppConfig();
assertEquals(someValue, config.getProperty(someKey, null));
final SettableFuture<Boolean> longPollFinished = SettableFuture.create();
......
......@@ -56,17 +56,11 @@ public class DefaultConfigManagerTest extends ComponentTestCase {
return new ConfigFactory() {
@Override
public Config create(final String namespace) {
return new Config() {
return new AbstractConfig() {
@Override
public String getProperty(String key, String defaultValue) {
return namespace + ":" + key;
}
@Override
public void addChangeListener(ConfigChangeListener listener) {
}
};
}
};
......
......@@ -156,7 +156,7 @@ public class DefaultConfigTest {
ConfigChangeEvent changeEvent = captor.getValue();
assertEquals(someNamespace, changeEvent.getNamespace());
assertEquals(4, changeEvent.getChanges().size());
assertEquals(4, changeEvent.changedKeys().size());
ConfigChange anotherKeyChange = changeEvent.getChange(anotherKey);
assertEquals(someLocalFileValue, anotherKeyChange.getOldValue());
......@@ -176,6 +176,6 @@ public class DefaultConfigTest {
ConfigChange newKeyChange = changeEvent.getChange(newKey);
assertEquals(null, newKeyChange.getOldValue());
assertEquals(newValue, newKeyChange.getNewValue());
assertEquals(PropertyChangeType.NEW, newKeyChange.getChangeType());
assertEquals(PropertyChangeType.ADDED, newKeyChange.getChangeType());
}
}
......@@ -93,7 +93,7 @@ public class SimpleConfigTest {
ConfigChangeEvent changeEvent = captor.getValue();
assertEquals(someNamespace, changeEvent.getNamespace());
assertEquals(3, changeEvent.getChanges().size());
assertEquals(3, changeEvent.changedKeys().size());
ConfigChange someKeyChange = changeEvent.getChange(someKey);
assertEquals(someValue, someKeyChange.getOldValue());
......@@ -108,6 +108,6 @@ public class SimpleConfigTest {
ConfigChange newKeyChange = changeEvent.getChange(newKey);
assertEquals(null, newKeyChange.getOldValue());
assertEquals(newValue, newKeyChange.getNewValue());
assertEquals(PropertyChangeType.NEW, newKeyChange.getChangeType());
assertEquals(PropertyChangeType.ADDED, newKeyChange.getChangeType());
}
}
......@@ -25,6 +25,7 @@ public class ConfigServiceAutoConfiguration {
private String host;
@Value("${apollo.redis.port}")
private int port;
@Bean
public JedisConnectionFactory redisConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory();
......
package com.ctrip.apollo.configservice;
import com.ctrip.apollo.biz.service.AppService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;
import com.ctrip.apollo.biz.service.AppService;
@Component
public class ConfigServiceHealthIndicator implements HealthIndicator {
......
package com.ctrip.apollo.configservice.controller;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
......@@ -9,7 +10,9 @@ import com.google.gson.reflect.TypeToken;
import com.ctrip.apollo.biz.entity.Release;
import com.ctrip.apollo.biz.service.ConfigService;
import com.ctrip.apollo.core.ConfigConsts;
import com.ctrip.apollo.core.dto.ApolloConfig;
import com.dianping.cat.Cat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
......@@ -45,8 +48,8 @@ public class ConfigController {
@RequestParam(value = "datacenter", required = false) String datacenter,
@RequestParam(value = "releaseId", defaultValue = "-1") String clientSideReleaseId,
HttpServletResponse response) throws IOException {
//default namespace is appId
return this.queryConfig(appId, clusterName, appId, datacenter, clientSideReleaseId, response);
return this.queryConfig(appId, clusterName, ConfigConsts.NAMESPACE_DEFAULT, datacenter,
clientSideReleaseId, response);
}
@RequestMapping(value = "/{appId}/{clusterName}/{namespace}", method = RequestMethod.GET)
......@@ -64,7 +67,7 @@ public class ConfigController {
}
//if namespace is not appId itself, should check if it has its own configurations
if (!Objects.equals(appId, namespace)) {
if (!Objects.equals(ConfigConsts.NAMESPACE_DEFAULT, namespace)) {
//TODO find id for this particular namespace, if not equal to current app id, then do more
if (!Objects.isNull(datacenter)) {
//TODO load newAppId+datacenter+namespace configurations
......@@ -77,6 +80,8 @@ public class ConfigController {
String.format(
"Could not load configurations with appId: %s, clusterName: %s, namespace: %s",
appId, clusterName, namespace));
Cat.logEvent("Apollo.Config.NotFound",
assembleKey(appId, clusterName, namespace, datacenter));
return null;
}
......@@ -86,20 +91,21 @@ public class ConfigController {
if (mergedReleaseId.equals(clientSideReleaseId)) {
// 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));
return null;
}
ApolloConfig apolloConfig = new ApolloConfig(appId, clusterName, namespace, mergedReleaseId);
apolloConfig.setConfigurations(mergeReleaseConfigurations(releases));
Cat.logEvent("Apollo.Config.Found", assembleKey(appId, clusterName, namespace, datacenter));
return apolloConfig;
}
/**
* Merge configurations of releases.
* Release in lower index override those in higher index
* @param releases
* @return
*/
Map<String, String> mergeReleaseConfigurations(List<Release> releases) {
Map<String, String> result = Maps.newHashMap();
......@@ -109,4 +115,12 @@ public class ConfigController {
return result;
}
private String assembleKey(String appId, String cluster, String namespace, String datacenter) {
String key = String.format("%s-%s-%s", appId, cluster, namespace);
if (!Strings.isNullOrEmpty(datacenter)) {
key += "-" + datacenter;
}
return key;
}
}
......@@ -8,10 +8,14 @@ import com.google.common.collect.Multimaps;
import com.ctrip.apollo.biz.message.MessageListener;
import com.ctrip.apollo.biz.message.Topics;
import com.ctrip.apollo.core.ConfigConsts;
import com.ctrip.apollo.core.dto.ApolloConfigNotification;
import com.dianping.cat.Cat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
......@@ -31,27 +35,23 @@ import javax.servlet.http.HttpServletResponse;
@RequestMapping("/notifications")
public class NotificationController implements MessageListener {
private static final Logger logger = LoggerFactory.getLogger(NotificationController.class);
private final static long TIMEOUT = 360 * 60 * 1000;//6 hours
private final Multimap<String, DeferredResult<ApolloConfigNotification>> deferredResults =
private static final long TIMEOUT = 360 * 60 * 1000;//6 hours
private final Multimap<String, DeferredResult<ResponseEntity<ApolloConfigNotification>>>
deferredResults =
Multimaps.synchronizedSetMultimap(HashMultimap.create());
@RequestMapping(method = RequestMethod.GET)
public DeferredResult<ApolloConfigNotification> pollNotification(
public DeferredResult<ResponseEntity<ApolloConfigNotification>> pollNotification(
@RequestParam(value = "appId") String appId,
@RequestParam(value = "cluster") String cluster,
@RequestParam(value = "namespace", required = false) String namespace,
@RequestParam(value = "namespace", defaultValue = ConfigConsts.NAMESPACE_DEFAULT) String namespace,
@RequestParam(value = "datacenter", required = false) String datacenter,
@RequestParam(value = "releaseId", defaultValue = "-1") String clientSideReleaseId,
HttpServletResponse response) {
//check default namespace
if (Objects.isNull(namespace)) {
namespace = appId;
}
List<String> watchedKeys = Lists.newArrayList(assembleKey(appId, cluster, namespace));
//Listen more namespaces, since it's not the default namespace
if (!Objects.equals(appId, namespace)) {
if (!Objects.equals(ConfigConsts.NAMESPACE_DEFAULT, namespace)) {
//TODO find id for this particular namespace, if not equal to current app id, then do more
if (!Objects.isNull(datacenter)) {
//TODO add newAppId+datacenter+namespace to listened keys
......@@ -59,8 +59,10 @@ public class NotificationController implements MessageListener {
//TODO add newAppId+defaultCluster+namespace to listened keys
}
DeferredResult<ApolloConfigNotification> deferredResult =
new DeferredResult<>(TIMEOUT);
ResponseEntity<ApolloConfigNotification> body = new ResponseEntity<>(
HttpStatus.NOT_MODIFIED);
DeferredResult<ResponseEntity<ApolloConfigNotification>> deferredResult =
new DeferredResult<>(TIMEOUT, body);
//register all keys
for (String key : watchedKeys) {
......@@ -74,10 +76,8 @@ public class NotificationController implements MessageListener {
}
});
deferredResult.onTimeout(() -> {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
});
logger.info("Listening {} from appId: {}, cluster: {}, namespace: {}, datacenter: {}",
watchedKeys, appId, cluster, namespace, datacenter);
return deferredResult;
}
......@@ -88,6 +88,7 @@ public class NotificationController implements MessageListener {
@Override
public void handleMessage(String message, String channel) {
logger.info("message received - channel: {}, message: {}", channel, message);
Cat.logEvent("Apollo.LongPoll.Message", message);
if (!Topics.APOLLO_RELEASE_TOPIC.equals(channel) || Strings.isNullOrEmpty(message)) {
return;
}
......@@ -98,12 +99,16 @@ public class NotificationController implements MessageListener {
return;
}
ApolloConfigNotification notification = new ApolloConfigNotification(keys[0], keys[1], keys[2]);
ResponseEntity<ApolloConfigNotification> notification =
new ResponseEntity<>(
new ApolloConfigNotification(keys[0], keys[1], keys[2]),
HttpStatus.OK);
Collection<DeferredResult<ApolloConfigNotification>> results = deferredResults.get(message);
Collection<DeferredResult<ResponseEntity<ApolloConfigNotification>>>
results = deferredResults.get(message);
logger.info("Notify {} clients for key {}", results.size(), message);
for (DeferredResult<ApolloConfigNotification> result : results) {
for (DeferredResult<ResponseEntity<ApolloConfigNotification>> result : results) {
result.setResult(notification);
}
}
......
......@@ -10,7 +10,7 @@ import com.ctrip.apollo.common.controller.WebSecurityConfig;
@Configuration
@ComponentScan(excludeFilters = {@Filter(type = FilterType.ASSIGNABLE_TYPE, value = {
SampleConfigServiceApplication.class, ConfigServiceApplication.class, WebSecurityConfig.class})})
SampleConfigServiceApplication.class, ConfigServiceApplication.class})})
@EnableAutoConfiguration
public class ConfigServiceTestConfiguration {
......
......@@ -2,13 +2,16 @@ package com.ctrip.apollo.configservice;
import com.ctrip.apollo.configservice.controller.ConfigControllerTest;
import com.ctrip.apollo.configservice.controller.NotificationControllerTest;
import com.ctrip.apollo.configservice.integration.ConfigControllerIntegrationTest;
import com.ctrip.apollo.configservice.integration.NotificationControllerIntegrationTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({ConfigControllerTest.class, NotificationControllerTest.class})
@SuiteClasses({ConfigControllerTest.class, NotificationControllerTest.class,
ConfigControllerIntegrationTest.class, NotificationControllerIntegrationTest.class})
public class AllTests {
}
package com.ctrip.apollo.configservice.controller;
import org.junit.runner.RunWith;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.WebIntegrationTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ctrip.apollo.ConfigServiceTestConfiguration;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ConfigServiceTestConfiguration.class)
@WebIntegrationTest(randomPort = true)
public abstract class AbstractControllerTest {
}
......@@ -10,6 +10,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.context.request.async.DeferredResult;
......@@ -31,7 +33,7 @@ public class NotificationControllerTest {
private String someReleaseId;
@Mock
private HttpServletResponse response;
private Multimap<String, DeferredResult<ApolloConfigNotification>> deferredResults;
private Multimap<String, DeferredResult<ResponseEntity<ApolloConfigNotification>>> deferredResults;
@Before
public void setUp() throws Exception {
......@@ -43,7 +45,7 @@ public class NotificationControllerTest {
someReleaseId = "someRelease";
deferredResults =
(Multimap<String, DeferredResult<ApolloConfigNotification>>) ReflectionTestUtils
(Multimap<String, DeferredResult<ResponseEntity<ApolloConfigNotification>>>) ReflectionTestUtils
.getField(controller, "deferredResults");
}
......@@ -51,7 +53,7 @@ public class NotificationControllerTest {
public void testPollNotificationWithDefaultNamespace() throws Exception {
someNamespace = someAppId; //default namespace
DeferredResult<ApolloConfigNotification>
DeferredResult<ResponseEntity<ApolloConfigNotification>>
deferredResult = controller
.pollNotification(someAppId, someCluster, someNamespace, someDataCenter, someReleaseId,
response);
......@@ -66,7 +68,7 @@ public class NotificationControllerTest {
public void testPollNotificationWithDefaultNamespaceAndHandleMessage() throws Exception {
someNamespace = someAppId; //default namespace
DeferredResult<ApolloConfigNotification>
DeferredResult<ResponseEntity<ApolloConfigNotification>>
deferredResult = controller
.pollNotification(someAppId, someCluster, someNamespace, someDataCenter, someReleaseId,
response);
......@@ -75,8 +77,11 @@ public class NotificationControllerTest {
controller.handleMessage(key, Topics.APOLLO_RELEASE_TOPIC);
ApolloConfigNotification notification = (ApolloConfigNotification) deferredResult.getResult();
ResponseEntity<ApolloConfigNotification> response =
(ResponseEntity<ApolloConfigNotification>) deferredResult.getResult();
ApolloConfigNotification notification = response.getBody();
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(someAppId, notification.getAppId());
assertEquals(someCluster, notification.getCluster());
assertEquals(someNamespace, notification.getNamespace());
......
package com.ctrip.apollo.configservice.integration;
import com.ctrip.apollo.ConfigServiceTestConfiguration;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.TestRestTemplate;
import org.springframework.boot.test.WebIntegrationTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import javax.annotation.PostConstruct;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = AbstractBaseIntegrationTest.TestConfiguration.class)
@WebIntegrationTest(randomPort = true)
public abstract class AbstractBaseIntegrationTest {
RestTemplate restTemplate = new TestRestTemplate("user", "");
@PostConstruct
private void postConstruct() {
restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
}
@Value("${local.server.port}")
int port;
protected String getHostUrl() {
return "http://localhost:" + port;
}
@Configuration
@Import(ConfigServiceTestConfiguration.class)
protected static class TestConfiguration {
}
}
package com.ctrip.apollo.configservice.integration;
import com.ctrip.apollo.core.ConfigConsts;
import com.ctrip.apollo.core.dto.ApolloConfig;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.web.client.HttpStatusCodeException;
import static org.junit.Assert.assertEquals;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class ConfigControllerIntegrationTest extends AbstractBaseIntegrationTest {
private String someAppId;
private String someCluster;
private String someNamespace;
@Before
public void setUp() throws Exception {
someAppId = "someAppId";
someCluster = "someCluster";
someNamespace = "someNamespace";
}
@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 testQueryConfigWithDefaultClusterAndDefaultNamespaceOK() throws Exception {
ResponseEntity<ApolloConfig> response = restTemplate
.getForEntity("{baseurl}/configs/{appId}/{clusterName}", ApolloConfig.class,
getHostUrl(), someAppId, ConfigConsts.CLUSTER_NAME_DEFAULT);
ApolloConfig result = response.getBody();
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(String.valueOf(990), result.getReleaseId());
assertEquals("v1", result.getConfigurations().get("k1"));
}
@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 testQueryConfigWithNamespaceOK() throws Exception {
ResponseEntity<ApolloConfig> response = restTemplate
.getForEntity("{baseurl}/configs/{appId}/{clusterName}/{namespace}", ApolloConfig.class,
getHostUrl(), someAppId, someCluster, someNamespace);
ApolloConfig result = response.getBody();
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(String.valueOf(991), result.getReleaseId());
assertEquals("v2", result.getConfigurations().get("k2"));
}
@Test
public void testQueryConfigError() throws Exception {
String someNamespaceNotExists = "someNamespaceNotExists";
HttpStatusCodeException httpException = null;
try {
ResponseEntity<ApolloConfig> response = restTemplate
.getForEntity("{baseurl}/configs/{appId}/{clusterName}/{namespace}", ApolloConfig.class,
getHostUrl(), someAppId, someCluster, someNamespaceNotExists);
} catch (HttpStatusCodeException ex) {
httpException = ex;
}
assertEquals(HttpStatus.NOT_FOUND, httpException.getStatusCode());
}
@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 testQueryConfigNotModified() throws Exception {
String releaseId = String.valueOf(991);
ResponseEntity<ApolloConfig> response = restTemplate
.getForEntity("{baseurl}/configs/{appId}/{clusterName}/{namespace}?releaseId={releaseId}", ApolloConfig.class,
getHostUrl(), someAppId, someCluster, someNamespace, releaseId);
assertEquals(HttpStatus.NOT_MODIFIED, response.getStatusCode());
}
}
package com.ctrip.apollo.configservice.integration;
import com.ctrip.apollo.biz.message.Topics;
import com.ctrip.apollo.configservice.controller.NotificationController;
import com.ctrip.apollo.core.ConfigConsts;
import com.ctrip.apollo.core.dto.ApolloConfigNotification;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class NotificationControllerIntegrationTest extends AbstractBaseIntegrationTest {
@Autowired
private NotificationController notificationController;
private String someAppId;
private String someCluster;
private String someNamespace;
private ExecutorService executorService;
@Before
public void setUp() throws Exception {
someAppId = "someAppId";
someCluster = ConfigConsts.CLUSTER_NAME_DEFAULT;
someNamespace = "someNamespace";
executorService = Executors.newSingleThreadExecutor();
}
@Test
public void testPollNotification() throws Exception {
Future<ResponseEntity<ApolloConfigNotification>> future =
executorService.submit(() -> restTemplate
.getForEntity(
"{baseurl}/notifications?appId={appId}&cluster={clusterName}&namespace={namespace}",
ApolloConfigNotification.class,
getHostUrl(), someAppId, someCluster, someNamespace));
//wait for the request connected to server
TimeUnit.MILLISECONDS.sleep(500);
notificationController.handleMessage(assembleKey(someAppId, someCluster, someNamespace),
Topics.APOLLO_RELEASE_TOPIC);
ResponseEntity<ApolloConfigNotification> result = future.get(500, TimeUnit.MILLISECONDS);
ApolloConfigNotification notification = result.getBody();
assertEquals(HttpStatus.OK, result.getStatusCode());
assertEquals(someAppId, notification.getAppId());
assertEquals(someCluster, notification.getCluster());
assertEquals(someNamespace, notification.getNamespace());
}
private String assembleKey(String appId, String cluster, String namespace) {
return String.format("%s-%s-%s", appId, cluster, namespace);
}
}
spring.datasource.url = jdbc:h2:mem:~/apolloconfigdb;mode=mysql
spring.datasource.url = jdbc:h2:mem:~/apolloconfigdb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1
spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy
spring.h2.console.enabled = true
spring.h2.console.settings.web-allow-others=true
spring.jpa.properties.hibernate.show_sql=true
\ No newline at end of file
spring.jpa.properties.hibernate.show_sql=true
......@@ -11,24 +11,24 @@ INSERT INTO Cluster (AppId, Name) VALUES ('100003173', 'default');
INSERT INTO Cluster (AppId, Name) VALUES ('100003173', 'cluster3');
INSERT INTO Cluster (AppId, Name) VALUES ('fxhermesproducer', 'default');
INSERT INTO AppNamespace (AppId, Name) VALUES ('100003171', '100003171');
INSERT INTO AppNamespace (AppId, Name) VALUES ('100003171', 'application');
INSERT INTO AppNamespace (AppId, Name) VALUES ('100003171', 'fx.apollo.config');
INSERT INTO AppNamespace (AppId, Name) VALUES ('100003172', '100003172');
INSERT INTO AppNamespace (AppId, Name) VALUES ('100003172', 'application');
INSERT INTO AppNamespace (AppId, Name) VALUES ('100003172', 'fx.apollo.admin');
INSERT INTO AppNamespace (AppId, Name) VALUES ('100003173', '100003173');
INSERT INTO AppNamespace (AppId, Name) VALUES ('100003173', 'application');
INSERT INTO AppNamespace (AppId, Name) VALUES ('100003173', 'fx.apollo.portal');
INSERT INTO AppNamespace (AppID, Name) VALUES ('fxhermesproducer', 'fx.hermes.producer');
INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (1, '100003171', 'default', '100003171');
INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (1, '100003171', 'default', 'application');
INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (2, 'fxhermesproducer', 'default', 'fx.hermes.producer');
INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (3, '100003172', 'default', '100003172');
INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (4, '100003173', 'default', '100003173');
INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (5, '100003171', 'default', '100003171');
INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (3, '100003172', 'default', 'application');
INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (4, '100003173', 'default', 'application');
INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (5, '100003171', 'default', 'application');
INSERT INTO Item (NamespaceId, `Key`, Value, Comment) VALUES (1, 'k1', 'v1', 'comment1');
INSERT INTO Item (NamespaceId, `Key`, Value, Comment) VALUES (1, 'k2', 'v2', 'comment2');
INSERT INTO Item (NamespaceId, `Key`, Value, Comment) VALUES (2, 'k3', 'v3', 'comment3');
INSERT INTO Item (NamespaceId, `Key`, Value, Comment) VALUES (5, 'k3', 'v4', 'comment4');
INSERT INTO RELEASE (Name, Comment, AppId, ClusterName, NamespaceName, Configurations) VALUES ('REV1','First Release','100003171', 'default', '100003171', '{"k1":"v1"}');
INSERT INTO RELEASE (Name, Comment, AppId, ClusterName, NamespaceName, Configurations) VALUES ('REV1','First Release','100003171', 'default', 'application', '{"k1":"v1"}');
DELETE FROM Release;
DELETE FROM Namespace;
DELETE FROM AppNamespace;
DELETE FROM Cluster;
DELETE FROM App;
INSERT INTO App (AppId, Name, OwnerName, OwnerEmail) VALUES ('someAppId','someAppName','someOwnerName','someOwnerName@ctrip.com');
INSERT INTO Cluster (AppId, Name) VALUES ('someAppId', 'default');
INSERT INTO Cluster (AppId, Name) VALUES ('someAppId', 'someCluster');
INSERT INTO AppNamespace (AppId, Name) VALUES ('someAppId', 'someAppId');
INSERT INTO AppNamespace (AppId, Name) VALUES ('someAppId', 'someNamespace');
INSERT INTO Namespace (AppId, ClusterName, NamespaceName) VALUES ('someAppId', 'default', 'someAppId');
INSERT INTO Namespace (AppId, ClusterName, NamespaceName) VALUES ('someAppId', 'someCluster', 'someNamespace');
INSERT INTO RELEASE (id, Name, Comment, AppId, ClusterName, NamespaceName, Configurations) VALUES (990, 'INTEGRATION-TEST-DEFAULT','First Release','someAppId', 'default', 'application', '{"k1":"v1"}');
INSERT INTO RELEASE (id, Name, Comment, AppId, ClusterName, NamespaceName, Configurations) VALUES (991, 'INTEGRATION-TEST-NAMESPACE','First Release','someAppId', 'someCluster', 'someNamespace', '{"k2":"v2"}');
package com.ctrip.apollo.core;
public interface ConfigConsts {
String NAMESPACE_DEFAULT = "application";
String CLUSTER_NAME_DEFAULT = "default";
}
......@@ -2,6 +2,8 @@ package com.ctrip.apollo.core.dto;
import com.google.common.base.MoreObjects;
import com.ctrip.apollo.Apollo;
import java.util.Map;
/**
......@@ -19,11 +21,13 @@ public class ApolloConfig {
private String releaseId;
public ApolloConfig() {
}
public ApolloConfig(String appId,
String cluster,
String namespace,
String releaseId) {
super();
this.appId = appId;
this.cluster = cluster;
this.namespace = namespace;
......@@ -50,6 +54,22 @@ public class ApolloConfig {
return configurations;
}
public void setAppId(String appId) {
this.appId = appId;
}
public void setCluster(String cluster) {
this.cluster = cluster;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public void setReleaseId(String releaseId) {
this.releaseId = releaseId;
}
public void setConfigurations(Map<String, String> configurations) {
this.configurations = configurations;
}
......
......@@ -4,9 +4,13 @@ package com.ctrip.apollo.core.dto;
* @author Jason Song(song_s@ctrip.com)
*/
public class ApolloConfigNotification {
private final String appId;
private final String cluster;
private final String namespace;
private String appId;
private String cluster;
private String namespace;
//for json converter
public ApolloConfigNotification() {
}
public ApolloConfigNotification(String appId, String cluster, String namespace) {
this.appId = appId;
......@@ -25,4 +29,16 @@ public class ApolloConfigNotification {
public String getNamespace() {
return namespace;
}
public void setAppId(String appId) {
this.appId = appId;
}
public void setCluster(String cluster) {
this.cluster = cluster;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
}
......@@ -22,7 +22,7 @@ public class ApolloConfigDemo implements ConfigChangeListener {
private Config config;
public ApolloConfigDemo() {
config = ConfigService.getConfig();
config = ConfigService.getAppConfig();
config.addChangeListener(this);
}
......@@ -53,7 +53,8 @@ public class ApolloConfigDemo implements ConfigChangeListener {
@Override
public void onChange(ConfigChangeEvent changeEvent) {
logger.info("Changes for namespace {}", changeEvent.getNamespace());
for (ConfigChange change : changeEvent.getChanges().values()) {
for (String key : changeEvent.changedKeys()) {
ConfigChange change = changeEvent.getChange(key);
logger.info("Change - key: {}, oldValue: {}, newValue: {}, changeType: {}",
change.getPropertyName(), change.getOldValue(), change.getNewValue(),
change.getChangeType());
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册