Commit d5a3d39f authored by Jason Song's avatar Jason Song

Client refactor, Config service integration test.

1. Refactor apollo client code according to  @qmwu2000's comments
2. Add config service integration tests
3. Add some cat events for config service
4. Fix several bugs
parent f6332935
...@@ -13,6 +13,81 @@ public interface Config { ...@@ -13,6 +13,81 @@ public interface Config {
*/ */
public String getProperty(String key, String defaultValue); 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. * Add change listener to this config instance.
* @param listener the config change listener * @param listener the config change listener
......
package com.ctrip.apollo; package com.ctrip.apollo;
import com.ctrip.apollo.core.ConfigConsts;
import com.ctrip.apollo.internals.ConfigManager; import com.ctrip.apollo.internals.ConfigManager;
import com.ctrip.apollo.spi.ConfigFactory; import com.ctrip.apollo.spi.ConfigFactory;
import com.ctrip.apollo.spi.ConfigRegistry; import com.ctrip.apollo.spi.ConfigRegistry;
...@@ -24,11 +25,11 @@ public class ConfigService { ...@@ -24,11 +25,11 @@ public class ConfigService {
} }
/** /**
* Get the config instance with default namespace. * Get Application's config instance.
* @return config instance * @return config instance
*/ */
public static Config getConfig() { public static Config getAppConfig() {
return getConfig(getDefaultNamespace()); return getConfig(ConfigConsts.NAMESPACE_DEFAULT);
} }
/** /**
...@@ -59,17 +60,8 @@ public class ConfigService { ...@@ -59,17 +60,8 @@ public class ConfigService {
} }
} }
private static String getDefaultNamespace() { static void setConfig(Config config) {
try { setConfig(ConfigConsts.NAMESPACE_DEFAULT, config);
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);
} }
/** /**
...@@ -77,7 +69,7 @@ public class ConfigService { ...@@ -77,7 +69,7 @@ public class ConfigService {
* @param namespace the namespace * @param namespace the namespace
* @param config the config instance * @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() { getRegistry().register(namespace, new ConfigFactory() {
@Override @Override
public Config create(String namespace) { public Config create(String namespace) {
...@@ -86,8 +78,8 @@ public class ConfigService { ...@@ -86,8 +78,8 @@ public class ConfigService {
}); });
} }
public static void setConfigFactory(ConfigFactory factory) { static void setConfigFactory(ConfigFactory factory) {
setConfigFactory(getDefaultNamespace(), factory); setConfigFactory(ConfigConsts.NAMESPACE_DEFAULT, factory);
} }
/** /**
...@@ -95,12 +87,12 @@ public class ConfigService { ...@@ -95,12 +87,12 @@ public class ConfigService {
* @param namespace the namespace * @param namespace the namespace
* @param factory the factory instance * @param factory the factory instance
*/ */
public static void setConfigFactory(String namespace, ConfigFactory factory) { static void setConfigFactory(String namespace, ConfigFactory factory) {
getRegistry().register(namespace, factory); getRegistry().register(namespace, factory);
} }
// for test only // for test only
public static void setContainer(PlexusContainer m_container) { static void setContainer(PlexusContainer m_container) {
s_instance.m_container = m_container; s_instance.m_container = m_container;
} }
} }
...@@ -5,5 +5,5 @@ package com.ctrip.apollo.enums; ...@@ -5,5 +5,5 @@ package com.ctrip.apollo.enums;
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
*/ */
public enum PropertyChangeType { 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 { ...@@ -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) { protected void fireConfigChange(ConfigChangeEvent changeEvent) {
for (ConfigChangeListener listener : m_listeners) { for (ConfigChangeListener listener : m_listeners) {
try { try {
...@@ -43,7 +85,8 @@ public abstract class AbstractConfig implements Config { ...@@ -43,7 +85,8 @@ public abstract class AbstractConfig implements Config {
} }
} }
List<ConfigChange> calcPropertyChanges(Properties previous, List<ConfigChange> calcPropertyChanges(String namespace,
Properties previous,
Properties current) { Properties current) {
if (previous == null) { if (previous == null) {
previous = new Properties(); previous = new Properties();
...@@ -64,11 +107,12 @@ public abstract class AbstractConfig implements Config { ...@@ -64,11 +107,12 @@ public abstract class AbstractConfig implements Config {
for (String newKey : newKeys) { for (String newKey : newKeys) {
changes 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) { 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)); PropertyChangeType.DELETED));
} }
...@@ -78,7 +122,7 @@ public abstract class AbstractConfig implements Config { ...@@ -78,7 +122,7 @@ public abstract class AbstractConfig implements Config {
if (Objects.equal(previousValue, currentValue)) { if (Objects.equal(previousValue, currentValue)) {
continue; continue;
} }
changes.add(new ConfigChange(commonKey, previousValue, changes.add(new ConfigChange(namespace, commonKey, previousValue,
currentValue, PropertyChangeType.MODIFIED)); currentValue, PropertyChangeType.MODIFIED));
} }
......
...@@ -18,15 +18,17 @@ public abstract class AbstractConfigRepository implements ConfigRepository { ...@@ -18,15 +18,17 @@ public abstract class AbstractConfigRepository implements ConfigRepository {
private static final Logger logger = LoggerFactory.getLogger(AbstractConfigRepository.class); private static final Logger logger = LoggerFactory.getLogger(AbstractConfigRepository.class);
private List<RepositoryChangeListener> m_listeners = Lists.newCopyOnWriteArrayList(); private List<RepositoryChangeListener> m_listeners = Lists.newCopyOnWriteArrayList();
protected void trySync() { protected boolean trySync() {
try { try {
sync(); sync();
return true;
} catch (Throwable ex) { } catch (Throwable ex) {
Cat.logError(ex); Cat.logError(ex);
logger logger
.warn("Sync config failed with repository {}, reason: {}", this.getClass(), ExceptionUtil .warn("Sync config failed with repository {}, reason: {}", this.getClass(), ExceptionUtil
.getDetailMessage(ex)); .getDetailMessage(ex));
} }
return false;
} }
protected abstract void sync(); protected abstract void sync();
......
...@@ -28,7 +28,7 @@ import java.util.concurrent.TimeUnit; ...@@ -28,7 +28,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
@Named(type = ConfigServiceLocator.class) @Named(type = ConfigServiceLocator.class)
public class ConfigServiceLocator implements Initializable{ public class ConfigServiceLocator implements Initializable {
private static final Logger logger = LoggerFactory.getLogger(ConfigServiceLocator.class); private static final Logger logger = LoggerFactory.getLogger(ConfigServiceLocator.class);
@Inject @Inject
private HttpUtil m_httpUtil; private HttpUtil m_httpUtil;
...@@ -69,12 +69,14 @@ public class ConfigServiceLocator implements Initializable{ ...@@ -69,12 +69,14 @@ public class ConfigServiceLocator implements Initializable{
return m_configServices.get(); return m_configServices.get();
} }
private void tryUpdateConfigServices() { private boolean tryUpdateConfigServices() {
try { try {
updateConfigServices(); updateConfigServices();
return true;
} catch (Throwable ex) { } catch (Throwable ex) {
//ignore //ignore
} }
return false;
} }
private void schedulePeriodicRefresh() { private void schedulePeriodicRefresh() {
...@@ -84,8 +86,9 @@ public class ConfigServiceLocator implements Initializable{ ...@@ -84,8 +86,9 @@ public class ConfigServiceLocator implements Initializable{
public void run() { public void run() {
logger.debug("refresh config services"); logger.debug("refresh config services");
Transaction transaction = Cat.newTransaction("Apollo.MetaService", "periodicRefresh"); Transaction transaction = Cat.newTransaction("Apollo.MetaService", "periodicRefresh");
tryUpdateConfigServices(); boolean syncResult = tryUpdateConfigServices();
transaction.setStatus(Message.SUCCESS); String status = syncResult ? Message.SUCCESS : "-1";
transaction.setStatus(status);
transaction.complete(); transaction.complete();
} }
}, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(), }, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(),
...@@ -129,8 +132,8 @@ public class ConfigServiceLocator implements Initializable{ ...@@ -129,8 +132,8 @@ public class ConfigServiceLocator implements Initializable{
} }
private void logConfigServicesToCat(List<ServiceDTO> serviceDtos) { private void logConfigServicesToCat(List<ServiceDTO> serviceDtos) {
for (ServiceDTO serviceDTO : serviceDtos) { for (ServiceDTO serviceDto : serviceDtos) {
Cat.logEvent("Apollo.Config.Services", serviceDTO.getHomepageUrl()); Cat.logEvent("Apollo.Config.Services", serviceDto.getHomepageUrl());
} }
} }
} }
...@@ -47,11 +47,14 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis ...@@ -47,11 +47,14 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
private void initialize() { private void initialize() {
try { try {
m_configProperties.set(m_configRepository.getConfig()); m_configProperties.set(m_configRepository.getConfig());
m_configRepository.addChangeListener(this);
} catch (Throwable ex) { } catch (Throwable ex) {
Cat.logError(ex); Cat.logError(ex);
logger.warn("Init Apollo Local Config failed - namespace: {}, reason: {}.", logger.warn("Init Apollo Local Config failed - namespace: {}, reason: {}.",
m_namespace, ExceptionUtil.getDetailMessage(ex)); 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 ...@@ -108,7 +111,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
private Map<String, ConfigChange> updateAndCalcConfigChanges(Properties newConfigProperties) { private Map<String, ConfigChange> updateAndCalcConfigChanges(Properties newConfigProperties) {
List<ConfigChange> configChanges = List<ConfigChange> configChanges =
calcPropertyChanges(m_configProperties.get(), newConfigProperties); calcPropertyChanges(m_namespace, m_configProperties.get(), newConfigProperties);
ImmutableMap.Builder<String, ConfigChange> actualChanges = ImmutableMap.Builder<String, ConfigChange> actualChanges =
new ImmutableMap.Builder<>(); new ImmutableMap.Builder<>();
...@@ -127,7 +130,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis ...@@ -127,7 +130,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
for (ConfigChange change : configChanges) { for (ConfigChange change : configChanges) {
change.setNewValue(this.getProperty(change.getPropertyName(), change.getNewValue())); change.setNewValue(this.getProperty(change.getPropertyName(), change.getNewValue()));
switch (change.getChangeType()) { switch (change.getChangeType()) {
case NEW: case ADDED:
if (Objects.equals(change.getOldValue(), change.getNewValue())) { if (Objects.equals(change.getOldValue(), change.getNewValue())) {
break; break;
} }
......
...@@ -99,8 +99,9 @@ public class RemoteConfigRepository extends AbstractConfigRepository { ...@@ -99,8 +99,9 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
public void run() { public void run() {
logger.debug("refresh config for namespace: {}", m_namespace); logger.debug("refresh config for namespace: {}", m_namespace);
Transaction transaction = Cat.newTransaction("Apollo.ConfigService", "periodicRefresh"); Transaction transaction = Cat.newTransaction("Apollo.ConfigService", "periodicRefresh");
trySync(); boolean syncSuccess = trySync();
transaction.setStatus(Message.SUCCESS); String status = syncSuccess ? Message.SUCCESS : "-1";
transaction.setStatus(status);
transaction.complete(); transaction.complete();
} }
}, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(), }, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(),
......
...@@ -39,11 +39,14 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList ...@@ -39,11 +39,14 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList
private void initialize() { private void initialize() {
try { try {
m_configProperties = m_configRepository.getConfig(); m_configProperties = m_configRepository.getConfig();
m_configRepository.addChangeListener(this);
} catch (Throwable ex) { } catch (Throwable ex) {
Cat.logError(ex); Cat.logError(ex);
logger.warn("Init Apollo Simple Config failed - namespace: {}, reason: {}", m_namespace, logger.warn("Init Apollo Simple Config failed - namespace: {}, reason: {}", m_namespace,
ExceptionUtil.getDetailMessage(ex)); 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 ...@@ -64,7 +67,9 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList
Properties newConfigProperties = new Properties(); Properties newConfigProperties = new Properties();
newConfigProperties.putAll(newProperties); 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, Map<String, ConfigChange> changeMap = Maps.uniqueIndex(changes,
new Function<ConfigChange, String>() { new Function<ConfigChange, String>() {
@Override @Override
......
...@@ -10,6 +10,7 @@ import com.ctrip.apollo.enums.PropertyChangeType; ...@@ -10,6 +10,7 @@ import com.ctrip.apollo.enums.PropertyChangeType;
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
*/ */
public class ConfigChange { public class ConfigChange {
private final String namespace;
private final String propertyName; private final String propertyName;
private String oldValue; private String oldValue;
private String newValue; private String newValue;
...@@ -17,13 +18,15 @@ public class ConfigChange { ...@@ -17,13 +18,15 @@ public class ConfigChange {
/** /**
* Constructor. * Constructor.
* @param namespace the namespace of the key
* @param propertyName the key whose value is changed * @param propertyName the key whose value is changed
* @param oldValue the value before change * @param oldValue the value before change
* @param newValue the value after change * @param newValue the value after change
* @param changeType the change type * @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) { PropertyChangeType changeType) {
this.namespace = namespace;
this.propertyName = propertyName; this.propertyName = propertyName;
this.oldValue = oldValue; this.oldValue = oldValue;
this.newValue = newValue; this.newValue = newValue;
...@@ -58,10 +61,15 @@ public class ConfigChange { ...@@ -58,10 +61,15 @@ public class ConfigChange {
this.changeType = changeType; this.changeType = changeType;
} }
public String getNamespace() {
return namespace;
}
@Override @Override
public String toString() { public String toString() {
return MoreObjects.toStringHelper(this) return MoreObjects.toStringHelper(this)
.omitNullValues() .omitNullValues()
.add("namespace", namespace)
.add("propertyName", propertyName) .add("propertyName", propertyName)
.add("oldValue", oldValue) .add("oldValue", oldValue)
.add("newValue", newValue) .add("newValue", newValue)
......
...@@ -9,7 +9,7 @@ import java.util.Set; ...@@ -9,7 +9,7 @@ import java.util.Set;
*/ */
public class ConfigChangeEvent { public class ConfigChangeEvent {
private final String m_namespace; private final String m_namespace;
private final Map<String, ConfigChange> changes; private final Map<String, ConfigChange> m_changes;
/** /**
* Constructor. * Constructor.
...@@ -19,7 +19,7 @@ public class ConfigChangeEvent { ...@@ -19,7 +19,7 @@ public class ConfigChangeEvent {
public ConfigChangeEvent(String namespace, public ConfigChangeEvent(String namespace,
Map<String, ConfigChange> changes) { Map<String, ConfigChange> changes) {
this.m_namespace = namespace; this.m_namespace = namespace;
this.changes = changes; this.m_changes = changes;
} }
/** /**
...@@ -27,7 +27,7 @@ public class ConfigChangeEvent { ...@@ -27,7 +27,7 @@ public class ConfigChangeEvent {
* @return the list of the keys * @return the list of the keys
*/ */
public Set<String> changedKeys() { public Set<String> changedKeys() {
return changes.keySet(); return m_changes.keySet();
} }
/** /**
...@@ -36,16 +36,16 @@ public class ConfigChangeEvent { ...@@ -36,16 +36,16 @@ public class ConfigChangeEvent {
* @return the change instance * @return the change instance
*/ */
public ConfigChange getChange(String key) { public ConfigChange getChange(String key) {
return changes.get(key); return m_changes.get(key);
} }
/** /**
* Get the changes as <Key, Change> map. * Check whether the specified key is changed
* Please note that the returned Map is immutable. * @param key the key
* @return changes * @return true if the key is changed, false otherwise.
*/ */
public Map<String, ConfigChange> getChanges() { public boolean isChanged(String key) {
return changes; return m_changes.containsKey(key);
} }
/** /**
......
package com.ctrip.apollo.util; package com.ctrip.apollo.util;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.ctrip.apollo.core.ConfigConsts; import com.ctrip.apollo.core.ConfigConsts;
import com.ctrip.apollo.core.MetaDomainConsts; import com.ctrip.apollo.core.MetaDomainConsts;
import com.ctrip.apollo.core.enums.Env; 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; import org.unidal.lookup.annotation.Named;
...@@ -28,7 +29,7 @@ public class ConfigUtil { ...@@ -28,7 +29,7 @@ public class ConfigUtil {
* @throws IllegalStateException if app id is not set * @throws IllegalStateException if app id is not set
*/ */
public String getAppId() { public String getAppId() {
String appId = ClientEnvironment.getAppId(); String appId = Foundation.app().getAppId();
Preconditions.checkState(appId != null, "app.id is not set"); Preconditions.checkState(appId != null, "app.id is not set");
return appId; return appId;
} }
...@@ -38,7 +39,7 @@ public class ConfigUtil { ...@@ -38,7 +39,7 @@ public class ConfigUtil {
* @return the cluster name, or "default" if not specified * @return the cluster name, or "default" if not specified
*/ */
public String getCluster() { public String getCluster() {
String cluster = ClientEnvironment.getCluster(); String cluster = System.getProperty("apollo.cluster");
if (cluster == null) { if (cluster == null) {
cluster = ConfigConsts.CLUSTER_NAME_DEFAULT; cluster = ConfigConsts.CLUSTER_NAME_DEFAULT;
} }
...@@ -51,11 +52,34 @@ public class ConfigUtil { ...@@ -51,11 +52,34 @@ public class ConfigUtil {
* @throws IllegalStateException if env is set * @throws IllegalStateException if env is set
*/ */
public Env getApolloEnv() { public Env getApolloEnv() {
Env env = ClientEnvironment.getEnv(); Env env = transformEnv(Foundation.server().getEnvType());
Preconditions.checkState(env != null, "env is not set"); Preconditions.checkState(env != null, "env is not set");
return env; 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() { public String getMetaServerDomainName() {
return MetaDomainConsts.getDomain(getApolloEnv()); return MetaDomainConsts.getDomain(getApolloEnv());
} }
......
...@@ -9,6 +9,11 @@ import java.util.List; ...@@ -9,6 +9,11 @@ import java.util.List;
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
*/ */
public class ExceptionUtil { 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) { public static String getDetailMessage(Throwable ex) {
if (ex == null || Strings.isNullOrEmpty(ex.getMessage())) { if (ex == null || Strings.isNullOrEmpty(ex.getMessage())) {
return ""; return "";
......
package com.ctrip.apollo.integration; package com.ctrip.apollo;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
...@@ -34,7 +34,7 @@ import javax.servlet.http.HttpServletResponse; ...@@ -34,7 +34,7 @@ import javax.servlet.http.HttpServletResponse;
/** /**
* @author Jason Song(song_s@ctrip.com) * @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 int PORT = findFreePort();
private static final String metaServiceUrl = "http://localhost:" + PORT; private static final String metaServiceUrl = "http://localhost:" + PORT;
private static final String someAppName = "someAppName"; private static final String someAppName = "someAppName";
......
package com.ctrip.apollo; 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.spi.ConfigFactory;
import com.ctrip.apollo.util.ConfigUtil; import com.ctrip.apollo.util.ConfigUtil;
...@@ -31,7 +33,7 @@ public class ConfigServiceTest extends ComponentTestCase { ...@@ -31,7 +33,7 @@ public class ConfigServiceTest extends ComponentTestCase {
String someKey = "first"; String someKey = "first";
ConfigService.setConfig(new MockConfig(someNamespace)); ConfigService.setConfig(new MockConfig(someNamespace));
Config config = ConfigService.getConfig(); Config config = ConfigService.getAppConfig();
assertEquals(someNamespace + ":" + someKey, config.getProperty(someKey, null)); assertEquals(someNamespace + ":" + someKey, config.getProperty(someKey, null));
assertEquals(null, config.getProperty("unknown", null)); assertEquals(null, config.getProperty("unknown", null));
...@@ -42,9 +44,9 @@ public class ConfigServiceTest extends ComponentTestCase { ...@@ -42,9 +44,9 @@ public class ConfigServiceTest extends ComponentTestCase {
String someKey = "someKey"; String someKey = "someKey";
ConfigService.setConfigFactory(new MockConfigFactory()); ConfigService.setConfigFactory(new MockConfigFactory());
Config config = ConfigService.getConfig(); Config config = ConfigService.getAppConfig();
assertEquals(someAppId + ":" + someKey, assertEquals(ConfigConsts.NAMESPACE_DEFAULT + ":" + someKey,
config.getProperty(someKey, null)); config.getProperty(someKey, null));
} }
...@@ -60,7 +62,7 @@ public class ConfigServiceTest extends ComponentTestCase { ...@@ -60,7 +62,7 @@ public class ConfigServiceTest extends ComponentTestCase {
assertEquals(null, config.getProperty("unknown", null)); assertEquals(null, config.getProperty("unknown", null));
} }
private static class MockConfig implements Config { private static class MockConfig extends AbstractConfig {
private final String m_namespace; private final String m_namespace;
public MockConfig(String namespace) { public MockConfig(String namespace) {
...@@ -75,11 +77,6 @@ public class ConfigServiceTest extends ComponentTestCase { ...@@ -75,11 +77,6 @@ public class ConfigServiceTest extends ComponentTestCase {
return m_namespace + ":" + key; return m_namespace + ":" + key;
} }
@Override
public void addChangeListener(ConfigChangeListener listener) {
}
} }
public static class MockConfigFactory implements ConfigFactory { public static class MockConfigFactory implements ConfigFactory {
......
...@@ -5,9 +5,11 @@ import com.google.common.collect.Lists; ...@@ -5,9 +5,11 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.SettableFuture;
import com.ctrip.apollo.BaseIntegrationTest;
import com.ctrip.apollo.Config; import com.ctrip.apollo.Config;
import com.ctrip.apollo.ConfigChangeListener; import com.ctrip.apollo.ConfigChangeListener;
import com.ctrip.apollo.ConfigService; import com.ctrip.apollo.ConfigService;
import com.ctrip.apollo.core.ConfigConsts;
import com.ctrip.apollo.core.dto.ApolloConfig; import com.ctrip.apollo.core.dto.ApolloConfig;
import com.ctrip.apollo.core.dto.ApolloConfigNotification; import com.ctrip.apollo.core.dto.ApolloConfigNotification;
import com.ctrip.apollo.core.utils.ClassLoaderUtil; import com.ctrip.apollo.core.utils.ClassLoaderUtil;
...@@ -37,6 +39,7 @@ import javax.servlet.http.HttpServletResponse; ...@@ -37,6 +39,7 @@ import javax.servlet.http.HttpServletResponse;
import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/** /**
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
...@@ -50,7 +53,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -50,7 +53,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
public void setUp() throws Exception { public void setUp() throws Exception {
super.setUp(); super.setUp();
defaultNamespace = someAppId; defaultNamespace = ConfigConsts.NAMESPACE_DEFAULT;
someReleaseId = "1"; someReleaseId = "1";
configDir = new File(ClassLoaderUtil.getClassPath() + "config-cache"); configDir = new File(ClassLoaderUtil.getClassPath() + "config-cache");
configDir.mkdirs(); configDir.mkdirs();
...@@ -90,7 +93,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -90,7 +93,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
ContextHandler handler = mockConfigServerHandler(HttpServletResponse.SC_OK, apolloConfig); ContextHandler handler = mockConfigServerHandler(HttpServletResponse.SC_OK, apolloConfig);
startServerWithHandlers(handler); startServerWithHandlers(handler);
Config config = ConfigService.getConfig(); Config config = ConfigService.getAppConfig();
assertEquals(someValue, config.getProperty(someKey, null)); assertEquals(someValue, config.getProperty(someKey, null));
assertEquals(someDefaultValue, config.getProperty(someNonExistedKey, someDefaultValue)); assertEquals(someDefaultValue, config.getProperty(someNonExistedKey, someDefaultValue));
...@@ -109,7 +112,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -109,7 +112,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
ContextHandler handler = mockConfigServerHandler(HttpServletResponse.SC_OK, apolloConfig); ContextHandler handler = mockConfigServerHandler(HttpServletResponse.SC_OK, apolloConfig);
startServerWithHandlers(handler); startServerWithHandlers(handler);
Config config = ConfigService.getConfig(); Config config = ConfigService.getAppConfig();
assertEquals(anotherValue, config.getProperty(someKey, null)); assertEquals(anotherValue, config.getProperty(someKey, null));
} }
...@@ -120,7 +123,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -120,7 +123,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
mockConfigServerHandler(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null); mockConfigServerHandler(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null);
startServerWithHandlers(handler); startServerWithHandlers(handler);
Config config = ConfigService.getConfig(); Config config = ConfigService.getAppConfig();
String someKey = "someKey"; String someKey = "someKey";
String someDefaultValue = "defaultValue" + Math.random(); String someDefaultValue = "defaultValue" + Math.random();
...@@ -140,7 +143,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -140,7 +143,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
mockConfigServerHandler(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null); mockConfigServerHandler(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null);
startServerWithHandlers(handler); startServerWithHandlers(handler);
Config config = ConfigService.getConfig(); Config config = ConfigService.getAppConfig();
assertEquals(someValue, config.getProperty(someKey, null)); assertEquals(someValue, config.getProperty(someKey, null));
} }
...@@ -154,7 +157,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -154,7 +157,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
ContextHandler metaServerHandler = mockMetaServerHandler(failAtFirstTime); ContextHandler metaServerHandler = mockMetaServerHandler(failAtFirstTime);
startServerWithHandlers(metaServerHandler, configHandler); startServerWithHandlers(metaServerHandler, configHandler);
Config config = ConfigService.getConfig(); Config config = ConfigService.getAppConfig();
assertEquals(someValue, config.getProperty(someKey, null)); assertEquals(someValue, config.getProperty(someKey, null));
} }
...@@ -169,7 +172,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -169,7 +172,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
mockConfigServerHandler(HttpServletResponse.SC_OK, apolloConfig, failedAtFirstTime); mockConfigServerHandler(HttpServletResponse.SC_OK, apolloConfig, failedAtFirstTime);
startServerWithHandlers(handler); startServerWithHandlers(handler);
Config config = ConfigService.getConfig(); Config config = ConfigService.getAppConfig();
assertEquals(someValue, config.getProperty(someKey, null)); assertEquals(someValue, config.getProperty(someKey, null));
} }
...@@ -192,7 +195,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -192,7 +195,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
ContextHandler handler = mockConfigServerHandler(HttpServletResponse.SC_OK, apolloConfig); ContextHandler handler = mockConfigServerHandler(HttpServletResponse.SC_OK, apolloConfig);
startServerWithHandlers(handler); startServerWithHandlers(handler);
Config config = ConfigService.getConfig(); Config config = ConfigService.getAppConfig();
final List<ConfigChangeEvent> changeEvents = Lists.newArrayList(); final List<ConfigChangeEvent> changeEvents = Lists.newArrayList();
final SettableFuture<Boolean> refreshFinished = SettableFuture.create(); final SettableFuture<Boolean> refreshFinished = SettableFuture.create();
...@@ -205,7 +208,8 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -205,7 +208,8 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
if (counter.incrementAndGet() > 1) { if (counter.incrementAndGet() > 1) {
return; return;
} }
assertEquals(1, changeEvent.getChanges().size()); assertEquals(1, changeEvent.changedKeys().size());
assertTrue(changeEvent.isChanged(someKey));
assertEquals(someValue, changeEvent.getChange(someKey).getOldValue()); assertEquals(someValue, changeEvent.getChange(someKey).getOldValue());
assertEquals(anotherValue, changeEvent.getChange(someKey).getNewValue()); assertEquals(anotherValue, changeEvent.getChange(someKey).getNewValue());
// if there is any assertion failed above, this line won't be executed // if there is any assertion failed above, this line won't be executed
...@@ -242,7 +246,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -242,7 +246,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
startServerWithHandlers(configHandler, pollHandler); startServerWithHandlers(configHandler, pollHandler);
Config config = ConfigService.getConfig(); Config config = ConfigService.getAppConfig();
assertEquals(someValue, config.getProperty(someKey, null)); assertEquals(someValue, config.getProperty(someKey, null));
final SettableFuture<Boolean> longPollFinished = SettableFuture.create(); final SettableFuture<Boolean> longPollFinished = SettableFuture.create();
......
...@@ -56,17 +56,11 @@ public class DefaultConfigManagerTest extends ComponentTestCase { ...@@ -56,17 +56,11 @@ public class DefaultConfigManagerTest extends ComponentTestCase {
return new ConfigFactory() { return new ConfigFactory() {
@Override @Override
public Config create(final String namespace) { public Config create(final String namespace) {
return new Config() { return new AbstractConfig() {
@Override @Override
public String getProperty(String key, String defaultValue) { public String getProperty(String key, String defaultValue) {
return namespace + ":" + key; return namespace + ":" + key;
} }
@Override
public void addChangeListener(ConfigChangeListener listener) {
}
}; };
} }
}; };
......
...@@ -156,7 +156,7 @@ public class DefaultConfigTest { ...@@ -156,7 +156,7 @@ public class DefaultConfigTest {
ConfigChangeEvent changeEvent = captor.getValue(); ConfigChangeEvent changeEvent = captor.getValue();
assertEquals(someNamespace, changeEvent.getNamespace()); assertEquals(someNamespace, changeEvent.getNamespace());
assertEquals(4, changeEvent.getChanges().size()); assertEquals(4, changeEvent.changedKeys().size());
ConfigChange anotherKeyChange = changeEvent.getChange(anotherKey); ConfigChange anotherKeyChange = changeEvent.getChange(anotherKey);
assertEquals(someLocalFileValue, anotherKeyChange.getOldValue()); assertEquals(someLocalFileValue, anotherKeyChange.getOldValue());
...@@ -176,6 +176,6 @@ public class DefaultConfigTest { ...@@ -176,6 +176,6 @@ public class DefaultConfigTest {
ConfigChange newKeyChange = changeEvent.getChange(newKey); ConfigChange newKeyChange = changeEvent.getChange(newKey);
assertEquals(null, newKeyChange.getOldValue()); assertEquals(null, newKeyChange.getOldValue());
assertEquals(newValue, newKeyChange.getNewValue()); assertEquals(newValue, newKeyChange.getNewValue());
assertEquals(PropertyChangeType.NEW, newKeyChange.getChangeType()); assertEquals(PropertyChangeType.ADDED, newKeyChange.getChangeType());
} }
} }
...@@ -93,7 +93,7 @@ public class SimpleConfigTest { ...@@ -93,7 +93,7 @@ public class SimpleConfigTest {
ConfigChangeEvent changeEvent = captor.getValue(); ConfigChangeEvent changeEvent = captor.getValue();
assertEquals(someNamespace, changeEvent.getNamespace()); assertEquals(someNamespace, changeEvent.getNamespace());
assertEquals(3, changeEvent.getChanges().size()); assertEquals(3, changeEvent.changedKeys().size());
ConfigChange someKeyChange = changeEvent.getChange(someKey); ConfigChange someKeyChange = changeEvent.getChange(someKey);
assertEquals(someValue, someKeyChange.getOldValue()); assertEquals(someValue, someKeyChange.getOldValue());
...@@ -108,6 +108,6 @@ public class SimpleConfigTest { ...@@ -108,6 +108,6 @@ public class SimpleConfigTest {
ConfigChange newKeyChange = changeEvent.getChange(newKey); ConfigChange newKeyChange = changeEvent.getChange(newKey);
assertEquals(null, newKeyChange.getOldValue()); assertEquals(null, newKeyChange.getOldValue());
assertEquals(newValue, newKeyChange.getNewValue()); assertEquals(newValue, newKeyChange.getNewValue());
assertEquals(PropertyChangeType.NEW, newKeyChange.getChangeType()); assertEquals(PropertyChangeType.ADDED, newKeyChange.getChangeType());
} }
} }
...@@ -25,6 +25,7 @@ public class ConfigServiceAutoConfiguration { ...@@ -25,6 +25,7 @@ public class ConfigServiceAutoConfiguration {
private String host; private String host;
@Value("${apollo.redis.port}") @Value("${apollo.redis.port}")
private int port; private int port;
@Bean @Bean
public JedisConnectionFactory redisConnectionFactory() { public JedisConnectionFactory redisConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory(); JedisConnectionFactory factory = new JedisConnectionFactory();
......
package com.ctrip.apollo.configservice; package com.ctrip.apollo.configservice;
import com.ctrip.apollo.biz.service.AppService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.ctrip.apollo.biz.service.AppService;
@Component @Component
public class ConfigServiceHealthIndicator implements HealthIndicator { public class ConfigServiceHealthIndicator implements HealthIndicator {
......
package com.ctrip.apollo.configservice.controller; package com.ctrip.apollo.configservice.controller;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.FluentIterable; import com.google.common.collect.FluentIterable;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
...@@ -9,7 +10,9 @@ import com.google.gson.reflect.TypeToken; ...@@ -9,7 +10,9 @@ import com.google.gson.reflect.TypeToken;
import com.ctrip.apollo.biz.entity.Release; import com.ctrip.apollo.biz.entity.Release;
import com.ctrip.apollo.biz.service.ConfigService; import com.ctrip.apollo.biz.service.ConfigService;
import com.ctrip.apollo.core.ConfigConsts;
import com.ctrip.apollo.core.dto.ApolloConfig; import com.ctrip.apollo.core.dto.ApolloConfig;
import com.dianping.cat.Cat;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
...@@ -45,8 +48,8 @@ public class ConfigController { ...@@ -45,8 +48,8 @@ public class ConfigController {
@RequestParam(value = "datacenter", required = false) String datacenter, @RequestParam(value = "datacenter", required = false) String datacenter,
@RequestParam(value = "releaseId", defaultValue = "-1") String clientSideReleaseId, @RequestParam(value = "releaseId", defaultValue = "-1") String clientSideReleaseId,
HttpServletResponse response) throws IOException { HttpServletResponse response) throws IOException {
//default namespace is appId return this.queryConfig(appId, clusterName, ConfigConsts.NAMESPACE_DEFAULT, datacenter,
return this.queryConfig(appId, clusterName, appId, datacenter, clientSideReleaseId, response); clientSideReleaseId, response);
} }
@RequestMapping(value = "/{appId}/{clusterName}/{namespace}", method = RequestMethod.GET) @RequestMapping(value = "/{appId}/{clusterName}/{namespace}", method = RequestMethod.GET)
...@@ -64,7 +67,7 @@ public class ConfigController { ...@@ -64,7 +67,7 @@ public class ConfigController {
} }
//if namespace is not appId itself, should check if it has its own configurations //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 //TODO find id for this particular namespace, if not equal to current app id, then do more
if (!Objects.isNull(datacenter)) { if (!Objects.isNull(datacenter)) {
//TODO load newAppId+datacenter+namespace configurations //TODO load newAppId+datacenter+namespace configurations
...@@ -77,6 +80,8 @@ public class ConfigController { ...@@ -77,6 +80,8 @@ public class ConfigController {
String.format( String.format(
"Could not load configurations with appId: %s, clusterName: %s, namespace: %s", "Could not load configurations with appId: %s, clusterName: %s, namespace: %s",
appId, clusterName, namespace)); appId, clusterName, namespace));
Cat.logEvent("Apollo.Config.NotFound",
assembleKey(appId, clusterName, namespace, datacenter));
return null; return null;
} }
...@@ -86,20 +91,21 @@ public class ConfigController { ...@@ -86,20 +91,21 @@ public class ConfigController {
if (mergedReleaseId.equals(clientSideReleaseId)) { if (mergedReleaseId.equals(clientSideReleaseId)) {
// Client side configuration is the same with server side, return 304 // Client side configuration is the same with server side, return 304
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
Cat.logEvent("Apollo.Config.NotModified",
assembleKey(appId, clusterName, namespace, datacenter));
return null; return null;
} }
ApolloConfig apolloConfig = new ApolloConfig(appId, clusterName, namespace, mergedReleaseId); ApolloConfig apolloConfig = new ApolloConfig(appId, clusterName, namespace, mergedReleaseId);
apolloConfig.setConfigurations(mergeReleaseConfigurations(releases)); apolloConfig.setConfigurations(mergeReleaseConfigurations(releases));
Cat.logEvent("Apollo.Config.Found", assembleKey(appId, clusterName, namespace, datacenter));
return apolloConfig; return apolloConfig;
} }
/** /**
* Merge configurations of releases. * Merge configurations of releases.
* Release in lower index override those in higher index * Release in lower index override those in higher index
* @param releases
* @return
*/ */
Map<String, String> mergeReleaseConfigurations(List<Release> releases) { Map<String, String> mergeReleaseConfigurations(List<Release> releases) {
Map<String, String> result = Maps.newHashMap(); Map<String, String> result = Maps.newHashMap();
...@@ -109,4 +115,12 @@ public class ConfigController { ...@@ -109,4 +115,12 @@ public class ConfigController {
return result; 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; ...@@ -8,10 +8,14 @@ import com.google.common.collect.Multimaps;
import com.ctrip.apollo.biz.message.MessageListener; import com.ctrip.apollo.biz.message.MessageListener;
import com.ctrip.apollo.biz.message.Topics; import com.ctrip.apollo.biz.message.Topics;
import com.ctrip.apollo.core.ConfigConsts;
import com.ctrip.apollo.core.dto.ApolloConfigNotification; import com.ctrip.apollo.core.dto.ApolloConfigNotification;
import com.dianping.cat.Cat;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
...@@ -31,27 +35,23 @@ import javax.servlet.http.HttpServletResponse; ...@@ -31,27 +35,23 @@ import javax.servlet.http.HttpServletResponse;
@RequestMapping("/notifications") @RequestMapping("/notifications")
public class NotificationController implements MessageListener { public class NotificationController implements MessageListener {
private static final Logger logger = LoggerFactory.getLogger(NotificationController.class); private static final Logger logger = LoggerFactory.getLogger(NotificationController.class);
private final static long TIMEOUT = 360 * 60 * 1000;//6 hours private static final long TIMEOUT = 360 * 60 * 1000;//6 hours
private final Multimap<String, DeferredResult<ApolloConfigNotification>> deferredResults = private final Multimap<String, DeferredResult<ResponseEntity<ApolloConfigNotification>>>
deferredResults =
Multimaps.synchronizedSetMultimap(HashMultimap.create()); Multimaps.synchronizedSetMultimap(HashMultimap.create());
@RequestMapping(method = RequestMethod.GET) @RequestMapping(method = RequestMethod.GET)
public DeferredResult<ApolloConfigNotification> pollNotification( public DeferredResult<ResponseEntity<ApolloConfigNotification>> pollNotification(
@RequestParam(value = "appId") String appId, @RequestParam(value = "appId") String appId,
@RequestParam(value = "cluster") String cluster, @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 = "datacenter", required = false) String datacenter,
@RequestParam(value = "releaseId", defaultValue = "-1") String clientSideReleaseId, @RequestParam(value = "releaseId", defaultValue = "-1") String clientSideReleaseId,
HttpServletResponse response) { HttpServletResponse response) {
//check default namespace
if (Objects.isNull(namespace)) {
namespace = appId;
}
List<String> watchedKeys = Lists.newArrayList(assembleKey(appId, cluster, namespace)); List<String> watchedKeys = Lists.newArrayList(assembleKey(appId, cluster, namespace));
//Listen more namespaces, since it's not the default 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 //TODO find id for this particular namespace, if not equal to current app id, then do more
if (!Objects.isNull(datacenter)) { if (!Objects.isNull(datacenter)) {
//TODO add newAppId+datacenter+namespace to listened keys //TODO add newAppId+datacenter+namespace to listened keys
...@@ -59,8 +59,10 @@ public class NotificationController implements MessageListener { ...@@ -59,8 +59,10 @@ public class NotificationController implements MessageListener {
//TODO add newAppId+defaultCluster+namespace to listened keys //TODO add newAppId+defaultCluster+namespace to listened keys
} }
DeferredResult<ApolloConfigNotification> deferredResult = ResponseEntity<ApolloConfigNotification> body = new ResponseEntity<>(
new DeferredResult<>(TIMEOUT); HttpStatus.NOT_MODIFIED);
DeferredResult<ResponseEntity<ApolloConfigNotification>> deferredResult =
new DeferredResult<>(TIMEOUT, body);
//register all keys //register all keys
for (String key : watchedKeys) { for (String key : watchedKeys) {
...@@ -74,10 +76,8 @@ public class NotificationController implements MessageListener { ...@@ -74,10 +76,8 @@ public class NotificationController implements MessageListener {
} }
}); });
deferredResult.onTimeout(() -> { logger.info("Listening {} from appId: {}, cluster: {}, namespace: {}, datacenter: {}",
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); watchedKeys, appId, cluster, namespace, datacenter);
});
return deferredResult; return deferredResult;
} }
...@@ -88,6 +88,7 @@ public class NotificationController implements MessageListener { ...@@ -88,6 +88,7 @@ public class NotificationController implements MessageListener {
@Override @Override
public void handleMessage(String message, String channel) { public void handleMessage(String message, String channel) {
logger.info("message received - channel: {}, message: {}", channel, message); logger.info("message received - channel: {}, message: {}", channel, message);
Cat.logEvent("Apollo.LongPoll.Message", message);
if (!Topics.APOLLO_RELEASE_TOPIC.equals(channel) || Strings.isNullOrEmpty(message)) { if (!Topics.APOLLO_RELEASE_TOPIC.equals(channel) || Strings.isNullOrEmpty(message)) {
return; return;
} }
...@@ -98,12 +99,16 @@ public class NotificationController implements MessageListener { ...@@ -98,12 +99,16 @@ public class NotificationController implements MessageListener {
return; 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); logger.info("Notify {} clients for key {}", results.size(), message);
for (DeferredResult<ApolloConfigNotification> result : results) { for (DeferredResult<ResponseEntity<ApolloConfigNotification>> result : results) {
result.setResult(notification); result.setResult(notification);
} }
} }
......
...@@ -10,7 +10,7 @@ import com.ctrip.apollo.common.controller.WebSecurityConfig; ...@@ -10,7 +10,7 @@ import com.ctrip.apollo.common.controller.WebSecurityConfig;
@Configuration @Configuration
@ComponentScan(excludeFilters = {@Filter(type = FilterType.ASSIGNABLE_TYPE, value = { @ComponentScan(excludeFilters = {@Filter(type = FilterType.ASSIGNABLE_TYPE, value = {
SampleConfigServiceApplication.class, ConfigServiceApplication.class, WebSecurityConfig.class})}) SampleConfigServiceApplication.class, ConfigServiceApplication.class})})
@EnableAutoConfiguration @EnableAutoConfiguration
public class ConfigServiceTestConfiguration { public class ConfigServiceTestConfiguration {
......
...@@ -2,13 +2,16 @@ package com.ctrip.apollo.configservice; ...@@ -2,13 +2,16 @@ package com.ctrip.apollo.configservice;
import com.ctrip.apollo.configservice.controller.ConfigControllerTest; import com.ctrip.apollo.configservice.controller.ConfigControllerTest;
import com.ctrip.apollo.configservice.controller.NotificationControllerTest; 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.runner.RunWith;
import org.junit.runners.Suite; import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses; import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class) @RunWith(Suite.class)
@SuiteClasses({ConfigControllerTest.class, NotificationControllerTest.class}) @SuiteClasses({ConfigControllerTest.class, NotificationControllerTest.class,
ConfigControllerIntegrationTest.class, NotificationControllerIntegrationTest.class})
public class AllTests { 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; ...@@ -10,6 +10,8 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.context.request.async.DeferredResult; import org.springframework.web.context.request.async.DeferredResult;
...@@ -31,7 +33,7 @@ public class NotificationControllerTest { ...@@ -31,7 +33,7 @@ public class NotificationControllerTest {
private String someReleaseId; private String someReleaseId;
@Mock @Mock
private HttpServletResponse response; private HttpServletResponse response;
private Multimap<String, DeferredResult<ApolloConfigNotification>> deferredResults; private Multimap<String, DeferredResult<ResponseEntity<ApolloConfigNotification>>> deferredResults;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
...@@ -43,7 +45,7 @@ public class NotificationControllerTest { ...@@ -43,7 +45,7 @@ public class NotificationControllerTest {
someReleaseId = "someRelease"; someReleaseId = "someRelease";
deferredResults = deferredResults =
(Multimap<String, DeferredResult<ApolloConfigNotification>>) ReflectionTestUtils (Multimap<String, DeferredResult<ResponseEntity<ApolloConfigNotification>>>) ReflectionTestUtils
.getField(controller, "deferredResults"); .getField(controller, "deferredResults");
} }
...@@ -51,7 +53,7 @@ public class NotificationControllerTest { ...@@ -51,7 +53,7 @@ public class NotificationControllerTest {
public void testPollNotificationWithDefaultNamespace() throws Exception { public void testPollNotificationWithDefaultNamespace() throws Exception {
someNamespace = someAppId; //default namespace someNamespace = someAppId; //default namespace
DeferredResult<ApolloConfigNotification> DeferredResult<ResponseEntity<ApolloConfigNotification>>
deferredResult = controller deferredResult = controller
.pollNotification(someAppId, someCluster, someNamespace, someDataCenter, someReleaseId, .pollNotification(someAppId, someCluster, someNamespace, someDataCenter, someReleaseId,
response); response);
...@@ -66,7 +68,7 @@ public class NotificationControllerTest { ...@@ -66,7 +68,7 @@ public class NotificationControllerTest {
public void testPollNotificationWithDefaultNamespaceAndHandleMessage() throws Exception { public void testPollNotificationWithDefaultNamespaceAndHandleMessage() throws Exception {
someNamespace = someAppId; //default namespace someNamespace = someAppId; //default namespace
DeferredResult<ApolloConfigNotification> DeferredResult<ResponseEntity<ApolloConfigNotification>>
deferredResult = controller deferredResult = controller
.pollNotification(someAppId, someCluster, someNamespace, someDataCenter, someReleaseId, .pollNotification(someAppId, someCluster, someNamespace, someDataCenter, someReleaseId,
response); response);
...@@ -75,8 +77,11 @@ public class NotificationControllerTest { ...@@ -75,8 +77,11 @@ public class NotificationControllerTest {
controller.handleMessage(key, Topics.APOLLO_RELEASE_TOPIC); 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(someAppId, notification.getAppId());
assertEquals(someCluster, notification.getCluster()); assertEquals(someCluster, notification.getCluster());
assertEquals(someNamespace, notification.getNamespace()); 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.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy
spring.h2.console.enabled = true spring.h2.console.enabled = true
spring.h2.console.settings.web-allow-others=true spring.h2.console.settings.web-allow-others=true
spring.jpa.properties.hibernate.show_sql=true spring.jpa.properties.hibernate.show_sql=true
\ No newline at end of file
...@@ -11,24 +11,24 @@ INSERT INTO Cluster (AppId, Name) VALUES ('100003173', 'default'); ...@@ -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 ('100003173', 'cluster3');
INSERT INTO Cluster (AppId, Name) VALUES ('fxhermesproducer', 'default'); 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 ('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 ('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 ('100003173', 'fx.apollo.portal');
INSERT INTO AppNamespace (AppID, Name) VALUES ('fxhermesproducer', 'fx.hermes.producer'); 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 (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 (3, '100003172', 'default', 'application');
INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (4, '100003173', 'default', '100003173'); INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (4, '100003173', 'default', 'application');
INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (5, '100003171', 'default', '100003171'); 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, 'k1', 'v1', 'comment1');
INSERT INTO Item (NamespaceId, `Key`, Value, Comment) VALUES (1, 'k2', 'v2', 'comment2'); 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 (2, 'k3', 'v3', 'comment3');
INSERT INTO Item (NamespaceId, `Key`, Value, Comment) VALUES (5, 'k3', 'v4', 'comment4'); 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; package com.ctrip.apollo.core;
public interface ConfigConsts { public interface ConfigConsts {
String NAMESPACE_DEFAULT = "application";
String CLUSTER_NAME_DEFAULT = "default"; String CLUSTER_NAME_DEFAULT = "default";
} }
...@@ -2,6 +2,8 @@ package com.ctrip.apollo.core.dto; ...@@ -2,6 +2,8 @@ package com.ctrip.apollo.core.dto;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import com.ctrip.apollo.Apollo;
import java.util.Map; import java.util.Map;
/** /**
...@@ -19,11 +21,13 @@ public class ApolloConfig { ...@@ -19,11 +21,13 @@ public class ApolloConfig {
private String releaseId; private String releaseId;
public ApolloConfig() {
}
public ApolloConfig(String appId, public ApolloConfig(String appId,
String cluster, String cluster,
String namespace, String namespace,
String releaseId) { String releaseId) {
super();
this.appId = appId; this.appId = appId;
this.cluster = cluster; this.cluster = cluster;
this.namespace = namespace; this.namespace = namespace;
...@@ -50,6 +54,22 @@ public class ApolloConfig { ...@@ -50,6 +54,22 @@ public class ApolloConfig {
return configurations; 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) { public void setConfigurations(Map<String, String> configurations) {
this.configurations = configurations; this.configurations = configurations;
} }
......
...@@ -4,9 +4,13 @@ package com.ctrip.apollo.core.dto; ...@@ -4,9 +4,13 @@ package com.ctrip.apollo.core.dto;
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
*/ */
public class ApolloConfigNotification { public class ApolloConfigNotification {
private final String appId; private String appId;
private final String cluster; private String cluster;
private final String namespace; private String namespace;
//for json converter
public ApolloConfigNotification() {
}
public ApolloConfigNotification(String appId, String cluster, String namespace) { public ApolloConfigNotification(String appId, String cluster, String namespace) {
this.appId = appId; this.appId = appId;
...@@ -25,4 +29,16 @@ public class ApolloConfigNotification { ...@@ -25,4 +29,16 @@ public class ApolloConfigNotification {
public String getNamespace() { public String getNamespace() {
return namespace; 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 { ...@@ -22,7 +22,7 @@ public class ApolloConfigDemo implements ConfigChangeListener {
private Config config; private Config config;
public ApolloConfigDemo() { public ApolloConfigDemo() {
config = ConfigService.getConfig(); config = ConfigService.getAppConfig();
config.addChangeListener(this); config.addChangeListener(this);
} }
...@@ -53,7 +53,8 @@ public class ApolloConfigDemo implements ConfigChangeListener { ...@@ -53,7 +53,8 @@ public class ApolloConfigDemo implements ConfigChangeListener {
@Override @Override
public void onChange(ConfigChangeEvent changeEvent) { public void onChange(ConfigChangeEvent changeEvent) {
logger.info("Changes for namespace {}", changeEvent.getNamespace()); 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: {}", logger.info("Change - key: {}, oldValue: {}, newValue: {}, changeType: {}",
change.getPropertyName(), change.getOldValue(), change.getNewValue(), change.getPropertyName(), change.getOldValue(), change.getNewValue(),
change.getChangeType()); change.getChangeType());
......
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