Commit f4a79c28 by Yiming Liu

Merge pull request #67 from nobodyiam/unidal-rewrite-merge

client rewrite using unidal
parents b4c6e2f3 7a1b0d1c
......@@ -7,7 +7,7 @@ import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
@Entity
@SQLDelete(sql = "Update App set isDeleted = 'false' where id = ?")
@SQLDelete(sql = "Update App set isDeleted = 1 where id = ?")
@Where(clause = "isDeleted = 0")
public class App extends BaseEntity {
......
......@@ -7,7 +7,7 @@ import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
@Entity
@SQLDelete(sql = "Update AppNamespace set isDeleted = 'false' where id = ?")
@SQLDelete(sql = "Update AppNamespace set isDeleted = 1 where id = ?")
@Where(clause = "isDeleted = 0")
public class AppNamespace extends BaseEntity{
......
......@@ -10,7 +10,7 @@ import org.hibernate.annotations.Where;
* @author Jason Song(song_s@ctrip.com)
*/
@Entity
@SQLDelete(sql = "Update Cluster set isDeleted = 'false' where id = ?")
@SQLDelete(sql = "Update Cluster set isDeleted = 1 where id = ?")
@Where(clause = "isDeleted = 0")
public class Cluster extends BaseEntity {
......
......@@ -7,7 +7,7 @@ import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
@Entity
@SQLDelete(sql = "Update Item set isDeleted = 'false' where id = ?")
@SQLDelete(sql = "Update Item set isDeleted = 1 where id = ?")
@Where(clause = "isDeleted = 0")
public class Item extends BaseEntity {
......
......@@ -7,7 +7,7 @@ import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
@Entity
@SQLDelete(sql = "Update Namespace set isDeleted = 'false' where id = ?")
@SQLDelete(sql = "Update Namespace set isDeleted = 1 where id = ?")
@Where(clause = "isDeleted = 0")
public class Namespace extends BaseEntity {
......
......@@ -7,7 +7,7 @@ import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
@Entity
@SQLDelete(sql = "Update Privilege set isDeleted = 'false' where id = ?")
@SQLDelete(sql = "Update Privilege set isDeleted = 1 where id = ?")
@Where(clause = "isDeleted = 0")
public class Privilege extends BaseEntity {
......
package com.ctrip.apollo.biz.entity;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Lob;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Entity
@SQLDelete(sql = "Update Release set isDeleted = 'false' where id = ?")
@SQLDelete(sql = "Update Release set isDeleted = 1 where id = ?")
@Where(clause = "isDeleted = 0")
public class Release extends BaseEntity {
......
......@@ -4,5 +4,12 @@ package com.ctrip.apollo;
* @author Jason Song(song_s@ctrip.com)
*/
public interface Config {
/**
* Return the 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
*/
public String getProperty(String key, String defaultValue);
}
......@@ -10,6 +10,7 @@ import org.codehaus.plexus.component.repository.exception.ComponentLookupExcepti
import org.unidal.lookup.ContainerLoader;
/**
* Entry point for client config use
* @author Jason Song(song_s@ctrip.com)
*/
public class ConfigService {
......@@ -21,10 +22,19 @@ public class ConfigService {
m_container = ContainerLoader.getDefaultContainer();
}
/**
* Get the config instance with default namespace
* @return config instance
*/
public static Config getConfig() {
return getConfig(ConfigConsts.NAMESPACE_APPLICATION);
}
/**
* Get the config instance for the namespace
* @param namespace the namespace of the config
* @return config instance
*/
public static Config getConfig(String namespace) {
return getManager().getConfig(namespace);
}
......
package com.ctrip.apollo.client;
import com.google.common.collect.Lists;
import com.ctrip.apollo.client.config.Config;
import com.ctrip.apollo.client.manager.ConfigManager;
import com.ctrip.apollo.client.manager.ConfigManagerManager;
import com.ctrip.apollo.core.ConfigConsts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.ServiceLoader;
/**
* Entry point for client config use
* @author Jason Song(song_s@ctrip.com)
*/
public class ConfigService {
private static final Logger logger = LoggerFactory.getLogger(ConfigService.class);
private static ConfigService instance = new ConfigService();
private List<ConfigManager> configManagers;
private ConfigService() {
this.loadConfigManagers();
}
/**
* Get the config instance with default namespace
* @return config instance
* @throws RuntimeException if config could not be loaded for the default namespace
*/
public static Config getConfig() {
return getConfig(ConfigConsts.NAMESPACE_APPLICATION);
}
/**
* Get the config instance for the namespace
* @param namespace the namespace of the config
* @return config instance
* @throws RuntimeException if config could not be loaded for the specified namespace
*/
public static Config getConfig(String namespace) {
return instance.doGetConfig(namespace);
}
Config doGetConfig(String namespace) {
for (ConfigManager configManager : this.configManagers) {
try {
return configManager.findOrCreate(namespace);
} catch (Throwable th) {
logger.error("Get config failed for namespace {} using config manager {}", namespace,
configManager.getClass(), th);
}
}
throw new RuntimeException(String.format("Could not get config for namespace: %s", namespace));
}
void loadConfigManagers() {
configManagers = Lists.newArrayList();
ServiceLoader<ConfigManagerManager> configManagerManagers =
ServiceLoader.load(ConfigManagerManager.class);
for (ConfigManagerManager configManagerManager : configManagerManagers) {
configManagers.add(configManagerManager.getConfigManager());
}
}
}
package com.ctrip.apollo.client.config;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public interface Config {
/**
* Return the property value with the given key, or {@code null}
* if the key doesn't exist.
*
* @param key the property name
* @return the property value
*/
String getProperty(String key);
/**
* Return the 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
*/
String getProperty(String key, String defaultValue);
}
package com.ctrip.apollo.client.config.impl;
import com.ctrip.apollo.client.config.Config;
import com.ctrip.apollo.client.loader.ConfigLoader;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class LocalFileConfig implements Config {
private ConfigLoader configLoader;
private String namespace;
public LocalFileConfig(ConfigLoader configLoader, String namespace) {
this.configLoader = configLoader;
this.namespace = namespace;
}
@Override
public String getProperty(String key) {
return null;
}
@Override
public String getProperty(String key, String defaultValue) {
String value = getProperty(key);
return value == null ? defaultValue : value;
}
}
package com.ctrip.apollo.client.config.impl;
import com.ctrip.apollo.client.config.Config;
import com.ctrip.apollo.client.loader.ConfigLoader;
import com.ctrip.apollo.client.model.ApolloRegistry;
import com.ctrip.apollo.client.model.PropertyChange;
import com.ctrip.apollo.client.util.ConfigUtil;
import com.ctrip.apollo.core.dto.ApolloConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.PropertySource;
import java.util.List;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class RemoteConfig implements Config {
private static final Logger logger = LoggerFactory.getLogger(RemoteConfig.class);
private ConfigLoader configLoader;
private ConfigUtil configUtil;
private String namespace;
private ApolloConfig currentApolloConfig;
private ApolloConfig previousApolloConfig;
public RemoteConfig(ConfigLoader configLoader, String namespace) {
this.configLoader = configLoader;
this.namespace = namespace;
this.configUtil = ConfigUtil.getInstance();
this.initialize();
}
void initialize() {
this.loadApolloConfig(
new ApolloRegistry(this.configUtil.getAppId(), this.configUtil.getCluster(),
namespace));
}
@Override
public String getProperty(String key) {
String value = this.currentApolloConfig.getProperty(key);
if (value == null) {
return null;
}
return value;
}
@Override
public String getProperty(String key, String defaultValue) {
String value = getProperty(key);
return value == null ? defaultValue : value;
}
synchronized ApolloConfig loadApolloConfig(ApolloRegistry apolloRegistry) {
resetApolloRegistryConfigCache();
ApolloConfig result =
configLoader.loadApolloConfig(apolloRegistry, getPreviousApolloConfig());
if (result == null) {
logger.error("Loaded config null...");
return null;
}
logger.info("Loaded config: {}", result);
updateCurrentApolloConfigCache(result);
return result;
}
void resetApolloRegistryConfigCache() {
this.previousApolloConfig = currentApolloConfig;
this.currentApolloConfig = null;
}
ApolloConfig getPreviousApolloConfig() {
return this.previousApolloConfig;
}
void updateCurrentApolloConfigCache(ApolloConfig apolloConfig) {
this.currentApolloConfig = apolloConfig;
}
}
package com.ctrip.apollo.client.factory;
import com.ctrip.apollo.client.config.Config;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public interface ConfigFactory {
/**
* create config instance for the namespace
* @param namespace
* @return
*/
Config createConfig(String namespace);
}
package com.ctrip.apollo.client.factory;
import com.ctrip.apollo.client.loader.ConfigLoader;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public interface ConfigLoaderFactory {
/**
* create config loader
* @return
*/
ConfigLoader createConfigLoader();
}
package com.ctrip.apollo.client.factory.impl;
import com.ctrip.apollo.client.config.Config;
import com.ctrip.apollo.client.config.impl.LocalFileConfig;
import com.ctrip.apollo.client.factory.ConfigFactory;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class LocalConfigFactory implements ConfigFactory {
private static final LocalConfigFactory instance = new LocalConfigFactory();
private LocalConfigFactory() {
}
public static LocalConfigFactory getInstance() {
return instance;
}
@Override
public Config createConfig(String namespace) {
return new LocalFileConfig(LocalConfigLoaderFactory.getInstance().createConfigLoader(),
namespace);
}
}
package com.ctrip.apollo.client.factory.impl;
import com.ctrip.apollo.client.factory.ConfigLoaderFactory;
import com.ctrip.apollo.client.loader.ConfigLoader;
import com.ctrip.apollo.client.loader.ConfigServiceLocator;
import com.ctrip.apollo.client.loader.impl.LocalFileConfigLoader;
import com.ctrip.apollo.client.loader.impl.RemoteConfigLoader;
import org.springframework.web.client.RestTemplate;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class LocalConfigLoaderFactory implements ConfigLoaderFactory {
private static LocalConfigLoaderFactory instance = new LocalConfigLoaderFactory();
private LocalConfigLoaderFactory() {
}
public static LocalConfigLoaderFactory getInstance() {
return instance;
}
@Override
public ConfigLoader createConfigLoader() {
ConfigLoader configLoader = new LocalFileConfigLoader();
return configLoader;
}
}
package com.ctrip.apollo.client.factory.impl;
import com.ctrip.apollo.client.config.Config;
import com.ctrip.apollo.client.config.impl.RemoteConfig;
import com.ctrip.apollo.client.factory.ConfigFactory;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class RemoteConfigFactory implements ConfigFactory {
private static final RemoteConfigFactory instance = new RemoteConfigFactory();
private RemoteConfigFactory() {
}
public static RemoteConfigFactory getInstance() {
return instance;
}
@Override
public Config createConfig(String namespace) {
return new RemoteConfig(RemoteConfigLoaderFactory.getInstance().createConfigLoader(), namespace);
}
}
package com.ctrip.apollo.client.factory.impl;
import com.ctrip.apollo.client.factory.ConfigLoaderFactory;
import com.ctrip.apollo.client.loader.ConfigLoader;
import com.ctrip.apollo.client.loader.ConfigServiceLocator;
import com.ctrip.apollo.client.loader.impl.RemoteConfigLoader;
import org.springframework.web.client.RestTemplate;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class RemoteConfigLoaderFactory implements ConfigLoaderFactory {
private static RemoteConfigLoaderFactory configLoaderFactory = new RemoteConfigLoaderFactory();
private RemoteConfigLoaderFactory() {
}
public static RemoteConfigLoaderFactory getInstance() {
return configLoaderFactory;
}
@Override
public ConfigLoader createConfigLoader() {
ConfigLoader
remoteConfigLoader =
new RemoteConfigLoader(new RestTemplate(), new ConfigServiceLocator());
return remoteConfigLoader;
}
}
package com.ctrip.apollo.client.loader;
import com.ctrip.apollo.client.model.ApolloRegistry;
import com.ctrip.apollo.core.dto.ApolloConfig;
/**
* @author Jason Song(songs_ctrip.com)
*/
public interface ConfigLoader {
/**
* Load apollo config
* @param apolloRegistry
* @param previous
* @return
*/
ApolloConfig loadApolloConfig(ApolloRegistry apolloRegistry, ApolloConfig previous);
}
package com.ctrip.apollo.client.loader.impl;
import com.ctrip.apollo.client.loader.ConfigLoader;
import com.ctrip.apollo.client.model.ApolloRegistry;
import com.ctrip.apollo.core.dto.ApolloConfig;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public abstract class AbstractConfigLoader implements ConfigLoader {
@Override
public ApolloConfig loadApolloConfig(ApolloRegistry apolloRegistry, ApolloConfig previous) {
try {
return doLoadApolloConfig(apolloRegistry, previous);
} catch (Throwable ex) {
throw new RuntimeException(
String.format("Load Apollo Config failed - %s", apolloRegistry.toString()), ex);
}
}
protected abstract ApolloConfig doLoadApolloConfig(ApolloRegistry apolloRegistry,
ApolloConfig previous);
}
package com.ctrip.apollo.client.loader.impl;
import com.ctrip.apollo.client.model.ApolloRegistry;
import com.ctrip.apollo.core.dto.ApolloConfig;
/**
* Load config from local backup file
*
* @author Jason Song(song_s@ctrip.com)
*/
public class LocalFileConfigLoader extends AbstractConfigLoader {
@Override
public ApolloConfig doLoadApolloConfig(ApolloRegistry apolloRegistry, ApolloConfig previous) {
throw new IllegalStateException("Not implemented yet!");
}
}
package com.ctrip.apollo.client.manager;
import com.ctrip.apollo.client.config.Config;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public interface ConfigManager {
/**
* get config according to the namespace
* @param namespace the namespace of the config
* @return config instance
*/
Config findOrCreate(String namespace);
}
package com.ctrip.apollo.client.manager;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public interface ConfigManagerManager {
/**
* get the config manager
* @return config manager instance
*/
ConfigManager getConfigManager();
}
package com.ctrip.apollo.client.manager.impl;
import com.ctrip.apollo.client.config.Config;
import com.ctrip.apollo.client.factory.ConfigFactory;
import com.ctrip.apollo.client.manager.ConfigManager;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public abstract class AbstractConfigManager implements ConfigManager {
private ConcurrentMap<String, Config> configs;
private ConfigFactory configFactory;
public AbstractConfigManager(
ConfigFactory configFactory) {
this.configs = new ConcurrentHashMap<>();
this.configFactory = configFactory;
}
@Override
public Config findOrCreate(String namespace) {
Config config = configs.get(namespace);
if (config == null) {
synchronized (configs) {
config = configs.get(namespace);
if (config == null) {
config = configFactory.createConfig(namespace);
configs.put(namespace, config);
}
}
}
return config;
}
}
package com.ctrip.apollo.client.manager.impl;
import com.ctrip.apollo.client.factory.ConfigFactory;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class LocalFileConfigManager extends AbstractConfigManager {
public LocalFileConfigManager(ConfigFactory configFactory) {
super(configFactory);
}
}
package com.ctrip.apollo.client.manager.impl;
import com.ctrip.apollo.client.factory.impl.LocalConfigFactory;
import com.ctrip.apollo.client.manager.ConfigManager;
import com.ctrip.apollo.client.manager.ConfigManagerManager;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class LocalFileConfigManagerManager implements ConfigManagerManager{
@Override
public ConfigManager getConfigManager() {
return new LocalFileConfigManager(LocalConfigFactory.getInstance());
}
}
package com.ctrip.apollo.client.manager.impl;
import com.ctrip.apollo.client.factory.ConfigFactory;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class RemoteConfigManager extends AbstractConfigManager{
public RemoteConfigManager(ConfigFactory configFactory) {
super(configFactory);
}
}
package com.ctrip.apollo.client.manager.impl;
import com.ctrip.apollo.client.factory.impl.RemoteConfigFactory;
import com.ctrip.apollo.client.manager.ConfigManager;
import com.ctrip.apollo.client.manager.ConfigManagerManager;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class RemoteConfigManagerManager implements ConfigManagerManager {
@Override
public ConfigManager getConfigManager() {
return new RemoteConfigManager(RemoteConfigFactory.getInstance());
}
}
package com.ctrip.apollo.client.model;
import com.google.common.base.MoreObjects;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class ApolloRegistry {
private String appId;
private String clusterName;
private String namespace;
public ApolloRegistry(String appId, String clusterName, String namespace) {
this.appId = appId;
this.clusterName = clusterName;
this.namespace = namespace;
}
public String getAppId() {
return appId;
}
public String getClusterName() {
return clusterName;
}
public String getNamespace() {
return namespace;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.omitNullValues()
.add("appId", appId)
.add("clusterName", clusterName)
.add("namespace", namespace)
.toString();
}
}
package com.ctrip.apollo.client.model;
import com.google.common.collect.Lists;
import org.springframework.core.env.CompositePropertySource;
import java.util.List;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class PropertySourceReloadResult {
private CompositePropertySource propertySource;
private List<PropertyChange> changes;
public PropertySourceReloadResult(CompositePropertySource propertySource) {
this.propertySource = propertySource;
changes = Lists.newArrayList();
}
public PropertySourceReloadResult(CompositePropertySource propertySource,
List<PropertyChange> changes) {
this.propertySource = propertySource;
this.changes = changes;
}
public CompositePropertySource getPropertySource() {
return propertySource;
}
public void setPropertySource(CompositePropertySource propertySource) {
this.propertySource = propertySource;
}
public List<PropertyChange> getChanges() {
return changes;
}
public void setChanges(List<PropertyChange> changes) {
this.changes = changes;
}
public boolean hasChanges() {
return !changes.isEmpty();
}
}
package com.ctrip.apollo.client.constants;
package com.ctrip.apollo.constants;
/**
* @author Jason Song(song_s@ctrip.com)
......
package com.ctrip.apollo.client.env;
package com.ctrip.apollo.env;
import com.ctrip.apollo.Apollo;
import com.ctrip.apollo.Apollo.Env;
import com.ctrip.apollo.client.constants.Constants;
import com.ctrip.apollo.constants.Constants;
import com.ctrip.apollo.core.MetaDomainConsts;
import com.ctrip.apollo.core.utils.ResourceUtils;
import com.ctrip.apollo.core.utils.StringUtils;
......
package com.ctrip.apollo.internals;
import java.util.Properties;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public interface ConfigLoader {
public Properties loadConfig();
}
package com.ctrip.apollo.client.loader;
package com.ctrip.apollo.internals;
import com.ctrip.apollo.client.env.ClientEnvironment;
import com.ctrip.apollo.core.dto.ServiceDTO;
import com.ctrip.apollo.env.ClientEnvironment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......
package com.ctrip.apollo.internals;
import com.ctrip.apollo.Config;
import com.ctrip.apollo.core.utils.ClassLoaderUtil;
import com.dianping.cat.Cat;
import java.io.File;
......@@ -12,22 +13,53 @@ import java.util.Properties;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class DefaultConfig implements Config {
public class DefaultConfig implements Config, ConfigLoader {
private final String m_namespace;
private final File m_baseDir;
private Properties m_resourceProperties;
private Properties m_fileProperties;
private ConfigLoader m_fallbackLoader;
public DefaultConfig(File baseDir, String namespace) {
public DefaultConfig(File baseDir, String namespace, ConfigLoader fallbackLoader) {
m_namespace = namespace;
m_resourceProperties = loadFromResource(namespace);
m_fileProperties = loadFromFile(baseDir, namespace);
m_baseDir = baseDir;
m_resourceProperties = loadFromResource(m_namespace);
m_fallbackLoader = fallbackLoader;
this.initLocalConfig();
}
@Override
public String getProperty(String key, String defaultValue) {
// step 1: check system properties, i.e. -Dkey=value
String value = System.getProperty(key);
// step 2: check local cached properties file
if (value == null) {
value = m_fileProperties.getProperty(key);
}
/**
* step 3: check env variable, i.e. PATH=...
* normally system environment variables are in UPPERCASE, however there might be exceptions.
* so the caller should provide the key in the right case
*/
if (value == null) {
value = System.getenv(key);
}
// step 4: check properties file from classpath
if (value == null) {
if (m_resourceProperties != null) {
value = (String) m_resourceProperties.get(key);
}
}
return value == null ? defaultValue : value;
}
private Properties loadFromResource(String namespace) {
String name = String.format("/META-INF/config/%s.properties", namespace);
InputStream in = getClass().getResourceAsStream(name);
String name = String.format("META-INF/config/%s.properties", namespace);
InputStream in = ClassLoaderUtil.getLoader().getResourceAsStream(name);
Properties properties = null;
if (in != null) {
......@@ -81,30 +113,28 @@ public class DefaultConfig implements Config {
return properties;
}
@Override
public String getProperty(String key, String defaultValue) {
// step 1: check system properties, i.e. -Dkey=value
String value = System.getProperty(key);
// step 2: check local cached properties file
if (value == null) {
if (m_fileProperties != null) {
value = (String) m_fileProperties.get(key);
}
void initLocalConfig() {
m_fileProperties = this.loadFromFile(m_baseDir, m_namespace);
//TODO check if local file is expired
if (m_fileProperties == null && m_fallbackLoader != null) {
m_fileProperties = m_fallbackLoader.loadConfig();
}
// step 3: check env variable, i.e. PATH=...
if (value == null) {
value = System.getenv(key); // TODO fix naming issues
if (m_fileProperties == null) {
throw new RuntimeException(
String.format("Init Apollo Local Config failed - namespace: %s",
m_namespace));
}
//TODO persist file
}
// step 4: check properties file from classpath
if (value == null) {
if (m_resourceProperties != null) {
value = (String) m_resourceProperties.get(key);
}
}
@Override
public Properties loadConfig() {
Properties result = new Properties();
result.putAll(m_fileProperties);
return result;
}
return value;
public ConfigLoader getFallbackLoader() {
return m_fallbackLoader;
}
}
......@@ -14,7 +14,7 @@ import java.util.Map;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Named(type = ConfigManager.class)
@Named(type = ConfigManager.class, value = "default")
public class DefaultConfigManager implements ConfigManager {
@Inject
private ConfigFactoryManager m_factoryManager;
......
package com.ctrip.apollo.client.loader.impl;
package com.ctrip.apollo.internals;
import com.google.common.collect.Maps;
import com.ctrip.apollo.client.loader.ConfigServiceLocator;
import com.ctrip.apollo.client.model.ApolloRegistry;
import com.ctrip.apollo.client.util.ConfigUtil;
import com.ctrip.apollo.Config;
import com.ctrip.apollo.core.dto.ApolloConfig;
import com.ctrip.apollo.core.dto.ServiceDTO;
import com.ctrip.apollo.util.ConfigUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -19,28 +18,72 @@ import org.springframework.web.client.RestTemplate;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* Load config from remote config server
*
* @author Jason Song(song_s@ctrip.com)
*/
public class RemoteConfigLoader extends AbstractConfigLoader {
private static final Logger logger = LoggerFactory.getLogger(RemoteConfigLoader.class);
private final RestTemplate restTemplate;
private final ConfigServiceLocator serviceLocator;
public RemoteConfigLoader(RestTemplate restTemplate,
ConfigServiceLocator locator) {
this.restTemplate = restTemplate;
this.serviceLocator = locator;
public class RemoteConfig implements Config, ConfigLoader {
private static final Logger logger = LoggerFactory.getLogger(RemoteConfig.class);
private RestTemplate m_restTemplate;
private ConfigServiceLocator m_serviceLocator;
private String m_namespace;
private Properties m_remoteProperties;
public RemoteConfig(RestTemplate restTemplate,
ConfigServiceLocator locator, String namespace) {
this.m_restTemplate = restTemplate;
this.m_serviceLocator = locator;
this.m_namespace = namespace;
this.initialize();
}
ApolloConfig getRemoteConfig(RestTemplate restTemplate, String uri,
ApolloRegistry apolloRegistry, ApolloConfig previousConfig) {
String appId = apolloRegistry.getAppId();
String cluster = apolloRegistry.getClusterName();
String namespace = apolloRegistry.getNamespace();
@Override
public String getProperty(String key, String defaultValue) {
return this.m_remoteProperties.getProperty(key, defaultValue);
}
@Override
public Properties loadConfig() {
if (m_remoteProperties == null) {
return null;
}
Properties result = new Properties();
result.putAll(m_remoteProperties);
return result;
}
private void initialize() {
ApolloConfig apolloConfig = this.loadApolloConfig();
m_remoteProperties = new Properties();
m_remoteProperties.putAll(apolloConfig.getConfigurations());
}
private ApolloConfig loadApolloConfig() {
String appId = ConfigUtil.getInstance().getAppId();
String cluster = ConfigUtil.getInstance().getCluster();
try {
ApolloConfig result =
this.getRemoteConfig(m_restTemplate, getConfigServiceUrl(),
appId, cluster,
m_namespace,
null);
if (result == null) {
return null;
}
logger.info("Loaded config: {}", result);
return result;
} catch (Throwable ex) {
throw new RuntimeException(
String.format("Load Apollo Config failed - appId: %s, cluster: %s, namespace: %s", appId,
cluster, m_namespace), ex);
}
}
private ApolloConfig getRemoteConfig(RestTemplate restTemplate, String uri,
String appId, String cluster, String namespace,
ApolloConfig previousConfig) {
logger.info("Loading config from {}, appId={}, cluster={}, namespace={}", uri, appId, cluster,
namespace);
......@@ -85,19 +128,12 @@ public class RemoteConfigLoader extends AbstractConfigLoader {
return result;
}
@Override
protected ApolloConfig doLoadApolloConfig(ApolloRegistry apolloRegistry, ApolloConfig previous) {
ApolloConfig result = this.getRemoteConfig(restTemplate,
getConfigServiceUrl(), apolloRegistry, previous);
//When remote server return 304, we need to return the previous result
return result == null ? previous : result;
}
private String getConfigServiceUrl() {
List<ServiceDTO> services = serviceLocator.getConfigServices();
List<ServiceDTO> services = m_serviceLocator.getConfigServices();
if (services.size() == 0) {
throw new RuntimeException("No available config service");
}
return services.get(0).getHomepageUrl();
}
}
package com.ctrip.apollo.model;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.Properties;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class ConfigRefreshResult {
private String m_namespace;
private Properties m_properties;
private List<PropertyChange> m_changes;
public ConfigRefreshResult(String namespace, Properties properties) {
this.m_namespace = namespace;
this.m_properties = properties;
m_changes = Lists.newArrayList();
}
public Properties getProperties() {
return m_properties;
}
public String getNamespace() {
return m_namespace;
}
public List<PropertyChange> getChanges() {
return m_changes;
}
public void setChanges(List<PropertyChange> changes) {
this.m_changes = changes;
}
public boolean hasChanges() {
return !m_changes.isEmpty();
}
}
package com.ctrip.apollo.client.model;
package com.ctrip.apollo.model;
import com.ctrip.apollo.client.enums.PropertyChangeType;
import com.ctrip.apollo.enums.PropertyChangeType;
/**
* @author Jason Song(song_s@ctrip.com)
......
package com.ctrip.apollo.spi;
import com.ctrip.apollo.Config;
import com.ctrip.apollo.core.utils.ClassLoaderUtil;
import com.ctrip.apollo.internals.ConfigServiceLocator;
import com.ctrip.apollo.internals.DefaultConfig;
import com.ctrip.apollo.internals.RemoteConfig;
import org.springframework.web.client.RestTemplate;
import org.unidal.lookup.annotation.Named;
import java.io.File;
......@@ -12,10 +16,21 @@ import java.io.File;
*/
@Named(type = ConfigFactory.class, value = "default")
public class DefaultConfigFactory implements ConfigFactory {
private static final String CONFIG_DIR = "/config-cache";
private File m_baseDir;
public DefaultConfigFactory() {
m_baseDir = new File(ClassLoaderUtil.getClassPath() + CONFIG_DIR);
}
@Override
public Config create(String namespace) {
return new DefaultConfig(m_baseDir, namespace);
RemoteConfig remoteConfig = this.createRemoteConfig(namespace);
DefaultConfig defaultConfig = new DefaultConfig(m_baseDir, namespace, remoteConfig);
return defaultConfig;
}
public RemoteConfig createRemoteConfig(String namespace) {
return new RemoteConfig(new RestTemplate(), new ConfigServiceLocator(), namespace);
}
}
......@@ -12,7 +12,7 @@ import java.util.Map;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Named(type = ConfigFactoryManager.class)
@Named(type = ConfigFactoryManager.class, value = "default")
public class DefaultConfigFactoryManager extends ContainerHolder implements ConfigFactoryManager {
@Inject
private ConfigRegistry m_registry;
......@@ -40,7 +40,6 @@ public class DefaultConfigFactoryManager extends ContainerHolder implements Conf
factory = lookup(ConfigFactory.class, namespace);
} catch (LookupException e) {
// ignore it
e.printStackTrace();
}
// step 4: check default config factory
......
......@@ -11,7 +11,7 @@ import java.util.Map;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Named(type = ConfigRegistry.class)
@Named(type = ConfigRegistry.class, value = "default")
public class DefaultConfigRegistry implements ConfigRegistry, LogEnabled {
private Map<String, ConfigFactory> m_instances = Maps.newConcurrentMap();
......
package com.ctrip.apollo.client.util;
package com.ctrip.apollo.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -13,8 +13,6 @@ import java.util.concurrent.TimeUnit;
* @author Jason Song(song_s@ctrip.com)
*/
public class ConfigUtil {
private static final Logger logger = LoggerFactory.getLogger(ConfigUtil.class);
public static final String APOLLO_PROPERTY = "apollo.properties";
//TODO read from config?
private static final int refreshInterval = 5;
private static final TimeUnit refreshIntervalTimeUnit = TimeUnit.MINUTES;
......@@ -30,7 +28,7 @@ public class ConfigUtil {
public String getAppId() {
// TODO return the actual app id
return "101";
return "100003171";
}
public String getCluster() {
......
com.ctrip.apollo.client.manager.impl.RemoteConfigManagerManager
com.ctrip.apollo.client.manager.impl.LocalFileConfigManagerManager
package com.ctrip.apollo.client;
package com.ctrip.apollo;
import com.ctrip.apollo.client.loader.impl.RemoteConfigLoaderTest;
import com.ctrip.apollo.internals.DefaultConfigManagerTest;
import com.ctrip.apollo.internals.DefaultConfigTest;
import com.ctrip.apollo.internals.RemoteConfigTest;
import com.ctrip.apollo.spi.DefaultConfigFactoryManagerTest;
import com.ctrip.apollo.spi.DefaultConfigFactoryTest;
import com.ctrip.apollo.spi.DefaultConfigRegistryTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
......@@ -8,7 +14,9 @@ import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({
RemoteConfigLoaderTest.class
ConfigServiceTest.class, DefaultConfigRegistryTest.class, DefaultConfigFactoryManagerTest.class,
DefaultConfigFactoryTest.class, DefaultConfigManagerTest.class, DefaultConfigTest.class,
RemoteConfigTest.class
})
public class AllTests {
......
package com.ctrip.apollo;
import com.ctrip.apollo.core.ConfigConsts;
import com.ctrip.apollo.spi.ConfigFactory;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.unidal.lookup.ComponentTestCase;
import static org.junit.Assert.assertEquals;
/**
* @author Jason Song(song_s@ctrip.com)
*/
......@@ -21,22 +23,37 @@ public class ConfigServiceTest extends ComponentTestCase {
@Test
public void testHackConfig() {
ConfigService.setConfig(new MockConfig("hack"));
String someNamespace = "hack";
String someKey = "first";
ConfigService.setConfig(new MockConfig(someNamespace));
Config config = ConfigService.getConfig();
assertEquals(someNamespace + ":" + someKey, config.getProperty(someKey, null));
assertEquals(null, config.getProperty("unknown", null));
}
@Test
public void testHackConfigFactory() throws Exception {
String someKey = "someKey";
ConfigService.setConfigFactory(new MockConfigFactory());
Config config = ConfigService.getConfig();
Assert.assertEquals("hack:first", config.getProperty("first", null));
Assert.assertEquals(null, config.getProperty("unknown", null));
assertEquals(ConfigConsts.NAMESPACE_APPLICATION + ":" + someKey,
config.getProperty(someKey, null));
}
@Test
public void testMockConfigFactory() throws Exception {
defineComponent(ConfigFactory.class, "mock", MockConfigFactory.class);
String someNamespace = "mock";
String someKey = "someKey";
defineComponent(ConfigFactory.class, someNamespace, MockConfigFactory.class);
Config config = ConfigService.getConfig("mock");
Config config = ConfigService.getConfig(someNamespace);
Assert.assertEquals("mock:first", config.getProperty("first", null));
Assert.assertEquals(null, config.getProperty("unknown", null));
assertEquals(someNamespace + ":" + someKey, config.getProperty(someKey, null));
assertEquals(null, config.getProperty("unknown", null));
}
private static class MockConfig implements Config {
......
package com.ctrip.apollo.client.loader.impl;
import com.ctrip.apollo.client.loader.ConfigServiceLocator;
import com.ctrip.apollo.client.model.ApolloRegistry;
import com.ctrip.apollo.client.util.ConfigUtil;
import com.ctrip.apollo.core.dto.ApolloConfig;
import com.ctrip.apollo.core.dto.ServiceDTO;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyMap;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@RunWith(MockitoJUnitRunner.class)
public class RemoteConfigLoaderTest {
private RemoteConfigLoader remoteConfigLoader;
@Mock
private RestTemplate restTemplate;
@Mock
private ConfigUtil configUtil;
@Mock
private ConfigServiceLocator serviceLocater;
@Mock
private ResponseEntity<ApolloConfig> someResponse;
@Before
public void setUp() {
remoteConfigLoader = spy(new RemoteConfigLoader(restTemplate, serviceLocater));
}
@Test
public void testLoadApolloConfig() throws Exception {
String someServerUrl = "http://someUrl";
String someCluster = "some cluster";
ApolloConfig apolloConfig = mock(ApolloConfig.class);
ApolloRegistry
apolloRegistry =
assembleSomeApolloRegistry("someAppId", "someCluster", "someNamespace");
ApolloConfig previousConfig = null;
ServiceDTO someService = new ServiceDTO();
someService.setHomepageUrl(someServerUrl);
List<ServiceDTO> someServices = new ArrayList<>();
someServices.add(someService);
when(serviceLocater.getConfigServices()).thenReturn(someServices);
when(configUtil.getCluster()).thenReturn(someCluster);
doReturn(apolloConfig).when(remoteConfigLoader)
.getRemoteConfig(restTemplate, someServerUrl, apolloRegistry, previousConfig);
ApolloConfig result = remoteConfigLoader.loadApolloConfig(apolloRegistry, previousConfig);
assertEquals(apolloConfig, result);
}
@Test
public void testGetRemoteConfig() throws Exception {
String someServerUrl = "http://someServer";
ApolloConfig someApolloConfig = mock(ApolloConfig.class);
ApolloRegistry
apolloRegistry =
assembleSomeApolloRegistry("someAppId", "someCluster", "someNamespace");
ApolloConfig previousConfig = null;
when(someResponse.getStatusCode()).thenReturn(HttpStatus.OK);
when(someResponse.getBody()).thenReturn(someApolloConfig);
when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class),
eq(ApolloConfig.class), anyMap())).thenReturn(someResponse);
ApolloConfig
result =
remoteConfigLoader
.getRemoteConfig(restTemplate, someServerUrl, apolloRegistry,
previousConfig);
assertEquals(someApolloConfig, result);
}
@Test(expected = RuntimeException.class)
public void testGetRemoteConfigWithServerError() throws Exception {
String someServerUrl = "http://someServer";
ApolloRegistry
apolloRegistry =
assembleSomeApolloRegistry("someAppId", "someCluster", "someNamespace");
ApolloConfig previousConfig = null;
HttpStatus someErrorCode = HttpStatus.INTERNAL_SERVER_ERROR;
when(someResponse.getStatusCode()).thenReturn(someErrorCode);
when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class),
eq(ApolloConfig.class), anyMap())).thenReturn(someResponse);
remoteConfigLoader.getRemoteConfig(restTemplate, someServerUrl, apolloRegistry,
previousConfig);
}
@Test
public void testGetRemoteConfigWith304Response() throws Exception {
String someServerUrl = "http://someServer";
ApolloRegistry
apolloRegistry =
assembleSomeApolloRegistry("someAppId", "someCluster", "someNamespace");
ApolloConfig previousConfig = null;
when(someResponse.getStatusCode()).thenReturn(HttpStatus.NOT_MODIFIED);
when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class),
eq(ApolloConfig.class), anyMap())).thenReturn(someResponse);
ApolloConfig
result =
remoteConfigLoader
.getRemoteConfig(restTemplate, someServerUrl, apolloRegistry,
previousConfig);
assertNull(result);
}
private ApolloRegistry assembleSomeApolloRegistry(String someAppId, String someClusterName,
String someNamespace) {
ApolloRegistry
someApolloRegistry =
new ApolloRegistry(someAppId, someClusterName, someNamespace);
return someApolloRegistry;
}
}
package com.ctrip.apollo.internals;
import com.ctrip.apollo.Config;
import com.ctrip.apollo.spi.ConfigFactory;
import com.ctrip.apollo.spi.ConfigFactoryManager;
import org.junit.Before;
import org.junit.Test;
import org.unidal.lookup.ComponentTestCase;
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)
*/
public class DefaultConfigManagerTest extends ComponentTestCase {
private DefaultConfigManager defaultConfigManager;
@Before
public void setUp() throws Exception {
super.setUp();
defineComponent(ConfigFactoryManager.class, MockConfigManager.class);
defaultConfigManager = (DefaultConfigManager) lookup(ConfigManager.class, "default");
}
@Test
public void testGetConfig() throws Exception {
String someNamespace = "someName";
String anotherNamespace = "anotherName";
String someKey = "someKey";
Config config = defaultConfigManager.getConfig(someNamespace);
Config anotherConfig = defaultConfigManager.getConfig(anotherNamespace);
assertEquals(someNamespace + ":" + someKey, config.getProperty(someKey, null));
assertEquals(anotherNamespace + ":" + someKey, anotherConfig.getProperty(someKey, null));
}
@Test
public void testGetConfigMultipleTimesWithSameNamespace() throws Exception {
String someNamespace = "someName";
Config config = defaultConfigManager.getConfig(someNamespace);
Config anotherConfig = defaultConfigManager.getConfig(someNamespace);
assertThat(
"Get config multiple times with the same namespace should return the same config instance",
config, equalTo(anotherConfig));
}
public static class MockConfigManager implements ConfigFactoryManager {
@Override
public ConfigFactory getFactory(String namespace) {
return new ConfigFactory() {
@Override
public Config create(final String namespace) {
return new Config() {
@Override
public String getProperty(String key, String defaultValue) {
return namespace + ":" + key;
}
};
}
};
}
}
}
package com.ctrip.apollo.internals;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import com.ctrip.apollo.core.utils.ClassLoaderUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.unidal.lookup.ComponentTestCase;
import java.io.File;
import java.util.Properties;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class DefaultConfigTest extends ComponentTestCase {
private File someBaseDir;
private File someResourceDir;
private String someNamespace;
private ConfigLoader fallbackLoader;
private Properties someProperties;
@Before
public void setUp() throws Exception {
super.setUp();
someBaseDir = new File("src/test/resources/config-cache");
someBaseDir.deleteOnExit();
someBaseDir.mkdir();
someResourceDir = new File(ClassLoaderUtil.getClassPath() + "/META-INF/config");
someResourceDir.deleteOnExit();
someResourceDir.mkdir();
someNamespace = "someName";
someProperties = new Properties();
someProperties.setProperty("defaultKey", "defaultValue");
fallbackLoader = mock(RemoteConfig.class);
when(fallbackLoader.loadConfig()).thenReturn(someProperties);
}
@Override
@After
public void tearDown() throws Exception {
}
@Test
public void testGetPropertyWithLocalFile() throws Exception {
File file = new File(someBaseDir, someNamespace + ".properties");
String someKey = "someKey";
String someValue = "someValue";
Files.write(someKey + "=" + someValue, file, Charsets.UTF_8);
DefaultConfig defaultConfig = new DefaultConfig(someBaseDir, someNamespace, fallbackLoader);
file.delete();
assertEquals(someValue, defaultConfig.getProperty(someKey, null));
}
@Test
public void testGetPropertyWithLocalResource() throws Exception {
File file = new File(someResourceDir, someNamespace + ".properties");
file.deleteOnExit();
Files.createParentDirs(file);
String someKey = "someKey";
String someValue = "someValue";
Files.write(someKey + "=" + someValue, file, Charsets.UTF_8);
DefaultConfig defaultConfig = new DefaultConfig(someBaseDir, someNamespace, fallbackLoader);
file.delete();
assertEquals(someValue, defaultConfig.getProperty(someKey, null));
}
@Test
public void testGetPropertyWithAllPropertyHierarchy() throws Exception {
String someKey = "someKey";
String someSystemPropertyValue = "system-property-value";
String anotherKey = "anotherKey";
String someLocalFileValue = "local-file-value";
String lastKey = "lastKey";
String someResourceValue = "resource-value";
//set up system property
System.setProperty(someKey, someSystemPropertyValue);
//set up local file
File localCacheFile = new File(someBaseDir, someNamespace + ".properties");
Files.write(someKey + "=" + someLocalFileValue, localCacheFile, Charsets.UTF_8);
Files.append(System.getProperty("line.separator"), localCacheFile, Charsets.UTF_8);
Files.append(anotherKey + "=" + someLocalFileValue, localCacheFile, Charsets.UTF_8);
//set up resource file
File resourceFile = new File(someResourceDir, someNamespace + ".properties");
Files.write(someKey + "=" + someResourceValue, resourceFile, Charsets.UTF_8);
Files.append(System.getProperty("line.separator"), resourceFile, Charsets.UTF_8);
Files.append(anotherKey + "=" + someResourceValue, resourceFile, Charsets.UTF_8);
Files.append(System.getProperty("line.separator"), resourceFile, Charsets.UTF_8);
Files.append(lastKey + "=" + someResourceValue, resourceFile, Charsets.UTF_8);
DefaultConfig defaultConfig = new DefaultConfig(someBaseDir, someNamespace, fallbackLoader);
String someKeyValue = defaultConfig.getProperty(someKey, null);
String anotherKeyValue = defaultConfig.getProperty(anotherKey, null);
String lastKeyValue = defaultConfig.getProperty(lastKey, null);
localCacheFile.delete();
resourceFile.delete();
assertEquals(someSystemPropertyValue, someKeyValue);
assertEquals(someLocalFileValue, anotherKeyValue);
assertEquals(someResourceValue, lastKeyValue);
}
@Test
public void testInitLocalConfigWithNoLocalFile() throws Exception {
DefaultConfig defaultConfig = new DefaultConfig(someBaseDir, someNamespace, fallbackLoader);
Properties result = defaultConfig.loadConfig();
assertThat(
"Default config's properties should be the same as fallback loader's when there is no local cache",
result.entrySet(), equalTo(someProperties.entrySet()));
}
}
package com.ctrip.apollo.internals;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ctrip.apollo.core.dto.ApolloConfig;
import com.ctrip.apollo.core.dto.ServiceDTO;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
import java.util.Properties;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyMap;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@RunWith(MockitoJUnitRunner.class)
public class RemoteConfigTest {
@Mock
private RestTemplate restTemplate;
@Mock
private ConfigServiceLocator configServiceLocator;
private String someNamespace;
@Mock
private ResponseEntity<ApolloConfig> someResponse;
@Before
public void setUp() throws Exception {
someNamespace = "someName";
String someServerUrl = "http://someServer";
mockConfigServiceLocator(someServerUrl);
}
@Test
public void testGetProperty() throws Exception {
String someKey = "someKey";
String someValue = "someValue";
String someKeyNotExisted = "key-not-existed";
String someDefaultValue = "someDefault";
Map<String, String> configurations = Maps.newHashMap();
configurations.put(someKey, someValue);
ApolloConfig someApolloConfig = assembleApolloConfig(configurations);
when(someResponse.getStatusCode()).thenReturn(HttpStatus.OK);
when(someResponse.getBody()).thenReturn(someApolloConfig);
when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class),
eq(ApolloConfig.class), anyMap())).thenReturn(someResponse);
RemoteConfig remoteConfig = new RemoteConfig(restTemplate, configServiceLocator, someNamespace);
assertEquals(someValue, remoteConfig.getProperty(someKey, null));
assertEquals(someDefaultValue, remoteConfig.getProperty(someKeyNotExisted, someDefaultValue));
}
@Test(expected = RuntimeException.class)
public void testGetRemoteConfigWithServerError() throws Exception {
when(someResponse.getStatusCode()).thenReturn(HttpStatus.INTERNAL_SERVER_ERROR);
when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class),
eq(ApolloConfig.class), anyMap())).thenReturn(someResponse);
RemoteConfig remoteConfig = new RemoteConfig(restTemplate, configServiceLocator, someNamespace);
}
@Test
public void testLoadConfig() throws Exception {
String someKey = "someKey";
String someValue = "someValue";
Map<String, String> configurations = Maps.newHashMap();
configurations.put(someKey, someValue);
ApolloConfig someApolloConfig = assembleApolloConfig(configurations);
when(someResponse.getStatusCode()).thenReturn(HttpStatus.OK);
when(someResponse.getBody()).thenReturn(someApolloConfig);
when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class),
eq(ApolloConfig.class), anyMap())).thenReturn(someResponse);
RemoteConfig remoteConfig = new RemoteConfig(restTemplate, configServiceLocator, someNamespace);
Properties config = remoteConfig.loadConfig();
assertEquals(configurations, config);
}
private ApolloConfig assembleApolloConfig(Map<String, String> configurations) {
String someAppId = "appId";
String someClusterName = "cluster";
long someReleaseId = 1;
ApolloConfig apolloConfig =
new ApolloConfig(someAppId, someClusterName, someNamespace, someReleaseId);
apolloConfig.setConfigurations(configurations);
return apolloConfig;
}
private void mockConfigServiceLocator(String serverUrl) {
ServiceDTO serviceDTO = mock(ServiceDTO.class);
when(serviceDTO.getHomepageUrl()).thenReturn(serverUrl);
when(configServiceLocator.getConfigServices()).thenReturn(Lists.newArrayList(serviceDTO));
}
}
package com.ctrip.apollo.spi;
import com.ctrip.apollo.Config;
import org.junit.Before;
import org.junit.Test;
import org.unidal.lookup.ComponentTestCase;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
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)
*/
public class DefaultConfigFactoryManagerTest extends ComponentTestCase {
private DefaultConfigFactoryManager defaultConfigFactoryManager;
@Before
public void setUp() throws Exception {
super.setUp();
defineComponent(ConfigRegistry.class, MockConfigRegistry.class);
defaultConfigFactoryManager =
(DefaultConfigFactoryManager) lookup(ConfigFactoryManager.class, "default");
}
@Test
public void testGetFactoryFromRegistry() throws Exception {
ConfigFactory result =
defaultConfigFactoryManager.getFactory(MockConfigRegistry.NAMESPACE_REGISTERED);
assertEquals(MockConfigRegistry.REGISTERED_CONFIGFACTORY, result);
}
@Test
public void testGetFactoryFromNamespace() throws Exception {
String someNamespace = "someName";
defineComponent(ConfigFactory.class, someNamespace, SomeConfigFactory.class);
ConfigFactory result = defaultConfigFactoryManager.getFactory(someNamespace);
assertThat("When namespace is registered, should return the registerd config factory", result,
instanceOf(SomeConfigFactory.class));
}
@Test
public void testGetFactoryFromNamespaceMultipleTimes() throws Exception {
String someNamespace = "someName";
defineComponent(ConfigFactory.class, someNamespace, SomeConfigFactory.class);
ConfigFactory result = defaultConfigFactoryManager.getFactory(someNamespace);
ConfigFactory anotherResult = defaultConfigFactoryManager.getFactory(someNamespace);
assertThat(
"Get config factory with the same namespace multiple times should returnt the same instance",
anotherResult, equalTo(result));
}
@Test
public void testGetFactoryFromDefault() throws Exception {
String someNamespace = "someName";
defineComponent(ConfigFactory.class, "default", AnotherConfigFactory.class);
ConfigFactory result = defaultConfigFactoryManager.getFactory(someNamespace);
assertThat("When namespace is not registered, should return the default config factory", result,
instanceOf(AnotherConfigFactory.class));
}
public static class MockConfigRegistry implements ConfigRegistry {
public static String NAMESPACE_REGISTERED = "some-namespace-registered";
public static ConfigFactory REGISTERED_CONFIGFACTORY = new ConfigFactory() {
@Override
public Config create(String namespace) {
return null;
}
};
@Override
public void register(String namespace, ConfigFactory factory) {
//do nothing
}
@Override
public ConfigFactory getFactory(String namespace) {
if (namespace.equals(NAMESPACE_REGISTERED)) {
return REGISTERED_CONFIGFACTORY;
}
return null;
}
}
public static class SomeConfigFactory implements ConfigFactory {
@Override
public Config create(String namespace) {
return null;
}
}
public static class AnotherConfigFactory implements ConfigFactory {
@Override
public Config create(String namespace) {
return null;
}
}
}
package com.ctrip.apollo.spi;
import com.ctrip.apollo.Config;
import com.ctrip.apollo.internals.DefaultConfig;
import com.ctrip.apollo.internals.RemoteConfig;
import org.junit.Before;
import org.junit.Test;
import org.unidal.lookup.ComponentTestCase;
import java.util.Properties;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class DefaultConfigFactoryTest extends ComponentTestCase {
private DefaultConfigFactory defaultConfigFactory;
@Before
public void setUp() throws Exception {
super.setUp();
defaultConfigFactory = spy((DefaultConfigFactory) lookup(ConfigFactory.class, "default"));
}
@Test
public void testCreate() throws Exception {
String someNamespace = "someName";
Properties someProperties = new Properties();
String someKey = "someKey";
String someValue = "someValue";
someProperties.setProperty(someKey, someValue);
RemoteConfig someRemoteConfig = mock(RemoteConfig.class);
when(someRemoteConfig.loadConfig()).thenReturn(someProperties);
doReturn(someRemoteConfig).when(defaultConfigFactory).createRemoteConfig(someNamespace);
Config result = defaultConfigFactory.create(someNamespace);
assertThat("DefaultConfigFactory should create DefaultConfig", result,
is(instanceOf(DefaultConfig.class)));
assertThat("DefaultConfigFactory should set remote config as the fallback loader",
((DefaultConfig) result).getFallbackLoader(), instanceOf(RemoteConfig.class));
}
}
package com.ctrip.apollo.spi;
import com.ctrip.apollo.Config;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
import org.unidal.lookup.ComponentTestCase;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.*;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class DefaultConfigRegistryTest extends ComponentTestCase {
private DefaultConfigRegistry defaultConfigRegistry;
@Before
public void setUp() throws Exception {
super.setUp();
defaultConfigRegistry = (DefaultConfigRegistry) lookup(ConfigRegistry.class, "default");
}
@Test
public void testGetFactory() throws Exception {
String someNamespace = "someName";
ConfigFactory someConfigFactory = new MockConfigFactory();
defaultConfigRegistry.register(someNamespace, someConfigFactory);
assertThat("Should return the registered config factory",
defaultConfigRegistry.getFactory(someNamespace), equalTo(someConfigFactory));
}
@Test
public void testGetFactoryWithNamespaceUnregistered() throws Exception {
String someUnregisteredNamespace = "someName";
assertNull(defaultConfigRegistry.getFactory(someUnregisteredNamespace));
}
public static class MockConfigFactory implements ConfigFactory {
@Override
public Config create(String namespace) {
return null;
}
}
}
......@@ -50,12 +50,12 @@ public class ApolloConfig {
return releaseId;
}
public void setConfigurations(Map<String, String> configurations) {
this.configurations = configurations;
public Map<String, String> getConfigurations() {
return configurations;
}
public String getProperty(String key) {
return this.configurations.get(key);
public void setConfigurations(Map<String, String> configurations) {
this.configurations = configurations;
}
@Override
......
......@@ -3,6 +3,10 @@ package com.ctrip.apollo.core.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
/**
* @author Jason Song(song_s@ctrip.com)
*/
......@@ -10,15 +14,36 @@ public class ClassLoaderUtil {
private static final Logger logger = LoggerFactory.getLogger(ClassLoaderUtil.class);
private static ClassLoader loader = Thread.currentThread().getContextClassLoader();
private static String classPath = "";
static {
if (loader == null) {
logger.info("Using system class loader");
loader = ClassLoader.getSystemClassLoader();
}
try {
URL url = loader.getResource("");
// get class path
classPath = url.getPath();
classPath = URLDecoder.decode(classPath, "utf-8");
// 如果是jar包内的,则返回当前路径
if (classPath.contains(".jar!")) {
logger.warn("using config file inline jar!");
classPath = System.getProperty("user.dir");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
public static ClassLoader getLoader() {
return loader;
}
public static String getClassPath() {
return classPath;
}
}
import com.ctrip.apollo.client.ConfigService;
import com.ctrip.apollo.client.config.Config;
import com.ctrip.apollo.Config;
import com.ctrip.apollo.ConfigService;
import java.io.BufferedReader;
import java.io.IOException;
......@@ -12,7 +13,7 @@ public class ApolloConfigDemo {
private Config config;
public ApolloConfigDemo() {
config = ConfigService.getConfig();
config = ConfigService.getConfig("apollo-config-service");
}
private String getConfig(String key) {
......
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