Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
apollo
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
openSource
apollo
Commits
5bb2aaf1
Commit
5bb2aaf1
authored
Apr 12, 2016
by
Yiming Liu
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #79 from nobodyiam/client-refresh-merge
Add client side auto refresh capability
parents
b1c4b7d8
df474afd
Show whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
679 additions
and
132 deletions
+679
-132
ReleaseRepository.java
...va/com/ctrip/apollo/biz/repository/ReleaseRepository.java
+1
-2
ConfigService.java
...main/java/com/ctrip/apollo/biz/service/ConfigService.java
+1
-1
Config.java
apollo-client/src/main/java/com/ctrip/apollo/Config.java
+2
-0
ConfigChangeListener.java
.../src/main/java/com/ctrip/apollo/ConfigChangeListener.java
+10
-0
AbstractConfig.java
.../main/java/com/ctrip/apollo/internals/AbstractConfig.java
+84
-0
AbstractConfigRepository.java
.../com/ctrip/apollo/internals/AbstractConfigRepository.java
+39
-0
ConfigRepository.java
...ain/java/com/ctrip/apollo/internals/ConfigRepository.java
+13
-1
DefaultConfig.java
...c/main/java/com/ctrip/apollo/internals/DefaultConfig.java
+74
-5
DefaultConfigManager.java
...java/com/ctrip/apollo/internals/DefaultConfigManager.java
+1
-1
LocalFileConfigRepository.java
...com/ctrip/apollo/internals/LocalFileConfigRepository.java
+41
-15
RemoteConfigRepository.java
...va/com/ctrip/apollo/internals/RemoteConfigRepository.java
+50
-15
RepositoryChangeListener.java
.../com/ctrip/apollo/internals/RepositoryChangeListener.java
+10
-0
SimpleConfig.java
...rc/main/java/com/ctrip/apollo/internals/SimpleConfig.java
+35
-7
ConfigChange.java
...nt/src/main/java/com/ctrip/apollo/model/ConfigChange.java
+27
-18
ConfigChangeEvent.java
...c/main/java/com/ctrip/apollo/model/ConfigChangeEvent.java
+38
-0
ConfigRefreshResult.java
...main/java/com/ctrip/apollo/model/ConfigRefreshResult.java
+0
-41
DefaultConfigFactory.java
.../main/java/com/ctrip/apollo/spi/DefaultConfigFactory.java
+1
-2
HttpUtil.java
...nt/src/main/java/com/ctrip/apollo/util/http/HttpUtil.java
+10
-9
ConfigServiceTest.java
...ent/src/test/java/com/ctrip/apollo/ConfigServiceTest.java
+5
-0
DefaultConfigManagerTest.java
.../com/ctrip/apollo/internals/DefaultConfigManagerTest.java
+7
-0
DefaultConfigTest.java
...st/java/com/ctrip/apollo/internals/DefaultConfigTest.java
+86
-3
LocalFileConfigRepositoryTest.java
...ctrip/apollo/internals/LocalFileConfigRepositoryTest.java
+34
-5
RemoteConfigRepositoryTest.java
...om/ctrip/apollo/internals/RemoteConfigRepositoryTest.java
+27
-2
SimpleConfigTest.java
...est/java/com/ctrip/apollo/internals/SimpleConfigTest.java
+62
-2
DefaultConfigFactoryTest.java
...t/java/com/ctrip/apollo/spi/DefaultConfigFactoryTest.java
+1
-1
ApolloConfigDemo.java
apollo-demo/src/main/java/ApolloConfigDemo.java
+20
-2
No files found.
apollo-biz/src/main/java/com/ctrip/apollo/biz/repository/ReleaseRepository.java
View file @
5bb2aaf1
...
...
@@ -13,8 +13,7 @@ import com.ctrip.apollo.biz.entity.Release;
*/
public
interface
ReleaseRepository
extends
PagingAndSortingRepository
<
Release
,
Long
>
{
@Query
(
"SELECT r FROM Release r WHERE r.appId = :appId AND r.clusterName = :clusterName AND r.namespaceName = :namespaceName order by r.id desc"
)
Release
findLatest
(
@Param
(
"appId"
)
String
appId
,
@Param
(
"clusterName"
)
String
clusterName
,
Release
findFirstByAppIdAndClusterNameAndNamespaceNameOrderByIdDesc
(
@Param
(
"appId"
)
String
appId
,
@Param
(
"clusterName"
)
String
clusterName
,
@Param
(
"namespaceName"
)
String
namespaceName
);
List
<
Release
>
findByAppIdAndClusterNameAndNamespaceName
(
String
appId
,
String
clusterName
,
...
...
apollo-biz/src/main/java/com/ctrip/apollo/biz/service/ConfigService.java
View file @
5bb2aaf1
...
...
@@ -30,7 +30,7 @@ public class ConfigService {
private
Type
configurationTypeReference
=
new
TypeToken
<
Map
<
String
,
String
>>(){}.
getType
();
public
Release
findRelease
(
String
appId
,
String
clusterName
,
String
namespaceName
)
{
Release
release
=
releaseRepository
.
find
Latest
(
appId
,
clusterName
,
namespaceName
);
Release
release
=
releaseRepository
.
find
FirstByAppIdAndClusterNameAndNamespaceNameOrderByIdDesc
(
appId
,
clusterName
,
namespaceName
);
return
release
;
}
...
...
apollo-client/src/main/java/com/ctrip/apollo/Config.java
View file @
5bb2aaf1
...
...
@@ -12,4 +12,6 @@ public interface Config {
* @return the property value
*/
public
String
getProperty
(
String
key
,
String
defaultValue
);
public
void
addChangeListener
(
ConfigChangeListener
listener
);
}
apollo-client/src/main/java/com/ctrip/apollo/ConfigChangeListener.java
0 → 100644
View file @
5bb2aaf1
package
com
.
ctrip
.
apollo
;
import
com.ctrip.apollo.model.ConfigChangeEvent
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
interface
ConfigChangeListener
{
public
void
onChange
(
ConfigChangeEvent
changeEvent
);
}
apollo-client/src/main/java/com/ctrip/apollo/internals/AbstractConfig.java
0 → 100644
View file @
5bb2aaf1
package
com
.
ctrip
.
apollo
.
internals
;
import
com.google.common.base.Objects
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Sets
;
import
com.ctrip.apollo.Config
;
import
com.ctrip.apollo.ConfigChangeListener
;
import
com.ctrip.apollo.enums.PropertyChangeType
;
import
com.ctrip.apollo.model.ConfigChange
;
import
com.ctrip.apollo.model.ConfigChangeEvent
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
java.util.List
;
import
java.util.Properties
;
import
java.util.Set
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
abstract
class
AbstractConfig
implements
Config
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
AbstractConfig
.
class
);
private
List
<
ConfigChangeListener
>
m_listeners
=
Lists
.
newCopyOnWriteArrayList
();
@Override
public
void
addChangeListener
(
ConfigChangeListener
listener
)
{
if
(!
m_listeners
.
contains
(
listener
))
{
m_listeners
.
add
(
listener
);
}
}
protected
void
fireConfigChange
(
ConfigChangeEvent
changeEvent
)
{
for
(
ConfigChangeListener
listener
:
m_listeners
)
{
try
{
listener
.
onChange
(
changeEvent
);
}
catch
(
Throwable
t
)
{
logger
.
error
(
"Failed to invoke config change listener {}"
,
listener
.
getClass
(),
t
);
}
}
}
List
<
ConfigChange
>
calcPropertyChanges
(
Properties
previous
,
Properties
current
)
{
if
(
previous
==
null
)
{
previous
=
new
Properties
();
}
if
(
current
==
null
)
{
current
=
new
Properties
();
}
Set
<
String
>
previousKeys
=
previous
.
stringPropertyNames
();
Set
<
String
>
currentKeys
=
current
.
stringPropertyNames
();
Set
<
String
>
commonKeys
=
Sets
.
intersection
(
previousKeys
,
currentKeys
);
Set
<
String
>
newKeys
=
Sets
.
difference
(
currentKeys
,
commonKeys
);
Set
<
String
>
removedKeys
=
Sets
.
difference
(
previousKeys
,
commonKeys
);
List
<
ConfigChange
>
changes
=
Lists
.
newArrayList
();
for
(
String
newKey
:
newKeys
)
{
changes
.
add
(
new
ConfigChange
(
newKey
,
null
,
current
.
getProperty
(
newKey
),
PropertyChangeType
.
NEW
));
}
for
(
String
removedKey
:
removedKeys
)
{
changes
.
add
(
new
ConfigChange
(
removedKey
,
previous
.
getProperty
(
removedKey
),
null
,
PropertyChangeType
.
DELETED
));
}
for
(
String
commonKey
:
commonKeys
)
{
String
previousValue
=
previous
.
getProperty
(
commonKey
);
String
currentValue
=
current
.
getProperty
(
commonKey
);
if
(
Objects
.
equal
(
previousValue
,
currentValue
))
{
continue
;
}
changes
.
add
(
new
ConfigChange
(
commonKey
,
previousValue
,
currentValue
,
PropertyChangeType
.
MODIFIED
));
}
return
changes
;
}
}
apollo-client/src/main/java/com/ctrip/apollo/internals/AbstractConfigRepository.java
0 → 100644
View file @
5bb2aaf1
package
com
.
ctrip
.
apollo
.
internals
;
import
com.google.common.collect.Lists
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
java.util.List
;
import
java.util.Properties
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
abstract
class
AbstractConfigRepository
implements
ConfigRepository
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
AbstractConfigRepository
.
class
);
private
List
<
RepositoryChangeListener
>
m_listeners
=
Lists
.
newCopyOnWriteArrayList
();
@Override
public
void
addChangeListener
(
RepositoryChangeListener
listener
)
{
if
(!
m_listeners
.
contains
(
listener
))
{
m_listeners
.
add
(
listener
);
}
}
@Override
public
void
removeChangeListener
(
RepositoryChangeListener
listener
)
{
m_listeners
.
remove
(
listener
);
}
protected
void
fireRepositoryChange
(
String
namespace
,
Properties
newProperties
)
{
for
(
RepositoryChangeListener
listener
:
m_listeners
)
{
try
{
listener
.
onRepositoryChange
(
namespace
,
newProperties
);
}
catch
(
Throwable
t
)
{
logger
.
error
(
"Failed to invoke repository change listener {}"
,
listener
.
getClass
(),
t
);
}
}
}
}
apollo-client/src/main/java/com/ctrip/apollo/internals/ConfigRepository.java
View file @
5bb2aaf1
...
...
@@ -6,7 +6,19 @@ import java.util.Properties;
* @author Jason Song(song_s@ctrip.com)
*/
public
interface
ConfigRepository
{
public
Properties
loadConfig
();
/**
* Get the config from this repository
* @return
*/
public
Properties
getConfig
();
/**
* Set the fallback repo for this repository
* @param fallbackConfigRepository
*/
public
void
setFallback
(
ConfigRepository
fallbackConfigRepository
);
public
void
addChangeListener
(
RepositoryChangeListener
listener
);
public
void
removeChangeListener
(
RepositoryChangeListener
listener
);
}
apollo-client/src/main/java/com/ctrip/apollo/internals/DefaultConfig.java
View file @
5bb2aaf1
package
com
.
ctrip
.
apollo
.
internals
;
import
com.ctrip.apollo.Config
;
import
com.google.common.collect.ImmutableMap
;
import
com.ctrip.apollo.core.utils.ClassLoaderUtil
;
import
com.ctrip.apollo.enums.PropertyChangeType
;
import
com.ctrip.apollo.model.ConfigChange
;
import
com.ctrip.apollo.model.ConfigChangeEvent
;
import
com.dianping.cat.Cat
;
import
org.slf4j.Logger
;
...
...
@@ -9,12 +13,15 @@ import org.slf4j.LoggerFactory;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Objects
;
import
java.util.Properties
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
DefaultConfig
implements
Config
{
public
class
DefaultConfig
extends
AbstractConfig
implements
RepositoryChangeListener
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
DefaultConfig
.
class
);
private
final
String
m_namespace
;
private
Properties
m_resourceProperties
;
...
...
@@ -30,7 +37,8 @@ public class DefaultConfig implements Config {
private
void
initialize
()
{
try
{
m_configProperties
=
m_configRepository
.
loadConfig
();
m_configProperties
=
m_configRepository
.
getConfig
();
m_configRepository
.
addChangeListener
(
this
);
}
catch
(
Throwable
ex
)
{
String
message
=
String
.
format
(
"Init Apollo Local Config failed - namespace: %s"
,
m_namespace
);
...
...
@@ -68,6 +76,69 @@ public class DefaultConfig implements Config {
return
value
==
null
?
defaultValue
:
value
;
}
@Override
public
synchronized
void
onRepositoryChange
(
String
namespace
,
Properties
newProperties
)
{
if
(
newProperties
.
equals
(
m_configProperties
))
{
return
;
}
Properties
newConfigProperties
=
new
Properties
();
newConfigProperties
.
putAll
(
newProperties
);
Map
<
String
,
ConfigChange
>
actualChanges
=
updateAndCalcConfigChanges
(
newConfigProperties
);
this
.
fireConfigChange
(
new
ConfigChangeEvent
(
m_namespace
,
actualChanges
));
}
private
Map
<
String
,
ConfigChange
>
updateAndCalcConfigChanges
(
Properties
newConfigProperties
)
{
List
<
ConfigChange
>
configChanges
=
calcPropertyChanges
(
m_configProperties
,
newConfigProperties
);
// List<ConfigChange> actualChanges = Lists.newArrayListWithCapacity(configChanges.size());
ImmutableMap
.
Builder
<
String
,
ConfigChange
>
actualChanges
=
new
ImmutableMap
.
Builder
<>();
/** === Double check since DefaultConfig has multiple config sources ==== **/
//1. use getProperty to update configChanges's old value
for
(
ConfigChange
change
:
configChanges
)
{
change
.
setOldValue
(
this
.
getProperty
(
change
.
getPropertyName
(),
change
.
getOldValue
()));
}
//2. update m_configProperties
m_configProperties
=
newConfigProperties
;
//3. use getProperty to update configChange's new value and calc the final changes
for
(
ConfigChange
change
:
configChanges
)
{
change
.
setNewValue
(
this
.
getProperty
(
change
.
getPropertyName
(),
change
.
getNewValue
()));
switch
(
change
.
getChangeType
())
{
case
NEW:
if
(
Objects
.
equals
(
change
.
getOldValue
(),
change
.
getNewValue
()))
{
break
;
}
if
(!
Objects
.
isNull
(
change
.
getOldValue
()))
{
change
.
setChangeType
(
PropertyChangeType
.
MODIFIED
);
}
actualChanges
.
put
(
change
.
getPropertyName
(),
change
);
break
;
case
MODIFIED:
if
(!
Objects
.
equals
(
change
.
getOldValue
(),
change
.
getNewValue
()))
{
actualChanges
.
put
(
change
.
getPropertyName
(),
change
);
}
break
;
case
DELETED:
if
(
Objects
.
equals
(
change
.
getOldValue
(),
change
.
getNewValue
()))
{
break
;
}
if
(!
Objects
.
isNull
(
change
.
getNewValue
()))
{
change
.
setChangeType
(
PropertyChangeType
.
MODIFIED
);
}
actualChanges
.
put
(
change
.
getPropertyName
(),
change
);
break
;
}
}
return
actualChanges
.
build
();
}
private
Properties
loadFromResource
(
String
namespace
)
{
String
name
=
String
.
format
(
"META-INF/config/%s.properties"
,
namespace
);
InputStream
in
=
ClassLoaderUtil
.
getLoader
().
getResourceAsStream
(
name
);
...
...
@@ -92,6 +163,4 @@ public class DefaultConfig implements Config {
return
properties
;
}
}
apollo-client/src/main/java/com/ctrip/apollo/internals/DefaultConfigManager.java
View file @
5bb2aaf1
...
...
@@ -19,7 +19,7 @@ public class DefaultConfigManager implements ConfigManager {
@Inject
private
ConfigFactoryManager
m_factoryManager
;
private
Map
<
String
,
Config
>
m_configs
=
Maps
.
new
Hash
Map
();
private
Map
<
String
,
Config
>
m_configs
=
Maps
.
new
Concurrent
Map
();
@Override
public
Config
getConfig
(
String
namespace
)
{
...
...
apollo-client/src/main/java/com/ctrip/apollo/internals/LocalFileConfigRepository.java
View file @
5bb2aaf1
...
...
@@ -22,14 +22,15 @@ import java.util.Properties;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
LocalFileConfigRepository
implements
ConfigRepository
{
public
class
LocalFileConfigRepository
extends
AbstractConfigRepository
implements
RepositoryChangeListener
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
LocalFileConfigRepository
.
class
);
private
PlexusContainer
m_container
;
private
final
PlexusContainer
m_container
;
private
final
String
m_namespace
;
private
final
File
m_baseDir
;
private
final
ConfigUtil
m_configUtil
;
private
Properties
m_fileProperties
;
private
ConfigRepository
m_fallback
;
private
volatile
Properties
m_fileProperties
;
private
volatile
ConfigRepository
m_fallback
;
public
LocalFileConfigRepository
(
File
baseDir
,
String
namespace
)
{
m_baseDir
=
baseDir
;
...
...
@@ -43,7 +44,7 @@ public class LocalFileConfigRepository implements ConfigRepository {
}
@Override
public
Properties
load
Config
()
{
public
Properties
get
Config
()
{
if
(
m_fileProperties
==
null
)
{
initLocalConfig
();
}
...
...
@@ -54,26 +55,51 @@ public class LocalFileConfigRepository implements ConfigRepository {
@Override
public
void
setFallback
(
ConfigRepository
fallbackConfigRepository
)
{
//clear previous listener
if
(
m_fallback
!=
null
)
{
m_fallback
.
removeChangeListener
(
this
);
}
m_fallback
=
fallbackConfigRepository
;
fallbackConfigRepository
.
addChangeListener
(
this
);
}
@Override
public
synchronized
void
onRepositoryChange
(
String
namespace
,
Properties
newProperties
)
{
if
(
newProperties
.
equals
(
m_fileProperties
))
{
return
;
}
Properties
newFileProperties
=
new
Properties
();
newFileProperties
.
putAll
(
newProperties
);
this
.
m_fileProperties
=
newFileProperties
;
persistLocalCacheFile
(
m_baseDir
,
m_namespace
);
this
.
fireRepositoryChange
(
namespace
,
newProperties
);
}
void
initLocalConfig
()
{
if
(
m_fallback
!=
null
)
{
try
{
m_fileProperties
=
m_fallback
.
loadConfig
();
//TODO register change listener
persistLocalCacheFile
(
m_baseDir
,
m_namespace
);
return
;
m_fileProperties
=
this
.
loadFromLocalCacheFile
(
m_baseDir
,
m_namespace
);
}
catch
(
Throwable
ex
)
{
logger
.
error
(
"Load config from fallback loader failed"
,
ex
);
Cat
.
logError
(
ex
);
logger
.
error
(
"Load config from local config cache file failed"
,
ex
);
}
//TODO check whether properties is expired or should we return after it's synced with fallback?
if
(
m_fileProperties
!=
null
)
{
return
;
}
if
(
m_fallback
==
null
)
{
throw
new
RuntimeException
(
"Load config from local config cache failed and there is no fallback repository!"
);
}
try
{
m_fileProperties
=
this
.
loadFromLocalCacheFile
(
m_baseDir
,
m_namespace
);
}
catch
(
IOException
ex
)
{
throw
new
RuntimeException
(
"Loading config from local cache file failed"
,
ex
);
m_fileProperties
=
m_fallback
.
getConfig
();
persistLocalCacheFile
(
m_baseDir
,
m_namespace
);
}
catch
(
Throwable
ex
)
{
String
message
=
String
.
format
(
"Load config from fallback repository %s failed"
,
m_fallback
.
getClass
());
logger
.
error
(
message
,
ex
);
throw
new
RuntimeException
(
message
,
ex
);
}
}
...
...
apollo-client/src/main/java/com/ctrip/apollo/internals/RemoteConfigRepository.java
View file @
5bb2aaf1
...
...
@@ -5,6 +5,7 @@ import com.google.common.collect.Lists;
import
com.ctrip.apollo.core.dto.ApolloConfig
;
import
com.ctrip.apollo.core.dto.ServiceDTO
;
import
com.ctrip.apollo.core.utils.ApolloThreadFactory
;
import
com.ctrip.apollo.util.ConfigUtil
;
import
com.ctrip.apollo.util.http.HttpRequest
;
import
com.ctrip.apollo.util.http.HttpResponse
;
...
...
@@ -18,19 +19,22 @@ import org.unidal.lookup.ContainerLoader;
import
java.util.List
;
import
java.util.Properties
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.ScheduledExecutorService
;
import
java.util.concurrent.atomic.AtomicReference
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
RemoteConfigRepository
implements
ConfigRepository
{
public
class
RemoteConfigRepository
extends
AbstractConfigRepository
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
RemoteConfigRepository
.
class
);
private
PlexusContainer
m_container
;
private
ConfigServiceLocator
m_serviceLocator
;
private
HttpUtil
m_httpUtil
;
private
ConfigUtil
m_configUtil
;
private
AtomicReference
<
ApolloConfig
>
m_configCache
;
private
String
m_namespace
;
private
final
ConfigServiceLocator
m_serviceLocator
;
private
final
HttpUtil
m_httpUtil
;
private
final
ConfigUtil
m_configUtil
;
private
volatile
AtomicReference
<
ApolloConfig
>
m_configCache
;
private
final
String
m_namespace
;
private
final
ScheduledExecutorService
m_executorService
;
public
RemoteConfigRepository
(
String
namespace
)
{
m_namespace
=
namespace
;
...
...
@@ -43,12 +47,15 @@ public class RemoteConfigRepository implements ConfigRepository {
}
catch
(
ComponentLookupException
e
)
{
throw
new
IllegalStateException
(
"Unable to load component!"
,
e
);
}
this
.
m_executorService
=
Executors
.
newScheduledThreadPool
(
1
,
ApolloThreadFactory
.
create
(
"RemoteConfigRepository"
,
true
));
this
.
schedulePeriodicRefresh
();
}
@Override
public
Properties
load
Config
()
{
public
Properties
get
Config
()
{
if
(
m_configCache
.
get
()
==
null
)
{
init
RemoteConfig
();
this
.
load
RemoteConfig
();
}
return
transformApolloConfigToProperties
(
m_configCache
.
get
());
}
...
...
@@ -58,8 +65,37 @@ public class RemoteConfigRepository implements ConfigRepository {
//remote config doesn't need fallback
}
private
void
initRemoteConfig
()
{
m_configCache
.
set
(
this
.
loadApolloConfig
());
private
void
schedulePeriodicRefresh
()
{
logger
.
info
(
"Schedule periodic refresh with interval: {} {}"
,
m_configUtil
.
getRefreshInterval
(),
m_configUtil
.
getRefreshTimeUnit
());
this
.
m_executorService
.
scheduleAtFixedRate
(
new
Runnable
()
{
@Override
public
void
run
()
{
try
{
loadRemoteConfig
();
}
catch
(
Throwable
ex
)
{
logger
.
error
(
"Refreshing config failed"
,
ex
);
}
}
},
m_configUtil
.
getRefreshInterval
(),
m_configUtil
.
getRefreshInterval
(),
m_configUtil
.
getRefreshTimeUnit
());
}
synchronized
void
loadRemoteConfig
()
{
ApolloConfig
previous
=
m_configCache
.
get
();
ApolloConfig
current
=
loadApolloConfig
();
//HTTP 304, nothing changed
if
(
previous
==
current
)
{
return
;
}
logger
.
info
(
"Remote Config changes!"
);
m_configCache
.
set
(
current
);
this
.
fireRepositoryChange
(
m_namespace
,
this
.
getConfig
());
}
private
Properties
transformApolloConfigToProperties
(
ApolloConfig
apolloConfig
)
{
...
...
@@ -72,16 +108,15 @@ public class RemoteConfigRepository implements ConfigRepository {
private
ApolloConfig
loadApolloConfig
()
{
String
appId
=
m_configUtil
.
getAppId
();
String
cluster
=
m_configUtil
.
getCluster
();
String
ur
i
=
getConfigServiceUrl
(
);
String
ur
l
=
assembleUrl
(
getConfigServiceUrl
(),
appId
,
cluster
,
m_namespace
,
m_configCache
.
get
()
);
logger
.
info
(
"Loading config from {}, appId={}, cluster={}, namespace={}"
,
uri
,
appId
,
cluster
,
m_namespace
);
HttpRequest
request
=
new
HttpRequest
(
assembleUrl
(
uri
,
appId
,
cluster
,
m_namespace
,
m_configCache
.
get
()));
logger
.
info
(
"Loading config from {}"
,
url
);
HttpRequest
request
=
new
HttpRequest
(
url
);
try
{
HttpResponse
<
ApolloConfig
>
response
=
m_httpUtil
.
doGet
(
request
,
ApolloConfig
.
class
);
if
(
response
.
getStatusCode
()
==
304
)
{
logger
.
info
(
"Config server responds with 304 HTTP status code."
);
return
m_configCache
.
get
();
}
...
...
apollo-client/src/main/java/com/ctrip/apollo/internals/RepositoryChangeListener.java
0 → 100644
View file @
5bb2aaf1
package
com
.
ctrip
.
apollo
.
internals
;
import
java.util.Properties
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
interface
RepositoryChangeListener
{
public
void
onRepositoryChange
(
String
namespace
,
Properties
newProperties
);
}
apollo-client/src/main/java/com/ctrip/apollo/internals/SimpleConfig.java
View file @
5bb2aaf1
package
com
.
ctrip
.
apollo
.
internals
;
import
com.ctrip.apollo.Config
;
import
com.google.common.base.Function
;
import
com.google.common.collect.Maps
;
import
com.ctrip.apollo.model.ConfigChange
;
import
com.ctrip.apollo.model.ConfigChangeEvent
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Properties
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
SimpleConfig
implements
Config
{
public
class
SimpleConfig
extends
AbstractConfig
implements
RepositoryChangeListener
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
SimpleConfig
.
class
);
private
String
m_namespace
;
private
ConfigRepository
m_configRepository
;
private
Properties
m_configProperties
;
private
final
String
m_namespace
;
private
final
ConfigRepository
m_configRepository
;
private
volatile
Properties
m_configProperties
;
public
SimpleConfig
(
String
namespace
,
ConfigRepository
configRepository
)
{
m_namespace
=
namespace
;
...
...
@@ -24,9 +30,10 @@ public class SimpleConfig implements Config {
private
void
initialize
()
{
try
{
m_configProperties
=
m_configRepository
.
loadConfig
();
m_configProperties
=
m_configRepository
.
getConfig
();
m_configRepository
.
addChangeListener
(
this
);
}
catch
(
Throwable
ex
)
{
String
message
=
String
.
format
(
"Init Apollo
Remot
e Config failed - namespace: %s"
,
String
message
=
String
.
format
(
"Init Apollo
Simpl
e Config failed - namespace: %s"
,
m_namespace
);
logger
.
error
(
message
,
ex
);
throw
new
RuntimeException
(
message
,
ex
);
...
...
@@ -38,4 +45,25 @@ public class SimpleConfig implements Config {
return
this
.
m_configProperties
.
getProperty
(
key
,
defaultValue
);
}
@Override
public
synchronized
void
onRepositoryChange
(
String
namespace
,
Properties
newProperties
)
{
if
(
newProperties
.
equals
(
m_configProperties
))
{
return
;
}
Properties
newConfigProperties
=
new
Properties
();
newConfigProperties
.
putAll
(
newProperties
);
List
<
ConfigChange
>
changes
=
calcPropertyChanges
(
m_configProperties
,
newConfigProperties
);
Map
<
String
,
ConfigChange
>
changeMap
=
Maps
.
uniqueIndex
(
changes
,
new
Function
<
ConfigChange
,
String
>()
{
@Override
public
String
apply
(
ConfigChange
input
)
{
return
input
.
getPropertyName
();
}
});
m_configProperties
=
newConfigProperties
;
this
.
fireConfigChange
(
new
ConfigChangeEvent
(
m_namespace
,
changeMap
));
}
}
apollo-client/src/main/java/com/ctrip/apollo/model/
Property
Change.java
→
apollo-client/src/main/java/com/ctrip/apollo/model/
Config
Change.java
View file @
5bb2aaf1
package
com
.
ctrip
.
apollo
.
model
;
import
com.google.common.base.MoreObjects
;
import
com.ctrip.apollo.enums.PropertyChangeType
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
Property
Change
{
private
String
propertyName
;
private
Object
oldValue
;
private
Object
newValue
;
public
class
Config
Change
{
private
final
String
propertyName
;
private
String
oldValue
;
private
String
newValue
;
private
PropertyChangeType
changeType
;
public
PropertyChange
(
String
propertyName
,
Object
oldValue
,
Object
newValue
,
public
ConfigChange
(
String
propertyName
,
String
oldValue
,
String
newValue
,
PropertyChangeType
changeType
)
{
this
.
propertyName
=
propertyName
;
this
.
oldValue
=
oldValue
;
...
...
@@ -24,31 +26,38 @@ public class PropertyChange {
return
propertyName
;
}
public
void
setPropertyName
(
String
propertyName
)
{
this
.
propertyName
=
propertyName
;
}
public
Object
getOldValue
()
{
public
String
getOldValue
()
{
return
oldValue
;
}
public
void
setOldValue
(
Object
oldValue
)
{
this
.
oldValue
=
old
Value
;
public
String
getNewValue
(
)
{
return
new
Value
;
}
public
Object
getNewValu
e
()
{
return
newValu
e
;
public
PropertyChangeType
getChangeTyp
e
()
{
return
changeTyp
e
;
}
public
void
set
NewValue
(
Object
new
Value
)
{
this
.
newValue
=
new
Value
;
public
void
set
OldValue
(
String
old
Value
)
{
this
.
oldValue
=
old
Value
;
}
public
PropertyChangeType
getChangeType
(
)
{
return
changeTyp
e
;
public
void
setNewValue
(
String
newValue
)
{
this
.
newValue
=
newValu
e
;
}
public
void
setChangeType
(
PropertyChangeType
changeType
)
{
this
.
changeType
=
changeType
;
}
@Override
public
String
toString
()
{
return
MoreObjects
.
toStringHelper
(
this
)
.
omitNullValues
()
.
add
(
"propertyName"
,
propertyName
)
.
add
(
"oldValue"
,
oldValue
)
.
add
(
"newValue"
,
newValue
)
.
add
(
"changeType"
,
changeType
)
.
toString
();
}
}
apollo-client/src/main/java/com/ctrip/apollo/model/ConfigChangeEvent.java
0 → 100644
View file @
5bb2aaf1
package
com
.
ctrip
.
apollo
.
model
;
import
java.util.Map
;
import
java.util.Set
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
ConfigChangeEvent
{
private
final
String
m_namespace
;
private
final
Map
<
String
,
ConfigChange
>
changes
;
public
ConfigChangeEvent
(
String
m_namespace
,
Map
<
String
,
ConfigChange
>
changes
)
{
this
.
m_namespace
=
m_namespace
;
this
.
changes
=
changes
;
}
public
Set
<
String
>
changedKeys
()
{
return
changes
.
keySet
();
}
public
ConfigChange
getChange
(
String
key
)
{
return
changes
.
get
(
key
);
}
/**
* Please note that the returned Map is immutable
* @return changes
*/
public
Map
<
String
,
ConfigChange
>
getChanges
()
{
return
changes
;
}
public
String
getNamespace
()
{
return
m_namespace
;
}
}
apollo-client/src/main/java/com/ctrip/apollo/model/ConfigRefreshResult.java
deleted
100644 → 0
View file @
b1c4b7d8
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
();
}
}
apollo-client/src/main/java/com/ctrip/apollo/spi/DefaultConfigFactory.java
View file @
5bb2aaf1
...
...
@@ -33,8 +33,7 @@ public class DefaultConfigFactory implements ConfigFactory {
}
LocalFileConfigRepository
createLocalConfigRepository
(
String
namespace
)
{
LocalFileConfigRepository
localFileConfigLoader
=
LocalFileConfigRepository
localFileConfigLoader
=
new
LocalFileConfigRepository
(
m_baseDir
,
namespace
);
localFileConfigLoader
.
setFallback
(
createRemoteConfigRepository
(
namespace
));
return
localFileConfigLoader
;
...
...
apollo-client/src/main/java/com/ctrip/apollo/util/http/HttpUtil.java
View file @
5bb2aaf1
...
...
@@ -39,18 +39,19 @@ public class HttpUtil {
conn
.
setRequestMethod
(
"GET"
);
if
(
httpRequest
.
getConnectTimeout
()
<
0
)
{
conn
.
setConnectTimeout
(
m_configUtil
.
getConnectTimeout
());
}
else
{
conn
.
setConnectTimeout
(
httpRequest
.
getConnectTimeout
());
int
connectTimeout
=
httpRequest
.
getConnectTimeout
();
if
(
connectTimeout
<
0
)
{
connectTimeout
=
m_configUtil
.
getConnectTimeout
();
}
if
(
httpRequest
.
getReadTimeout
()
<
0
)
{
conn
.
setReadTimeout
(
m_configUtil
.
getReadTimeout
());
}
else
{
conn
.
setReadTimeout
(
httpRequest
.
getReadTimeout
());
int
readTimeout
=
httpRequest
.
getReadTimeout
();
if
(
readTimeout
<
0
)
{
readTimeout
=
m_configUtil
.
getReadTimeout
();
}
conn
.
setConnectTimeout
(
connectTimeout
);
conn
.
setReadTimeout
(
readTimeout
);
conn
.
connect
();
int
statusCode
=
conn
.
getResponseCode
();
...
...
@@ -66,7 +67,7 @@ public class HttpUtil {
}
throw
new
RuntimeException
(
String
.
format
(
"Get operation failed
, status code - %d"
,
statusCode
));
String
.
format
(
"Get operation failed
for %s, status code - %d"
,
httpRequest
.
getUrl
()
,
statusCode
));
}
catch
(
Throwable
ex
)
{
throw
new
RuntimeException
(
"Could not complete get operation"
,
ex
);
...
...
apollo-client/src/test/java/com/ctrip/apollo/ConfigServiceTest.java
View file @
5bb2aaf1
...
...
@@ -71,6 +71,11 @@ public class ConfigServiceTest extends ComponentTestCase {
return
m_namespace
+
":"
+
key
;
}
@Override
public
void
addChangeListener
(
ConfigChangeListener
listener
)
{
}
}
public
static
class
MockConfigFactory
implements
ConfigFactory
{
...
...
apollo-client/src/test/java/com/ctrip/apollo/internals/DefaultConfigManagerTest.java
View file @
5bb2aaf1
package
com
.
ctrip
.
apollo
.
internals
;
import
com.ctrip.apollo.Config
;
import
com.ctrip.apollo.ConfigChangeListener
;
import
com.ctrip.apollo.spi.ConfigFactory
;
import
com.ctrip.apollo.spi.ConfigFactoryManager
;
...
...
@@ -60,6 +61,12 @@ public class DefaultConfigManagerTest extends ComponentTestCase {
public
String
getProperty
(
String
key
,
String
defaultValue
)
{
return
namespace
+
":"
+
key
;
}
@Override
public
void
addChangeListener
(
ConfigChangeListener
listener
)
{
}
};
}
};
...
...
apollo-client/src/test/java/com/ctrip/apollo/internals/DefaultConfigTest.java
View file @
5bb2aaf1
package
com
.
ctrip
.
apollo
.
internals
;
import
com.google.common.base.Charsets
;
import
com.google.common.collect.ImmutableMap
;
import
com.google.common.io.Files
;
import
com.ctrip.apollo.ConfigChangeListener
;
import
com.ctrip.apollo.core.utils.ClassLoaderUtil
;
import
com.ctrip.apollo.enums.PropertyChangeType
;
import
com.ctrip.apollo.model.ConfigChange
;
import
com.ctrip.apollo.model.ConfigChangeEvent
;
import
org.junit.After
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.mockito.ArgumentCaptor
;
import
java.io.File
;
import
java.util.Properties
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
/**
...
...
@@ -69,7 +77,7 @@ public class DefaultConfigTest {
someProperties
=
new
Properties
();
someProperties
.
setProperty
(
someKey
,
someLocalFileValue
);
someProperties
.
setProperty
(
anotherKey
,
someLocalFileValue
);
when
(
configRepository
.
load
Config
()).
thenReturn
(
someProperties
);
when
(
configRepository
.
get
Config
()).
thenReturn
(
someProperties
);
//set up resource file
File
resourceFile
=
new
File
(
someResourceDir
,
someNamespace
+
".properties"
);
...
...
@@ -79,8 +87,7 @@ public class DefaultConfigTest {
Files
.
append
(
System
.
getProperty
(
"line.separator"
),
resourceFile
,
Charsets
.
UTF_8
);
Files
.
append
(
lastKey
+
"="
+
someResourceValue
,
resourceFile
,
Charsets
.
UTF_8
);
DefaultConfig
defaultConfig
=
DefaultConfig
defaultConfig
=
new
DefaultConfig
(
someNamespace
,
configRepository
);
String
someKeyValue
=
defaultConfig
.
getProperty
(
someKey
,
null
);
...
...
@@ -95,4 +102,80 @@ public class DefaultConfigTest {
assertEquals
(
someResourceValue
,
lastKeyValue
);
}
@Test
public
void
testOnRepositoryChange
()
throws
Exception
{
String
someKey
=
"someKey"
;
String
someSystemPropertyValue
=
"system-property-value"
;
String
anotherKey
=
"anotherKey"
;
String
someLocalFileValue
=
"local-file-value"
;
String
keyToBeDeleted
=
"keyToBeDeleted"
;
String
keyToBeDeletedValue
=
"keyToBeDeletedValue"
;
String
yetAnotherKey
=
"yetAnotherKey"
;
String
yetAnotherValue
=
"yetAnotherValue"
;
String
yetAnotherResourceValue
=
"yetAnotherResourceValue"
;
//set up system property
System
.
setProperty
(
someKey
,
someSystemPropertyValue
);
//set up config repo
someProperties
=
new
Properties
();
someProperties
.
putAll
(
ImmutableMap
.
of
(
someKey
,
someLocalFileValue
,
anotherKey
,
someLocalFileValue
,
keyToBeDeleted
,
keyToBeDeletedValue
,
yetAnotherKey
,
yetAnotherValue
));
when
(
configRepository
.
getConfig
()).
thenReturn
(
someProperties
);
//set up resource file
File
resourceFile
=
new
File
(
someResourceDir
,
someNamespace
+
".properties"
);
Files
.
append
(
yetAnotherKey
+
"="
+
yetAnotherResourceValue
,
resourceFile
,
Charsets
.
UTF_8
);
DefaultConfig
defaultConfig
=
new
DefaultConfig
(
someNamespace
,
configRepository
);
ConfigChangeListener
someListener
=
mock
(
ConfigChangeListener
.
class
);
defaultConfig
.
addChangeListener
(
someListener
);
Properties
newProperties
=
new
Properties
();
String
someKeyNewValue
=
"new-some-value"
;
String
anotherKeyNewValue
=
"another-new-value"
;
String
newKey
=
"newKey"
;
String
newValue
=
"newValue"
;
newProperties
.
putAll
(
ImmutableMap
.
of
(
someKey
,
someKeyNewValue
,
anotherKey
,
anotherKeyNewValue
,
newKey
,
newValue
));
final
ArgumentCaptor
<
ConfigChangeEvent
>
captor
=
ArgumentCaptor
.
forClass
(
ConfigChangeEvent
.
class
);
defaultConfig
.
onRepositoryChange
(
someNamespace
,
newProperties
);
verify
(
someListener
,
times
(
1
)).
onChange
(
captor
.
capture
());
ConfigChangeEvent
changeEvent
=
captor
.
getValue
();
assertEquals
(
someNamespace
,
changeEvent
.
getNamespace
());
assertEquals
(
4
,
changeEvent
.
getChanges
().
size
());
ConfigChange
anotherKeyChange
=
changeEvent
.
getChange
(
anotherKey
);
assertEquals
(
someLocalFileValue
,
anotherKeyChange
.
getOldValue
());
assertEquals
(
anotherKeyNewValue
,
anotherKeyChange
.
getNewValue
());
assertEquals
(
PropertyChangeType
.
MODIFIED
,
anotherKeyChange
.
getChangeType
());
ConfigChange
yetAnotherKeyChange
=
changeEvent
.
getChange
(
yetAnotherKey
);
assertEquals
(
yetAnotherValue
,
yetAnotherKeyChange
.
getOldValue
());
assertEquals
(
yetAnotherResourceValue
,
yetAnotherKeyChange
.
getNewValue
());
assertEquals
(
PropertyChangeType
.
MODIFIED
,
yetAnotherKeyChange
.
getChangeType
());
ConfigChange
keyToBeDeletedChange
=
changeEvent
.
getChange
(
keyToBeDeleted
);
assertEquals
(
keyToBeDeletedValue
,
keyToBeDeletedChange
.
getOldValue
());
assertEquals
(
null
,
keyToBeDeletedChange
.
getNewValue
());
assertEquals
(
PropertyChangeType
.
DELETED
,
keyToBeDeletedChange
.
getChangeType
());
ConfigChange
newKeyChange
=
changeEvent
.
getChange
(
newKey
);
assertEquals
(
null
,
newKeyChange
.
getOldValue
());
assertEquals
(
newValue
,
newKeyChange
.
getNewValue
());
assertEquals
(
PropertyChangeType
.
NEW
,
newKeyChange
.
getChangeType
());
}
}
apollo-client/src/test/java/com/ctrip/apollo/internals/LocalFileConfigRepositoryTest.java
View file @
5bb2aaf1
...
...
@@ -8,6 +8,7 @@ import com.ctrip.apollo.util.ConfigUtil;
import
org.junit.After
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.mockito.ArgumentCaptor
;
import
org.unidal.lookup.ComponentTestCase
;
import
java.io.File
;
...
...
@@ -16,7 +17,11 @@ 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
.
Matchers
.
eq
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
only
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
/**
...
...
@@ -40,7 +45,7 @@ public class LocalFileConfigRepositoryTest extends ComponentTestCase {
someProperties
=
new
Properties
();
someProperties
.
setProperty
(
"defaultKey"
,
"defaultValue"
);
fallbackRepo
=
mock
(
ConfigRepository
.
class
);
when
(
fallbackRepo
.
load
Config
()).
thenReturn
(
someProperties
);
when
(
fallbackRepo
.
get
Config
()).
thenReturn
(
someProperties
);
defineComponent
(
ConfigUtil
.
class
,
MockConfigUtil
.
class
);
}
...
...
@@ -83,7 +88,7 @@ public class LocalFileConfigRepositoryTest extends ComponentTestCase {
Files
.
write
(
someKey
+
"="
+
someValue
,
file
,
Charsets
.
UTF_8
);
LocalFileConfigRepository
localRepo
=
new
LocalFileConfigRepository
(
someBaseDir
,
someNamespace
);
Properties
properties
=
localRepo
.
load
Config
();
Properties
properties
=
localRepo
.
get
Config
();
assertEquals
(
someValue
,
properties
.
getProperty
(
someKey
));
...
...
@@ -97,7 +102,7 @@ public class LocalFileConfigRepositoryTest extends ComponentTestCase {
localFileConfigRepository
.
setFallback
(
fallbackRepo
);
Properties
result
=
localFileConfigRepository
.
load
Config
();
Properties
result
=
localFileConfigRepository
.
get
Config
();
assertThat
(
"LocalFileConfigRepository's properties should be the same as fallback repo's when there is no local cache"
,
...
...
@@ -111,13 +116,13 @@ public class LocalFileConfigRepositoryTest extends ComponentTestCase {
localRepo
.
setFallback
(
fallbackRepo
);
Properties
someProperties
=
localRepo
.
load
Config
();
Properties
someProperties
=
localRepo
.
get
Config
();
LocalFileConfigRepository
anotherLocalRepoWithNoFallback
=
new
LocalFileConfigRepository
(
someBaseDir
,
someNamespace
);
Properties
anotherProperties
=
anotherLocalRepoWithNoFallback
.
load
Config
();
Properties
anotherProperties
=
anotherLocalRepoWithNoFallback
.
get
Config
();
assertThat
(
"LocalFileConfigRepository should persist local cache files and return that afterwards"
,
...
...
@@ -125,6 +130,30 @@ public class LocalFileConfigRepositoryTest extends ComponentTestCase {
}
@Test
public
void
testOnRepositoryChange
()
throws
Exception
{
RepositoryChangeListener
someListener
=
mock
(
RepositoryChangeListener
.
class
);
LocalFileConfigRepository
localFileConfigRepository
=
new
LocalFileConfigRepository
(
someBaseDir
,
someNamespace
);
localFileConfigRepository
.
setFallback
(
fallbackRepo
);
localFileConfigRepository
.
addChangeListener
(
someListener
);
localFileConfigRepository
.
getConfig
();
Properties
anotherProperties
=
new
Properties
();
anotherProperties
.
put
(
"anotherKey"
,
"anotherValue"
);
localFileConfigRepository
.
onRepositoryChange
(
someNamespace
,
anotherProperties
);
final
ArgumentCaptor
<
Properties
>
captor
=
ArgumentCaptor
.
forClass
(
Properties
.
class
);
verify
(
someListener
,
times
(
1
)).
onRepositoryChange
(
eq
(
someNamespace
),
captor
.
capture
());
assertEquals
(
anotherProperties
,
captor
.
getValue
());
}
public
static
class
MockConfigUtil
extends
ConfigUtil
{
@Override
public
String
getAppId
()
{
...
...
apollo-client/src/test/java/com/ctrip/apollo/internals/RemoteConfigRepositoryTest.java
View file @
5bb2aaf1
package
com
.
ctrip
.
apollo
.
internals
;
import
com.google.common.collect.ImmutableMap
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Maps
;
...
...
@@ -13,6 +14,7 @@ import com.ctrip.apollo.util.http.HttpUtil;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.mockito.ArgumentCaptor
;
import
org.mockito.Mock
;
import
org.mockito.runners.MockitoJUnitRunner
;
import
org.unidal.lookup.ComponentTestCase
;
...
...
@@ -22,7 +24,10 @@ import java.util.Map;
import
java.util.Properties
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
mockito
.
Matchers
.
eq
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
/**
...
...
@@ -60,7 +65,7 @@ public class RemoteConfigRepositoryTest extends ComponentTestCase {
when
(
someResponse
.
getBody
()).
thenReturn
(
someApolloConfig
);
RemoteConfigRepository
remoteConfigRepository
=
new
RemoteConfigRepository
(
someNamespace
);
Properties
config
=
remoteConfigRepository
.
load
Config
();
Properties
config
=
remoteConfigRepository
.
get
Config
();
assertEquals
(
configurations
,
config
);
}
...
...
@@ -71,7 +76,27 @@ public class RemoteConfigRepositoryTest extends ComponentTestCase {
when
(
someResponse
.
getStatusCode
()).
thenReturn
(
500
);
RemoteConfigRepository
remoteConfigRepository
=
new
RemoteConfigRepository
(
someNamespace
);
remoteConfigRepository
.
loadConfig
();
remoteConfigRepository
.
getConfig
();
}
@Test
public
void
testRepositoryChangeListener
()
throws
Exception
{
Map
<
String
,
String
>
configurations
=
ImmutableMap
.
of
(
"someKey"
,
"someValue"
);
ApolloConfig
someApolloConfig
=
assembleApolloConfig
(
configurations
);
when
(
someResponse
.
getStatusCode
()).
thenReturn
(
200
);
when
(
someResponse
.
getBody
()).
thenReturn
(
someApolloConfig
);
RepositoryChangeListener
someListener
=
mock
(
RepositoryChangeListener
.
class
);
RemoteConfigRepository
remoteConfigRepository
=
new
RemoteConfigRepository
(
someNamespace
);
remoteConfigRepository
.
addChangeListener
(
someListener
);
final
ArgumentCaptor
<
Properties
>
captor
=
ArgumentCaptor
.
forClass
(
Properties
.
class
);
remoteConfigRepository
.
loadRemoteConfig
();
verify
(
someListener
,
times
(
1
)).
onRepositoryChange
(
eq
(
someNamespace
),
captor
.
capture
());
assertEquals
(
configurations
,
captor
.
getValue
());
}
private
ApolloConfig
assembleApolloConfig
(
Map
<
String
,
String
>
configurations
)
{
...
...
apollo-client/src/test/java/com/ctrip/apollo/internals/SimpleConfigTest.java
View file @
5bb2aaf1
package
com
.
ctrip
.
apollo
.
internals
;
import
com.google.common.collect.ImmutableMap
;
import
com.ctrip.apollo.ConfigChangeListener
;
import
com.ctrip.apollo.enums.PropertyChangeType
;
import
com.ctrip.apollo.model.ConfigChange
;
import
com.ctrip.apollo.model.ConfigChangeEvent
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.mockito.ArgumentCaptor
;
import
org.mockito.Mock
;
import
org.mockito.runners.MockitoJUnitRunner
;
import
java.util.Properties
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
/**
...
...
@@ -32,7 +43,7 @@ public class SimpleConfigTest {
String
someValue
=
"someValue"
;
someProperties
.
setProperty
(
someKey
,
someValue
);
when
(
configRepository
.
load
Config
()).
thenReturn
(
someProperties
);
when
(
configRepository
.
get
Config
()).
thenReturn
(
someProperties
);
SimpleConfig
config
=
new
SimpleConfig
(
someNamespace
,
configRepository
);
...
...
@@ -41,8 +52,57 @@ public class SimpleConfigTest {
@Test
(
expected
=
RuntimeException
.
class
)
public
void
testLoadConfigFromConfigRepositoryError
()
throws
Exception
{
when
(
configRepository
.
load
Config
()).
thenThrow
(
Throwable
.
class
);
when
(
configRepository
.
get
Config
()).
thenThrow
(
Throwable
.
class
);
new
SimpleConfig
(
someNamespace
,
configRepository
);
}
@Test
public
void
testOnRepositoryChange
()
throws
Exception
{
Properties
someProperties
=
new
Properties
();
String
someKey
=
"someKey"
;
String
someValue
=
"someValue"
;
String
anotherKey
=
"anotherKey"
;
String
anotherValue
=
"anotherValue"
;
someProperties
.
putAll
(
ImmutableMap
.
of
(
someKey
,
someValue
,
anotherKey
,
anotherValue
));
Properties
anotherProperties
=
new
Properties
();
String
newKey
=
"newKey"
;
String
newValue
=
"newValue"
;
String
someValueNew
=
"someValueNew"
;
anotherProperties
.
putAll
(
ImmutableMap
.
of
(
someKey
,
someValueNew
,
newKey
,
newValue
));
when
(
configRepository
.
getConfig
()).
thenReturn
(
someProperties
);
ConfigChangeListener
someListener
=
mock
(
ConfigChangeListener
.
class
);
SimpleConfig
config
=
new
SimpleConfig
(
someNamespace
,
configRepository
);
config
.
addChangeListener
(
someListener
);
config
.
onRepositoryChange
(
someNamespace
,
anotherProperties
);
ArgumentCaptor
<
ConfigChangeEvent
>
captor
=
ArgumentCaptor
.
forClass
(
ConfigChangeEvent
.
class
);
verify
(
someListener
,
times
(
1
)).
onChange
(
captor
.
capture
());
ConfigChangeEvent
changeEvent
=
captor
.
getValue
();
assertEquals
(
someNamespace
,
changeEvent
.
getNamespace
());
assertEquals
(
3
,
changeEvent
.
getChanges
().
size
());
ConfigChange
someKeyChange
=
changeEvent
.
getChange
(
someKey
);
assertEquals
(
someValue
,
someKeyChange
.
getOldValue
());
assertEquals
(
someValueNew
,
someKeyChange
.
getNewValue
());
assertEquals
(
PropertyChangeType
.
MODIFIED
,
someKeyChange
.
getChangeType
());
ConfigChange
anotherKeyChange
=
changeEvent
.
getChange
(
anotherKey
);
assertEquals
(
anotherValue
,
anotherKeyChange
.
getOldValue
());
assertEquals
(
null
,
anotherKeyChange
.
getNewValue
());
assertEquals
(
PropertyChangeType
.
DELETED
,
anotherKeyChange
.
getChangeType
());
ConfigChange
newKeyChange
=
changeEvent
.
getChange
(
newKey
);
assertEquals
(
null
,
newKeyChange
.
getOldValue
());
assertEquals
(
newValue
,
newKeyChange
.
getNewValue
());
assertEquals
(
PropertyChangeType
.
NEW
,
newKeyChange
.
getChangeType
());
}
}
apollo-client/src/test/java/com/ctrip/apollo/spi/DefaultConfigFactoryTest.java
View file @
5bb2aaf1
...
...
@@ -40,7 +40,7 @@ public class DefaultConfigFactoryTest extends ComponentTestCase {
someProperties
.
setProperty
(
someKey
,
someValue
);
LocalFileConfigRepository
someLocalConfigRepo
=
mock
(
LocalFileConfigRepository
.
class
);
when
(
someLocalConfigRepo
.
load
Config
()).
thenReturn
(
someProperties
);
when
(
someLocalConfigRepo
.
get
Config
()).
thenReturn
(
someProperties
);
doReturn
(
someLocalConfigRepo
).
when
(
defaultConfigFactory
).
createLocalConfigRepository
(
someNamespace
);
...
...
apollo-demo/src/main/java/ApolloConfigDemo.java
View file @
5bb2aaf1
import
com.ctrip.apollo.Config
;
import
com.ctrip.apollo.ConfigChangeListener
;
import
com.ctrip.apollo.ConfigService
;
import
com.ctrip.apollo.model.ConfigChange
;
import
com.ctrip.apollo.model.ConfigChangeEvent
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
java.io.BufferedReader
;
import
java.io.IOException
;
...
...
@@ -9,16 +15,18 @@ import java.io.InputStreamReader;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
ApolloConfigDemo
{
public
class
ApolloConfigDemo
implements
ConfigChangeListener
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
ApolloConfigDemo
.
class
);
private
Config
config
;
public
ApolloConfigDemo
()
{
config
=
ConfigService
.
getConfig
();
config
.
addChangeListener
(
this
);
}
private
String
getConfig
(
String
key
)
{
String
result
=
config
.
getProperty
(
key
,
"undefined"
);
System
.
out
.
println
(
String
.
format
(
"Loading key: %s with value: %s"
,
key
,
result
));
logger
.
info
(
String
.
format
(
"Loading key: %s with value: %s"
,
key
,
result
));
return
result
;
}
...
...
@@ -35,4 +43,14 @@ public class ApolloConfigDemo {
apolloConfigDemo
.
getConfig
(
input
);
}
}
@Override
public
void
onChange
(
ConfigChangeEvent
changeEvent
)
{
logger
.
info
(
"Changes for namespace {}"
,
changeEvent
.
getNamespace
());
for
(
ConfigChange
change
:
changeEvent
.
getChanges
().
values
())
{
logger
.
info
(
"Change - key: {}, oldValue: {}, newValue: {}, changeType: {}"
,
change
.
getPropertyName
(),
change
.
getOldValue
(),
change
.
getNewValue
(),
change
.
getChangeType
());
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment