Commit b351b484 authored by Yiming Liu's avatar Yiming Liu

Merge pull request #96 from nobodyiam/client-integration-test-merge

Client integration test and integrate foundation framework
parents 36076667 c6b4dd50
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent> <parent>
<groupId>com.ctrip.apollo</groupId> <groupId>com.ctrip.apollo</groupId>
<artifactId>apollo</artifactId> <artifactId>apollo</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>apollo-client</artifactId> <artifactId>apollo-client</artifactId>
<name>Apollo Client</name> <name>Apollo Client</name>
<properties> <properties>
<java.version>1.7</java.version> <java.version>1.7</java.version>
</properties> </properties>
<dependencies> <dependencies>
<!-- apollo --> <!-- apollo -->
<dependency> <dependency>
<groupId>com.ctrip.apollo</groupId> <groupId>com.ctrip.apollo</groupId>
<artifactId>apollo-core</artifactId> <artifactId>apollo-core</artifactId>
</dependency> </dependency>
<!-- end of apollo --> <!-- end of apollo -->
<dependency> <!-- foundation service -->
<groupId>com.ctrip.framework</groupId> <dependency>
<artifactId>framework-foundation</artifactId> <groupId>com.ctrip.framework</groupId>
</dependency> <artifactId>framework-foundation</artifactId>
<dependency> </dependency>
<groupId>com.dianping.cat</groupId> <!-- end of foundation service -->
<artifactId>cat-client</artifactId> <!-- cat -->
</dependency> <dependency>
<dependency> <groupId>com.dianping.cat</groupId>
<groupId>org.slf4j</groupId> <artifactId>cat-client</artifactId>
<artifactId>slf4j-api</artifactId> </dependency>
</dependency> <!-- end of cat -->
<dependency> <!-- log -->
<groupId>org.apache.logging.log4j</groupId> <dependency>
<artifactId>log4j-slf4j-impl</artifactId> <groupId>org.slf4j</groupId>
<exclusions> <artifactId>slf4j-api</artifactId>
<exclusion> </dependency>
<groupId>org.slf4j</groupId> <dependency>
<artifactId>slf4j-api</artifactId> <groupId>org.apache.logging.log4j</groupId>
</exclusion> <artifactId>log4j-slf4j-impl</artifactId>
<exclusion> <exclusions>
<groupId>org.apache.logging.log4j</groupId> <exclusion>
<artifactId>log4j-api</artifactId> <groupId>org.slf4j</groupId>
</exclusion> <artifactId>slf4j-api</artifactId>
</exclusions> </exclusion>
<scope>provided</scope> <exclusion>
</dependency> <groupId>org.apache.logging.log4j</groupId>
<dependency> <artifactId>log4j-api</artifactId>
<groupId>org.apache.logging.log4j</groupId> </exclusion>
<artifactId>log4j-core</artifactId> </exclusions>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
</dependencies> <dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<scope>provided</scope>
</dependency>
<!-- end of log -->
<!-- test -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<scope>test</scope>
</dependency>
<!-- end of test -->
</dependencies>
</project> </project>
...@@ -13,5 +13,9 @@ public interface Config { ...@@ -13,5 +13,9 @@ public interface Config {
*/ */
public String getProperty(String key, String defaultValue); public String getProperty(String key, String defaultValue);
/**
* Add change listener to this config instance.
* @param listener the config change listener
*/
public void addChangeListener(ConfigChangeListener listener); public void addChangeListener(ConfigChangeListener listener);
} }
...@@ -6,5 +6,9 @@ import com.ctrip.apollo.model.ConfigChangeEvent; ...@@ -6,5 +6,9 @@ import com.ctrip.apollo.model.ConfigChangeEvent;
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
*/ */
public interface ConfigChangeListener { public interface ConfigChangeListener {
/**
* Invoked when there is any config change for the namespace.
* @param changeEvent the event for this change
*/
public void onChange(ConfigChangeEvent changeEvent); public void onChange(ConfigChangeEvent changeEvent);
} }
...@@ -23,7 +23,7 @@ public class ConfigService { ...@@ -23,7 +23,7 @@ public class ConfigService {
} }
/** /**
* Get the config instance with default namespace * Get the config instance with default namespace.
* @return config instance * @return config instance
*/ */
public static Config getConfig() { public static Config getConfig() {
...@@ -31,7 +31,7 @@ public class ConfigService { ...@@ -31,7 +31,7 @@ public class ConfigService {
} }
/** /**
* Get the config instance for the namespace * Get the config instance for the namespace.
* @param namespace the namespace of the config * @param namespace the namespace of the config
* @return config instance * @return config instance
*/ */
...@@ -42,16 +42,16 @@ public class ConfigService { ...@@ -42,16 +42,16 @@ public class ConfigService {
private static ConfigManager getManager() { private static ConfigManager getManager() {
try { try {
return s_instance.m_container.lookup(ConfigManager.class); return s_instance.m_container.lookup(ConfigManager.class);
} catch (ComponentLookupException e) { } catch (ComponentLookupException ex) {
throw new IllegalStateException("Unable to load ConfigManager!", e); throw new IllegalStateException("Unable to load ConfigManager!", ex);
} }
} }
private static ConfigRegistry getRegistry() { private static ConfigRegistry getRegistry() {
try { try {
return s_instance.m_container.lookup(ConfigRegistry.class); return s_instance.m_container.lookup(ConfigRegistry.class);
} catch (ComponentLookupException e) { } catch (ComponentLookupException ex) {
throw new IllegalStateException("Unable to load ConfigRegistry!", e); throw new IllegalStateException("Unable to load ConfigRegistry!", ex);
} }
} }
...@@ -59,6 +59,11 @@ public class ConfigService { ...@@ -59,6 +59,11 @@ public class ConfigService {
setConfig(ConfigConsts.NAMESPACE_APPLICATION, config); setConfig(ConfigConsts.NAMESPACE_APPLICATION, config);
} }
/**
* Manually set the config for the namespace specified, use with caution!
* @param namespace the namespace
* @param config the config instance
*/
public static void setConfig(String namespace, final Config config) { public static void setConfig(String namespace, final Config config) {
getRegistry().register(namespace, new ConfigFactory() { getRegistry().register(namespace, new ConfigFactory() {
@Override @Override
...@@ -72,6 +77,11 @@ public class ConfigService { ...@@ -72,6 +77,11 @@ public class ConfigService {
setConfigFactory(ConfigConsts.NAMESPACE_APPLICATION, factory); setConfigFactory(ConfigConsts.NAMESPACE_APPLICATION, factory);
} }
/**
* Manually set the config factory for the namespace specified, use with caution!
* @param namespace the namespace
* @param factory the factory instance
*/
public static void setConfigFactory(String namespace, ConfigFactory factory) { public static void setConfigFactory(String namespace, ConfigFactory factory) {
getRegistry().register(namespace, factory); getRegistry().register(namespace, factory);
} }
......
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 Apollo {
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":
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;
}
}
}
package com.ctrip.apollo.env;
import com.ctrip.apollo.Apollo;
import com.ctrip.apollo.Apollo.Env;
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;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicReference;
public class ClientEnvironment {
private static final Logger logger = LoggerFactory.getLogger(ClientEnvironment.class);
private static final String DEFAULT_FILE = "apollo.properties";
private AtomicReference<Env> env = new AtomicReference<Env>();
private static ClientEnvironment instance = new ClientEnvironment();
private ClientEnvironment() {
}
public static ClientEnvironment getInstance() {
return instance;
}
public Env getEnv() {
if (env.get() == null) {
Env resultEnv = Apollo.getEnv();
Properties apolloProperties = null;
apolloProperties = ResourceUtils.readConfigFile(DEFAULT_FILE, null);
if (apolloProperties != null) {
String strEnv = apolloProperties.getProperty(Constants.ENV);
if (!StringUtils.isBlank(strEnv)) {
resultEnv = Env.valueOf(strEnv.trim().toUpperCase());
}
}
env.compareAndSet(null, resultEnv);
}
if (env.get() == null) {
throw new IllegalArgumentException("Apollo env is not set");
}
return env.get();
}
public String getMetaServerDomainName() {
return MetaDomainConsts.getDomain(getEnv());
}
}
...@@ -35,8 +35,8 @@ public abstract class AbstractConfig implements Config { ...@@ -35,8 +35,8 @@ public abstract class AbstractConfig implements Config {
for (ConfigChangeListener listener : m_listeners) { for (ConfigChangeListener listener : m_listeners) {
try { try {
listener.onChange(changeEvent); listener.onChange(changeEvent);
} catch (Throwable t) { } catch (Throwable ex) {
logger.error("Failed to invoke config change listener {}", listener.getClass(), t); logger.error("Failed to invoke config change listener {}", listener.getClass(), ex);
} }
} }
} }
...@@ -61,7 +61,8 @@ public abstract class AbstractConfig implements Config { ...@@ -61,7 +61,8 @@ public abstract class AbstractConfig implements Config {
List<ConfigChange> changes = Lists.newArrayList(); List<ConfigChange> changes = Lists.newArrayList();
for (String newKey : newKeys) { for (String newKey : newKeys) {
changes.add(new ConfigChange(newKey, null, current.getProperty(newKey), PropertyChangeType.NEW)); changes
.add(new ConfigChange(newKey, null, current.getProperty(newKey), PropertyChangeType.NEW));
} }
for (String removedKey : removedKeys) { for (String removedKey : removedKeys) {
......
...@@ -15,6 +15,16 @@ public abstract class AbstractConfigRepository implements ConfigRepository { ...@@ -15,6 +15,16 @@ 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() {
try {
sync();
} catch (Throwable ex) {
logger.error("Sync config failed with repository {}", this.getClass(), ex);
}
}
protected abstract void sync();
@Override @Override
public void addChangeListener(RepositoryChangeListener listener) { public void addChangeListener(RepositoryChangeListener listener) {
if (!m_listeners.contains(listener)) { if (!m_listeners.contains(listener)) {
...@@ -31,8 +41,8 @@ public abstract class AbstractConfigRepository implements ConfigRepository { ...@@ -31,8 +41,8 @@ public abstract class AbstractConfigRepository implements ConfigRepository {
for (RepositoryChangeListener listener : m_listeners) { for (RepositoryChangeListener listener : m_listeners) {
try { try {
listener.onRepositoryChange(namespace, newProperties); listener.onRepositoryChange(namespace, newProperties);
} catch (Throwable t) { } catch (Throwable ex) {
logger.error("Failed to invoke repository change listener {}", listener.getClass(), t); logger.error("Failed to invoke repository change listener {}", listener.getClass(), ex);
} }
} }
} }
......
...@@ -6,5 +6,10 @@ import com.ctrip.apollo.Config; ...@@ -6,5 +6,10 @@ import com.ctrip.apollo.Config;
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
*/ */
public interface ConfigManager { public interface ConfigManager {
public Config getConfig(String namespace); /**
* Get the config instance for the namespace specified.
* @param namespace the namespace
* @return the config instance for the namespace
*/
public Config getConfig(String namespace);
} }
...@@ -7,18 +7,26 @@ import java.util.Properties; ...@@ -7,18 +7,26 @@ import java.util.Properties;
*/ */
public interface ConfigRepository { public interface ConfigRepository {
/** /**
* Get the config from this repository * Get the config from this repository.
* @return * @return config
*/ */
public Properties getConfig(); public Properties getConfig();
/** /**
* Set the fallback repo for this repository * Set the fallback repo for this repository.
* @param fallbackConfigRepository * @param fallbackConfigRepository the fallback repo
*/ */
public void setFallback(ConfigRepository fallbackConfigRepository); public void setFallback(ConfigRepository fallbackConfigRepository);
/**
* Add change listener.
* @param listener the listener to observe the changes
*/
public void addChangeListener(RepositoryChangeListener listener); public void addChangeListener(RepositoryChangeListener listener);
/**
* Remove change listener.
* @param listener the listener to remove
*/
public void removeChangeListener(RepositoryChangeListener listener); public void removeChangeListener(RepositoryChangeListener listener);
} }
package com.ctrip.apollo.internals; package com.ctrip.apollo.internals;
import com.ctrip.apollo.core.dto.ServiceDTO; import com.ctrip.apollo.core.dto.ServiceDTO;
import com.ctrip.apollo.env.ClientEnvironment; import com.ctrip.apollo.util.ConfigUtil;
import com.ctrip.apollo.util.http.HttpRequest; import com.ctrip.apollo.util.http.HttpRequest;
import com.ctrip.apollo.util.http.HttpResponse; import com.ctrip.apollo.util.http.HttpResponse;
import com.ctrip.apollo.util.http.HttpUtil; import com.ctrip.apollo.util.http.HttpUtil;
...@@ -19,11 +19,16 @@ public class ConfigServiceLocator { ...@@ -19,11 +19,16 @@ public class ConfigServiceLocator {
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;
@Inject
private ConfigUtil m_configUtil;
private List<ServiceDTO> serviceCaches = new ArrayList<>(); private List<ServiceDTO> serviceCaches = new ArrayList<>();
/**
* Get the config service info from remote meta server.
* @return the services dto
*/
public List<ServiceDTO> getConfigServices() { public List<ServiceDTO> getConfigServices() {
ClientEnvironment env = ClientEnvironment.getInstance(); String domainName = m_configUtil.getMetaServerDomainName();
String domainName = env.getMetaServerDomainName();
String url = domainName + "/services/config"; String url = domainName + "/services/config";
HttpRequest request = new HttpRequest(url); HttpRequest request = new HttpRequest(url);
...@@ -37,9 +42,9 @@ public class ConfigServiceLocator { ...@@ -37,9 +42,9 @@ public class ConfigServiceLocator {
serviceCaches.add(service); serviceCaches.add(service);
} }
} }
} catch (Throwable t) { } catch (Throwable ex) {
logger.error("Get config services failed", t); logger.error("Get config services failed", ex);
throw new RuntimeException("Get config services failed", t); throw new RuntimeException("Get config services failed", ex);
} }
return serviceCaches; return serviceCaches;
......
...@@ -17,6 +17,7 @@ import java.util.List; ...@@ -17,6 +17,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.atomic.AtomicReference;
/** /**
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
...@@ -25,25 +26,31 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis ...@@ -25,25 +26,31 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
private static final Logger logger = LoggerFactory.getLogger(DefaultConfig.class); private static final Logger logger = LoggerFactory.getLogger(DefaultConfig.class);
private final String m_namespace; private final String m_namespace;
private Properties m_resourceProperties; private Properties m_resourceProperties;
private Properties m_configProperties; private AtomicReference<Properties> m_configProperties;
private ConfigRepository m_configRepository; private ConfigRepository m_configRepository;
/**
* Constructor.
*
* @param namespace the namespace of this config instance
* @param configRepository the config repository for this config instance
*/
public DefaultConfig(String namespace, ConfigRepository configRepository) { public DefaultConfig(String namespace, ConfigRepository configRepository) {
m_namespace = namespace; m_namespace = namespace;
m_resourceProperties = loadFromResource(m_namespace); m_resourceProperties = loadFromResource(m_namespace);
m_configRepository = configRepository; m_configRepository = configRepository;
m_configProperties = new AtomicReference<>();
initialize(); initialize();
} }
private void initialize() { private void initialize() {
try { try {
m_configProperties = m_configRepository.getConfig(); m_configProperties.set(m_configRepository.getConfig());
m_configRepository.addChangeListener(this); m_configRepository.addChangeListener(this);
} catch (Throwable ex) { } catch (Throwable ex) {
String message = String.format("Init Apollo Local Config failed - namespace: %s", String message = String.format("Init Apollo Local Config failed - namespace: %s",
m_namespace); m_namespace);
logger.error(message, ex); logger.error(message, ex);
throw new RuntimeException(message, ex);
} }
} }
...@@ -53,8 +60,8 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis ...@@ -53,8 +60,8 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
String value = System.getProperty(key); String value = System.getProperty(key);
// step 2: check local cached properties file // step 2: check local cached properties file
if (value == null) { if (value == null && m_configProperties.get() != null) {
value = m_configProperties.getProperty(key); value = m_configProperties.get().getProperty(key);
} }
/** /**
...@@ -67,10 +74,12 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis ...@@ -67,10 +74,12 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
} }
// step 4: check properties file from classpath // step 4: check properties file from classpath
if (value == null) { if (value == null && m_resourceProperties != null) {
if (m_resourceProperties != null) { value = (String) m_resourceProperties.get(key);
value = (String) m_resourceProperties.get(key); }
}
if (value == null && m_configProperties.get() == null) {
logger.error("Config initialization failed, always return default value!");
} }
return value == null ? defaultValue : value; return value == null ? defaultValue : value;
...@@ -78,7 +87,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis ...@@ -78,7 +87,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
@Override @Override
public synchronized void onRepositoryChange(String namespace, Properties newProperties) { public synchronized void onRepositoryChange(String namespace, Properties newProperties) {
if (newProperties.equals(m_configProperties)) { if (newProperties.equals(m_configProperties.get())) {
return; return;
} }
Properties newConfigProperties = new Properties(); Properties newConfigProperties = new Properties();
...@@ -91,8 +100,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis ...@@ -91,8 +100,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, newConfigProperties); calcPropertyChanges(m_configProperties.get(), newConfigProperties);
// List<ConfigChange> actualChanges = Lists.newArrayListWithCapacity(configChanges.size());
ImmutableMap.Builder<String, ConfigChange> actualChanges = ImmutableMap.Builder<String, ConfigChange> actualChanges =
new ImmutableMap.Builder<>(); new ImmutableMap.Builder<>();
...@@ -105,7 +113,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis ...@@ -105,7 +113,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
} }
//2. update m_configProperties //2. update m_configProperties
m_configProperties = newConfigProperties; m_configProperties.set(newConfigProperties);
//3. use getProperty to update configChange's new value and calc the final changes //3. use getProperty to update configChange's new value and calc the final changes
for (ConfigChange change : configChanges) { for (ConfigChange change : configChanges) {
...@@ -134,6 +142,9 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis ...@@ -134,6 +142,9 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
} }
actualChanges.put(change.getPropertyName(), change); actualChanges.put(change.getPropertyName(), change);
break; break;
default:
//do nothing
break;
} }
} }
return actualChanges.build(); return actualChanges.build();
...@@ -149,13 +160,13 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis ...@@ -149,13 +160,13 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
try { try {
properties.load(in); properties.load(in);
} catch (IOException e) { } catch (IOException ex) {
logger.error("Load resource config for namespace {} failed", namespace, e); logger.error("Load resource config for namespace {} failed", namespace, ex);
Cat.logError(e); Cat.logError(ex);
} finally { } finally {
try { try {
in.close(); in.close();
} catch (IOException e) { } catch (IOException ex) {
// ignore // ignore
} }
} }
......
...@@ -32,21 +32,27 @@ public class LocalFileConfigRepository extends AbstractConfigRepository ...@@ -32,21 +32,27 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
private volatile Properties m_fileProperties; private volatile Properties m_fileProperties;
private volatile ConfigRepository m_fallback; private volatile ConfigRepository m_fallback;
/**
* Constructor.
* @param baseDir the base dir for this local file config repository
* @param namespace the namespace
*/
public LocalFileConfigRepository(File baseDir, String namespace) { public LocalFileConfigRepository(File baseDir, String namespace) {
m_baseDir = baseDir; m_baseDir = baseDir;
m_namespace = namespace; m_namespace = namespace;
m_container = ContainerLoader.getDefaultContainer(); m_container = ContainerLoader.getDefaultContainer();
try { try {
m_configUtil = m_container.lookup(ConfigUtil.class); m_configUtil = m_container.lookup(ConfigUtil.class);
} catch (ComponentLookupException e) { } catch (ComponentLookupException ex) {
throw new IllegalStateException("Unable to load component!", e); throw new IllegalStateException("Unable to load component!", ex);
} }
this.trySync();
} }
@Override @Override
public Properties getConfig() { public Properties getConfig() {
if (m_fileProperties == null) { if (m_fileProperties == null) {
initLocalConfig(); sync();
} }
Properties result = new Properties(); Properties result = new Properties();
result.putAll(m_fileProperties); result.putAll(m_fileProperties);
...@@ -60,47 +66,59 @@ public class LocalFileConfigRepository extends AbstractConfigRepository ...@@ -60,47 +66,59 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
m_fallback.removeChangeListener(this); m_fallback.removeChangeListener(this);
} }
m_fallback = fallbackConfigRepository; m_fallback = fallbackConfigRepository;
trySyncFromFallback();
fallbackConfigRepository.addChangeListener(this); fallbackConfigRepository.addChangeListener(this);
} }
@Override @Override
public synchronized void onRepositoryChange(String namespace, Properties newProperties) { public void onRepositoryChange(String namespace, Properties newProperties) {
if (newProperties.equals(m_fileProperties)) { if (newProperties.equals(m_fileProperties)) {
return; return;
} }
Properties newFileProperties = new Properties(); Properties newFileProperties = new Properties();
newFileProperties.putAll(newProperties); newFileProperties.putAll(newProperties);
this.m_fileProperties = newFileProperties; updateFileProperties(newFileProperties);
persistLocalCacheFile(m_baseDir, m_namespace);
this.fireRepositoryChange(namespace, newProperties); this.fireRepositoryChange(namespace, newProperties);
} }
void initLocalConfig() { @Override
protected void sync() {
try { try {
m_fileProperties = this.loadFromLocalCacheFile(m_baseDir, m_namespace); m_fileProperties = this.loadFromLocalCacheFile(m_baseDir, m_namespace);
} catch (Throwable ex) { } catch (Throwable ex) {
logger.error("Load config from local config cache file failed", ex); ex.printStackTrace();
//ignore
} }
//TODO check whether properties is expired or should we return after it's synced with fallback? //sync with fallback immediately
if (m_fileProperties != null) { trySyncFromFallback();
return;
}
if (m_fallback == null) { if (m_fileProperties == null) {
throw new RuntimeException( throw new RuntimeException(
"Load config from local config cache failed and there is no fallback repository!"); "Load config from local config failed!");
} }
}
private void trySyncFromFallback() {
if (m_fallback == null) {
return;
}
try { try {
m_fileProperties = m_fallback.getConfig(); Properties properties = m_fallback.getConfig();
persistLocalCacheFile(m_baseDir, m_namespace); updateFileProperties(properties);
} catch (Throwable ex) { } catch (Throwable ex) {
String message = String message =
String.format("Load config from fallback repository %s failed", m_fallback.getClass()); String.format("Sync config from fallback repository %s failed", m_fallback.getClass());
logger.error(message, ex); logger.warn(message, ex);
throw new RuntimeException(message, ex); }
}
private synchronized void updateFileProperties(Properties newProperties) {
if (newProperties.equals(m_fileProperties)) {
return;
} }
this.m_fileProperties = newProperties;
persistLocalCacheFile(m_baseDir, m_namespace);
} }
private Properties loadFromLocalCacheFile(File baseDir, String namespace) throws IOException { private Properties loadFromLocalCacheFile(File baseDir, String namespace) throws IOException {
...@@ -117,16 +135,16 @@ public class LocalFileConfigRepository extends AbstractConfigRepository ...@@ -117,16 +135,16 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
properties = new Properties(); properties = new Properties();
properties.load(in); properties.load(in);
} catch (IOException e) { } catch (IOException ex) {
logger.error("Loading config from local cache file {} failed", file.getAbsolutePath(), e); logger.error("Loading config from local cache file {} failed", file.getAbsolutePath(), ex);
Cat.logError(e); Cat.logError(ex);
throw e; throw ex;
} finally { } finally {
try { try {
if (in != null) { if (in != null) {
in.close(); in.close();
} }
} catch (IOException e) { } catch (IOException ex) {
// ignore // ignore
} }
} }
...@@ -158,7 +176,7 @@ public class LocalFileConfigRepository extends AbstractConfigRepository ...@@ -158,7 +176,7 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
if (out != null) { if (out != null) {
try { try {
out.close(); out.close();
} catch (IOException e) { } catch (IOException ex) {
//ignore //ignore
} }
} }
......
...@@ -26,7 +26,7 @@ import java.util.concurrent.atomic.AtomicReference; ...@@ -26,7 +26,7 @@ import java.util.concurrent.atomic.AtomicReference;
/** /**
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
*/ */
public class RemoteConfigRepository extends AbstractConfigRepository{ public class RemoteConfigRepository extends AbstractConfigRepository {
private static final Logger logger = LoggerFactory.getLogger(RemoteConfigRepository.class); private static final Logger logger = LoggerFactory.getLogger(RemoteConfigRepository.class);
private PlexusContainer m_container; private PlexusContainer m_container;
private final ConfigServiceLocator m_serviceLocator; private final ConfigServiceLocator m_serviceLocator;
...@@ -36,6 +36,10 @@ public class RemoteConfigRepository extends AbstractConfigRepository{ ...@@ -36,6 +36,10 @@ public class RemoteConfigRepository extends AbstractConfigRepository{
private final String m_namespace; private final String m_namespace;
private final ScheduledExecutorService m_executorService; private final ScheduledExecutorService m_executorService;
/**
* Constructor.
* @param namespace the namespace
*/
public RemoteConfigRepository(String namespace) { public RemoteConfigRepository(String namespace) {
m_namespace = namespace; m_namespace = namespace;
m_configCache = new AtomicReference<>(); m_configCache = new AtomicReference<>();
...@@ -44,18 +48,19 @@ public class RemoteConfigRepository extends AbstractConfigRepository{ ...@@ -44,18 +48,19 @@ public class RemoteConfigRepository extends AbstractConfigRepository{
m_configUtil = m_container.lookup(ConfigUtil.class); m_configUtil = m_container.lookup(ConfigUtil.class);
m_httpUtil = m_container.lookup(HttpUtil.class); m_httpUtil = m_container.lookup(HttpUtil.class);
m_serviceLocator = m_container.lookup(ConfigServiceLocator.class); m_serviceLocator = m_container.lookup(ConfigServiceLocator.class);
} catch (ComponentLookupException e) { } catch (ComponentLookupException ex) {
throw new IllegalStateException("Unable to load component!", e); throw new IllegalStateException("Unable to load component!", ex);
} }
this.m_executorService = Executors.newScheduledThreadPool(1, this.m_executorService = Executors.newScheduledThreadPool(1,
ApolloThreadFactory.create("RemoteConfigRepository", true)); ApolloThreadFactory.create("RemoteConfigRepository", true));
this.trySync();
this.schedulePeriodicRefresh(); this.schedulePeriodicRefresh();
} }
@Override @Override
public Properties getConfig() { public Properties getConfig() {
if (m_configCache.get() == null) { if (m_configCache.get() == null) {
this.loadRemoteConfig(); this.sync();
} }
return transformApolloConfigToProperties(m_configCache.get()); return transformApolloConfigToProperties(m_configCache.get());
} }
...@@ -72,17 +77,14 @@ public class RemoteConfigRepository extends AbstractConfigRepository{ ...@@ -72,17 +77,14 @@ public class RemoteConfigRepository extends AbstractConfigRepository{
new Runnable() { new Runnable() {
@Override @Override
public void run() { public void run() {
try { trySync();
loadRemoteConfig();
} catch (Throwable ex) {
logger.error("Refreshing config failed", ex);
}
} }
}, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(), }, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(),
m_configUtil.getRefreshTimeUnit()); m_configUtil.getRefreshTimeUnit());
} }
synchronized void loadRemoteConfig() { @Override
protected synchronized void sync() {
ApolloConfig previous = m_configCache.get(); ApolloConfig previous = m_configCache.get();
ApolloConfig current = loadApolloConfig(); ApolloConfig current = loadApolloConfig();
...@@ -108,7 +110,9 @@ public class RemoteConfigRepository extends AbstractConfigRepository{ ...@@ -108,7 +110,9 @@ public class RemoteConfigRepository extends AbstractConfigRepository{
private ApolloConfig loadApolloConfig() { private ApolloConfig loadApolloConfig() {
String appId = m_configUtil.getAppId(); String appId = m_configUtil.getAppId();
String cluster = m_configUtil.getCluster(); String cluster = m_configUtil.getCluster();
String url = assembleUrl(getConfigServiceUrl(), appId, cluster, m_namespace, m_configCache.get()); String
url =
assembleUrl(getConfigServiceUrl(), appId, cluster, m_namespace, m_configCache.get());
logger.info("Loading config from {}", url); logger.info("Loading config from {}", url);
HttpRequest request = new HttpRequest(url); HttpRequest request = new HttpRequest(url);
...@@ -123,12 +127,12 @@ public class RemoteConfigRepository extends AbstractConfigRepository{ ...@@ -123,12 +127,12 @@ public class RemoteConfigRepository extends AbstractConfigRepository{
logger.info("Loaded config: {}", response.getBody()); logger.info("Loaded config: {}", response.getBody());
return response.getBody(); return response.getBody();
} catch (Throwable t) { } catch (Throwable ex) {
String message = String message =
String.format("Load Apollo Config failed - appId: %s, cluster: %s, namespace: %s", appId, String.format("Load Apollo Config failed - appId: %s, cluster: %s, namespace: %s", appId,
cluster, m_namespace); cluster, m_namespace);
logger.error(message, t); logger.error(message, ex);
throw new RuntimeException(message, t); throw new RuntimeException(message, ex);
} }
} }
......
...@@ -6,5 +6,10 @@ import java.util.Properties; ...@@ -6,5 +6,10 @@ import java.util.Properties;
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
*/ */
public interface RepositoryChangeListener { public interface RepositoryChangeListener {
/**
* Invoked when config repository changes.
* @param namespace the namespace of this repository change
* @param newProperties the properties after change
*/
public void onRepositoryChange(String namespace, Properties newProperties); public void onRepositoryChange(String namespace, Properties newProperties);
} }
...@@ -22,6 +22,11 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList ...@@ -22,6 +22,11 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList
private final ConfigRepository m_configRepository; private final ConfigRepository m_configRepository;
private volatile Properties m_configProperties; private volatile Properties m_configProperties;
/**
* Constructor.
* @param namespace the namespace for this config instance
* @param configRepository the config repository for this config instance
*/
public SimpleConfig(String namespace, ConfigRepository configRepository) { public SimpleConfig(String namespace, ConfigRepository configRepository) {
m_namespace = namespace; m_namespace = namespace;
m_configRepository = configRepository; m_configRepository = configRepository;
...@@ -36,12 +41,15 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList ...@@ -36,12 +41,15 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList
String message = String.format("Init Apollo Simple Config failed - namespace: %s", String message = String.format("Init Apollo Simple Config failed - namespace: %s",
m_namespace); m_namespace);
logger.error(message, ex); logger.error(message, ex);
throw new RuntimeException(message, ex);
} }
} }
@Override @Override
public String getProperty(String key, String defaultValue) { public String getProperty(String key, String defaultValue) {
if (m_configProperties == null) {
logger.error("Config initialization failed, always return default value!");
return defaultValue;
}
return this.m_configProperties.getProperty(key, defaultValue); return this.m_configProperties.getProperty(key, defaultValue);
} }
......
...@@ -6,6 +6,7 @@ import com.google.common.base.MoreObjects; ...@@ -6,6 +6,7 @@ import com.google.common.base.MoreObjects;
import com.ctrip.apollo.enums.PropertyChangeType; import com.ctrip.apollo.enums.PropertyChangeType;
/** /**
* Holds the information for a config change.
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
*/ */
public class ConfigChange { public class ConfigChange {
...@@ -14,6 +15,13 @@ public class ConfigChange { ...@@ -14,6 +15,13 @@ public class ConfigChange {
private String newValue; private String newValue;
private PropertyChangeType changeType; private PropertyChangeType changeType;
/**
* Constructor.
* @param propertyName the key whose value is changed
* @param oldValue the value before change
* @param newValue the value after change
* @param changeType the change type
*/
public ConfigChange(String propertyName, String oldValue, String newValue, public ConfigChange(String propertyName, String oldValue, String newValue,
PropertyChangeType changeType) { PropertyChangeType changeType) {
this.propertyName = propertyName; this.propertyName = propertyName;
......
...@@ -4,34 +4,53 @@ import java.util.Map; ...@@ -4,34 +4,53 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
* A change event when a namespace's config is changed.
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
*/ */
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> changes;
public ConfigChangeEvent(String m_namespace, /**
* Constructor.
* @param namespace the namespace of this change
* @param changes the actual changes
*/
public ConfigChangeEvent(String namespace,
Map<String, ConfigChange> changes) { Map<String, ConfigChange> changes) {
this.m_namespace = m_namespace; this.m_namespace = namespace;
this.changes = changes; this.changes = changes;
} }
/**
* Get the keys changed.
* @return the list of the keys
*/
public Set<String> changedKeys() { public Set<String> changedKeys() {
return changes.keySet(); return changes.keySet();
} }
/**
* Get a specific change instance for the key specified.
* @param key the changed key
* @return the change instance
*/
public ConfigChange getChange(String key) { public ConfigChange getChange(String key) {
return changes.get(key); return changes.get(key);
} }
/** /**
* Please note that the returned Map is immutable * Get the changes. Please note that the returned Map is immutable.
* @return changes * @return changes
*/ */
public Map<String, ConfigChange> getChanges() { public Map<String, ConfigChange> getChanges() {
return changes; return changes;
} }
/**
* Get the namespace of this change event.
* @return the namespace
*/
public String getNamespace() { public String getNamespace() {
return m_namespace; return m_namespace;
} }
......
...@@ -6,5 +6,11 @@ import com.ctrip.apollo.Config; ...@@ -6,5 +6,11 @@ import com.ctrip.apollo.Config;
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
*/ */
public interface ConfigFactory { public interface ConfigFactory {
public Config create(String namespace); /**
* Create the config instance for the namespace.
*
* @param namespace the namespace
* @return the newly created config instance
*/
public Config create(String namespace);
} }
...@@ -4,5 +4,11 @@ package com.ctrip.apollo.spi; ...@@ -4,5 +4,11 @@ package com.ctrip.apollo.spi;
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
*/ */
public interface ConfigFactoryManager { public interface ConfigFactoryManager {
/**
* Get the config factory for the namespace.
*
* @param namespace the namespace
* @return the config factory for this namespace
*/
public ConfigFactory getFactory(String namespace); public ConfigFactory getFactory(String namespace);
} }
package com.ctrip.apollo.spi; package com.ctrip.apollo.spi;
/** /**
* The manually config registry, use with caution!
*
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
*/ */
public interface ConfigRegistry { public interface ConfigRegistry {
/**
* Register the config factory for the namespace specified.
*
* @param namespace the namespace
* @param factory the factory for this namespace
*/
public void register(String namespace, ConfigFactory factory); public void register(String namespace, ConfigFactory factory);
/**
* Get the registered config factory for the namespace.
*
* @param namespace the namespace
* @return the factory registered for this namespace
*/
public ConfigFactory getFactory(String namespace); public ConfigFactory getFactory(String namespace);
} }
...@@ -6,6 +6,8 @@ import com.ctrip.apollo.internals.DefaultConfig; ...@@ -6,6 +6,8 @@ import com.ctrip.apollo.internals.DefaultConfig;
import com.ctrip.apollo.internals.LocalFileConfigRepository; import com.ctrip.apollo.internals.LocalFileConfigRepository;
import com.ctrip.apollo.internals.RemoteConfigRepository; import com.ctrip.apollo.internals.RemoteConfigRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.unidal.lookup.annotation.Named; import org.unidal.lookup.annotation.Named;
import java.io.File; import java.io.File;
...@@ -15,13 +17,19 @@ import java.io.File; ...@@ -15,13 +17,19 @@ import java.io.File;
*/ */
@Named(type = ConfigFactory.class, value = "default") @Named(type = ConfigFactory.class, value = "default")
public class DefaultConfigFactory implements ConfigFactory { public class DefaultConfigFactory implements ConfigFactory {
private static final Logger logger = LoggerFactory.getLogger(DefaultConfigFactory.class);
private static final String CONFIG_DIR = "/config-cache"; private static final String CONFIG_DIR = "/config-cache";
private File m_baseDir; private File m_baseDir;
/**
* Create the config factory.
*/
public DefaultConfigFactory() { public DefaultConfigFactory() {
m_baseDir = new File(ClassLoaderUtil.getClassPath() + CONFIG_DIR); m_baseDir = new File(ClassLoaderUtil.getClassPath() + CONFIG_DIR);
if (!m_baseDir.exists()) { if (!m_baseDir.exists()) {
m_baseDir.mkdir(); if(!m_baseDir.mkdir()){
logger.error("Creating local cache dir failed.");
}
} }
} }
...@@ -33,10 +41,10 @@ public class DefaultConfigFactory implements ConfigFactory { ...@@ -33,10 +41,10 @@ public class DefaultConfigFactory implements ConfigFactory {
} }
LocalFileConfigRepository createLocalConfigRepository(String namespace) { LocalFileConfigRepository createLocalConfigRepository(String namespace) {
LocalFileConfigRepository localFileConfigLoader = LocalFileConfigRepository localFileConfigRepository =
new LocalFileConfigRepository(m_baseDir, namespace); new LocalFileConfigRepository(m_baseDir, namespace);
localFileConfigLoader.setFallback(createRemoteConfigRepository(namespace)); localFileConfigRepository.setFallback(createRemoteConfigRepository(namespace));
return localFileConfigLoader; return localFileConfigRepository;
} }
RemoteConfigRepository createRemoteConfigRepository(String namespace) { RemoteConfigRepository createRemoteConfigRepository(String namespace) {
......
...@@ -38,7 +38,7 @@ public class DefaultConfigFactoryManager extends ContainerHolder implements Conf ...@@ -38,7 +38,7 @@ public class DefaultConfigFactoryManager extends ContainerHolder implements Conf
// step 3: check declared config factory // step 3: check declared config factory
try { try {
factory = lookup(ConfigFactory.class, namespace); factory = lookup(ConfigFactory.class, namespace);
} catch (LookupException e) { } catch (LookupException ex) {
// ignore it // ignore it
} }
......
package com.ctrip.apollo.util; package com.ctrip.apollo.util;
import com.google.common.base.Preconditions;
import com.ctrip.apollo.core.ConfigConsts;
import com.ctrip.apollo.core.MetaDomainConsts;
import com.ctrip.apollo.core.enums.Env;
import com.ctrip.apollo.env.Apollo;
import org.unidal.lookup.annotation.Named; import org.unidal.lookup.annotation.Named;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
...@@ -15,14 +22,42 @@ public class ConfigUtil { ...@@ -15,14 +22,42 @@ public class ConfigUtil {
private static final int connectTimeout = 5000; //5 seconds private static final int connectTimeout = 5000; //5 seconds
private static final int readTimeout = 10000; //10 seconds private static final int readTimeout = 10000; //10 seconds
/**
* Get the app id for the current application.
* @return the app id
* @throws IllegalStateException if app id is not set
*/
public String getAppId() { public String getAppId() {
// TODO return the actual app id String appId = Apollo.getAppId();
return "100003171"; Preconditions.checkState(appId != null, "app.id is not set");
return appId;
} }
/**
* Get the cluster name for the current application.
* @return the cluster name, or "default" if not specified
*/
public String getCluster() { public String getCluster() {
// TODO return the actual cluster String cluster = Apollo.getCluster();
return "default"; if (cluster == null) {
cluster = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
return cluster;
}
/**
* Get the current environment.
* @return the env
* @throws IllegalStateException if env is set
*/
public Env getApolloEnv() {
Env env = Apollo.getEnv();
Preconditions.checkState(env != null, "env is not set");
return env;
}
public String getMetaServerDomainName() {
return MetaDomainConsts.getDomain(getApolloEnv());
} }
public int getConnectTimeout() { public int getConnectTimeout() {
......
...@@ -8,6 +8,10 @@ public class HttpRequest { ...@@ -8,6 +8,10 @@ public class HttpRequest {
private int m_connectTimeout; private int m_connectTimeout;
private int m_readTimeout; private int m_readTimeout;
/**
* Create the request for the url.
* @param url the url
*/
public HttpRequest(String url) { public HttpRequest(String url) {
this.m_url = url; this.m_url = url;
m_connectTimeout = -1; m_connectTimeout = -1;
......
...@@ -28,8 +28,9 @@ public class HttpUtil { ...@@ -28,8 +28,9 @@ public class HttpUtil {
} }
/** /**
* Do get operation for the http request * Do get operation for the http request.
* *
* @return the http response
* @throws RuntimeException if any error happened or response code is neither 200 nor 304 * @throws RuntimeException if any error happened or response code is neither 200 nor 304
*/ */
public <T> HttpResponse<T> doGet(HttpRequest httpRequest, Class<T> responseType) { public <T> HttpResponse<T> doGet(HttpRequest httpRequest, Class<T> responseType) {
...@@ -67,7 +68,8 @@ public class HttpUtil { ...@@ -67,7 +68,8 @@ public class HttpUtil {
} }
throw new RuntimeException( throw new RuntimeException(
String.format("Get operation failed for %s, status code - %d", httpRequest.getUrl(), statusCode)); String.format("Get operation failed for %s, status code - %d", httpRequest.getUrl(),
statusCode));
} catch (Throwable ex) { } catch (Throwable ex) {
throw new RuntimeException("Could not complete get operation", ex); throw new RuntimeException("Could not complete get operation", ex);
...@@ -75,7 +77,7 @@ public class HttpUtil { ...@@ -75,7 +77,7 @@ public class HttpUtil {
if (is != null) { if (is != null) {
try { try {
is.close(); is.close();
} catch (IOException e) { } catch (IOException ex) {
//ignore //ignore
} }
} }
......
...@@ -37,6 +37,9 @@ ...@@ -37,6 +37,9 @@
<requirement> <requirement>
<role>com.ctrip.apollo.util.http.HttpUtil</role> <role>com.ctrip.apollo.util.http.HttpUtil</role>
</requirement> </requirement>
<requirement>
<role>com.ctrip.apollo.util.ConfigUtil</role>
</requirement>
</requirements> </requirements>
</component> </component>
<component> <component>
......
package com.ctrip.apollo; package com.ctrip.apollo;
import com.ctrip.apollo.integration.ConfigIntegrationTest;
import com.ctrip.apollo.internals.DefaultConfigManagerTest; import com.ctrip.apollo.internals.DefaultConfigManagerTest;
import com.ctrip.apollo.internals.DefaultConfigTest; import com.ctrip.apollo.internals.DefaultConfigTest;
import com.ctrip.apollo.internals.LocalFileConfigRepositoryTest; import com.ctrip.apollo.internals.LocalFileConfigRepositoryTest;
...@@ -18,7 +19,8 @@ import org.junit.runners.Suite.SuiteClasses; ...@@ -18,7 +19,8 @@ import org.junit.runners.Suite.SuiteClasses;
@SuiteClasses({ @SuiteClasses({
ConfigServiceTest.class, DefaultConfigRegistryTest.class, DefaultConfigFactoryManagerTest.class, ConfigServiceTest.class, DefaultConfigRegistryTest.class, DefaultConfigFactoryManagerTest.class,
DefaultConfigManagerTest.class, DefaultConfigTest.class, LocalFileConfigRepositoryTest.class, DefaultConfigManagerTest.class, DefaultConfigTest.class, LocalFileConfigRepositoryTest.class,
RemoteConfigRepositoryTest.class, SimpleConfigTest.class, DefaultConfigFactoryTest.class RemoteConfigRepositoryTest.class, SimpleConfigTest.class, DefaultConfigFactoryTest.class,
ConfigIntegrationTest.class
}) })
public class AllTests { public class AllTests {
......
...@@ -18,6 +18,7 @@ public class ConfigServiceTest extends ComponentTestCase { ...@@ -18,6 +18,7 @@ public class ConfigServiceTest extends ComponentTestCase {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
super.setUp(); super.setUp();
//as ConfigService is singleton, so we must manually clear its container
ConfigService.setContainer(getContainer()); ConfigService.setContainer(getContainer());
} }
......
package com.ctrip.apollo.integration;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.google.common.io.Files;
import com.google.gson.Gson;
import com.ctrip.apollo.ConfigService;
import com.ctrip.apollo.core.enums.Env;
import com.ctrip.apollo.core.dto.ServiceDTO;
import com.ctrip.apollo.core.utils.ClassLoaderUtil;
import com.ctrip.apollo.util.ConfigUtil;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.unidal.lookup.ComponentTestCase;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class BaseIntegrationTest extends ComponentTestCase {
private static final int PORT = 5678;
private static final String metaServiceUrl = "http://localhost:" + PORT;
private static final String someAppName = "someAppName";
private static final String someInstanceId = "someInstanceId";
private static final String configServiceURL = "http://localhost:" + PORT;
protected static String someAppId;
protected static String someClusterName;
protected static int refreshInterval;
protected static TimeUnit refreshTimeUnit;
private Server server;
protected Gson gson = new Gson();
@BeforeClass
public static void beforeClass() throws Exception {
File apolloEnvPropertiesFile = new File(ClassLoaderUtil.getClassPath(), "apollo-env.properties");
Files.write("local.meta=" + metaServiceUrl, apolloEnvPropertiesFile, Charsets.UTF_8);
apolloEnvPropertiesFile.deleteOnExit();
}
@Before
public void setUp() throws Exception {
super.setUp();
someAppId = "1003171";
someClusterName = "someClusterName";
refreshInterval = 5;
refreshTimeUnit = TimeUnit.MINUTES;
//as ConfigService is singleton, so we must manually clear its container
ConfigService.setContainer(getContainer());
defineComponent(ConfigUtil.class, MockConfigUtil.class);
}
/**
* init and start a jetty server, remember to call server.stop when the task is finished
* @param handlers
* @throws Exception
*/
protected Server startServerWithHandlers(ContextHandler... handlers) throws Exception {
server = new Server(PORT);
ContextHandlerCollection contexts = new ContextHandlerCollection();
contexts.setHandlers(handlers);
contexts.addHandler(mockMetaServerHandler());
server.setHandler(contexts);
server.start();
return server;
}
@After
public void tearDown() throws Exception {
super.tearDown();
if (server != null && server.isStarted()) {
server.stop();
}
}
private ContextHandler mockMetaServerHandler() {
final ServiceDTO someServiceDTO = new ServiceDTO();
someServiceDTO.setAppName(someAppName);
someServiceDTO.setInstanceId(someInstanceId);
someServiceDTO.setHomepageUrl(configServiceURL);
ContextHandler context = new ContextHandler("/services/config");
context.setHandler(new AbstractHandler() {
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println(gson.toJson(Lists.newArrayList(someServiceDTO)));
baseRequest.setHandled(true);
}
});
return context;
}
protected void setRefreshInterval(int refreshInterval) {
BaseIntegrationTest.refreshInterval = refreshInterval;
}
protected void setRefreshTimeUnit(TimeUnit refreshTimeUnit) {
BaseIntegrationTest.refreshTimeUnit = refreshTimeUnit;
}
public static class MockConfigUtil extends ConfigUtil {
@Override
public String getAppId() {
return someAppId;
}
@Override
public String getCluster() {
return someClusterName;
}
@Override
public int getRefreshInterval() {
return refreshInterval;
}
@Override
public TimeUnit getRefreshTimeUnit() {
return refreshTimeUnit;
}
@Override
public Env getApolloEnv() {
return Env.LOCAL;
}
}
}
package com.ctrip.apollo.integration;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ctrip.apollo.Config;
import com.ctrip.apollo.ConfigChangeListener;
import com.ctrip.apollo.ConfigService;
import com.ctrip.apollo.core.ConfigConsts;
import com.ctrip.apollo.core.dto.ApolloConfig;
import com.ctrip.apollo.core.utils.ClassLoaderUtil;
import com.ctrip.apollo.model.ConfigChangeEvent;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class ConfigIntegrationTest extends BaseIntegrationTest {
private long someReleaseId;
private File configDir;
private String someNamespace;
@Before
public void setUp() throws Exception {
super.setUp();
someNamespace = ConfigConsts.NAMESPACE_APPLICATION;
someReleaseId = 1;
configDir = new File(ClassLoaderUtil.getClassPath() + "config-cache");
configDir.mkdirs();
}
@Override
@After
public void tearDown() throws Exception {
super.tearDown();
recursiveDelete(configDir);
}
private void recursiveDelete(File file) {
if (!file.exists()) {
return;
}
if (file.isDirectory()) {
for (File f : file.listFiles()) {
recursiveDelete(f);
}
}
file.delete();
}
@Test
public void testGetConfigWithNoLocalFileButWithRemoteConfig() throws Exception {
String someKey = "someKey";
String someValue = "someValue";
String someNonExistedKey = "someNonExistedKey";
String someDefaultValue = "someDefaultValue";
ApolloConfig apolloConfig = assembleApolloConfig(ImmutableMap.of(someKey, someValue));
ContextHandler handler = mockConfigServerHandler(HttpServletResponse.SC_OK, apolloConfig);
startServerWithHandlers(handler);
Config config = ConfigService.getConfig();
assertEquals(someValue, config.getProperty(someKey, null));
assertEquals(someDefaultValue, config.getProperty(someNonExistedKey, someDefaultValue));
}
@Test
public void testGetConfigWithLocalFileAndWithRemoteConfig() throws Exception {
String someKey = "someKey";
String someValue = "someValue";
String anotherValue = "anotherValue";
Properties properties = new Properties();
properties.put(someKey, someValue);
createLocalCachePropertyFile(properties);
ApolloConfig apolloConfig = assembleApolloConfig(ImmutableMap.of(someKey, anotherValue));
ContextHandler handler = mockConfigServerHandler(HttpServletResponse.SC_OK, apolloConfig);
startServerWithHandlers(handler);
Config config = ConfigService.getConfig();
assertEquals(anotherValue, config.getProperty(someKey, null));
}
@Test
public void testGetConfigWithNoLocalFileAndRemoteConfigError() throws Exception {
ContextHandler
handler =
mockConfigServerHandler(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null);
startServerWithHandlers(handler);
Config config = ConfigService.getConfig();
String someKey = "someKey";
String someDefaultValue = "defaultValue" + Math.random();
assertEquals(someDefaultValue, config.getProperty(someKey, someDefaultValue));
}
@Test
public void testGetConfigWithLocalFileAndRemoteConfigError() throws Exception {
String someKey = "someKey";
String someValue = "someValue";
Properties properties = new Properties();
properties.put(someKey, someValue);
createLocalCachePropertyFile(properties);
ContextHandler
handler =
mockConfigServerHandler(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null);
startServerWithHandlers(handler);
Config config = ConfigService.getConfig();
assertEquals(someValue, config.getProperty(someKey, null));
}
@Test
public void testRefreshConfig() throws Exception {
final String someKey = "someKey";
final String someValue = "someValue";
final String anotherValue = "anotherValue";
int someRefreshInterval = 500;
TimeUnit someRefreshTimeUnit = TimeUnit.MILLISECONDS;
setRefreshInterval(someRefreshInterval);
setRefreshTimeUnit(someRefreshTimeUnit);
Map<String, String> configurations = Maps.newHashMap();
configurations.put(someKey, someValue);
ApolloConfig apolloConfig = assembleApolloConfig(configurations);
ContextHandler handler = mockConfigServerHandler(HttpServletResponse.SC_OK, apolloConfig);
startServerWithHandlers(handler);
Config config = ConfigService.getConfig();
final List<ConfigChangeEvent> changeEvents = Lists.newArrayList();
config.addChangeListener(new ConfigChangeListener() {
@Override
public void onChange(ConfigChangeEvent changeEvent) {
assertEquals(1, changeEvent.getChanges().size());
assertEquals(someValue, changeEvent.getChange(someKey).getOldValue());
assertEquals(anotherValue, changeEvent.getChange(someKey).getNewValue());
//if there is any assertion failed above, this line won't be executed
changeEvents.add(changeEvent);
}
});
apolloConfig.getConfigurations().put(someKey, anotherValue);
Thread.sleep(someRefreshTimeUnit.toMillis(someRefreshInterval * 2));
assertThat(
"Change event's size should equal to one or there must be some assertion failed in change listener",
1, equalTo(changeEvents.size()));
assertEquals(anotherValue, config.getProperty(someKey, null));
}
private ContextHandler mockConfigServerHandler(final int statusCode, final ApolloConfig result) {
ContextHandler context = new ContextHandler("/config/*");
context.setHandler(new AbstractHandler() {
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
response.setContentType("application/json;charset=UTF-8");
response.setStatus(statusCode);
response.getWriter().println(gson.toJson(result));
baseRequest.setHandled(true);
}
});
return context;
}
private ApolloConfig assembleApolloConfig(Map<String, String> configurations) {
ApolloConfig apolloConfig =
new ApolloConfig(someAppId, someClusterName, someNamespace, someReleaseId);
apolloConfig.setConfigurations(configurations);
return apolloConfig;
}
private File createLocalCachePropertyFile(Properties properties) throws IOException {
File file = new File(configDir, assembleLocalCacheFileName());
properties.store(new FileOutputStream(file), "Persisted by ConfigIntegrationTest");
return file;
}
private String assembleLocalCacheFileName() {
return String.format("%s-%s-%s.properties", someAppId,
someClusterName, someNamespace);
}
}
...@@ -19,7 +19,6 @@ import static org.junit.Assert.assertEquals; ...@@ -19,7 +19,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.only;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
...@@ -34,6 +33,8 @@ public class LocalFileConfigRepositoryTest extends ComponentTestCase { ...@@ -34,6 +33,8 @@ public class LocalFileConfigRepositoryTest extends ComponentTestCase {
private Properties someProperties; private Properties someProperties;
private static String someAppId = "someApp"; private static String someAppId = "someApp";
private static String someCluster = "someCluster"; private static String someCluster = "someCluster";
private String defaultKey;
private String defaultValue;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
...@@ -43,7 +44,9 @@ public class LocalFileConfigRepositoryTest extends ComponentTestCase { ...@@ -43,7 +44,9 @@ public class LocalFileConfigRepositoryTest extends ComponentTestCase {
someNamespace = "someName"; someNamespace = "someName";
someProperties = new Properties(); someProperties = new Properties();
someProperties.setProperty("defaultKey", "defaultValue"); defaultKey = "defaultKey";
defaultValue = "defaultValue";
someProperties.setProperty(defaultKey, defaultValue);
fallbackRepo = mock(ConfigRepository.class); fallbackRepo = mock(ConfigRepository.class);
when(fallbackRepo.getConfig()).thenReturn(someProperties); when(fallbackRepo.getConfig()).thenReturn(someProperties);
...@@ -52,6 +55,7 @@ public class LocalFileConfigRepositoryTest extends ComponentTestCase { ...@@ -52,6 +55,7 @@ public class LocalFileConfigRepositoryTest extends ComponentTestCase {
@After @After
public void tearDown() throws Exception { public void tearDown() throws Exception {
super.tearDown();
recursiveDelete(someBaseDir); recursiveDelete(someBaseDir);
} }
...@@ -73,10 +77,6 @@ public class LocalFileConfigRepositoryTest extends ComponentTestCase { ...@@ -73,10 +77,6 @@ public class LocalFileConfigRepositoryTest extends ComponentTestCase {
someCluster, someNamespace); someCluster, someNamespace);
} }
@Test
public void testLoadConfig() throws Exception {
}
@Test @Test
public void testLoadConfigWithLocalFile() throws Exception { public void testLoadConfigWithLocalFile() throws Exception {
...@@ -94,6 +94,24 @@ public class LocalFileConfigRepositoryTest extends ComponentTestCase { ...@@ -94,6 +94,24 @@ public class LocalFileConfigRepositoryTest extends ComponentTestCase {
} }
@Test
public void testLoadConfigWithLocalFileAndFallbackRepo() throws Exception {
File file = new File(someBaseDir, assembleLocalCacheFileName());
String someValue = "someValue";
Files.write(defaultKey + "=" + someValue, file, Charsets.UTF_8);
LocalFileConfigRepository localRepo = new LocalFileConfigRepository(someBaseDir, someNamespace);
//when fallback is set, it will try to sync from it
localRepo.setFallback(fallbackRepo);
Properties properties = localRepo.getConfig();
assertEquals(defaultValue, properties.getProperty(defaultKey));
}
@Test @Test
public void testLoadConfigWithNoLocalFile() throws Exception { public void testLoadConfigWithNoLocalFile() throws Exception {
LocalFileConfigRepository LocalFileConfigRepository
......
...@@ -92,11 +92,16 @@ public class RemoteConfigRepositoryTest extends ComponentTestCase { ...@@ -92,11 +92,16 @@ public class RemoteConfigRepositoryTest extends ComponentTestCase {
remoteConfigRepository.addChangeListener(someListener); remoteConfigRepository.addChangeListener(someListener);
final ArgumentCaptor<Properties> captor = ArgumentCaptor.forClass(Properties.class); final ArgumentCaptor<Properties> captor = ArgumentCaptor.forClass(Properties.class);
remoteConfigRepository.loadRemoteConfig(); Map<String, String> newConfigurations = ImmutableMap.of("someKey", "anotherValue");
ApolloConfig newApolloConfig = assembleApolloConfig(newConfigurations);
when(someResponse.getBody()).thenReturn(newApolloConfig);
remoteConfigRepository.sync();
verify(someListener, times(1)).onRepositoryChange(eq(someNamespace), captor.capture()); verify(someListener, times(1)).onRepositoryChange(eq(someNamespace), captor.capture());
assertEquals(configurations, captor.getValue()); assertEquals(newConfigurations, captor.getValue());
} }
private ApolloConfig assembleApolloConfig(Map<String, String> configurations) { private ApolloConfig assembleApolloConfig(Map<String, String> configurations) {
......
...@@ -2,6 +2,7 @@ package com.ctrip.apollo.internals; ...@@ -2,6 +2,7 @@ package com.ctrip.apollo.internals;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.ctrip.apollo.Config;
import com.ctrip.apollo.ConfigChangeListener; import com.ctrip.apollo.ConfigChangeListener;
import com.ctrip.apollo.enums.PropertyChangeType; import com.ctrip.apollo.enums.PropertyChangeType;
import com.ctrip.apollo.model.ConfigChange; import com.ctrip.apollo.model.ConfigChange;
...@@ -50,11 +51,15 @@ public class SimpleConfigTest { ...@@ -50,11 +51,15 @@ public class SimpleConfigTest {
assertEquals(someValue, config.getProperty(someKey, null)); assertEquals(someValue, config.getProperty(someKey, null));
} }
@Test(expected = RuntimeException.class) @Test
public void testLoadConfigFromConfigRepositoryError() throws Exception { public void testLoadConfigFromConfigRepositoryError() throws Exception {
when(configRepository.getConfig()).thenThrow(Throwable.class); when(configRepository.getConfig()).thenThrow(Throwable.class);
new SimpleConfig(someNamespace, configRepository); Config config = new SimpleConfig(someNamespace, configRepository);
String someKey = "someKey";
String anyValue = "anyValue" + Math.random();
assertEquals(anyValue, config.getProperty(someKey, anyValue));
} }
@Test @Test
......
package com.ctrip.apollo;
public class Apollo {
public static final String VERSION = "java-0.0.1-SNAPSHOT";
private static Env m_env;
public enum Env {
LOCAL, DEV, FWS, FAT, UAT, LPT, PRO, TOOLS
}
public static void initialize(Env env) {
m_env = env;
}
public static Env getEnv() {
return m_env;
}
}
...@@ -4,7 +4,7 @@ import java.util.HashMap; ...@@ -4,7 +4,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import com.ctrip.apollo.Apollo.Env; import com.ctrip.apollo.core.enums.Env;
import com.ctrip.apollo.core.utils.ResourceUtils; import com.ctrip.apollo.core.utils.ResourceUtils;
public class MetaDomainConsts { public class MetaDomainConsts {
......
package com.ctrip.apollo.core.dto; package com.ctrip.apollo.core.dto;
import com.ctrip.apollo.Apollo.Env; import com.ctrip.apollo.core.enums.Env;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
......
package com.ctrip.apollo.constants; package com.ctrip.apollo.core.enums;
/** /**
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
*/ */
public class Constants { public enum Env {
public static final String ENV = "env"; LOCAL, DEV, FWS, FAT, UAT, LPT, PRO, TOOLS
} }
package com.ctrip.apollo.core; package com.ctrip.apollo.core;
import com.ctrip.apollo.core.enums.Env;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import com.ctrip.apollo.Apollo.Env;
public class MetaDomainTest { public class MetaDomainTest {
@Test @Test
......
...@@ -36,7 +36,11 @@ public class ApolloConfigDemo implements ConfigChangeListener { ...@@ -36,7 +36,11 @@ public class ApolloConfigDemo implements ConfigChangeListener {
"Apollo Config Demo. Please input key to get the value."); "Apollo Config Demo. Please input key to get the value.");
while (true) { while (true) {
System.out.print("> "); System.out.print("> ");
String input = (new BufferedReader(new InputStreamReader(System.in)).readLine()).trim(); String input = new BufferedReader(new InputStreamReader(System.in)).readLine();
if (input == null) {
continue;
}
input = input.trim();
if (input.equalsIgnoreCase("quit")) { if (input.equalsIgnoreCase("quit")) {
System.exit(0); System.exit(0);
} }
......
...@@ -8,7 +8,7 @@ import javax.annotation.PostConstruct; ...@@ -8,7 +8,7 @@ import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.ctrip.apollo.Apollo.Env; import com.ctrip.apollo.core.enums.Env;
@Component @Component
public class PortalSettings { public class PortalSettings {
......
package com.ctrip.apollo.portal.api; package com.ctrip.apollo.portal.api;
import com.ctrip.apollo.Apollo; import com.ctrip.apollo.core.enums.Env;
import com.ctrip.apollo.core.exception.ServiceException; import com.ctrip.apollo.core.exception.ServiceException;
import com.ctrip.apollo.portal.service.ServiceLocator; import com.ctrip.apollo.portal.service.ServiceLocator;
...@@ -14,7 +14,7 @@ public class API { ...@@ -14,7 +14,7 @@ public class API {
protected RestTemplate restTemplate = new RestTemplate(); protected RestTemplate restTemplate = new RestTemplate();
public String getAdminServiceHost(Apollo.Env env) { public String getAdminServiceHost(Env env) {
// 本地测试用 // 本地测试用
// return "http://localhost:8090"; // return "http://localhost:8090";
try { try {
......
package com.ctrip.apollo.portal.api; package com.ctrip.apollo.portal.api;
import com.ctrip.apollo.Apollo; import com.ctrip.apollo.core.enums.Env;
import com.ctrip.apollo.core.dto.AppDTO; import com.ctrip.apollo.core.dto.AppDTO;
import com.ctrip.apollo.core.dto.ClusterDTO; import com.ctrip.apollo.core.dto.ClusterDTO;
import com.ctrip.apollo.core.dto.ItemChangeSets; import com.ctrip.apollo.core.dto.ItemChangeSets;
...@@ -36,11 +36,11 @@ public class AdminServiceAPI { ...@@ -36,11 +36,11 @@ public class AdminServiceAPI {
public static String APP_API = "/apps"; public static String APP_API = "/apps";
public List<AppDTO> getApps(Apollo.Env env) { public List<AppDTO> getApps(Env env) {
return Arrays.asList(restTemplate.getForObject(getAdminServiceHost(env) + APP_API, AppDTO[].class)); return Arrays.asList(restTemplate.getForObject(getAdminServiceHost(env) + APP_API, AppDTO[].class));
} }
public AppDTO save(Apollo.Env env, AppDTO app) { public AppDTO save(Env env, AppDTO app) {
return restTemplate.postForEntity(getAdminServiceHost(env) + APP_API, app, AppDTO.class).getBody(); return restTemplate.postForEntity(getAdminServiceHost(env) + APP_API, app, AppDTO.class).getBody();
} }
} }
...@@ -49,7 +49,7 @@ public class AdminServiceAPI { ...@@ -49,7 +49,7 @@ public class AdminServiceAPI {
@Service @Service
public static class NamespaceAPI extends API { public static class NamespaceAPI extends API {
public List<NamespaceDTO> findGroupsByAppAndCluster(String appId, Apollo.Env env, public List<NamespaceDTO> findGroupsByAppAndCluster(String appId, Env env,
String clusterName) { String clusterName) {
if (StringUtils.isContainEmpty(appId, clusterName)) { if (StringUtils.isContainEmpty(appId, clusterName)) {
return null; return null;
...@@ -60,7 +60,7 @@ public class AdminServiceAPI { ...@@ -60,7 +60,7 @@ public class AdminServiceAPI {
NamespaceDTO[].class)); NamespaceDTO[].class));
} }
public NamespaceDTO loadNamespace(String appId, Apollo.Env env, public NamespaceDTO loadNamespace(String appId, Env env,
String clusterName, String namespaceName) { String clusterName, String namespaceName) {
if (StringUtils.isContainEmpty(appId, clusterName, namespaceName)) { if (StringUtils.isContainEmpty(appId, clusterName, namespaceName)) {
return null; return null;
...@@ -74,7 +74,7 @@ public class AdminServiceAPI { ...@@ -74,7 +74,7 @@ public class AdminServiceAPI {
@Service @Service
public static class ItemAPI extends API { public static class ItemAPI extends API {
public List<ItemDTO> findItems(String appId, Apollo.Env env, String clusterName, String namespace) { public List<ItemDTO> findItems(String appId, Env env, String clusterName, String namespace) {
if (StringUtils.isContainEmpty(appId, clusterName, namespace)) { if (StringUtils.isContainEmpty(appId, clusterName, namespace)) {
return Collections.EMPTY_LIST; return Collections.EMPTY_LIST;
} }
...@@ -85,7 +85,7 @@ public class AdminServiceAPI { ...@@ -85,7 +85,7 @@ public class AdminServiceAPI {
ItemDTO[].class)); ItemDTO[].class));
} }
public void updateItems(String appId, Apollo.Env env, String clusterName, String namespace, public void updateItems(String appId, Env env, String clusterName, String namespace,
ItemChangeSets changeSets) { ItemChangeSets changeSets) {
if (StringUtils.isContainEmpty(appId, clusterName, namespace)) { if (StringUtils.isContainEmpty(appId, clusterName, namespace)) {
return; return;
...@@ -101,7 +101,7 @@ public class AdminServiceAPI { ...@@ -101,7 +101,7 @@ public class AdminServiceAPI {
@Service @Service
public static class ClusterAPI extends API { public static class ClusterAPI extends API {
public List<ClusterDTO> findClustersByApp(String appId, Apollo.Env env) { public List<ClusterDTO> findClustersByApp(String appId, Env env) {
if (StringUtils.isContainEmpty(appId)) { if (StringUtils.isContainEmpty(appId)) {
return null; return null;
} }
...@@ -115,7 +115,7 @@ public class AdminServiceAPI { ...@@ -115,7 +115,7 @@ public class AdminServiceAPI {
@Service @Service
public static class ReleaseAPI extends API { public static class ReleaseAPI extends API {
public ReleaseDTO loadLatestRelease(String appId, Apollo.Env env, String clusterName, String namespace) { public ReleaseDTO loadLatestRelease(String appId, Env env, String clusterName, String namespace) {
if (StringUtils.isContainEmpty(appId, clusterName, namespace)) { if (StringUtils.isContainEmpty(appId, clusterName, namespace)) {
return null; return null;
} }
...@@ -132,7 +132,7 @@ public class AdminServiceAPI { ...@@ -132,7 +132,7 @@ public class AdminServiceAPI {
} }
} }
public ReleaseDTO release(String appId, Apollo.Env env, String clusterName, String namespace, String releaseBy, public ReleaseDTO release(String appId, Env env, String clusterName, String namespace, String releaseBy,
String comment) { String comment) {
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>(); MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
parameters.add("name", releaseBy); parameters.add("name", releaseBy);
......
package com.ctrip.apollo.portal.controller; package com.ctrip.apollo.portal.controller;
import com.ctrip.apollo.Apollo; import com.ctrip.apollo.core.enums.Env;
import com.ctrip.apollo.core.dto.ReleaseDTO; import com.ctrip.apollo.core.dto.ReleaseDTO;
import com.ctrip.apollo.core.exception.BadRequestException; import com.ctrip.apollo.core.exception.BadRequestException;
import com.ctrip.apollo.core.utils.StringUtils; import com.ctrip.apollo.core.utils.StringUtils;
...@@ -34,7 +34,7 @@ public class ConfigController { ...@@ -34,7 +34,7 @@ public class ConfigController {
throw new BadRequestException("app id and cluster name can not be empty"); throw new BadRequestException("app id and cluster name can not be empty");
} }
return configService.findNampspaces(appId, Apollo.Env.valueOf(env), clusterName); return configService.findNampspaces(appId, Env.valueOf(env), clusterName);
} }
@RequestMapping(value = "/apps/{appId}/env/{env}/clusters/{clusterName}/namespaces/{namespaceName}/items", method = RequestMethod.PUT, consumes = { @RequestMapping(value = "/apps/{appId}/env/{env}/clusters/{clusterName}/namespaces/{namespaceName}/items", method = RequestMethod.PUT, consumes = {
......
package com.ctrip.apollo.portal.entity; package com.ctrip.apollo.portal.entity;
import com.ctrip.apollo.Apollo; import com.ctrip.apollo.core.enums.Env;
import com.ctrip.apollo.core.dto.ClusterDTO; import com.ctrip.apollo.core.dto.ClusterDTO;
import java.util.LinkedList; import java.util.LinkedList;
...@@ -19,18 +19,18 @@ public class ClusterNavTree { ...@@ -19,18 +19,18 @@ public class ClusterNavTree {
} }
public static class Node{ public static class Node{
private Apollo.Env env; private Env env;
private List<ClusterDTO> clusters; private List<ClusterDTO> clusters;
public Node(Apollo.Env env){ public Node(Env env){
this.env = env; this.env = env;
} }
public Apollo.Env getEnv() { public Env getEnv() {
return env; return env;
} }
public void setEnv(Apollo.Env env) { public void setEnv(Env env) {
this.env = env; this.env = env;
} }
......
package com.ctrip.apollo.portal.entity.form; package com.ctrip.apollo.portal.entity.form;
import com.ctrip.apollo.Apollo; import com.ctrip.apollo.core.enums.Env;
import com.ctrip.apollo.core.utils.StringUtils; import com.ctrip.apollo.core.utils.StringUtils;
public class NamespaceReleaseModel implements FormModel{ public class NamespaceReleaseModel implements FormModel{
...@@ -26,8 +26,8 @@ public class NamespaceReleaseModel implements FormModel{ ...@@ -26,8 +26,8 @@ public class NamespaceReleaseModel implements FormModel{
this.appId = appId; this.appId = appId;
} }
public Apollo.Env getEnv() { public Env getEnv() {
return Apollo.Env.valueOf(env); return Env.valueOf(env);
} }
public void setEnv(String env) { public void setEnv(String env) {
......
package com.ctrip.apollo.portal.entity.form; package com.ctrip.apollo.portal.entity.form;
import com.ctrip.apollo.Apollo; import com.ctrip.apollo.core.enums.Env;
import com.ctrip.apollo.core.utils.StringUtils; import com.ctrip.apollo.core.utils.StringUtils;
public class NamespaceTextModel implements FormModel{ public class NamespaceTextModel implements FormModel{
...@@ -26,8 +26,8 @@ public class NamespaceTextModel implements FormModel{ ...@@ -26,8 +26,8 @@ public class NamespaceTextModel implements FormModel{
this.appId = appId; this.appId = appId;
} }
public Apollo.Env getEnv() { public Env getEnv() {
return Apollo.Env.valueOf(env); return Env.valueOf(env);
} }
public void setEnv(String env) { public void setEnv(String env) {
......
...@@ -8,7 +8,7 @@ import org.slf4j.LoggerFactory; ...@@ -8,7 +8,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.ctrip.apollo.Apollo.Env; import com.ctrip.apollo.core.enums.Env;
import com.ctrip.apollo.core.dto.AppDTO; import com.ctrip.apollo.core.dto.AppDTO;
import com.ctrip.apollo.portal.PortalSettings; import com.ctrip.apollo.portal.PortalSettings;
import com.ctrip.apollo.portal.api.AdminServiceAPI; import com.ctrip.apollo.portal.api.AdminServiceAPI;
......
package com.ctrip.apollo.portal.service; package com.ctrip.apollo.portal.service;
import com.ctrip.apollo.Apollo; import com.ctrip.apollo.core.enums.Env;
import com.ctrip.apollo.core.dto.ClusterDTO; import com.ctrip.apollo.core.dto.ClusterDTO;
import com.ctrip.apollo.portal.api.AdminServiceAPI; import com.ctrip.apollo.portal.api.AdminServiceAPI;
...@@ -15,7 +15,7 @@ public class ClusterService { ...@@ -15,7 +15,7 @@ public class ClusterService {
@Autowired @Autowired
private AdminServiceAPI.ClusterAPI clusterAPI; private AdminServiceAPI.ClusterAPI clusterAPI;
public List<ClusterDTO> findClusters(Apollo.Env env, String appId){ public List<ClusterDTO> findClusters(Env env, String appId){
return clusterAPI.findClustersByApp(appId, env); return clusterAPI.findClustersByApp(appId, env);
} }
......
...@@ -6,7 +6,7 @@ import org.slf4j.LoggerFactory; ...@@ -6,7 +6,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.ctrip.apollo.Apollo; import com.ctrip.apollo.core.enums.Env;
import com.ctrip.apollo.core.dto.ItemChangeSets; import com.ctrip.apollo.core.dto.ItemChangeSets;
import com.ctrip.apollo.core.dto.ItemDTO; import com.ctrip.apollo.core.dto.ItemDTO;
import com.ctrip.apollo.core.dto.NamespaceDTO; import com.ctrip.apollo.core.dto.NamespaceDTO;
...@@ -52,7 +52,7 @@ public class ConfigService { ...@@ -52,7 +52,7 @@ public class ConfigService {
* @param clusterName * @param clusterName
* @return * @return
*/ */
public List<NamespaceVO> findNampspaces(String appId, Apollo.Env env, String clusterName) { public List<NamespaceVO> findNampspaces(String appId, Env env, String clusterName) {
List<NamespaceDTO> namespaces = groupAPI.findGroupsByAppAndCluster(appId, env, clusterName); List<NamespaceDTO> namespaces = groupAPI.findGroupsByAppAndCluster(appId, env, clusterName);
if (namespaces == null || namespaces.size() == 0) { if (namespaces == null || namespaces.size() == 0) {
...@@ -76,7 +76,7 @@ public class ConfigService { ...@@ -76,7 +76,7 @@ public class ConfigService {
return namespaceVOs; return namespaceVOs;
} }
private NamespaceVO parseNamespace(String appId, Apollo.Env env, String clusterName, NamespaceDTO namespace) { private NamespaceVO parseNamespace(String appId, Env env, String clusterName, NamespaceDTO namespace) {
NamespaceVO namespaceVO = new NamespaceVO(); NamespaceVO namespaceVO = new NamespaceVO();
namespaceVO.setNamespace(namespace); namespaceVO.setNamespace(namespace);
...@@ -137,7 +137,7 @@ public class ConfigService { ...@@ -137,7 +137,7 @@ public class ConfigService {
*/ */
public void updateConfigItemByText(NamespaceTextModel model) { public void updateConfigItemByText(NamespaceTextModel model) {
String appId = model.getAppId(); String appId = model.getAppId();
Apollo.Env env = model.getEnv(); Env env = model.getEnv();
String clusterName = model.getClusterName(); String clusterName = model.getClusterName();
String namespaceName = model.getNamespaceName(); String namespaceName = model.getNamespaceName();
long namespaceId = model.getNamespaceId(); long namespaceId = model.getNamespaceId();
......
...@@ -9,7 +9,7 @@ import org.slf4j.LoggerFactory; ...@@ -9,7 +9,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import com.ctrip.apollo.Apollo.Env; import com.ctrip.apollo.core.enums.Env;
import com.ctrip.apollo.core.MetaDomainConsts; import com.ctrip.apollo.core.MetaDomainConsts;
import com.ctrip.apollo.core.dto.ServiceDTO; import com.ctrip.apollo.core.dto.ServiceDTO;
import com.ctrip.apollo.core.exception.ServiceException; import com.ctrip.apollo.core.exception.ServiceException;
......
...@@ -81,6 +81,7 @@ ...@@ -81,6 +81,7 @@
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version> <java.version>1.8</java.version>
<jetty.version>9.3.8.v20160314</jetty.version>
<github.global.server>github</github.global.server> <github.global.server>github</github.global.server>
<github.global.oauth2Token>${env.GITHUB_OAUTH_TOKEN}</github.global.oauth2Token> <github.global.oauth2Token>${env.GITHUB_OAUTH_TOKEN}</github.global.oauth2Token>
</properties> </properties>
...@@ -135,6 +136,26 @@ ...@@ -135,6 +136,26 @@
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
<version>19.0</version> <version>19.0</version>
</dependency> </dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-io</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${jetty.version}</version>
</dependency>
<!--for test --> <!--for test -->
<dependency> <dependency>
<groupId>com.h2database</groupId> <groupId>com.h2database</groupId>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment