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
f435f27d
Commit
f435f27d
authored
Jul 13, 2016
by
Jason Song
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add config file controller to support get config as plain properties file
parent
f5bc9f83
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
691 additions
and
111 deletions
+691
-111
pom.xml
apollo-adminservice/pom.xml
+1
-1
pom.xml
apollo-assembly/pom.xml
+1
-1
pom.xml
apollo-biz/pom.xml
+1
-1
pom.xml
apollo-buildtools/pom.xml
+1
-1
pom.xml
apollo-client/pom.xml
+1
-1
PropertiesConfigFile.java
...trip/framework/apollo/internals/PropertiesConfigFile.java
+4
-27
pom.xml
apollo-common/pom.xml
+1
-1
pom.xml
apollo-configservice/pom.xml
+1
-1
ConfigServiceAutoConfiguration.java
.../apollo/configservice/ConfigServiceAutoConfiguration.java
+5
-0
ConfigFileController.java
...apollo/configservice/controller/ConfigFileController.java
+187
-0
NotificationController.java
...ollo/configservice/controller/NotificationController.java
+9
-66
WatchKeysUtil.java
...ip/framework/apollo/configservice/util/WatchKeysUtil.java
+88
-0
AllTests.java
...va/com/ctrip/framework/apollo/configservice/AllTests.java
+4
-1
ConfigFileControllerTest.java
...lo/configservice/controller/ConfigFileControllerTest.java
+164
-0
NotificationControllerTest.java
.../configservice/controller/NotificationControllerTest.java
+5
-1
AbstractBaseIntegrationTest.java
...onfigservice/integration/AbstractBaseIntegrationTest.java
+39
-0
ConfigFileControllerIntegrationTest.java
...vice/integration/ConfigFileControllerIntegrationTest.java
+128
-0
NotificationControllerIntegrationTest.java
...ce/integration/NotificationControllerIntegrationTest.java
+2
-4
pom.xml
apollo-core/pom.xml
+1
-1
PropertiesUtil.java
...com/ctrip/framework/apollo/core/utils/PropertiesUtil.java
+42
-0
pom.xml
apollo-demo/pom.xml
+1
-1
ApolloConfigFileDemo.java
apollo-demo/src/main/java/ApolloConfigFileDemo.java
+3
-1
pom.xml
apollo-portal/pom.xml
+1
-1
pom.xml
pom.xml
+1
-1
No files found.
apollo-adminservice/pom.xml
View file @
f435f27d
...
...
@@ -4,7 +4,7 @@
<parent>
<groupId>
com.ctrip.framework.apollo
</groupId>
<artifactId>
apollo
</artifactId>
<version>
0.0.
5
</version>
<version>
0.0.
6-SNAPSHOT
</version>
<relativePath>
../pom.xml
</relativePath>
</parent>
<modelVersion>
4.0.0
</modelVersion>
...
...
apollo-assembly/pom.xml
View file @
f435f27d
...
...
@@ -4,7 +4,7 @@
<parent>
<groupId>
com.ctrip.framework.apollo
</groupId>
<artifactId>
apollo
</artifactId>
<version>
0.0.
5
</version>
<version>
0.0.
6-SNAPSHOT
</version>
<relativePath>
../pom.xml
</relativePath>
</parent>
<modelVersion>
4.0.0
</modelVersion>
...
...
apollo-biz/pom.xml
View file @
f435f27d
...
...
@@ -4,7 +4,7 @@
<parent>
<artifactId>
apollo
</artifactId>
<groupId>
com.ctrip.framework.apollo
</groupId>
<version>
0.0.
5
</version>
<version>
0.0.
6-SNAPSHOT
</version>
</parent>
<modelVersion>
4.0.0
</modelVersion>
<artifactId>
apollo-biz
</artifactId>
...
...
apollo-buildtools/pom.xml
View file @
f435f27d
...
...
@@ -4,7 +4,7 @@
<parent>
<groupId>
com.ctrip.framework.apollo
</groupId>
<artifactId>
apollo
</artifactId>
<version>
0.0.
5
</version>
<version>
0.0.
6-SNAPSHOT
</version>
<relativePath>
../pom.xml
</relativePath>
</parent>
<modelVersion>
4.0.0
</modelVersion>
...
...
apollo-client/pom.xml
View file @
f435f27d
...
...
@@ -4,7 +4,7 @@
<parent>
<groupId>
com.ctrip.framework.apollo
</groupId>
<artifactId>
apollo
</artifactId>
<version>
0.0.
5
</version>
<version>
0.0.
6-SNAPSHOT
</version>
<relativePath>
../pom.xml
</relativePath>
</parent>
<modelVersion>
4.0.0
</modelVersion>
...
...
apollo-client/src/main/java/com/ctrip/framework/apollo/internals/PropertiesConfigFile.java
View file @
f435f27d
package
com
.
ctrip
.
framework
.
apollo
.
internals
;
import
com.ctrip.framework.apollo.core.enums.ConfigFileFormat
;
import
com.ctrip.framework.apollo.core.utils.PropertiesUtil
;
import
com.ctrip.framework.apollo.exceptions.ApolloConfigException
;
import
com.ctrip.framework.apollo.util.ExceptionUtil
;
import
com.dianping.cat.Cat
;
...
...
@@ -8,8 +9,6 @@ import com.dianping.cat.Cat;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
java.io.IOException
;
import
java.io.StringWriter
;
import
java.util.Properties
;
import
java.util.concurrent.atomic.AtomicReference
;
...
...
@@ -38,13 +37,10 @@ public class PropertiesConfigFile extends AbstractConfigFile {
if
(
m_configProperties
.
get
()
==
null
)
{
return
null
;
}
StringWriter
writer
=
new
StringWriter
();
try
{
m_configProperties
.
get
().
store
(
writer
,
null
);
StringBuffer
stringBuffer
=
writer
.
getBuffer
();
filterPropertiesComment
(
stringBuffer
);
return
stringBuffer
.
toString
();
}
catch
(
IOException
ex
)
{
return
PropertiesUtil
.
toString
(
m_configProperties
.
get
());
}
catch
(
Throwable
ex
)
{
ApolloConfigException
exception
=
new
ApolloConfigException
(
String
.
format
(
"Parse properties file content failed for namespace: %s, cause: %s"
,
...
...
@@ -54,25 +50,6 @@ public class PropertiesConfigFile extends AbstractConfigFile {
}
}
/**
* filter out the first comment line
* @param stringBuffer the string buffer
* @return true if filtered successfully, false otherwise
*/
boolean
filterPropertiesComment
(
StringBuffer
stringBuffer
)
{
//check whether has comment in the first line
if
(
stringBuffer
.
charAt
(
0
)
!=
'#'
)
{
return
false
;
}
int
commentLineIndex
=
stringBuffer
.
indexOf
(
"\n"
);
if
(
commentLineIndex
==
-
1
)
{
return
false
;
}
stringBuffer
.
delete
(
0
,
commentLineIndex
+
1
);
return
true
;
}
@Override
public
boolean
hasContent
()
{
return
m_configProperties
.
get
()
!=
null
&&
!
m_configProperties
.
get
().
isEmpty
();
...
...
apollo-common/pom.xml
View file @
f435f27d
...
...
@@ -4,7 +4,7 @@
<parent>
<groupId>
com.ctrip.framework.apollo
</groupId>
<artifactId>
apollo
</artifactId>
<version>
0.0.
5
</version>
<version>
0.0.
6-SNAPSHOT
</version>
<relativePath>
../pom.xml
</relativePath>
</parent>
<modelVersion>
4.0.0
</modelVersion>
...
...
apollo-configservice/pom.xml
View file @
f435f27d
...
...
@@ -4,7 +4,7 @@
<parent>
<groupId>
com.ctrip.framework.apollo
</groupId>
<artifactId>
apollo
</artifactId>
<version>
0.0.
5
</version>
<version>
0.0.
6-SNAPSHOT
</version>
<relativePath>
../pom.xml
</relativePath>
</parent>
<modelVersion>
4.0.0
</modelVersion>
...
...
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceAutoConfiguration.java
View file @
f435f27d
package
com
.
ctrip
.
framework
.
apollo
.
configservice
;
import
com.ctrip.framework.apollo.biz.message.ReleaseMessageScanner
;
import
com.ctrip.framework.apollo.configservice.controller.ConfigFileController
;
import
com.ctrip.framework.apollo.configservice.controller.NotificationController
;
import
org.springframework.beans.factory.annotation.Autowired
;
...
...
@@ -14,10 +15,14 @@ import org.springframework.context.annotation.Configuration;
public
class
ConfigServiceAutoConfiguration
{
@Autowired
private
NotificationController
notificationController
;
@Autowired
private
ConfigFileController
configFileController
;
@Bean
public
ReleaseMessageScanner
releaseMessageScanner
()
{
ReleaseMessageScanner
releaseMessageScanner
=
new
ReleaseMessageScanner
();
//handle server cache first
releaseMessageScanner
.
addMessageListener
(
configFileController
);
releaseMessageScanner
.
addMessageListener
(
notificationController
);
return
releaseMessageScanner
;
}
...
...
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/ConfigFileController.java
0 → 100644
View file @
f435f27d
package
com
.
ctrip
.
framework
.
apollo
.
configservice
.
controller
;
import
com.google.common.base.Joiner
;
import
com.google.common.base.Strings
;
import
com.google.common.cache.Cache
;
import
com.google.common.cache.CacheBuilder
;
import
com.google.common.cache.RemovalListener
;
import
com.google.common.cache.RemovalNotification
;
import
com.google.common.cache.Weigher
;
import
com.google.common.collect.HashMultimap
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Multimap
;
import
com.google.common.collect.Multimaps
;
import
com.ctrip.framework.apollo.biz.entity.ReleaseMessage
;
import
com.ctrip.framework.apollo.biz.message.ReleaseMessageListener
;
import
com.ctrip.framework.apollo.biz.message.Topics
;
import
com.ctrip.framework.apollo.configservice.util.NamespaceUtil
;
import
com.ctrip.framework.apollo.configservice.util.WatchKeysUtil
;
import
com.ctrip.framework.apollo.core.ConfigConsts
;
import
com.ctrip.framework.apollo.core.dto.ApolloConfig
;
import
com.ctrip.framework.apollo.core.dto.ApolloConfigNotification
;
import
com.ctrip.framework.apollo.core.utils.PropertiesUtil
;
import
com.dianping.cat.Cat
;
import
org.hibernate.cache.spi.CacheKey
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.bind.annotation.RequestParam
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.context.request.async.DeferredResult
;
import
java.io.IOException
;
import
java.io.StringWriter
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.List
;
import
java.util.Properties
;
import
java.util.Set
;
import
java.util.concurrent.TimeUnit
;
import
javax.servlet.http.HttpServletResponse
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@RestController
@RequestMapping
(
"/configfiles"
)
public
class
ConfigFileController
implements
ReleaseMessageListener
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
ConfigFileController
.
class
);
private
static
final
Joiner
STRING_JOINER
=
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
);
private
static
final
long
MAX_CACHE_SIZE
=
50
*
1024
*
1024
;
// 50MB
private
static
final
long
EXPIRE_AFTER_WRITE
=
10
;
private
final
HttpHeaders
responseHeaders
;
private
final
ResponseEntity
<
String
>
NOT_FOUND_RESPONSE
;
private
Cache
<
String
,
String
>
localCache
;
private
final
Multimap
<
String
,
String
>
watchedKeys2CacheKey
=
Multimaps
.
synchronizedSetMultimap
(
HashMultimap
.
create
());
private
final
Multimap
<
String
,
String
>
cacheKey2WatchedKeys
=
Multimaps
.
synchronizedSetMultimap
(
HashMultimap
.
create
());
@Autowired
private
ConfigController
configController
;
@Autowired
private
NamespaceUtil
namespaceUtil
;
@Autowired
private
WatchKeysUtil
watchKeysUtil
;
public
ConfigFileController
()
{
localCache
=
CacheBuilder
.
newBuilder
()
.
expireAfterWrite
(
EXPIRE_AFTER_WRITE
,
TimeUnit
.
MINUTES
)
.
weigher
(
new
Weigher
<
String
,
String
>()
{
@Override
public
int
weigh
(
String
key
,
String
value
)
{
return
value
==
null
?
0
:
value
.
length
();
}
})
.
maximumWeight
(
MAX_CACHE_SIZE
)
.
removalListener
(
new
RemovalListener
<
String
,
String
>()
{
@Override
public
void
onRemoval
(
RemovalNotification
<
String
,
String
>
notification
)
{
String
cacheKey
=
notification
.
getKey
();
logger
.
debug
(
"removing cache key: {}"
,
cacheKey
);
if
(!
cacheKey2WatchedKeys
.
containsKey
(
cacheKey
))
{
return
;
}
//create a new list to avoid ConcurrentModificationException
List
<
String
>
watchedKeys
=
new
ArrayList
<>(
cacheKey2WatchedKeys
.
get
(
cacheKey
));
for
(
String
watchedKey
:
watchedKeys
)
{
watchedKeys2CacheKey
.
remove
(
watchedKey
,
cacheKey
);
}
cacheKey2WatchedKeys
.
removeAll
(
cacheKey
);
logger
.
debug
(
"removed cache key: {}"
,
cacheKey
);
}
})
.
build
();
responseHeaders
=
new
HttpHeaders
();
responseHeaders
.
add
(
"Content-Type"
,
"text/plain;charset=UTF-8"
);
NOT_FOUND_RESPONSE
=
new
ResponseEntity
<>(
HttpStatus
.
NOT_FOUND
);
}
@RequestMapping
(
value
=
"/{appId}/{clusterName}/{namespace:.+}"
,
method
=
RequestMethod
.
GET
)
public
ResponseEntity
<
String
>
queryConfigAsFile
(
@PathVariable
String
appId
,
@PathVariable
String
clusterName
,
@PathVariable
String
namespace
,
@RequestParam
(
value
=
"dataCenter"
,
required
=
false
)
String
dataCenter
,
@RequestParam
(
value
=
"ip"
,
required
=
false
)
String
clientIp
,
HttpServletResponse
response
)
throws
IOException
{
//strip out .properties suffix
namespace
=
namespaceUtil
.
filterNamespaceName
(
namespace
);
//TODO add clientIp as key parts?
String
cacheKey
=
assembleCacheKey
(
appId
,
clusterName
,
namespace
,
dataCenter
);
String
result
=
localCache
.
getIfPresent
(
cacheKey
);
if
(
Strings
.
isNullOrEmpty
(
result
))
{
ApolloConfig
apolloConfig
=
configController
.
queryConfig
(
appId
,
clusterName
,
namespace
,
dataCenter
,
"-1"
,
clientIp
,
response
);
if
(
apolloConfig
==
null
||
apolloConfig
.
getConfigurations
()
==
null
)
{
return
NOT_FOUND_RESPONSE
;
}
Properties
properties
=
new
Properties
();
properties
.
putAll
(
apolloConfig
.
getConfigurations
());
result
=
PropertiesUtil
.
toString
(
properties
);
localCache
.
put
(
cacheKey
,
result
);
logger
.
debug
(
"adding cache for key: {}"
,
cacheKey
);
Set
<
String
>
watchedKeys
=
watchKeysUtil
.
assembleAllWatchKeys
(
appId
,
clusterName
,
namespace
,
dataCenter
);
for
(
String
watchedKey
:
watchedKeys
)
{
watchedKeys2CacheKey
.
put
(
watchedKey
,
cacheKey
);
}
cacheKey2WatchedKeys
.
putAll
(
cacheKey
,
watchedKeys
);
logger
.
debug
(
"added cache for key: {}"
,
cacheKey
);
}
return
new
ResponseEntity
<>(
result
,
responseHeaders
,
HttpStatus
.
OK
);
}
String
assembleCacheKey
(
String
appId
,
String
clusterName
,
String
namespace
,
String
dataCenter
)
{
List
<
String
>
keyParts
=
Lists
.
newArrayList
(
appId
,
clusterName
,
namespace
);
if
(!
Strings
.
isNullOrEmpty
(
dataCenter
))
{
keyParts
.
add
(
dataCenter
);
}
return
STRING_JOINER
.
join
(
keyParts
);
}
@Override
public
void
handleMessage
(
ReleaseMessage
message
,
String
channel
)
{
logger
.
info
(
"message received - channel: {}, message: {}"
,
channel
,
message
);
String
content
=
message
.
getMessage
();
if
(!
Topics
.
APOLLO_RELEASE_TOPIC
.
equals
(
channel
)
||
Strings
.
isNullOrEmpty
(
content
))
{
return
;
}
if
(!
watchedKeys2CacheKey
.
containsKey
(
content
))
{
return
;
}
//create a new list to avoid ConcurrentModificationException
List
<
String
>
cacheKeys
=
new
ArrayList
<>(
watchedKeys2CacheKey
.
get
(
content
));
for
(
String
cacheKey
:
cacheKeys
)
{
logger
.
debug
(
"invalidate cache key: {}"
,
cacheKey
);
localCache
.
invalidate
(
cacheKey
);
}
}
}
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/NotificationController.java
View file @
f435f27d
package
com
.
ctrip
.
framework
.
apollo
.
configservice
.
controller
;
import
com.google.common.base.Joiner
;
import
com.google.common.base.Splitter
;
import
com.google.common.base.Strings
;
import
com.google.common.collect.HashMultimap
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Multimap
;
import
com.google.common.collect.Multimaps
;
import
com.google.common.collect.Sets
;
import
com.ctrip.framework.apollo.common.entity.AppNamespace
;
import
com.ctrip.framework.apollo.biz.entity.ReleaseMessage
;
import
com.ctrip.framework.apollo.biz.message.ReleaseMessageListener
;
import
com.ctrip.framework.apollo.biz.message.Topics
;
import
com.ctrip.framework.apollo.biz.service.AppNamespaceService
;
import
com.ctrip.framework.apollo.biz.service.ReleaseMessageService
;
import
com.ctrip.framework.apollo.biz.utils.EntityManagerUtil
;
import
com.ctrip.framework.apollo.configservice.util.NamespaceUtil
;
import
com.ctrip.framework.apollo.configservice.util.WatchKeysUtil
;
import
com.ctrip.framework.apollo.core.ConfigConsts
;
import
com.ctrip.framework.apollo.core.dto.ApolloConfigNotification
;
import
com.dianping.cat.Cat
;
...
...
@@ -33,7 +30,6 @@ import org.springframework.web.bind.annotation.RestController;
import
org.springframework.web.context.request.async.DeferredResult
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.Set
;
/**
...
...
@@ -48,12 +44,11 @@ public class NotificationController implements ReleaseMessageListener {
deferredResults
=
Multimaps
.
synchronizedSetMultimap
(
HashMultimap
.
create
());
private
static
final
ResponseEntity
<
ApolloConfigNotification
>
NOT_MODIFIED_RESPONSE
=
new
ResponseEntity
<>(
HttpStatus
.
NOT_MODIFIED
);
private
static
final
Joiner
STRING_JOINER
=
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
);
private
static
final
Splitter
STRING_SPLITTER
=
Splitter
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
).
omitEmptyStrings
();
@Autowired
private
AppNamespaceService
appNamespaceService
;
private
WatchKeysUtil
watchKeysUtil
;
@Autowired
private
ReleaseMessageService
releaseMessageService
;
...
...
@@ -75,12 +70,7 @@ public class NotificationController implements ReleaseMessageListener {
//strip out .properties suffix
namespace
=
namespaceUtil
.
filterNamespaceName
(
namespace
);
Set
<
String
>
watchedKeys
=
assembleWatchKeys
(
appId
,
cluster
,
namespace
,
dataCenter
);
//Listen on more namespaces if it's a public namespace
if
(!
namespaceBelongsToAppId
(
appId
,
namespace
))
{
watchedKeys
.
addAll
(
this
.
findPublicConfigWatchKey
(
appId
,
cluster
,
namespace
,
dataCenter
));
}
Set
<
String
>
watchedKeys
=
watchKeysUtil
.
assembleAllWatchKeys
(
appId
,
cluster
,
namespace
,
dataCenter
);
DeferredResult
<
ResponseEntity
<
ApolloConfigNotification
>>
deferredResult
=
new
DeferredResult
<>(
TIMEOUT
,
NOT_MODIFIED_RESPONSE
);
...
...
@@ -117,52 +107,13 @@ public class NotificationController implements ReleaseMessageListener {
});
logWatchedKeysToCat
(
watchedKeys
,
"Apollo.LongPoll.RegisteredKeys"
);
logger
.
info
(
"Listening {} from appId: {}, cluster: {}, namespace: {}, datacenter: {}"
,
logger
.
debug
(
"Listening {} from appId: {}, cluster: {}, namespace: {}, datacenter: {}"
,
watchedKeys
,
appId
,
cluster
,
namespace
,
dataCenter
);
}
return
deferredResult
;
}
private
String
assembleKey
(
String
appId
,
String
cluster
,
String
namespace
)
{
return
STRING_JOINER
.
join
(
appId
,
cluster
,
namespace
);
}
private
Set
<
String
>
findPublicConfigWatchKey
(
String
applicationId
,
String
clusterName
,
String
namespace
,
String
dataCenter
)
{
AppNamespace
appNamespace
=
appNamespaceService
.
findPublicNamespaceByName
(
namespace
);
//check whether the namespace's appId equals to current one
if
(
Objects
.
isNull
(
appNamespace
)
||
Objects
.
equals
(
applicationId
,
appNamespace
.
getAppId
()))
{
return
Sets
.
newHashSet
();
}
String
publicConfigAppId
=
appNamespace
.
getAppId
();
return
assembleWatchKeys
(
publicConfigAppId
,
clusterName
,
namespace
,
dataCenter
);
}
private
Set
<
String
>
assembleWatchKeys
(
String
appId
,
String
clusterName
,
String
namespace
,
String
dataCenter
)
{
Set
<
String
>
watchedKeys
=
Sets
.
newHashSet
();
//watch specified cluster config change
if
(!
Objects
.
equals
(
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
clusterName
))
{
watchedKeys
.
add
(
assembleKey
(
appId
,
clusterName
,
namespace
));
}
//watch data center config change
if
(!
Strings
.
isNullOrEmpty
(
dataCenter
)
&&
!
Objects
.
equals
(
dataCenter
,
clusterName
))
{
watchedKeys
.
add
(
assembleKey
(
appId
,
dataCenter
,
namespace
));
}
//watch default cluster config change
watchedKeys
.
add
(
assembleKey
(
appId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
namespace
));
return
watchedKeys
;
}
@Override
public
void
handleMessage
(
ReleaseMessage
message
,
String
channel
)
{
logger
.
info
(
"message received - channel: {}, message: {}"
,
channel
,
message
);
...
...
@@ -183,26 +134,18 @@ public class NotificationController implements ReleaseMessageListener {
new
ResponseEntity
<>(
new
ApolloConfigNotification
(
keys
.
get
(
2
),
message
.
getId
()),
HttpStatus
.
OK
);
if
(!
deferredResults
.
containsKey
(
content
))
{
return
;
}
//create a new list to avoid ConcurrentModificationException
List
<
DeferredResult
<
ResponseEntity
<
ApolloConfigNotification
>>>
results
=
Lists
.
newArrayList
(
deferredResults
.
get
(
content
));
logger
.
info
(
"Notify {} clients for key {}"
,
results
.
size
(),
content
);
logger
.
debug
(
"Notify {} clients for key {}"
,
results
.
size
(),
content
);
for
(
DeferredResult
<
ResponseEntity
<
ApolloConfigNotification
>>
result
:
results
)
{
result
.
setResult
(
notification
);
}
logger
.
info
(
"Notification completed"
);
}
private
boolean
namespaceBelongsToAppId
(
String
appId
,
String
namespaceName
)
{
//Every app has an 'application' namespace
if
(
Objects
.
equals
(
ConfigConsts
.
NAMESPACE_APPLICATION
,
namespaceName
))
{
return
true
;
}
AppNamespace
appNamespace
=
appNamespaceService
.
findOne
(
appId
,
namespaceName
);
return
appNamespace
!=
null
;
logger
.
debug
(
"Notification completed"
);
}
private
void
logWatchedKeysToCat
(
Set
<
String
>
watchedKeys
,
String
eventName
)
{
...
...
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/util/WatchKeysUtil.java
0 → 100644
View file @
f435f27d
package
com
.
ctrip
.
framework
.
apollo
.
configservice
.
util
;
import
com.google.common.base.Joiner
;
import
com.google.common.base.Strings
;
import
com.google.common.collect.Sets
;
import
com.ctrip.framework.apollo.biz.service.AppNamespaceService
;
import
com.ctrip.framework.apollo.common.entity.AppNamespace
;
import
com.ctrip.framework.apollo.core.ConfigConsts
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Component
;
import
java.util.Objects
;
import
java.util.Set
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Component
public
class
WatchKeysUtil
{
private
static
final
Joiner
STRING_JOINER
=
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
);
@Autowired
private
AppNamespaceService
appNamespaceService
;
public
Set
<
String
>
assembleAllWatchKeys
(
String
appId
,
String
clusterName
,
String
namespace
,
String
dataCenter
)
{
Set
<
String
>
watchedKeys
=
assembleWatchKeys
(
appId
,
clusterName
,
namespace
,
dataCenter
);
//Listen on more namespaces if it's a public namespace
if
(!
namespaceBelongsToAppId
(
appId
,
namespace
))
{
watchedKeys
.
addAll
(
this
.
findPublicConfigWatchKey
(
appId
,
clusterName
,
namespace
,
dataCenter
));
}
return
watchedKeys
;
}
private
Set
<
String
>
findPublicConfigWatchKey
(
String
applicationId
,
String
clusterName
,
String
namespace
,
String
dataCenter
)
{
AppNamespace
appNamespace
=
appNamespaceService
.
findPublicNamespaceByName
(
namespace
);
//check whether the namespace's appId equals to current one
if
(
Objects
.
isNull
(
appNamespace
)
||
Objects
.
equals
(
applicationId
,
appNamespace
.
getAppId
()))
{
return
Sets
.
newHashSet
();
}
String
publicConfigAppId
=
appNamespace
.
getAppId
();
return
assembleWatchKeys
(
publicConfigAppId
,
clusterName
,
namespace
,
dataCenter
);
}
private
String
assembleKey
(
String
appId
,
String
cluster
,
String
namespace
)
{
return
STRING_JOINER
.
join
(
appId
,
cluster
,
namespace
);
}
private
Set
<
String
>
assembleWatchKeys
(
String
appId
,
String
clusterName
,
String
namespace
,
String
dataCenter
)
{
Set
<
String
>
watchedKeys
=
Sets
.
newHashSet
();
//watch specified cluster config change
if
(!
Objects
.
equals
(
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
clusterName
))
{
watchedKeys
.
add
(
assembleKey
(
appId
,
clusterName
,
namespace
));
}
//watch data center config change
if
(!
Strings
.
isNullOrEmpty
(
dataCenter
)
&&
!
Objects
.
equals
(
dataCenter
,
clusterName
))
{
watchedKeys
.
add
(
assembleKey
(
appId
,
dataCenter
,
namespace
));
}
//watch default cluster config change
watchedKeys
.
add
(
assembleKey
(
appId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
namespace
));
return
watchedKeys
;
}
private
boolean
namespaceBelongsToAppId
(
String
appId
,
String
namespaceName
)
{
//Every app has an 'application' namespace
if
(
Objects
.
equals
(
ConfigConsts
.
NAMESPACE_APPLICATION
,
namespaceName
))
{
return
true
;
}
AppNamespace
appNamespace
=
appNamespaceService
.
findOne
(
appId
,
namespaceName
);
return
appNamespace
!=
null
;
}
}
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/AllTests.java
View file @
f435f27d
package
com
.
ctrip
.
framework
.
apollo
.
configservice
;
import
com.ctrip.framework.apollo.configservice.controller.ConfigControllerTest
;
import
com.ctrip.framework.apollo.configservice.controller.ConfigFileControllerTest
;
import
com.ctrip.framework.apollo.configservice.controller.NotificationControllerTest
;
import
com.ctrip.framework.apollo.configservice.integration.ConfigControllerIntegrationTest
;
import
com.ctrip.framework.apollo.configservice.integration.ConfigFileControllerIntegrationTest
;
import
com.ctrip.framework.apollo.configservice.integration.NotificationControllerIntegrationTest
;
import
com.ctrip.framework.apollo.configservice.util.NamespaceUtilTest
;
...
...
@@ -13,7 +15,8 @@ import org.junit.runners.Suite.SuiteClasses;
@RunWith
(
Suite
.
class
)
@SuiteClasses
({
ConfigControllerTest
.
class
,
NotificationControllerTest
.
class
,
ConfigControllerIntegrationTest
.
class
,
NotificationControllerIntegrationTest
.
class
,
NamespaceUtilTest
.
class
})
NamespaceUtilTest
.
class
,
ConfigFileControllerTest
.
class
,
ConfigFileControllerIntegrationTest
.
class
})
public
class
AllTests
{
}
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/controller/ConfigFileControllerTest.java
0 → 100644
View file @
f435f27d
package
com
.
ctrip
.
framework
.
apollo
.
configservice
.
controller
;
import
com.google.common.cache.Cache
;
import
com.google.common.collect.ImmutableMap
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Multimap
;
import
com.google.common.collect.Sets
;
import
com.ctrip.framework.apollo.biz.entity.ReleaseMessage
;
import
com.ctrip.framework.apollo.biz.message.Topics
;
import
com.ctrip.framework.apollo.configservice.util.NamespaceUtil
;
import
com.ctrip.framework.apollo.configservice.util.WatchKeysUtil
;
import
com.ctrip.framework.apollo.core.dto.ApolloConfig
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.mockito.Mock
;
import
org.mockito.runners.MockitoJUnitRunner
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.test.util.ReflectionTestUtils
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
javax.servlet.http.HttpServletResponse
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertThat
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@RunWith
(
MockitoJUnitRunner
.
class
)
public
class
ConfigFileControllerTest
{
@Mock
private
ConfigController
configController
;
@Mock
private
WatchKeysUtil
watchKeysUtil
;
@Mock
private
NamespaceUtil
namespaceUtil
;
private
ConfigFileController
configFileController
;
private
String
someAppId
;
private
String
someClusterName
;
private
String
someNamespace
;
private
String
someDataCenter
;
private
String
someClientIp
;
@Mock
private
HttpServletResponse
someResponse
;
Multimap
<
String
,
String
>
watchedKeys2CacheKey
;
Multimap
<
String
,
String
>
cacheKey2WatchedKeys
;
@Before
public
void
setUp
()
throws
Exception
{
configFileController
=
new
ConfigFileController
();
ReflectionTestUtils
.
setField
(
configFileController
,
"configController"
,
configController
);
ReflectionTestUtils
.
setField
(
configFileController
,
"watchKeysUtil"
,
watchKeysUtil
);
ReflectionTestUtils
.
setField
(
configFileController
,
"namespaceUtil"
,
namespaceUtil
);
someAppId
=
"someAppId"
;
someClusterName
=
"someClusterName"
;
someNamespace
=
"someNamespace"
;
someDataCenter
=
"someDataCenter"
;
someClientIp
=
"10.1.1.1"
;
when
(
namespaceUtil
.
filterNamespaceName
(
someNamespace
)).
thenReturn
(
someNamespace
);
watchedKeys2CacheKey
=
(
Multimap
<
String
,
String
>)
ReflectionTestUtils
.
getField
(
configFileController
,
"watchedKeys2CacheKey"
);
cacheKey2WatchedKeys
=
(
Multimap
<
String
,
String
>)
ReflectionTestUtils
.
getField
(
configFileController
,
"cacheKey2WatchedKeys"
);
}
@Test
public
void
testQueryConfigAsFile
()
throws
Exception
{
String
someKey
=
"someKey"
;
String
someValue
=
"someValue"
;
String
anotherKey
=
"anotherKey"
;
String
anotherValue
=
"anotherValue"
;
String
someWatchKey
=
"someWatchKey"
;
String
anotherWatchKey
=
"anotherWatchKey"
;
Set
<
String
>
watchKeys
=
Sets
.
newHashSet
(
someWatchKey
,
anotherWatchKey
);
String
cacheKey
=
configFileController
.
assembleCacheKey
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
);
Map
<
String
,
String
>
configurations
=
ImmutableMap
.
of
(
someKey
,
someValue
,
anotherKey
,
anotherValue
);
ApolloConfig
someApolloConfig
=
mock
(
ApolloConfig
.
class
);
when
(
someApolloConfig
.
getConfigurations
()).
thenReturn
(
configurations
);
when
(
configController
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
"-1"
,
someClientIp
,
someResponse
)).
thenReturn
(
someApolloConfig
);
when
(
watchKeysUtil
.
assembleAllWatchKeys
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
))
.
thenReturn
(
watchKeys
);
ResponseEntity
<
String
>
response
=
configFileController
.
queryConfigAsFile
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
someClientIp
,
someResponse
);
assertEquals
(
2
,
watchedKeys2CacheKey
.
size
());
assertEquals
(
2
,
cacheKey2WatchedKeys
.
size
());
assertTrue
(
watchedKeys2CacheKey
.
containsEntry
(
someWatchKey
,
cacheKey
));
assertTrue
(
watchedKeys2CacheKey
.
containsEntry
(
anotherWatchKey
,
cacheKey
));
assertTrue
(
cacheKey2WatchedKeys
.
containsEntry
(
cacheKey
,
someWatchKey
));
assertTrue
(
cacheKey2WatchedKeys
.
containsEntry
(
cacheKey
,
anotherWatchKey
));
assertEquals
(
HttpStatus
.
OK
,
response
.
getStatusCode
());
assertTrue
(
response
.
getBody
().
contains
(
String
.
format
(
"%s=%s"
,
someKey
,
someValue
)));
assertTrue
(
response
.
getBody
().
contains
(
String
.
format
(
"%s=%s"
,
anotherKey
,
anotherValue
)));
ResponseEntity
<
String
>
anotherResponse
=
configFileController
.
queryConfigAsFile
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
someClientIp
,
someResponse
);
assertEquals
(
response
,
anotherResponse
);
verify
(
configController
,
times
(
1
))
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
"-1"
,
someClientIp
,
someResponse
);
}
@Test
public
void
testHandleMessage
()
throws
Exception
{
String
someWatchKey
=
"someWatchKey"
;
String
anotherWatchKey
=
"anotherWatchKey"
;
String
someCacheKey
=
"someCacheKey"
;
String
anotherCacheKey
=
"anotherCacheKey"
;
String
someValue
=
"someValue"
;
ReleaseMessage
someReleaseMessage
=
mock
(
ReleaseMessage
.
class
);
when
(
someReleaseMessage
.
getMessage
()).
thenReturn
(
someWatchKey
);
Cache
<
String
,
String
>
cache
=
(
Cache
<
String
,
String
>)
ReflectionTestUtils
.
getField
(
configFileController
,
"localCache"
);
cache
.
put
(
someCacheKey
,
someValue
);
cache
.
put
(
anotherCacheKey
,
someValue
);
watchedKeys2CacheKey
.
putAll
(
someWatchKey
,
Lists
.
newArrayList
(
someCacheKey
,
anotherCacheKey
));
watchedKeys2CacheKey
.
putAll
(
anotherWatchKey
,
Lists
.
newArrayList
(
someCacheKey
,
anotherCacheKey
));
cacheKey2WatchedKeys
.
putAll
(
someCacheKey
,
Lists
.
newArrayList
(
someWatchKey
,
anotherWatchKey
));
cacheKey2WatchedKeys
.
putAll
(
anotherCacheKey
,
Lists
.
newArrayList
(
someWatchKey
,
anotherWatchKey
));
configFileController
.
handleMessage
(
someReleaseMessage
,
Topics
.
APOLLO_RELEASE_TOPIC
);
assertTrue
(
watchedKeys2CacheKey
.
isEmpty
());
assertTrue
(
cacheKey2WatchedKeys
.
isEmpty
());
}
}
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/controller/NotificationControllerTest.java
View file @
f435f27d
...
...
@@ -11,6 +11,7 @@ import com.ctrip.framework.apollo.biz.service.ReleaseMessageService;
import
com.ctrip.framework.apollo.biz.utils.EntityManagerUtil
;
import
com.ctrip.framework.apollo.common.entity.AppNamespace
;
import
com.ctrip.framework.apollo.configservice.util.NamespaceUtil
;
import
com.ctrip.framework.apollo.configservice.util.WatchKeysUtil
;
import
com.ctrip.framework.apollo.core.ConfigConsts
;
import
com.ctrip.framework.apollo.core.dto.ApolloConfigNotification
;
...
...
@@ -61,10 +62,13 @@ public class NotificationControllerTest {
@Before
public
void
setUp
()
throws
Exception
{
controller
=
new
NotificationController
();
ReflectionTestUtils
.
setField
(
controller
,
"appNamespaceService"
,
appNamespaceService
);
ReflectionTestUtils
.
setField
(
controller
,
"releaseMessageService"
,
releaseMessageService
);
ReflectionTestUtils
.
setField
(
controller
,
"entityManagerUtil"
,
entityManagerUtil
);
ReflectionTestUtils
.
setField
(
controller
,
"namespaceUtil"
,
namespaceUtil
);
WatchKeysUtil
watchKeysUtil
=
new
WatchKeysUtil
();
ReflectionTestUtils
.
setField
(
watchKeysUtil
,
"appNamespaceService"
,
appNamespaceService
);
ReflectionTestUtils
.
setField
(
controller
,
"watchKeysUtil"
,
watchKeysUtil
);
someAppId
=
"someAppId"
;
someCluster
=
"someCluster"
;
...
...
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/AbstractBaseIntegrationTest.java
View file @
f435f27d
package
com
.
ctrip
.
framework
.
apollo
.
configservice
.
integration
;
import
com.google.gson.Gson
;
import
com.ctrip.framework.apollo.ConfigServiceTestConfiguration
;
import
com.ctrip.framework.apollo.biz.entity.Namespace
;
import
com.ctrip.framework.apollo.biz.entity.Release
;
import
com.ctrip.framework.apollo.biz.entity.ReleaseMessage
;
import
com.ctrip.framework.apollo.biz.repository.ReleaseMessageRepository
;
import
com.ctrip.framework.apollo.biz.repository.ReleaseRepository
;
import
com.ctrip.framework.apollo.biz.utils.ReleaseKeyGenerator
;
import
org.junit.runner.RunWith
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.test.SpringApplicationConfiguration
;
import
org.springframework.boot.test.TestRestTemplate
;
...
...
@@ -13,6 +22,9 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import
org.springframework.web.client.DefaultResponseErrorHandler
;
import
org.springframework.web.client.RestTemplate
;
import
java.util.Date
;
import
java.util.Map
;
import
javax.annotation.PostConstruct
;
/**
...
...
@@ -22,6 +34,12 @@ import javax.annotation.PostConstruct;
@SpringApplicationConfiguration
(
classes
=
AbstractBaseIntegrationTest
.
TestConfiguration
.
class
)
@WebIntegrationTest
(
randomPort
=
true
)
public
abstract
class
AbstractBaseIntegrationTest
{
@Autowired
private
ReleaseMessageRepository
releaseMessageRepository
;
@Autowired
private
ReleaseRepository
releaseRepository
;
private
Gson
gson
=
new
Gson
();
RestTemplate
restTemplate
=
new
TestRestTemplate
(
"user"
,
""
);
...
...
@@ -40,8 +58,29 @@ public abstract class AbstractBaseIntegrationTest {
@Configuration
@Import
(
ConfigServiceTestConfiguration
.
class
)
protected
static
class
TestConfiguration
{
}
protected
void
sendReleaseMessage
(
String
message
)
{
ReleaseMessage
releaseMessage
=
new
ReleaseMessage
(
message
);
releaseMessageRepository
.
save
(
releaseMessage
);
}
public
Release
buildRelease
(
String
name
,
String
comment
,
Namespace
namespace
,
Map
<
String
,
String
>
configurations
,
String
owner
)
{
Release
release
=
new
Release
();
release
.
setReleaseKey
(
ReleaseKeyGenerator
.
generateReleaseKey
(
namespace
));
release
.
setDataChangeCreatedTime
(
new
Date
());
release
.
setDataChangeCreatedBy
(
owner
);
release
.
setDataChangeLastModifiedBy
(
owner
);
release
.
setName
(
name
);
release
.
setComment
(
comment
);
release
.
setAppId
(
namespace
.
getAppId
());
release
.
setClusterName
(
namespace
.
getClusterName
());
release
.
setNamespaceName
(
namespace
.
getNamespaceName
());
release
.
setConfigurations
(
gson
.
toJson
(
configurations
));
release
=
releaseRepository
.
save
(
release
);
return
release
;
}
}
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/ConfigFileControllerIntegrationTest.java
0 → 100644
View file @
f435f27d
package
com
.
ctrip
.
framework
.
apollo
.
configservice
.
integration
;
import
com.google.common.collect.ImmutableMap
;
import
com.google.common.collect.Lists
;
import
com.ctrip.framework.apollo.biz.entity.Namespace
;
import
com.ctrip.framework.apollo.core.ConfigConsts
;
import
com.netflix.servo.util.Strings
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.test.context.jdbc.Sql
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.concurrent.TimeUnit
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
ConfigFileControllerIntegrationTest
extends
AbstractBaseIntegrationTest
{
private
String
someAppId
;
private
String
someCluster
;
private
String
someNamespace
;
private
String
somePublicNamespace
;
private
String
someDC
;
private
String
someDefaultCluster
;
@Before
public
void
setUp
()
throws
Exception
{
someDefaultCluster
=
ConfigConsts
.
CLUSTER_NAME_DEFAULT
;
someAppId
=
"someAppId"
;
someCluster
=
"someCluster"
;
someNamespace
=
"someNamespace"
;
somePublicNamespace
=
"somePublicNamespace"
;
someDC
=
"someDC"
;
}
@Test
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testQueryConfigAsFile
()
throws
Exception
{
ResponseEntity
<
String
>
response
=
restTemplate
.
getForEntity
(
"{baseurl}/configfiles/{appId}/{clusterName}/{namespace}"
,
String
.
class
,
getHostUrl
(),
someAppId
,
someCluster
,
someNamespace
);
String
result
=
response
.
getBody
();
assertEquals
(
HttpStatus
.
OK
,
response
.
getStatusCode
());
assertTrue
(
result
.
contains
(
"k2=v2"
));
}
@Test
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/test-release-public-dc-override.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testQueryPublicConfigAsFile
()
throws
Exception
{
ResponseEntity
<
String
>
response
=
restTemplate
.
getForEntity
(
"{baseurl}/configfiles/{appId}/{clusterName}/{namespace}?dataCenter={dateCenter}"
,
String
.
class
,
getHostUrl
(),
someAppId
,
someDefaultCluster
,
somePublicNamespace
,
someDC
);
String
result
=
response
.
getBody
();
assertEquals
(
HttpStatus
.
OK
,
response
.
getStatusCode
());
assertTrue
(
result
.
contains
(
"k1=override-someDC-v1"
));
assertTrue
(
result
.
contains
(
"k2=someDC-v2"
));
}
@Test
@Sql
(
scripts
=
"/integration-test/test-release.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
BEFORE_TEST_METHOD
)
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testConfigChanged
()
throws
Exception
{
ResponseEntity
<
String
>
response
=
restTemplate
.
getForEntity
(
"{baseurl}/configfiles/{appId}/{clusterName}/{namespace}"
,
String
.
class
,
getHostUrl
(),
someAppId
,
someCluster
,
someNamespace
);
String
result
=
response
.
getBody
();
assertEquals
(
HttpStatus
.
OK
,
response
.
getStatusCode
());
assertTrue
(
result
.
contains
(
"k2=v2"
));
String
someReleaseName
=
"someReleaseName"
;
String
someReleaseComment
=
"someReleaseComment"
;
Namespace
namespace
=
new
Namespace
();
namespace
.
setAppId
(
someAppId
);
namespace
.
setClusterName
(
someCluster
);
namespace
.
setNamespaceName
(
someNamespace
);
String
someOwner
=
"someOwner"
;
Map
<
String
,
String
>
newConfigurations
=
ImmutableMap
.
of
(
"k1"
,
"v1-changed"
,
"k2"
,
"v2-changed"
);
buildRelease
(
someReleaseName
,
someReleaseComment
,
namespace
,
newConfigurations
,
someOwner
);
ResponseEntity
<
String
>
anotherResponse
=
restTemplate
.
getForEntity
(
"{baseurl}/configfiles/{appId}/{clusterName}/{namespace}"
,
String
.
class
,
getHostUrl
(),
someAppId
,
someCluster
,
someNamespace
);
assertEquals
(
response
.
getBody
(),
anotherResponse
.
getBody
());
List
<
String
>
keys
=
Lists
.
newArrayList
(
someAppId
,
someCluster
,
someNamespace
);
String
message
=
Strings
.
join
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
,
keys
.
iterator
());
sendReleaseMessage
(
message
);
TimeUnit
.
MILLISECONDS
.
sleep
(
500
);
ResponseEntity
<
String
>
newResponse
=
restTemplate
.
getForEntity
(
"{baseurl}/configfiles/{appId}/{clusterName}/{namespace}"
,
String
.
class
,
getHostUrl
(),
someAppId
,
someCluster
,
someNamespace
);
result
=
newResponse
.
getBody
();
assertEquals
(
HttpStatus
.
OK
,
response
.
getStatusCode
());
assertTrue
(
result
.
contains
(
"k1=v1-changed"
));
assertTrue
(
result
.
contains
(
"k2=v2-changed"
));
}
}
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/NotificationControllerIntegrationTest.java
View file @
f435f27d
...
...
@@ -29,8 +29,7 @@ import static org.junit.Assert.assertNotEquals;
public
class
NotificationControllerIntegrationTest
extends
AbstractBaseIntegrationTest
{
@Autowired
private
NotificationController
notificationController
;
@Autowired
private
ReleaseMessageRepository
releaseMessageRepository
;
private
String
someAppId
;
private
String
someCluster
;
private
String
defaultNamespace
;
...
...
@@ -244,8 +243,7 @@ public class NotificationControllerIntegrationTest extends AbstractBaseIntegrati
break
;
}
ReleaseMessage
releaseMessage
=
new
ReleaseMessage
(
message
);
releaseMessageRepository
.
save
(
releaseMessage
);
sendReleaseMessage
(
message
);
}
});
}
...
...
apollo-core/pom.xml
View file @
f435f27d
...
...
@@ -4,7 +4,7 @@
<parent>
<groupId>
com.ctrip.framework.apollo
</groupId>
<artifactId>
apollo
</artifactId>
<version>
0.0.
5
</version>
<version>
0.0.
6-SNAPSHOT
</version>
<relativePath>
../pom.xml
</relativePath>
</parent>
<modelVersion>
4.0.0
</modelVersion>
...
...
apollo-core/src/main/java/com/ctrip/framework/apollo/core/utils/PropertiesUtil.java
0 → 100644
View file @
f435f27d
package
com
.
ctrip
.
framework
.
apollo
.
core
.
utils
;
import
java.io.IOException
;
import
java.io.StringWriter
;
import
java.util.Properties
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
PropertiesUtil
{
/**
* Transform the properties to string format
* @param properties the properties object
* @return the string containing the properties
* @throws IOException
*/
public
static
String
toString
(
Properties
properties
)
throws
IOException
{
StringWriter
writer
=
new
StringWriter
();
properties
.
store
(
writer
,
null
);
StringBuffer
stringBuffer
=
writer
.
getBuffer
();
filterPropertiesComment
(
stringBuffer
);
return
stringBuffer
.
toString
();
}
/**
* filter out the first comment line
* @param stringBuffer the string buffer
* @return true if filtered successfully, false otherwise
*/
static
boolean
filterPropertiesComment
(
StringBuffer
stringBuffer
)
{
//check whether has comment in the first line
if
(
stringBuffer
.
charAt
(
0
)
!=
'#'
)
{
return
false
;
}
int
commentLineIndex
=
stringBuffer
.
indexOf
(
"\n"
);
if
(
commentLineIndex
==
-
1
)
{
return
false
;
}
stringBuffer
.
delete
(
0
,
commentLineIndex
+
1
);
return
true
;
}
}
apollo-demo/pom.xml
View file @
f435f27d
...
...
@@ -4,7 +4,7 @@
<parent>
<artifactId>
apollo
</artifactId>
<groupId>
com.ctrip.framework.apollo
</groupId>
<version>
0.0.
5
</version>
<version>
0.0.
6-SNAPSHOT
</version>
</parent>
<modelVersion>
4.0.0
</modelVersion>
<artifactId>
apollo-demo
</artifactId>
...
...
apollo-demo/src/main/java/ApolloConfigFileDemo.java
View file @
f435f27d
...
...
@@ -8,6 +8,8 @@ import org.slf4j.LoggerFactory;
import
java.io.BufferedReader
;
import
java.io.IOException
;
import
java.io.InputStreamReader
;
import
java.io.StringReader
;
import
java.util.Properties
;
/**
* @author Jason Song(song_s@ctrip.com)
...
...
@@ -18,7 +20,7 @@ public class ApolloConfigFileDemo {
private
String
namespace
=
"application"
;
public
ApolloConfigFileDemo
()
{
configFile
=
ConfigService
.
getConfigFile
(
namespace
,
ConfigFileFormat
.
XML
);
configFile
=
ConfigService
.
getConfigFile
(
namespace
,
ConfigFileFormat
.
Properties
);
}
private
void
print
()
{
...
...
apollo-portal/pom.xml
View file @
f435f27d
...
...
@@ -4,7 +4,7 @@
<parent>
<groupId>
com.ctrip.framework.apollo
</groupId>
<artifactId>
apollo
</artifactId>
<version>
0.0.
5
</version>
<version>
0.0.
6-SNAPSHOT
</version>
<relativePath>
../pom.xml
</relativePath>
</parent>
<modelVersion>
4.0.0
</modelVersion>
...
...
pom.xml
View file @
f435f27d
...
...
@@ -4,7 +4,7 @@
<modelVersion>
4.0.0
</modelVersion>
<groupId>
com.ctrip.framework.apollo
</groupId>
<artifactId>
apollo
</artifactId>
<version>
0.0.
5
</version>
<version>
0.0.
6-SNAPSHOT
</version>
<name>
Apollo
</name>
<packaging>
pom
</packaging>
<description>
Ctrip Configuration Center
</description>
...
...
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