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
0be1e703
Commit
0be1e703
authored
Apr 28, 2016
by
Jason Song
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use database as MQ, change separator to +.
parent
39fb6a84
Hide whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
580 additions
and
290 deletions
+580
-290
AdminServiceAutoConfiguration.java
...ip/apollo/adminservice/AdminServiceAutoConfiguration.java
+0
-56
ReleaseController.java
...rip/apollo/adminservice/controller/ReleaseController.java
+26
-19
AdminServiceTestConfiguration.java
.../java/com/ctrip/apollo/AdminServiceTestConfiguration.java
+2
-0
ReleaseControllerTest.java
...apollo/adminservice/controller/ReleaseControllerTest.java
+19
-15
TestWebSecurityConfig.java
...apollo/adminservice/controller/TestWebSecurityConfig.java
+4
-0
data.sql
apollo-adminservice/src/test/resources/data.sql
+7
-8
pom.xml
apollo-biz/pom.xml
+0
-4
ReleaseMessage.java
...main/java/com/ctrip/apollo/biz/entity/ReleaseMessage.java
+58
-0
DatabaseMessageSender.java
...a/com/ctrip/apollo/biz/message/DatabaseMessageSender.java
+20
-11
DummyMessageSender.java
...java/com/ctrip/apollo/biz/message/DummyMessageSender.java
+0
-15
ReleaseMessageScanner.java
...a/com/ctrip/apollo/biz/message/ReleaseMessageScanner.java
+145
-0
ReleaseMessageRepository.java
...ctrip/apollo/biz/repository/ReleaseMessageRepository.java
+16
-0
AllTests.java
apollo-biz/src/test/java/com/ctrip/apollo/biz/AllTests.java
+3
-1
DatabaseMessageSenderTest.java
...m/ctrip/apollo/biz/message/DatabaseMessageSenderTest.java
+23
-17
ReleaseMessageScannerTest.java
...m/ctrip/apollo/biz/message/ReleaseMessageScannerTest.java
+87
-0
AbstractConfigRepository.java
.../com/ctrip/apollo/internals/AbstractConfigRepository.java
+1
-1
LocalFileConfigRepository.java
...com/ctrip/apollo/internals/LocalFileConfigRepository.java
+6
-2
RemoteConfigRepository.java
...va/com/ctrip/apollo/internals/RemoteConfigRepository.java
+8
-6
ConfigIntegrationTest.java
...a/com/ctrip/apollo/integration/ConfigIntegrationTest.java
+3
-1
LocalFileConfigRepositoryTest.java
...ctrip/apollo/internals/LocalFileConfigRepositoryTest.java
+5
-3
ConfigServiceAutoConfiguration.java
.../apollo/configservice/ConfigServiceAutoConfiguration.java
+11
-45
ConfigController.java
...rip/apollo/configservice/controller/ConfigController.java
+7
-6
NotificationController.java
...ollo/configservice/controller/NotificationController.java
+26
-15
ConfigServiceTestConfiguration.java
...java/com/ctrip/apollo/ConfigServiceTestConfiguration.java
+3
-1
ConfigControllerTest.java
...apollo/configservice/controller/ConfigControllerTest.java
+3
-1
NotificationControllerTest.java
.../configservice/controller/NotificationControllerTest.java
+21
-15
TestWebSecurityConfig.java
...pollo/configservice/controller/TestWebSecurityConfig.java
+29
-0
ConfigControllerIntegrationTest.java
...gservice/integration/ConfigControllerIntegrationTest.java
+12
-7
NotificationControllerIntegrationTest.java
...ce/integration/NotificationControllerIntegrationTest.java
+31
-41
application.properties
...o-configservice/src/test/resources/application.properties
+3
-0
ConfigConsts.java
...ore/src/main/java/com/ctrip/apollo/core/ConfigConsts.java
+1
-0
No files found.
apollo-adminservice/src/main/java/com/ctrip/apollo/adminservice/AdminServiceAutoConfiguration.java
deleted
100644 → 0
View file @
39fb6a84
package
com
.
ctrip
.
apollo
.
adminservice
;
import
com.ctrip.apollo.biz.message.DummyMessageSender
;
import
com.ctrip.apollo.biz.message.MessageSender
;
import
com.ctrip.apollo.biz.message.RedisMessageSender
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.data.redis.connection.RedisConnectionFactory
;
import
org.springframework.data.redis.connection.jedis.JedisConnectionFactory
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.data.redis.core.StringRedisTemplate
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Configuration
public
class
AdminServiceAutoConfiguration
{
@ConditionalOnProperty
(
value
=
"apollo.redis.enabled"
,
havingValue
=
"true"
,
matchIfMissing
=
false
)
public
static
class
AdminRedisConfiguration
{
@Value
(
"${apollo.redis.host}"
)
private
String
host
;
@Value
(
"${apollo.redis.port}"
)
private
int
port
;
@Bean
public
JedisConnectionFactory
redisConnectionFactory
()
{
JedisConnectionFactory
factory
=
new
JedisConnectionFactory
();
factory
.
setHostName
(
host
);
factory
.
setPort
(
port
);
return
factory
;
}
@Bean
public
RedisTemplate
<
String
,
String
>
redisTemplate
(
RedisConnectionFactory
factory
)
{
StringRedisTemplate
template
=
new
StringRedisTemplate
(
factory
);
return
template
;
}
@Bean
public
MessageSender
redisMessageSender
(
RedisTemplate
<
String
,
String
>
redisTemplate
)
{
return
new
RedisMessageSender
(
redisTemplate
);
}
}
@Configuration
@ConditionalOnProperty
(
value
=
"apollo.redis.enabled"
,
havingValue
=
"false"
,
matchIfMissing
=
true
)
public
static
class
ConfigDefaultConfiguration
{
@Bean
public
MessageSender
defaultMessageSender
()
{
return
new
DummyMessageSender
();
}
}
}
apollo-adminservice/src/main/java/com/ctrip/apollo/adminservice/controller/ReleaseController.java
View file @
0be1e703
package
com
.
ctrip
.
apollo
.
adminservice
.
controller
;
import
java.util.List
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.security.core.userdetails.UserDetails
;
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
com.google.common.base.Joiner
;
import
com.ctrip.apollo.biz.entity.Namespace
;
import
com.ctrip.apollo.biz.entity.Release
;
...
...
@@ -19,9 +11,20 @@ import com.ctrip.apollo.biz.service.NamespaceService;
import
com.ctrip.apollo.biz.service.ReleaseService
;
import
com.ctrip.apollo.common.auth.ActiveUser
;
import
com.ctrip.apollo.common.utils.BeanUtils
;
import
com.ctrip.apollo.core.ConfigConsts
;
import
com.ctrip.apollo.core.dto.ReleaseDTO
;
import
com.ctrip.apollo.core.exception.NotFoundException
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.security.core.userdetails.UserDetails
;
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
java.util.List
;
@RestController
public
class
ReleaseController
{
...
...
@@ -37,26 +40,29 @@ public class ReleaseController {
@Autowired
private
MessageSender
messageSender
;
private
static
final
Joiner
STRING_JOINER
=
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
);
@RequestMapping
(
"/release/{releaseId}"
)
public
ReleaseDTO
get
(
@PathVariable
(
"releaseId"
)
long
releaseId
)
{
Release
release
=
releaseService
.
findOne
(
releaseId
);
if
(
release
==
null
)
if
(
release
==
null
)
{
throw
new
NotFoundException
(
String
.
format
(
"release not found for %s"
,
releaseId
));
}
return
BeanUtils
.
transfrom
(
ReleaseDTO
.
class
,
release
);
}
@RequestMapping
(
"/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases"
)
public
List
<
ReleaseDTO
>
find
(
@PathVariable
(
"appId"
)
String
appId
,
@PathVariable
(
"clusterName"
)
String
clusterName
,
@PathVariable
(
"namespaceName"
)
String
namespaceName
)
{
@PathVariable
(
"clusterName"
)
String
clusterName
,
@PathVariable
(
"namespaceName"
)
String
namespaceName
)
{
List
<
Release
>
releases
=
releaseService
.
findReleases
(
appId
,
clusterName
,
namespaceName
);
return
BeanUtils
.
batchTransform
(
ReleaseDTO
.
class
,
releases
);
}
@RequestMapping
(
"/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases/latest"
)
public
ReleaseDTO
getLatest
(
@PathVariable
(
"appId"
)
String
appId
,
@PathVariable
(
"clusterName"
)
String
clusterName
,
@PathVariable
(
"namespaceName"
)
String
namespaceName
)
{
@PathVariable
(
"clusterName"
)
String
clusterName
,
@PathVariable
(
"namespaceName"
)
String
namespaceName
)
{
Release
release
=
configService
.
findRelease
(
appId
,
clusterName
,
namespaceName
);
if
(
release
==
null
)
{
throw
new
NotFoundException
(
String
.
format
(
"latest release not found for %s %s %s"
,
appId
,
...
...
@@ -68,10 +74,11 @@ public class ReleaseController {
@RequestMapping
(
path
=
"/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases"
,
method
=
RequestMethod
.
POST
)
public
ReleaseDTO
buildRelease
(
@PathVariable
(
"appId"
)
String
appId
,
@PathVariable
(
"clusterName"
)
String
clusterName
,
@PathVariable
(
"namespaceName"
)
String
namespaceName
,
@RequestParam
(
"name"
)
String
name
,
@RequestParam
(
name
=
"comment"
,
required
=
false
)
String
comment
,
@ActiveUser
UserDetails
user
)
{
@PathVariable
(
"clusterName"
)
String
clusterName
,
@PathVariable
(
"namespaceName"
)
String
namespaceName
,
@RequestParam
(
"name"
)
String
name
,
@RequestParam
(
name
=
"comment"
,
required
=
false
)
String
comment
,
@ActiveUser
UserDetails
user
)
{
Namespace
namespace
=
namespaceService
.
findOne
(
appId
,
clusterName
,
namespaceName
);
if
(
namespace
==
null
)
{
throw
new
NotFoundException
(
String
.
format
(
"Could not find namespace for %s %s %s"
,
appId
,
...
...
@@ -84,6 +91,6 @@ public class ReleaseController {
}
private
String
assembleKey
(
String
appId
,
String
cluster
,
String
namespace
)
{
return
S
tring
.
format
(
"%s-%s-%s"
,
appId
,
cluster
,
namespace
);
return
S
TRING_JOINER
.
join
(
appId
,
cluster
,
namespace
);
}
}
apollo-adminservice/src/test/java/com/ctrip/apollo/AdminServiceTestConfiguration.java
View file @
0be1e703
...
...
@@ -5,6 +5,8 @@ import org.springframework.context.annotation.ComponentScan;
import
org.springframework.context.annotation.ComponentScan.Filter
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.FilterType
;
import
org.springframework.security.config.annotation.web.builders.HttpSecurity
;
import
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
;
@Configuration
@ComponentScan
(
excludeFilters
=
{
@Filter
(
type
=
FilterType
.
ASSIGNABLE_TYPE
,
value
=
{
...
...
apollo-adminservice/src/test/java/com/ctrip/apollo/adminservice/controller/ReleaseControllerTest.java
View file @
0be1e703
package
com
.
ctrip
.
apollo
.
adminservice
.
controller
;
import
java.util.HashMap
;
import
java.util.Map
;
import
com.google.common.base.Joiner
;
import
com.google.gson.Gson
;
import
com.ctrip.apollo.biz.entity.Namespace
;
import
com.ctrip.apollo.biz.message.MessageSender
;
import
com.ctrip.apollo.biz.message.Topics
;
import
com.ctrip.apollo.biz.repository.ReleaseRepository
;
import
com.ctrip.apollo.biz.service.NamespaceService
;
import
com.ctrip.apollo.biz.service.ReleaseService
;
import
com.ctrip.apollo.core.ConfigConsts
;
import
com.ctrip.apollo.core.dto.AppDTO
;
import
com.ctrip.apollo.core.dto.ClusterDTO
;
import
com.ctrip.apollo.core.dto.ItemDTO
;
import
com.ctrip.apollo.core.dto.NamespaceDTO
;
import
com.ctrip.apollo.core.dto.ReleaseDTO
;
import
org.junit.Assert
;
import
org.junit.Test
;
...
...
@@ -16,18 +29,8 @@ import org.springframework.test.util.ReflectionTestUtils;
import
org.springframework.util.LinkedMultiValueMap
;
import
org.springframework.util.MultiValueMap
;
import
com.ctrip.apollo.biz.entity.Namespace
;
import
com.ctrip.apollo.biz.message.MessageSender
;
import
com.ctrip.apollo.biz.message.Topics
;
import
com.ctrip.apollo.biz.repository.ReleaseRepository
;
import
com.ctrip.apollo.biz.service.NamespaceService
;
import
com.ctrip.apollo.biz.service.ReleaseService
;
import
com.ctrip.apollo.core.dto.AppDTO
;
import
com.ctrip.apollo.core.dto.ClusterDTO
;
import
com.ctrip.apollo.core.dto.ItemDTO
;
import
com.ctrip.apollo.core.dto.NamespaceDTO
;
import
com.ctrip.apollo.core.dto.ReleaseDTO
;
import
com.google.gson.Gson
;
import
java.util.HashMap
;
import
java.util.Map
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
times
;
...
...
@@ -119,7 +122,8 @@ public class ReleaseControllerTest extends AbstractControllerTest {
.
buildRelease
(
someAppId
,
someCluster
,
someNamespaceName
,
someName
,
someComment
,
someUser
);
verify
(
someMessageSender
,
times
(
1
))
.
sendMessage
(
String
.
format
(
"%s-%s-%s"
,
someAppId
,
someCluster
,
someNamespaceName
),
.
sendMessage
(
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
)
.
join
(
someAppId
,
someCluster
,
someNamespaceName
),
Topics
.
APOLLO_RELEASE_TOPIC
);
}
...
...
apollo-adminservice/src/test/java/com/ctrip/apollo/adminservice/controller/TestWebSecurityConfig.java
View file @
0be1e703
...
...
@@ -15,6 +15,10 @@ public class TestWebSecurityConfig extends WebSecurityConfigurerAdapter {
protected
void
configure
(
HttpSecurity
http
)
throws
Exception
{
http
.
httpBasic
();
http
.
csrf
().
disable
();
http
.
authorizeRequests
().
antMatchers
(
"/"
).
permitAll
().
and
()
.
authorizeRequests
().
antMatchers
(
"/console/**"
).
permitAll
();
http
.
headers
().
frameOptions
().
disable
();
}
@Autowired
...
...
apollo-adminservice/src/test/resources/data.sql
View file @
0be1e703
...
...
@@ -11,24 +11,23 @@ INSERT INTO Cluster (AppId, Name) VALUES ('100003173', 'default');
INSERT
INTO
Cluster
(
AppId
,
Name
)
VALUES
(
'100003173'
,
'cluster3'
);
INSERT
INTO
Cluster
(
AppId
,
Name
)
VALUES
(
'fxhermesproducer'
,
'default'
);
INSERT
INTO
AppNamespace
(
AppId
,
Name
)
VALUES
(
'100003171'
,
'
100003171
'
);
INSERT
INTO
AppNamespace
(
AppId
,
Name
)
VALUES
(
'100003171'
,
'
application
'
);
INSERT
INTO
AppNamespace
(
AppId
,
Name
)
VALUES
(
'100003171'
,
'fx.apollo.config'
);
INSERT
INTO
AppNamespace
(
AppId
,
Name
)
VALUES
(
'100003172'
,
'
100003172
'
);
INSERT
INTO
AppNamespace
(
AppId
,
Name
)
VALUES
(
'100003172'
,
'
application
'
);
INSERT
INTO
AppNamespace
(
AppId
,
Name
)
VALUES
(
'100003172'
,
'fx.apollo.admin'
);
INSERT
INTO
AppNamespace
(
AppId
,
Name
)
VALUES
(
'100003173'
,
'
100003173
'
);
INSERT
INTO
AppNamespace
(
AppId
,
Name
)
VALUES
(
'100003173'
,
'
application
'
);
INSERT
INTO
AppNamespace
(
AppId
,
Name
)
VALUES
(
'100003173'
,
'fx.apollo.portal'
);
INSERT
INTO
AppNamespace
(
AppID
,
Name
)
VALUES
(
'fxhermesproducer'
,
'fx.hermes.producer'
);
INSERT
INTO
Namespace
(
Id
,
AppId
,
ClusterName
,
NamespaceName
)
VALUES
(
1
,
'100003171'
,
'default'
,
'
100003171
'
);
INSERT
INTO
Namespace
(
Id
,
AppId
,
ClusterName
,
NamespaceName
)
VALUES
(
1
,
'100003171'
,
'default'
,
'
application
'
);
INSERT
INTO
Namespace
(
Id
,
AppId
,
ClusterName
,
NamespaceName
)
VALUES
(
2
,
'fxhermesproducer'
,
'default'
,
'fx.hermes.producer'
);
INSERT
INTO
Namespace
(
Id
,
AppId
,
ClusterName
,
NamespaceName
)
VALUES
(
3
,
'100003172'
,
'default'
,
'100003172'
);
INSERT
INTO
Namespace
(
Id
,
AppId
,
ClusterName
,
NamespaceName
)
VALUES
(
4
,
'100003173'
,
'default'
,
'100003173'
);
INSERT
INTO
Namespace
(
Id
,
AppId
,
ClusterName
,
NamespaceName
)
VALUES
(
5
,
'100003171'
,
'default'
,
'100003171'
);
INSERT
INTO
Namespace
(
Id
,
AppId
,
ClusterName
,
NamespaceName
)
VALUES
(
3
,
'100003172'
,
'default'
,
'application'
);
INSERT
INTO
Namespace
(
Id
,
AppId
,
ClusterName
,
NamespaceName
)
VALUES
(
4
,
'100003173'
,
'default'
,
'application'
);
INSERT
INTO
Item
(
NamespaceId
,
`Key`
,
Value
,
Comment
)
VALUES
(
1
,
'k1'
,
'v1'
,
'comment1'
);
INSERT
INTO
Item
(
NamespaceId
,
`Key`
,
Value
,
Comment
)
VALUES
(
1
,
'k2'
,
'v2'
,
'comment2'
);
INSERT
INTO
Item
(
NamespaceId
,
`Key`
,
Value
,
Comment
)
VALUES
(
2
,
'k3'
,
'v3'
,
'comment3'
);
INSERT
INTO
Item
(
NamespaceId
,
`Key`
,
Value
,
Comment
)
VALUES
(
5
,
'k3'
,
'v4'
,
'comment4'
);
INSERT
INTO
RELEASE
(
Name
,
Comment
,
AppId
,
ClusterName
,
NamespaceName
,
Configurations
)
VALUES
(
'REV1'
,
'First Release'
,
'100003171'
,
'default'
,
'
100003171
'
,
'{"k1":"v1"}'
);
INSERT
INTO
RELEASE
(
Name
,
Comment
,
AppId
,
ClusterName
,
NamespaceName
,
Configurations
)
VALUES
(
'REV1'
,
'First Release'
,
'100003171'
,
'default'
,
'
application
'
,
'{"k1":"v1"}'
);
apollo-biz/pom.xml
View file @
0be1e703
...
...
@@ -23,10 +23,6 @@
<artifactId>
spring-boot-starter-data-jpa
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-redis
</artifactId>
</dependency>
<dependency>
<groupId>
mysql
</groupId>
<artifactId>
mysql-connector-java
</artifactId>
</dependency>
...
...
apollo-biz/src/main/java/com/ctrip/apollo/biz/entity/ReleaseMessage.java
0 → 100644
View file @
0be1e703
package
com
.
ctrip
.
apollo
.
biz
.
entity
;
import
java.util.Date
;
import
javax.persistence.Column
;
import
javax.persistence.Entity
;
import
javax.persistence.GeneratedValue
;
import
javax.persistence.Id
;
import
javax.persistence.PrePersist
;
import
javax.persistence.Table
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Entity
@Table
(
name
=
"ReleaseMessage"
)
public
class
ReleaseMessage
{
@Id
@GeneratedValue
@Column
(
name
=
"Id"
)
private
long
id
;
@Column
(
name
=
"Message"
,
nullable
=
false
)
private
String
message
;
@Column
(
name
=
"DataChange_LastTime"
)
private
Date
dataChangeLastModifiedTime
;
@PrePersist
protected
void
prePersist
()
{
if
(
this
.
dataChangeLastModifiedTime
==
null
)
{
dataChangeLastModifiedTime
=
new
Date
();
}
}
public
ReleaseMessage
()
{
}
public
ReleaseMessage
(
String
message
)
{
this
.
message
=
message
;
}
public
long
getId
()
{
return
id
;
}
public
void
setId
(
long
id
)
{
this
.
id
=
id
;
}
public
String
getMessage
()
{
return
message
;
}
public
void
setMessage
(
String
message
)
{
this
.
message
=
message
;
}
}
apollo-biz/src/main/java/com/ctrip/apollo/biz/message/
Redis
MessageSender.java
→
apollo-biz/src/main/java/com/ctrip/apollo/biz/message/
Database
MessageSender.java
View file @
0be1e703
package
com
.
ctrip
.
apollo
.
biz
.
message
;
import
com.ctrip.apollo.biz.entity.ReleaseMessage
;
import
com.ctrip.apollo.biz.repository.ReleaseMessageRepository
;
import
com.dianping.cat.Cat
;
import
com.dianping.cat.message.Message
;
import
com.dianping.cat.message.Transaction
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Component
;
import
java.util.Objects
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
RedisMessageSender
implements
MessageSender
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
RedisMessageSender
.
class
);
private
RedisTemplate
<
String
,
String
>
redisTemplate
;
@Component
public
class
DatabaseMessageSender
implements
MessageSender
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
DatabaseMessageSender
.
class
)
;
public
RedisMessageSender
(
RedisTemplate
<
String
,
String
>
redisTemplate
)
{
this
.
redisTemplate
=
redisTemplate
;
}
@Autowired
private
ReleaseMessageRepository
releaseMessageRepository
;
@Override
public
void
sendMessage
(
String
message
,
String
channel
)
{
logger
.
info
(
"Sending message {} to channel {}"
,
message
,
channel
);
Transaction
transaction
=
Cat
.
newTransaction
(
"Apollo.AdminService"
,
"RedisMessageSender"
);
if
(!
Objects
.
equals
(
channel
,
Topics
.
APOLLO_RELEASE_TOPIC
))
{
logger
.
warn
(
"Channel {} not supported by DatabaseMessageSender!"
);
return
;
}
Cat
.
logEvent
(
"Apollo.AdminService.ReleaseMessage"
,
message
);
Transaction
transaction
=
Cat
.
newTransaction
(
"Apollo.AdminService"
,
"sendMessage"
);
try
{
re
disTemplate
.
convertAndSend
(
channel
,
message
);
re
leaseMessageRepository
.
save
(
new
ReleaseMessage
(
message
)
);
transaction
.
setStatus
(
Message
.
SUCCESS
);
}
catch
(
Throwable
ex
)
{
logger
.
error
(
"Sending message to
redis
failed"
,
ex
);
logger
.
error
(
"Sending message to
database
failed"
,
ex
);
transaction
.
setStatus
(
ex
);
}
finally
{
transaction
.
complete
();
...
...
apollo-biz/src/main/java/com/ctrip/apollo/biz/message/DummyMessageSender.java
deleted
100644 → 0
View file @
39fb6a84
package
com
.
ctrip
.
apollo
.
biz
.
message
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
DummyMessageSender
implements
MessageSender
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
DummyMessageSender
.
class
);
@Override
public
void
sendMessage
(
String
message
,
String
channel
)
{
logger
.
warn
(
"No message sender available! message: {}, channel: {}"
,
message
,
channel
);
}
}
apollo-biz/src/main/java/com/ctrip/apollo/biz/message/ReleaseMessageScanner.java
0 → 100644
View file @
0be1e703
package
com
.
ctrip
.
apollo
.
biz
.
message
;
import
com.google.common.collect.Lists
;
import
com.ctrip.apollo.biz.entity.ReleaseMessage
;
import
com.ctrip.apollo.biz.repository.ReleaseMessageRepository
;
import
com.ctrip.apollo.core.utils.ApolloThreadFactory
;
import
com.dianping.cat.Cat
;
import
com.dianping.cat.message.Message
;
import
com.dianping.cat.message.Transaction
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.InitializingBean
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.core.env.Environment
;
import
org.springframework.util.CollectionUtils
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.ScheduledExecutorService
;
import
java.util.concurrent.TimeUnit
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
ReleaseMessageScanner
implements
InitializingBean
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
ReleaseMessageScanner
.
class
);
private
static
final
int
DEFAULT_SCAN_INTERVAL_IN_MS
=
1000
;
@Autowired
private
Environment
env
;
@Autowired
private
ReleaseMessageRepository
releaseMessageRepository
;
private
int
databaseScanInterval
;
private
List
<
MessageListener
>
listeners
;
private
ScheduledExecutorService
executorService
;
private
long
maxIdScanned
;
public
ReleaseMessageScanner
()
{
listeners
=
Lists
.
newLinkedList
();
executorService
=
Executors
.
newScheduledThreadPool
(
1
,
ApolloThreadFactory
.
create
(
"ReleaseMessageScanner"
,
true
));
}
@Override
public
void
afterPropertiesSet
()
throws
Exception
{
populateDataBaseInterval
();
maxIdScanned
=
loadLargestMessageId
();
executorService
.
scheduleWithFixedDelay
((
Runnable
)
()
->
{
Transaction
transaction
=
Cat
.
newTransaction
(
"Apollo.ReleaseMessageScanner"
,
"scanMessage"
);
try
{
scanMessages
();
transaction
.
setStatus
(
Message
.
SUCCESS
);
}
catch
(
Throwable
ex
)
{
transaction
.
setStatus
(
ex
);
logger
.
error
(
"Scan and send message failed"
,
ex
);
}
finally
{
transaction
.
complete
();
}
},
getDatabaseScanIntervalMs
(),
getDatabaseScanIntervalMs
(),
TimeUnit
.
MILLISECONDS
);
}
/**
* add message listeners for release message
* @param listener
*/
public
void
addMessageListener
(
MessageListener
listener
)
{
if
(!
listeners
.
contains
(
listener
))
{
listeners
.
add
(
listener
);
}
}
/**
* Scan messages, continue scanning until there is no more messages
*/
private
void
scanMessages
()
{
boolean
hasMoreMessages
=
true
;
while
(
hasMoreMessages
&&
!
Thread
.
currentThread
().
isInterrupted
())
{
hasMoreMessages
=
scanAndSendMessages
();
}
}
/**
* scan messages and send
*
* @return whether there are more messages
*/
private
boolean
scanAndSendMessages
()
{
//current batch is 500
List
<
ReleaseMessage
>
releaseMessages
=
releaseMessageRepository
.
findFirst500ByIdGreaterThanOrderByIdAsc
(
maxIdScanned
);
if
(
CollectionUtils
.
isEmpty
(
releaseMessages
))
{
return
false
;
}
fireMessageScanned
(
releaseMessages
);
int
messageScanned
=
releaseMessages
.
size
();
maxIdScanned
=
releaseMessages
.
get
(
messageScanned
-
1
).
getId
();
return
messageScanned
==
500
;
}
/**
* find largest message id as the current start point
* @return current largest message id
*/
private
long
loadLargestMessageId
()
{
ReleaseMessage
releaseMessage
=
releaseMessageRepository
.
findTopByOrderByIdDesc
();
return
releaseMessage
==
null
?
0
:
releaseMessage
.
getId
();
}
/**
* Notify listeners with messages loaded
* @param messages
*/
private
void
fireMessageScanned
(
List
<
ReleaseMessage
>
messages
)
{
for
(
ReleaseMessage
message
:
messages
)
{
for
(
MessageListener
listener
:
listeners
)
{
try
{
listener
.
handleMessage
(
message
.
getMessage
(),
Topics
.
APOLLO_RELEASE_TOPIC
);
}
catch
(
Throwable
ex
)
{
Cat
.
logError
(
ex
);
logger
.
error
(
"Failed to invoke message listener {}"
,
listener
.
getClass
(),
ex
);
}
}
}
}
private
void
populateDataBaseInterval
()
{
databaseScanInterval
=
DEFAULT_SCAN_INTERVAL_IN_MS
;
try
{
String
interval
=
env
.
getProperty
(
"apollo.message-scan.interval"
);
if
(!
Objects
.
isNull
(
interval
))
{
databaseScanInterval
=
Integer
.
parseInt
(
interval
);
}
}
catch
(
Throwable
ex
)
{
Cat
.
logError
(
ex
);
logger
.
error
(
"Load apollo message scan interval from system property failed"
,
ex
);
}
}
private
int
getDatabaseScanIntervalMs
()
{
return
databaseScanInterval
;
}
}
apollo-biz/src/main/java/com/ctrip/apollo/biz/repository/ReleaseMessageRepository.java
0 → 100644
View file @
0be1e703
package
com
.
ctrip
.
apollo
.
biz
.
repository
;
import
com.ctrip.apollo.biz.entity.ReleaseMessage
;
import
org.springframework.data.repository.PagingAndSortingRepository
;
import
java.util.List
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
interface
ReleaseMessageRepository
extends
PagingAndSortingRepository
<
ReleaseMessage
,
Long
>
{
List
<
ReleaseMessage
>
findFirst500ByIdGreaterThanOrderByIdAsc
(
Long
id
);
ReleaseMessage
findTopByOrderByIdDesc
();
}
apollo-biz/src/test/java/com/ctrip/apollo/biz/AllTests.java
View file @
0be1e703
package
com
.
ctrip
.
apollo
.
biz
;
import
com.ctrip.apollo.biz.message.DatabaseMessageSenderTest
;
import
com.ctrip.apollo.biz.repository.AppRepositoryTest
;
import
com.ctrip.apollo.biz.service.AdminServiceTest
;
import
com.ctrip.apollo.biz.service.AdminServiceTransactionTest
;
...
...
@@ -16,7 +17,8 @@ import org.junit.runners.Suite.SuiteClasses;
AdminServiceTest
.
class
,
ConfigServiceTest
.
class
,
PrivilegeServiceTest
.
class
,
AdminServiceTransactionTest
.
class
})
AdminServiceTransactionTest
.
class
,
DatabaseMessageSenderTest
.
class
})
public
class
AllTests
{
}
apollo-biz/src/test/java/com/ctrip/apollo/biz/message/
Redis
MessageSenderTest.java
→
apollo-biz/src/test/java/com/ctrip/apollo/biz/message/
Database
MessageSenderTest.java
View file @
0be1e703
package
com
.
ctrip
.
apollo
.
biz
.
message
;
import
com.ctrip.apollo.biz.entity.ReleaseMessage
;
import
com.ctrip.apollo.biz.repository.ReleaseMessageRepository
;
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.springframework.
data.redis.core.RedisTemplate
;
import
org.springframework.
test.util.ReflectionTestUtils
;
import
static
org
.
mockito
.
Mockito
.
doThrow
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
mockito
.
Mockito
.
any
;
import
static
org
.
mockito
.
Mockito
.
never
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
...
...
@@ -15,35 +21,35 @@ import static org.mockito.Mockito.verify;
* @author Jason Song(song_s@ctrip.com)
*/
@RunWith
(
MockitoJUnitRunner
.
class
)
public
class
RedisMessageSenderTest
{
public
class
DatabaseMessageSenderTest
{
private
DatabaseMessageSender
messageSender
;
@Mock
private
RedisTemplate
<
String
,
String
>
redisTemplate
;
private
RedisMessageSender
redisMessageSender
;
private
ReleaseMessageRepository
releaseMessageRepository
;
@Before
public
void
setUp
()
throws
Exception
{
redisMessageSender
=
new
RedisMessageSender
(
redisTemplate
);
messageSender
=
new
DatabaseMessageSender
();
ReflectionTestUtils
.
setField
(
messageSender
,
"releaseMessageRepository"
,
releaseMessageRepository
);
}
@Test
public
void
testSendMessage
()
throws
Exception
{
String
someMessage
=
"some
M
essage"
;
String
someChannel
=
"someChannel"
;
String
someMessage
=
"some
-m
essage"
;
ArgumentCaptor
<
ReleaseMessage
>
captor
=
ArgumentCaptor
.
forClass
(
ReleaseMessage
.
class
)
;
redisMessageSender
.
sendMessage
(
someMessage
,
someChannel
);
messageSender
.
sendMessage
(
someMessage
,
Topics
.
APOLLO_RELEASE_TOPIC
);
verify
(
redisTemplate
,
times
(
1
)).
convertAndSend
(
someChannel
,
someMessage
);
verify
(
releaseMessageRepository
,
times
(
1
)).
save
(
captor
.
capture
());
assertEquals
(
someMessage
,
captor
.
getValue
().
getMessage
());
}
@Test
public
void
testSendMessageWithError
()
throws
Exception
{
String
someMessage
=
"someMessage"
;
String
someChannel
=
"someChannel"
;
doThrow
(
new
RuntimeException
()).
when
(
redisTemplate
).
convertAndSend
(
someChannel
,
someMessage
);
public
void
testSendUnsupportedMessage
()
throws
Exception
{
String
someMessage
=
"some-message"
;
String
someUnsupportedTopic
=
"some-invalid-topic"
;
redisMessageSender
.
sendMessage
(
someMessage
,
someChannel
);
messageSender
.
sendMessage
(
someMessage
,
someUnsupportedTopic
);
verify
(
releaseMessageRepository
,
never
()).
save
(
any
(
ReleaseMessage
.
class
));
}
}
apollo-biz/src/test/java/com/ctrip/apollo/biz/message/ReleaseMessageScannerTest.java
0 → 100644
View file @
0be1e703
package
com
.
ctrip
.
apollo
.
biz
.
message
;
import
com.google.common.collect.Lists
;
import
com.google.common.util.concurrent.SettableFuture
;
import
com.ctrip.apollo.biz.entity.ReleaseMessage
;
import
com.ctrip.apollo.biz.repository.ReleaseMessageRepository
;
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.core.env.Environment
;
import
org.springframework.test.util.ReflectionTestUtils
;
import
java.util.concurrent.TimeUnit
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
mockito
.
Mockito
.
when
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@RunWith
(
MockitoJUnitRunner
.
class
)
public
class
ReleaseMessageScannerTest
{
private
ReleaseMessageScanner
releaseMessageScanner
;
@Mock
private
ReleaseMessageRepository
releaseMessageRepository
;
@Mock
private
Environment
env
;
private
int
databaseScanInterval
;
@Before
public
void
setUp
()
throws
Exception
{
releaseMessageScanner
=
new
ReleaseMessageScanner
();
ReflectionTestUtils
.
setField
(
releaseMessageScanner
,
"releaseMessageRepository"
,
releaseMessageRepository
);
ReflectionTestUtils
.
setField
(
releaseMessageScanner
,
"env"
,
env
);
databaseScanInterval
=
100
;
//100 ms
when
(
env
.
getProperty
(
"apollo.message-scan.interval"
)).
thenReturn
(
String
.
valueOf
(
databaseScanInterval
));
releaseMessageScanner
.
afterPropertiesSet
();
}
@Test
public
void
testScanMessageAndNotifyMessageListener
()
throws
Exception
{
SettableFuture
<
String
>
someListenerFuture
=
SettableFuture
.
create
();
MessageListener
someListener
=
(
message
,
channel
)
->
someListenerFuture
.
set
(
message
);
releaseMessageScanner
.
addMessageListener
(
someListener
);
String
someMessage
=
"someMessage"
;
long
someId
=
100
;
ReleaseMessage
someReleaseMessage
=
assembleReleaseMessage
(
someId
,
someMessage
);
when
(
releaseMessageRepository
.
findFirst500ByIdGreaterThanOrderByIdAsc
(
0L
)).
thenReturn
(
Lists
.
newArrayList
(
someReleaseMessage
));
String
someListenerMessage
=
someListenerFuture
.
get
(
5000
,
TimeUnit
.
MILLISECONDS
);
assertEquals
(
someMessage
,
someListenerMessage
);
SettableFuture
<
String
>
anotherListenerFuture
=
SettableFuture
.
create
();
MessageListener
anotherListener
=
(
message
,
channel
)
->
anotherListenerFuture
.
set
(
message
);
releaseMessageScanner
.
addMessageListener
(
anotherListener
);
String
anotherMessage
=
"anotherMessage"
;
long
anotherId
=
someId
+
1
;
ReleaseMessage
anotherReleaseMessage
=
assembleReleaseMessage
(
anotherId
,
anotherMessage
);
when
(
releaseMessageRepository
.
findFirst500ByIdGreaterThanOrderByIdAsc
(
someId
)).
thenReturn
(
Lists
.
newArrayList
(
anotherReleaseMessage
));
String
anotherListenerMessage
=
anotherListenerFuture
.
get
(
5000
,
TimeUnit
.
MILLISECONDS
);
assertEquals
(
anotherMessage
,
anotherListenerMessage
);
}
private
ReleaseMessage
assembleReleaseMessage
(
long
id
,
String
message
)
{
ReleaseMessage
releaseMessage
=
new
ReleaseMessage
();
releaseMessage
.
setId
(
id
);
releaseMessage
.
setMessage
(
message
);
return
releaseMessage
;
}
}
apollo-client/src/main/java/com/ctrip/apollo/internals/AbstractConfigRepository.java
View file @
0be1e703
...
...
@@ -25,7 +25,7 @@ public abstract class AbstractConfigRepository implements ConfigRepository {
}
catch
(
Throwable
ex
)
{
Cat
.
logError
(
ex
);
logger
.
warn
(
"Sync config failed
with r
epository {}, reason: {}"
,
this
.
getClass
(),
ExceptionUtil
.
warn
(
"Sync config failed
, will retry. R
epository {}, reason: {}"
,
this
.
getClass
(),
ExceptionUtil
.
getDetailMessage
(
ex
));
}
return
false
;
...
...
apollo-client/src/main/java/com/ctrip/apollo/internals/LocalFileConfigRepository.java
View file @
0be1e703
package
com
.
ctrip
.
apollo
.
internals
;
import
com.google.common.base.Joiner
;
import
com.google.common.base.Preconditions
;
import
com.ctrip.apollo.core.ConfigConsts
;
import
com.ctrip.apollo.util.ConfigUtil
;
import
com.ctrip.apollo.util.ExceptionUtil
;
import
com.dianping.cat.Cat
;
...
...
@@ -202,8 +204,10 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
}
File
assembleLocalCacheFile
(
File
baseDir
,
String
namespace
)
{
String
fileName
=
String
.
format
(
"%s-%s-%s.properties"
,
m_configUtil
.
getAppId
(),
m_configUtil
.
getCluster
(),
namespace
);
String
fileName
=
String
.
format
(
"%s.properties"
,
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
)
.
join
(
m_configUtil
.
getAppId
(),
m_configUtil
.
getCluster
(),
namespace
));
return
new
File
(
baseDir
,
fileName
);
}
}
apollo-client/src/main/java/com/ctrip/apollo/internals/RemoteConfigRepository.java
View file @
0be1e703
...
...
@@ -7,6 +7,7 @@ import com.google.common.collect.Maps;
import
com.google.common.escape.Escaper
;
import
com.google.common.net.UrlEscapers
;
import
com.ctrip.apollo.core.ConfigConsts
;
import
com.ctrip.apollo.core.dto.ApolloConfig
;
import
com.ctrip.apollo.core.dto.ApolloConfigNotification
;
import
com.ctrip.apollo.core.dto.ServiceDTO
;
...
...
@@ -43,6 +44,8 @@ import java.util.concurrent.atomic.AtomicReference;
*/
public
class
RemoteConfigRepository
extends
AbstractConfigRepository
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
RemoteConfigRepository
.
class
);
private
static
final
Joiner
STRING_JOINER
=
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
);
private
static
final
Joiner
.
MapJoiner
MAP_JOINER
=
Joiner
.
on
(
"&"
).
withKeyValueSeparator
(
"="
);
private
PlexusContainer
m_container
;
private
final
ConfigServiceLocator
m_serviceLocator
;
private
final
HttpUtil
m_httpUtil
;
...
...
@@ -135,8 +138,7 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
String
appId
=
m_configUtil
.
getAppId
();
String
cluster
=
m_configUtil
.
getCluster
();
String
dataCenter
=
m_configUtil
.
getDataCenter
();
Cat
.
logEvent
(
"Apollo.Client.ConfigInfo"
,
String
.
format
(
"%s-%s-%s"
,
appId
,
cluster
,
m_namespace
));
Cat
.
logEvent
(
"Apollo.Client.ConfigInfo"
,
STRING_JOINER
.
join
(
appId
,
cluster
,
m_namespace
));
int
maxRetries
=
2
;
Throwable
exception
=
null
;
...
...
@@ -214,7 +216,7 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
String
pathExpanded
=
String
.
format
(
path
,
pathParams
.
toArray
());
if
(!
queryParams
.
isEmpty
())
{
pathExpanded
+=
"?"
+
Joiner
.
on
(
"&"
).
withKeyValueSeparator
(
"="
)
.
join
(
queryParams
);
pathExpanded
+=
"?"
+
MAP_JOINER
.
join
(
queryParams
);
}
if
(!
uri
.
endsWith
(
"/"
))
{
uri
+=
"/"
;
...
...
@@ -276,7 +278,7 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
transaction
.
addData
(
"StatusCode"
,
response
.
getStatusCode
());
transaction
.
setStatus
(
Message
.
SUCCESS
);
}
catch
(
Throwable
ex
)
{
logger
.
warn
(
"Long polling failed
for
appId: {}, cluster: {}, namespace: {}, reason: {}"
,
logger
.
warn
(
"Long polling failed
, will retry.
appId: {}, cluster: {}, namespace: {}, reason: {}"
,
appId
,
cluster
,
m_namespace
,
ExceptionUtil
.
getDetailMessage
(
ex
));
lastServiceDto
=
null
;
Cat
.
logError
(
ex
);
...
...
@@ -284,7 +286,7 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
transaction
.
setStatus
(
ex
);
}
try
{
TimeUnit
.
SECONDS
.
sleep
(
10
);
TimeUnit
.
SECONDS
.
sleep
(
5
);
}
catch
(
InterruptedException
ie
)
{
//ignore
}
...
...
@@ -314,7 +316,7 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
queryParams
.
put
(
"releaseId"
,
escaper
.
escape
(
previousConfig
.
getReleaseId
()));
}
String
params
=
Joiner
.
on
(
"&"
).
withKeyValueSeparator
(
"="
)
.
join
(
queryParams
);
String
params
=
MAP_JOINER
.
join
(
queryParams
);
if
(!
uri
.
endsWith
(
"/"
))
{
uri
+=
"/"
;
}
...
...
apollo-client/src/test/java/com/ctrip/apollo/integration/ConfigIntegrationTest.java
View file @
0be1e703
package
com
.
ctrip
.
apollo
.
integration
;
import
com.google.common.base.Joiner
;
import
com.google.common.collect.ImmutableMap
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Maps
;
...
...
@@ -350,6 +351,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
}
private
String
assembleLocalCacheFileName
()
{
return
String
.
format
(
"%s-%s-%s.properties"
,
someAppId
,
someClusterName
,
defaultNamespace
);
return
String
.
format
(
"%s.properties"
,
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
)
.
join
(
someAppId
,
someClusterName
,
defaultNamespace
));
}
}
apollo-client/src/test/java/com/ctrip/apollo/internals/LocalFileConfigRepositoryTest.java
View file @
0be1e703
package
com
.
ctrip
.
apollo
.
internals
;
import
com.google.common.base.Charsets
;
import
com.google.common.base.Joiner
;
import
com.google.common.io.Files
;
import
com.ctrip.apollo.core.ConfigConsts
;
import
com.ctrip.apollo.util.ConfigUtil
;
import
org.junit.After
;
...
...
@@ -73,8 +75,8 @@ public class LocalFileConfigRepositoryTest extends ComponentTestCase {
}
private
String
assembleLocalCacheFileName
()
{
return
String
.
format
(
"%s
-%s-%s.properties"
,
someAppId
,
someCluster
,
someNamespace
);
return
String
.
format
(
"%s
.properties"
,
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
)
.
join
(
someAppId
,
someCluster
,
someNamespace
)
);
}
...
...
@@ -144,7 +146,7 @@ public class LocalFileConfigRepositoryTest extends ComponentTestCase {
assertThat
(
"LocalFileConfigRepository should persist local cache files and return that afterwards"
,
someProperties
.
entrySet
(),
equalTo
(
anotherProperties
.
entrySet
()));
someProperties
.
entrySet
(),
equalTo
(
anotherProperties
.
entrySet
()));
}
...
...
apollo-configservice/src/main/java/com/ctrip/apollo/configservice/ConfigServiceAutoConfiguration.java
View file @
0be1e703
package
com
.
ctrip
.
apollo
.
configservice
;
import
com.ctrip.apollo.biz.message.
Topics
;
import
com.ctrip.apollo.biz.message.
ReleaseMessageScanner
;
import
com.ctrip.apollo.configservice.controller.NotificationController
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.data.redis.connection.RedisConnectionFactory
;
import
org.springframework.data.redis.connection.jedis.JedisConnectionFactory
;
import
org.springframework.data.redis.listener.ChannelTopic
;
import
org.springframework.data.redis.listener.RedisMessageListenerContainer
;
import
org.springframework.data.redis.listener.adapter.MessageListenerAdapter
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Configuration
public
class
ConfigServiceAutoConfiguration
{
@ConditionalOnProperty
(
value
=
"apollo.redis.enabled"
,
havingValue
=
"true"
,
matchIfMissing
=
false
)
public
static
class
ConfigRedisConfiguration
{
@Value
(
"${apollo.redis.host}"
)
private
String
host
;
@Value
(
"${apollo.redis.port}"
)
private
int
port
;
@Bean
public
JedisConnectionFactory
redisConnectionFactory
()
{
JedisConnectionFactory
factory
=
new
JedisConnectionFactory
();
factory
.
setHostName
(
host
);
factory
.
setPort
(
port
);
return
factory
;
}
@Bean
public
RedisMessageListenerContainer
redisMessageListenerContainer
(
RedisConnectionFactory
factory
)
{
RedisMessageListenerContainer
container
=
new
RedisMessageListenerContainer
();
container
.
setConnectionFactory
(
factory
);
return
container
;
}
@Bean
public
ChannelTopic
apolloReleaseTopic
()
{
return
new
ChannelTopic
(
Topics
.
APOLLO_RELEASE_TOPIC
);
}
@Bean
public
MessageListenerAdapter
apolloMessageListener
(
RedisMessageListenerContainer
container
,
NotificationController
notification
,
ChannelTopic
topic
)
{
MessageListenerAdapter
adapter
=
new
MessageListenerAdapter
(
notification
);
container
.
addMessageListener
(
adapter
,
topic
);
return
adapter
;
}
@Autowired
private
NotificationController
notificationController
;
@Bean
public
ReleaseMessageScanner
releaseMessageScanner
()
{
ReleaseMessageScanner
releaseMessageScanner
=
new
ReleaseMessageScanner
();
releaseMessageScanner
.
addMessageListener
(
notificationController
);
return
releaseMessageScanner
;
}
}
apollo-configservice/src/main/java/com/ctrip/apollo/configservice/controller/ConfigController.java
View file @
0be1e703
...
...
@@ -42,10 +42,11 @@ public class ConfigController {
@Autowired
private
AppNamespaceService
appNamespaceService
;
private
Gson
gson
=
new
Gson
();
private
Type
configurationTypeReference
=
private
static
final
Gson
gson
=
new
Gson
();
private
static
final
Type
configurationTypeReference
=
new
TypeToken
<
Map
<
java
.
lang
.
String
,
java
.
lang
.
String
>>()
{
}.
getType
();
private
static
final
Joiner
STRING_JOINER
=
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
);
@RequestMapping
(
value
=
"/{appId}/{clusterName}"
,
method
=
RequestMethod
.
GET
)
public
ApolloConfig
queryConfig
(
@PathVariable
String
appId
,
@PathVariable
String
clusterName
,
...
...
@@ -89,7 +90,7 @@ public class ConfigController {
}
String
mergedReleaseId
=
FluentIterable
.
from
(
releases
).
transform
(
input
->
String
.
valueOf
(
input
.
getId
())).
join
(
Joiner
.
on
(
"|"
)
);
input
->
String
.
valueOf
(
input
.
getId
())).
join
(
STRING_JOINER
);
if
(
mergedReleaseId
.
equals
(
clientSideReleaseId
))
{
// Client side configuration is the same with server side, return 304
...
...
@@ -148,11 +149,11 @@ public class ConfigController {
}
private
String
assembleKey
(
String
appId
,
String
cluster
,
String
namespace
,
String
datacenter
)
{
String
key
=
String
.
format
(
"%s-%s-%s"
,
appId
,
cluster
,
namespace
);
List
<
String
>
keyParts
=
Lists
.
newArrayList
(
appId
,
cluster
,
namespace
);
if
(!
Strings
.
isNullOrEmpty
(
datacenter
))
{
key
+=
"-"
+
datacenter
;
key
Parts
.
add
(
datacenter
)
;
}
return
key
;
return
STRING_JOINER
.
join
(
keyParts
)
;
}
}
apollo-configservice/src/main/java/com/ctrip/apollo/configservice/controller/NotificationController.java
View file @
0be1e703
package
com
.
ctrip
.
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
;
...
...
@@ -29,8 +31,6 @@ import java.util.Collection;
import
java.util.List
;
import
java.util.Objects
;
import
javax.servlet.http.HttpServletResponse
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
...
...
@@ -40,8 +40,12 @@ public class NotificationController implements MessageListener {
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
NotificationController
.
class
);
private
static
final
long
TIMEOUT
=
360
*
60
*
1000
;
//6 hours
private
final
Multimap
<
String
,
DeferredResult
<
ResponseEntity
<
ApolloConfigNotification
>>>
deferredResults
=
Multimaps
.
synchronizedSetMultimap
(
HashMultimap
.
create
());
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
);
@Autowired
private
AppNamespaceService
appNamespaceService
;
...
...
@@ -52,8 +56,7 @@ public class NotificationController implements MessageListener {
@RequestParam
(
value
=
"cluster"
)
String
cluster
,
@RequestParam
(
value
=
"namespace"
,
defaultValue
=
ConfigConsts
.
NAMESPACE_DEFAULT
)
String
namespace
,
@RequestParam
(
value
=
"dataCenter"
,
required
=
false
)
String
dataCenter
,
@RequestParam
(
value
=
"releaseId"
,
defaultValue
=
"-1"
)
String
clientSideReleaseId
,
HttpServletResponse
response
)
{
@RequestParam
(
value
=
"releaseId"
,
defaultValue
=
"-1"
)
String
clientSideReleaseId
)
{
List
<
String
>
watchedKeys
=
Lists
.
newArrayList
(
assembleKey
(
appId
,
cluster
,
namespace
));
//Listen on more namespaces, since it's not the default namespace
...
...
@@ -61,30 +64,32 @@ public class NotificationController implements MessageListener {
watchedKeys
.
addAll
(
this
.
findPublicConfigWatchKey
(
appId
,
namespace
,
dataCenter
));
}
ResponseEntity
<
ApolloConfigNotification
>
body
=
new
ResponseEntity
<>(
HttpStatus
.
NOT_MODIFIED
);
DeferredResult
<
ResponseEntity
<
ApolloConfigNotification
>>
deferredResult
=
new
DeferredResult
<>(
TIMEOUT
,
body
);
new
DeferredResult
<>(
TIMEOUT
,
NOT_MODIFIED_RESPONSE
);
//register all keys
for
(
String
key
:
watchedKeys
)
{
this
.
deferredResults
.
put
(
key
,
deferredResult
);
}
deferredResult
.
onTimeout
(()
->
logWatchedKeysToCat
(
watchedKeys
,
"Apollo.LongPoll.TimeOutKeys"
));
deferredResult
.
onCompletion
(()
->
{
//unregister all keys
for
(
String
key
:
watchedKeys
)
{
deferredResults
.
remove
(
key
,
deferredResult
);
}
logWatchedKeysToCat
(
watchedKeys
,
"Apollo.LongPoll.CompletedKeys"
);
});
logWatchedKeysToCat
(
watchedKeys
,
"Apollo.LongPoll.RegisteredKeys"
);
logger
.
info
(
"Listening {} from appId: {}, cluster: {}, namespace: {}, datacenter: {}"
,
watchedKeys
,
appId
,
cluster
,
namespace
,
dataCenter
);
return
deferredResult
;
}
private
String
assembleKey
(
String
appId
,
String
cluster
,
String
namespace
)
{
return
S
tring
.
format
(
"%s-%s-%s"
,
appId
,
cluster
,
namespace
);
return
S
TRING_JOINER
.
join
(
appId
,
cluster
,
namespace
);
}
private
List
<
String
>
findPublicConfigWatchKey
(
String
applicationId
,
String
namespace
,
...
...
@@ -114,20 +119,20 @@ public class NotificationController implements MessageListener {
@Override
public
void
handleMessage
(
String
message
,
String
channel
)
{
logger
.
info
(
"message received - channel: {}, message: {}"
,
channel
,
message
);
Cat
.
logEvent
(
"Apollo.LongPoll.Message"
,
message
);
Cat
.
logEvent
(
"Apollo.LongPoll.Message
s
"
,
message
);
if
(!
Topics
.
APOLLO_RELEASE_TOPIC
.
equals
(
channel
)
||
Strings
.
isNullOrEmpty
(
message
))
{
return
;
}
String
[]
keys
=
message
.
split
(
"-"
);
//message should be appId
-cluster-
namespace
if
(
keys
.
length
!=
3
)
{
List
<
String
>
keys
=
STRING_SPLITTER
.
splitToList
(
message
);
//message should be appId
|cluster|
namespace
if
(
keys
.
size
()
!=
3
)
{
logger
.
error
(
"message format invalid - {}"
,
message
);
return
;
}
ResponseEntity
<
ApolloConfigNotification
>
notification
=
new
ResponseEntity
<>(
new
ApolloConfigNotification
(
keys
[
2
]
),
HttpStatus
.
OK
);
new
ApolloConfigNotification
(
keys
.
get
(
2
)
),
HttpStatus
.
OK
);
Collection
<
DeferredResult
<
ResponseEntity
<
ApolloConfigNotification
>>>
results
=
deferredResults
.
get
(
message
);
...
...
@@ -137,5 +142,11 @@ public class NotificationController implements MessageListener {
result
.
setResult
(
notification
);
}
}
private
void
logWatchedKeysToCat
(
List
<
String
>
watchedKeys
,
String
eventName
)
{
for
(
String
watchedKey
:
watchedKeys
)
{
Cat
.
logEvent
(
eventName
,
watchedKey
);
}
}
}
apollo-configservice/src/test/java/com/ctrip/apollo/ConfigServiceTestConfiguration.java
View file @
0be1e703
package
com
.
ctrip
.
apollo
;
import
com.ctrip.apollo.common.controller.WebSecurityConfig
;
import
org.springframework.boot.autoconfigure.EnableAutoConfiguration
;
import
org.springframework.context.annotation.ComponentScan
;
import
org.springframework.context.annotation.ComponentScan.Filter
;
...
...
@@ -8,7 +10,7 @@ import org.springframework.context.annotation.FilterType;
@Configuration
@ComponentScan
(
excludeFilters
=
{
@Filter
(
type
=
FilterType
.
ASSIGNABLE_TYPE
,
value
=
{
SampleConfigServiceApplication
.
class
,
ConfigServiceApplication
.
class
})})
SampleConfigServiceApplication
.
class
,
ConfigServiceApplication
.
class
,
WebSecurityConfig
.
class
})})
@EnableAutoConfiguration
public
class
ConfigServiceTestConfiguration
{
...
...
apollo-configservice/src/test/java/com/ctrip/apollo/configservice/controller/ConfigControllerTest.java
View file @
0be1e703
package
com
.
ctrip
.
apollo
.
configservice
.
controller
;
import
com.google.common.base.Joiner
;
import
com.google.common.collect.ImmutableMap
;
import
com.google.common.collect.Lists
;
import
com.google.gson.Gson
;
...
...
@@ -243,7 +244,8 @@ public class ConfigControllerTest {
.
queryConfig
(
someAppId
,
someClusterName
,
somePublicNamespaceName
,
someDataCenter
,
someAppSideReleaseId
,
someResponse
);
assertEquals
(
String
.
format
(
"%s|%s"
,
someAppSideReleaseId
,
somePublicAppSideReleaseId
),
assertEquals
(
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
)
.
join
(
someAppSideReleaseId
,
somePublicAppSideReleaseId
),
result
.
getReleaseId
());
assertEquals
(
someAppId
,
result
.
getAppId
());
assertEquals
(
someClusterName
,
result
.
getCluster
());
...
...
apollo-configservice/src/test/java/com/ctrip/apollo/configservice/controller/NotificationControllerTest.java
View file @
0be1e703
package
com
.
ctrip
.
apollo
.
configservice
.
controller
;
import
com.google.common.base.Joiner
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Multimap
;
...
...
@@ -40,8 +41,6 @@ public class NotificationControllerTest {
private
String
someDataCenter
;
private
String
someReleaseId
;
@Mock
private
HttpServletResponse
response
;
@Mock
private
AppNamespaceService
appNamespaceService
;
private
Multimap
<
String
,
DeferredResult
<
ResponseEntity
<
ApolloConfigNotification
>>>
deferredResults
;
...
...
@@ -67,10 +66,11 @@ public class NotificationControllerTest {
public
void
testPollNotificationWithDefaultNamespace
()
throws
Exception
{
DeferredResult
<
ResponseEntity
<
ApolloConfigNotification
>>
deferredResult
=
controller
.
pollNotification
(
someAppId
,
someCluster
,
defaultNamespace
,
someDataCenter
,
someReleaseId
,
response
);
.
pollNotification
(
someAppId
,
someCluster
,
defaultNamespace
,
someDataCenter
,
someReleaseId
);
String
key
=
String
.
format
(
"%s-%s-%s"
,
someAppId
,
someCluster
,
defaultNamespace
);
String
key
=
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
)
.
join
(
someAppId
,
someCluster
,
defaultNamespace
);
assertEquals
(
1
,
deferredResults
.
size
());
assertTrue
(
deferredResults
.
get
(
key
).
contains
(
deferredResult
));
}
...
...
@@ -87,18 +87,21 @@ public class NotificationControllerTest {
DeferredResult
<
ResponseEntity
<
ApolloConfigNotification
>>
deferredResult
=
controller
.
pollNotification
(
someAppId
,
someCluster
,
somePublicNamespace
,
someDataCenter
,
someReleaseId
,
response
);
someReleaseId
);
List
<
String
>
publicClusters
=
Lists
.
newArrayList
(
someDataCenter
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
);
assertEquals
(
3
,
deferredResults
.
size
());
String
key
=
String
.
format
(
"%s-%s-%s"
,
someAppId
,
someCluster
,
somePublicNamespace
);
String
key
=
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
)
.
join
(
someAppId
,
someCluster
,
somePublicNamespace
);
assertTrue
(
deferredResults
.
get
(
key
).
contains
(
deferredResult
));
for
(
String
cluster
:
publicClusters
)
{
String
publicKey
=
String
.
format
(
"%s-%s-%s"
,
somePublicAppId
,
cluster
,
somePublicNamespace
);
String
publicKey
=
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
)
.
join
(
somePublicAppId
,
cluster
,
somePublicNamespace
);
assertTrue
(
deferredResults
.
get
(
publicKey
).
contains
(
deferredResult
));
}
}
...
...
@@ -107,10 +110,11 @@ public class NotificationControllerTest {
public
void
testPollNotificationWithDefaultNamespaceAndHandleMessage
()
throws
Exception
{
DeferredResult
<
ResponseEntity
<
ApolloConfigNotification
>>
deferredResult
=
controller
.
pollNotification
(
someAppId
,
someCluster
,
defaultNamespace
,
someDataCenter
,
someReleaseId
,
response
);
.
pollNotification
(
someAppId
,
someCluster
,
defaultNamespace
,
someDataCenter
,
someReleaseId
);
String
key
=
String
.
format
(
"%s-%s-%s"
,
someAppId
,
someCluster
,
defaultNamespace
);
String
key
=
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
)
.
join
(
someAppId
,
someCluster
,
defaultNamespace
);
controller
.
handleMessage
(
key
,
Topics
.
APOLLO_RELEASE_TOPIC
);
...
...
@@ -133,10 +137,12 @@ public class NotificationControllerTest {
DeferredResult
<
ResponseEntity
<
ApolloConfigNotification
>>
deferredResult
=
controller
.
pollNotification
(
someAppId
,
someCluster
,
somePublicNamespace
,
someDataCenter
,
someReleaseId
,
response
);
.
pollNotification
(
someAppId
,
someCluster
,
somePublicNamespace
,
someDataCenter
,
someReleaseId
);
String
key
=
String
.
format
(
"%s-%s-%s"
,
somePublicAppId
,
someDataCenter
,
somePublicNamespace
);
String
key
=
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
)
.
join
(
somePublicAppId
,
someDataCenter
,
somePublicNamespace
);
controller
.
handleMessage
(
key
,
Topics
.
APOLLO_RELEASE_TOPIC
);
...
...
apollo-configservice/src/test/java/com/ctrip/apollo/configservice/controller/TestWebSecurityConfig.java
0 → 100644
View file @
0be1e703
package
com
.
ctrip
.
apollo
.
configservice
.
controller
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.core.annotation.Order
;
import
org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
;
import
org.springframework.security.config.annotation.web.builders.HttpSecurity
;
import
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
;
@Configuration
@Order
(
99
)
public
class
TestWebSecurityConfig
extends
WebSecurityConfigurerAdapter
{
@Override
protected
void
configure
(
HttpSecurity
http
)
throws
Exception
{
http
.
httpBasic
();
http
.
csrf
().
disable
();
http
.
authorizeRequests
().
antMatchers
(
"/"
).
permitAll
().
and
()
.
authorizeRequests
().
antMatchers
(
"/console/**"
).
permitAll
();
http
.
headers
().
frameOptions
().
disable
();
}
@Autowired
public
void
configureGlobal
(
AuthenticationManagerBuilder
auth
)
throws
Exception
{
auth
.
inMemoryAuthentication
().
withUser
(
"user"
).
password
(
""
).
roles
(
"USER"
);
auth
.
inMemoryAuthentication
().
withUser
(
"apollo"
).
password
(
""
).
roles
(
"USER"
,
"ADMIN"
);
}
}
apollo-configservice/src/test/java/com/ctrip/apollo/configservice/integration/ConfigControllerIntegrationTest.java
View file @
0be1e703
...
...
@@ -83,7 +83,8 @@ public class ConfigControllerIntegrationTest extends AbstractBaseIntegrationTest
public
void
testQueryConfigNotModified
()
throws
Exception
{
String
releaseId
=
String
.
valueOf
(
991
);
ResponseEntity
<
ApolloConfig
>
response
=
restTemplate
.
getForEntity
(
"{baseurl}/configs/{appId}/{clusterName}/{namespace}?releaseId={releaseId}"
,
ApolloConfig
.
class
,
.
getForEntity
(
"{baseurl}/configs/{appId}/{clusterName}/{namespace}?releaseId={releaseId}"
,
ApolloConfig
.
class
,
getHostUrl
(),
someAppId
,
someCluster
,
someNamespace
,
releaseId
);
assertEquals
(
HttpStatus
.
NOT_MODIFIED
,
response
.
getStatusCode
());
...
...
@@ -94,7 +95,8 @@ public class ConfigControllerIntegrationTest extends AbstractBaseIntegrationTest
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testQueryPublicConfigWithDataCenterFoundAndNoOverride
()
throws
Exception
{
ResponseEntity
<
ApolloConfig
>
response
=
restTemplate
.
getForEntity
(
"{baseurl}/configs/{appId}/{clusterName}/{namespace}?dataCenter={dateCenter}"
,
ApolloConfig
.
class
,
.
getForEntity
(
"{baseurl}/configs/{appId}/{clusterName}/{namespace}?dataCenter={dateCenter}"
,
ApolloConfig
.
class
,
getHostUrl
(),
someAppId
,
someCluster
,
somePublicNamespace
,
someDC
);
ApolloConfig
result
=
response
.
getBody
();
...
...
@@ -111,11 +113,12 @@ public class ConfigControllerIntegrationTest extends AbstractBaseIntegrationTest
@Sql
(
scripts
=
"/integration-test/cleanup.sql"
,
executionPhase
=
Sql
.
ExecutionPhase
.
AFTER_TEST_METHOD
)
public
void
testQueryPublicConfigWithDataCenterFoundAndOverride
()
throws
Exception
{
ResponseEntity
<
ApolloConfig
>
response
=
restTemplate
.
getForEntity
(
"{baseurl}/configs/{appId}/{clusterName}/{namespace}?dataCenter={dateCenter}"
,
ApolloConfig
.
class
,
.
getForEntity
(
"{baseurl}/configs/{appId}/{clusterName}/{namespace}?dataCenter={dateCenter}"
,
ApolloConfig
.
class
,
getHostUrl
(),
someAppId
,
someDefaultCluster
,
somePublicNamespace
,
someDC
);
ApolloConfig
result
=
response
.
getBody
();
assertEquals
(
"994
|
993"
,
result
.
getReleaseId
());
assertEquals
(
"994
"
+
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
+
"
993"
,
result
.
getReleaseId
());
assertEquals
(
someAppId
,
result
.
getAppId
());
assertEquals
(
someDefaultCluster
,
result
.
getCluster
());
assertEquals
(
somePublicNamespace
,
result
.
getNamespace
());
...
...
@@ -129,7 +132,8 @@ public class ConfigControllerIntegrationTest extends AbstractBaseIntegrationTest
public
void
testQueryPublicConfigWithDataCenterNotFoundAndNoOverride
()
throws
Exception
{
String
someDCNotFound
=
"someDCNotFound"
;
ResponseEntity
<
ApolloConfig
>
response
=
restTemplate
.
getForEntity
(
"{baseurl}/configs/{appId}/{clusterName}/{namespace}?dataCenter={dateCenter}"
,
ApolloConfig
.
class
,
.
getForEntity
(
"{baseurl}/configs/{appId}/{clusterName}/{namespace}?dataCenter={dateCenter}"
,
ApolloConfig
.
class
,
getHostUrl
(),
someAppId
,
someCluster
,
somePublicNamespace
,
someDCNotFound
);
ApolloConfig
result
=
response
.
getBody
();
...
...
@@ -147,11 +151,12 @@ public class ConfigControllerIntegrationTest extends AbstractBaseIntegrationTest
public
void
testQueryPublicConfigWithDataCenterNotFoundAndOverride
()
throws
Exception
{
String
someDCNotFound
=
"someDCNotFound"
;
ResponseEntity
<
ApolloConfig
>
response
=
restTemplate
.
getForEntity
(
"{baseurl}/configs/{appId}/{clusterName}/{namespace}?dataCenter={dateCenter}"
,
ApolloConfig
.
class
,
.
getForEntity
(
"{baseurl}/configs/{appId}/{clusterName}/{namespace}?dataCenter={dateCenter}"
,
ApolloConfig
.
class
,
getHostUrl
(),
someAppId
,
someDefaultCluster
,
somePublicNamespace
,
someDCNotFound
);
ApolloConfig
result
=
response
.
getBody
();
assertEquals
(
"994
|
992"
,
result
.
getReleaseId
());
assertEquals
(
"994
"
+
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
+
"
992"
,
result
.
getReleaseId
());
assertEquals
(
someAppId
,
result
.
getAppId
());
assertEquals
(
someDefaultCluster
,
result
.
getCluster
());
assertEquals
(
somePublicNamespace
,
result
.
getNamespace
());
...
...
apollo-configservice/src/test/java/com/ctrip/apollo/configservice/integration/NotificationControllerIntegrationTest.java
View file @
0be1e703
package
com
.
ctrip
.
apollo
.
configservice
.
integration
;
import
com.ctrip.apollo.biz.message.Topics
;
import
com.google.common.base.Joiner
;
import
com.ctrip.apollo.biz.entity.ReleaseMessage
;
import
com.ctrip.apollo.biz.repository.ReleaseMessageRepository
;
import
com.ctrip.apollo.configservice.controller.NotificationController
;
import
com.ctrip.apollo.core.ConfigConsts
;
import
com.ctrip.apollo.core.dto.ApolloConfigNotification
;
...
...
@@ -14,7 +17,6 @@ import org.springframework.test.context.jdbc.Sql;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.Future
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.atomic.AtomicBoolean
;
...
...
@@ -26,6 +28,8 @@ import static org.junit.Assert.assertEquals;
public
class
NotificationControllerIntegrationTest
extends
AbstractBaseIntegrationTest
{
@Autowired
private
NotificationController
notificationController
;
@Autowired
private
ReleaseMessageRepository
releaseMessageRepository
;
private
String
someAppId
;
private
String
someCluster
;
private
String
defaultNamespace
;
...
...
@@ -43,20 +47,16 @@ public class NotificationControllerIntegrationTest extends AbstractBaseIntegrati
@Test
public
void
testPollNotificationWithDefaultNamespace
()
throws
Exception
{
Future
<
ResponseEntity
<
ApolloConfigNotification
>>
future
=
executorService
.
submit
(()
->
restTemplate
.
getForEntity
(
"{baseurl}/notifications?appId={appId}&cluster={clusterName}&namespace={namespace}"
,
ApolloConfigNotification
.
class
,
getHostUrl
(),
someAppId
,
someCluster
,
defaultNamespace
));
AtomicBoolean
stop
=
new
AtomicBoolean
();
perodicSendMessage
(
assembleKey
(
someAppId
,
someCluster
,
defaultNamespace
),
stop
);
//wait for the request connected to server
TimeUnit
.
MILLISECONDS
.
sleep
(
500
);
ResponseEntity
<
ApolloConfigNotification
>
result
=
restTemplate
.
getForEntity
(
"{baseurl}/notifications?appId={appId}&cluster={clusterName}&namespace={namespace}"
,
ApolloConfigNotification
.
class
,
getHostUrl
(),
someAppId
,
someCluster
,
defaultNamespace
);
notificationController
.
handleMessage
(
assembleKey
(
someAppId
,
someCluster
,
defaultNamespace
),
Topics
.
APOLLO_RELEASE_TOPIC
);
stop
.
set
(
true
);
ResponseEntity
<
ApolloConfigNotification
>
result
=
future
.
get
(
500
,
TimeUnit
.
MILLISECONDS
);
ApolloConfigNotification
notification
=
result
.
getBody
();
assertEquals
(
HttpStatus
.
OK
,
result
.
getStatusCode
());
assertEquals
(
defaultNamespace
,
notification
.
getNamespace
());
...
...
@@ -69,19 +69,7 @@ public class NotificationControllerIntegrationTest extends AbstractBaseIntegrati
String
publicAppId
=
"somePublicAppId"
;
AtomicBoolean
stop
=
new
AtomicBoolean
();
executorService
.
submit
((
Runnable
)
()
->
{
//wait for the request connected to server
while
(!
stop
.
get
()
&&
!
Thread
.
currentThread
().
isInterrupted
())
{
try
{
TimeUnit
.
MILLISECONDS
.
sleep
(
100
);
}
catch
(
InterruptedException
e
)
{
}
notificationController
.
handleMessage
(
assembleKey
(
publicAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
somePublicNamespace
),
Topics
.
APOLLO_RELEASE_TOPIC
);
}
});
perodicSendMessage
(
assembleKey
(
publicAppId
,
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
somePublicNamespace
),
stop
);
ResponseEntity
<
ApolloConfigNotification
>
result
=
restTemplate
.
getForEntity
(
...
...
@@ -104,19 +92,7 @@ public class NotificationControllerIntegrationTest extends AbstractBaseIntegrati
String
someDC
=
"someDC"
;
AtomicBoolean
stop
=
new
AtomicBoolean
();
executorService
.
submit
((
Runnable
)
()
->
{
//wait for the request connected to server
while
(!
stop
.
get
()
&&
!
Thread
.
currentThread
().
isInterrupted
())
{
try
{
TimeUnit
.
MILLISECONDS
.
sleep
(
100
);
}
catch
(
InterruptedException
e
)
{
}
notificationController
.
handleMessage
(
assembleKey
(
publicAppId
,
someDC
,
somePublicNamespace
),
Topics
.
APOLLO_RELEASE_TOPIC
);
}
});
perodicSendMessage
(
assembleKey
(
publicAppId
,
someDC
,
somePublicNamespace
),
stop
);
ResponseEntity
<
ApolloConfigNotification
>
result
=
restTemplate
.
getForEntity
(
...
...
@@ -131,8 +107,22 @@ public class NotificationControllerIntegrationTest extends AbstractBaseIntegrati
assertEquals
(
somePublicNamespace
,
notification
.
getNamespace
());
}
private
String
assembleKey
(
String
appId
,
String
cluster
,
String
namespace
)
{
return
String
.
format
(
"%s-%s-%s"
,
appId
,
cluster
,
namespace
);
return
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
).
join
(
appId
,
cluster
,
namespace
);
}
private
void
perodicSendMessage
(
String
message
,
AtomicBoolean
stop
)
{
executorService
.
submit
((
Runnable
)
()
->
{
//wait for the request connected to server
while
(!
stop
.
get
()
&&
!
Thread
.
currentThread
().
isInterrupted
())
{
try
{
TimeUnit
.
MILLISECONDS
.
sleep
(
100
);
}
catch
(
InterruptedException
e
)
{
}
ReleaseMessage
releaseMessage
=
new
ReleaseMessage
(
message
);
releaseMessageRepository
.
save
(
releaseMessage
);
}
});
}
}
apollo-configservice/src/test/resources/application.properties
View file @
0be1e703
...
...
@@ -3,3 +3,6 @@ spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy
spring.h2.console.enabled
=
true
spring.h2.console.settings.web-allow-others
=
true
spring.jpa.properties.hibernate.show_sql
=
true
# for ReleaseMessageScanner test
apollo.message-scan.interval
=
100
apollo-core/src/main/java/com/ctrip/apollo/core/ConfigConsts.java
View file @
0be1e703
...
...
@@ -3,4 +3,5 @@ package com.ctrip.apollo.core;
public
interface
ConfigConsts
{
String
NAMESPACE_DEFAULT
=
"application"
;
String
CLUSTER_NAME_DEFAULT
=
"default"
;
String
CLUSTER_NAMESPACE_SEPARATOR
=
"+"
;
}
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