INTEXT-142: Add Spring Integration Hazelcast
JIRA: https://jira.spring.io/browse/INTEXT-142
This commit is contained in:
committed by
Artem Bilan
parent
fddd7e47b4
commit
bfec7640ca
301
spring-integration-hazelcast/README.md
Normal file
301
spring-integration-hazelcast/README.md
Normal file
@@ -0,0 +1,301 @@
|
||||
SPRING INTEGRATION HAZELCAST SUPPORT
|
||||
====================================
|
||||
|
||||
## HAZELCAST EVENT-DRIVEN INBOUND CHANNEL ADAPTER
|
||||
|
||||
Hazelcast provides distributed data structures such as
|
||||
|
||||
* com.hazelcast.core.IMap,
|
||||
* com.hazelcast.core.MultiMap,
|
||||
* com.hazelcast.core.IList,
|
||||
* com.hazelcast.core.ISet,
|
||||
* com.hazelcast.core.IQueue,
|
||||
* com.hazelcast.core.ITopic,
|
||||
* com.hazelcast.core.ReplicatedMap.
|
||||
|
||||
It also provides event listeners in order to listen to the modifications performed on these data structures.
|
||||
|
||||
* com.hazelcast.core.EntryListener<K, V>
|
||||
* com.hazelcast.core.ItemListener<E>
|
||||
* com.hazelcast.core.MessageListener<E>
|
||||
|
||||
Hazelcast Event-Driven Inbound Channel Adapter listens related cache events and sends event messages to defined channel. Its basic definition is as follows :
|
||||
```
|
||||
<int-hazelcast:inbound-channel-adapter channel="mapChannel"
|
||||
cache="map"
|
||||
cache-events="UPDATED, REMOVED"
|
||||
cache-listening-policy="SINGLE" />
|
||||
```
|
||||
Basically, Hazelcast Event-Driven Inbound Channel Adapter requires following attributes :
|
||||
|
||||
* **channel :** Specifies channel which message is sent. It is mandatory attribute.
|
||||
* **cache :** Specifies the distributed Object reference which is listened. It is mandatory attribute.
|
||||
* **cache-events :** Specifies cache events which are listened. It is optional attribute and its default value is ADDED. Its supported values are as follows :
|
||||
|
||||
1. Supported cache event types for IMap and MultiMap : ADDED, REMOVED, UPDATED, EVICTED, EVICT_ALL and CLEAR_ALL.
|
||||
2. Supported cache event types for ReplicatedMap : ADDED, REMOVED, UPDATED, EVICTED.
|
||||
3. Supported cache event types for IList, ISet and IQueue : ADDED, REMOVED.
|
||||
4. There is no need to cache event type definition for ITopic.
|
||||
|
||||
* **cache-listening-policy :** Specifies cache listening policy as SINGLE or ALL. It is optional attribute and its default value is SINGLE. Each Hazelcast inbound channel adapter which listens same cache object with same cache-events attribute, can receive a single event message or all event messages. If this is ALL, all Hazelcast inbound channel adapters which listens same cache object with same cache-events attribute, will receive same event messages. If this is SINGLE, they will receive unique event messages.
|
||||
|
||||
Sample namespace and schemaLocation definitions are as follows :
|
||||
```
|
||||
xmlns:int-hazelcast= “http://www.springframework.org/schema/integration/hazelcast”
|
||||
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration/hazelcast
|
||||
http://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd”
|
||||
```
|
||||
Sample definitions are as follows :
|
||||
|
||||
**Distributed Map :**
|
||||
```
|
||||
<int:channel id="mapChannel"/>
|
||||
|
||||
<int-hazelcast:inbound-channel-adapter channel="mapChannel"
|
||||
cache="map"
|
||||
cache-events="UPDATED, REMOVED" />
|
||||
|
||||
<bean id="map" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="map"/>
|
||||
</bean>
|
||||
|
||||
<bean id="instance" class="com.hazelcast.core.Hazelcast"
|
||||
factory-method="newHazelcastInstance">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config" />
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
```
|
||||
|
||||
**Distributed MultiMap :**
|
||||
```
|
||||
<int:channel id="multiMapChannel"/>
|
||||
|
||||
<int-hazelcast:inbound-channel-adapter channel="multiMapChannel"
|
||||
cache="multiMap"
|
||||
cache-events="ADDED,
|
||||
REMOVED,
|
||||
CLEAR_ALL" />
|
||||
|
||||
<bean id="multiMap" factory-bean="instance" factory-method="getMultiMap">
|
||||
<constructor-arg value="multiMap"/>
|
||||
</bean>
|
||||
```
|
||||
|
||||
**Distributed List :**
|
||||
```
|
||||
<int:channel id="listChannel"/>
|
||||
|
||||
<int-hazelcast:inbound-channel-adapter channel="listChannel"
|
||||
cache="list"
|
||||
cache-events="ADDED, REMOVED"
|
||||
cache-listening-policy="ALL" />
|
||||
|
||||
<bean id="list" factory-bean="instance" factory-method="getList">
|
||||
<constructor-arg value="list"/>
|
||||
</bean>
|
||||
```
|
||||
|
||||
**Distributed Set :**
|
||||
```
|
||||
<int:channel id="setChannel"/>
|
||||
|
||||
<int-hazelcast:inbound-channel-adapter channel="setChannel" cache="set" />
|
||||
|
||||
<bean id="set" factory-bean="instance" factory-method="getSet">
|
||||
<constructor-arg value="set"/>
|
||||
</bean>
|
||||
```
|
||||
|
||||
**Distributed Queue :**
|
||||
```
|
||||
<int:channel id="queueChannel"/>
|
||||
|
||||
<int-hazelcast:inbound-channel-adapter channel="queueChannel"
|
||||
cache="queue"
|
||||
cache-events="REMOVED"
|
||||
cache-listening-policy="ALL" />
|
||||
|
||||
<bean id="queue" factory-bean="instance" factory-method="getQueue">
|
||||
<constructor-arg value="queue"/>
|
||||
</bean>
|
||||
```
|
||||
|
||||
**Distributed Topic :**
|
||||
```
|
||||
<int:channel id="topicChannel"/>
|
||||
|
||||
<int-hazelcast:inbound-channel-adapter channel="topicChannel" cache="topic" />
|
||||
|
||||
<bean id="topic" factory-bean="instance" factory-method="getTopic">
|
||||
<constructor-arg value="topic"/>
|
||||
</bean>
|
||||
```
|
||||
|
||||
**Replicated Map :**
|
||||
```
|
||||
<int:channel id="replicatedMapChannel"/>
|
||||
|
||||
<int-hazelcast:inbound-channel-adapter channel="replicatedMapChannel"
|
||||
cache="replicatedMap"
|
||||
cache-events="ADDED,UPDATED, REMOVED"
|
||||
cache-listening-policy="SINGLE" />
|
||||
|
||||
<bean id="replicatedMap" factory-bean="instance" factory-method="getReplicatedMap">
|
||||
<constructor-arg value="replicatedMap"/>
|
||||
</bean>
|
||||
<bean id="instance" class="com.hazelcast.core.Hazelcast"
|
||||
factory-method="newHazelcastInstance">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config" />
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
```
|
||||
**Reference :** http://docs.hazelcast.org/docs/3.4/manual/html-single/hazelcast-documentation.html#distributed-data-structures
|
||||
|
||||
|
||||
## HAZELCAST CONTINUOUS QUERY INBOUND CHANNEL ADAPTER
|
||||
|
||||
Hazelcast Continuous Query enables to listen to the modifications performed on specific map entries. Hazelcast Continuous Query Inbound Channel Adapter is an event-driven inbound channel adapter and listens related distributed map events in the light of defined predicate. Its basic definition is as follows :
|
||||
```
|
||||
<int-hazelcast:cq-inbound-channel-adapter
|
||||
channel="cqMapChannel"
|
||||
cache="cqMap"
|
||||
cache-events="UPDATED, REMOVED"
|
||||
predicate="name=TestName AND surname=TestSurname" />
|
||||
```
|
||||
Basically, it requires four attributes as follows :
|
||||
|
||||
* **channel :** Specifies channel which message is sent. It is mandatory attribute.
|
||||
* **cache :** Specifies distributed Map reference which is listened. It is mandatory attribute.
|
||||
* **cache-events :** Specifies cache events which are listened. It is optional attribute with ADDED default value. Supported values are ADDED, REMOVED, UPDATED, EVICTED, EVICT_ALL and CLEAR_ALL.
|
||||
* **predicate :** Specifies predicate to listen to the modifications performed on specific map entries. It is mandatory attribute.
|
||||
|
||||
Sample definition is as follows :
|
||||
```
|
||||
<int:channel id="cqMapChannel"/>
|
||||
|
||||
<int-hazelcast:cq-inbound-channel-adapter
|
||||
channel="cqMapChannel"
|
||||
cache="cqMap"
|
||||
cache-events="UPDATED, REMOVED"
|
||||
predicate="name=TestName AND surname=TestSurname"/>
|
||||
|
||||
<bean id="cqMap" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="cqMap"/>
|
||||
</bean>
|
||||
|
||||
<bean id="instance" class="com.hazelcast.core.Hazelcast"
|
||||
factory-method="newHazelcastInstance">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config" />
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
```
|
||||
**Reference :** http://docs.hazelcast.org/docs/3.4/manual/html-single/hazelcast-documentation.html#continuous-query
|
||||
|
||||
|
||||
## HAZELCAST DISTRIBUTED-SQL INBOUND CHANNEL ADAPTER
|
||||
|
||||
Hazelcast allows to run distributed queries on the distributed map. Hazelcast Distributed SQL Inbound Channel Adapter is a poller-driven inbound channel adapter. It runs defined distributed-sql and returns results in the light of iteration type. Its basic definition is as follows :
|
||||
```
|
||||
<int-hazelcast:ds-inbound-channel-adapter
|
||||
channel="dsMapChannel"
|
||||
cache="dsMap"
|
||||
iteration-type="ENTRY"
|
||||
distributed-sql="active=false OR age >= 25 OR name = 'TestName'">
|
||||
<int:poller cron="*/10 * * * * *"/>
|
||||
</int-hazelcast:ds-inbound-channel-adapter>
|
||||
```
|
||||
Basically, it requires a poller and four attributes such as
|
||||
|
||||
* **channel :** Specifies channel which message is sent. It is mandatory attribute.
|
||||
* **cache :** Specifies distributed Map reference which is queried. It is mandatory attribute.
|
||||
* **iteration-type :** Specifies result type. Distributed SQL can be run on EntrySet, KeySet, LocalKeySet or Values. It is optional attribute with VALUE default value. Supported values are ENTRY, KEY, LOCAL_KEY and VALUE.
|
||||
* **distributed-sql :** Specifies where clause of sql statement. It is mandatory attribute.
|
||||
|
||||
Sample definition is as follows :
|
||||
```
|
||||
<int:channel id="dsMapChannel"/>
|
||||
|
||||
<int-hazelcast:ds-inbound-channel-adapter
|
||||
channel="dsMapChannel"
|
||||
cache="dsMap"
|
||||
iteration-type="ENTRY"
|
||||
distributed-sql="active=false OR age >= 25 OR name = 'TestName'">
|
||||
<int:poller cron="*/10 * * * * *"/>
|
||||
</int-hazelcast:ds-inbound-channel-adapter>
|
||||
|
||||
<bean id="dsMap" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="dsMap"/>
|
||||
</bean>
|
||||
|
||||
<bean id="instance" class="com.hazelcast.core.Hazelcast"
|
||||
factory-method="newHazelcastInstance">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config" />
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
```
|
||||
**Reference :** http://docs.hazelcast.org/docs/3.4/manual/html-single/hazelcast-documentation.html#query-overview
|
||||
|
||||
|
||||
## HAZELCAST OUTBOUND CHANNEL ADAPTER
|
||||
|
||||
Hazelcast Outbound Channel Adapter listens its defined channel and writes incoming messages to related distributed cache. It expects one of java.util.Map, List, Set and Queue data structures in incoming message's payload. Its definition is as follows :
|
||||
```
|
||||
<int-hazelcast:outbound-channel-adapter channel="mapChannel" cache="distributedMap" />
|
||||
```
|
||||
Basically, it requires two attributes as follows :
|
||||
|
||||
* **channel :** Specifies channel which message is sent. It is mandatory attribute.
|
||||
* **cache :** Specifies distributed Map reference which is queried. It is mandatory attribute.
|
||||
|
||||
**Case 1-** If incoming messages need to be written to distributed map(com.hazelcast.core.IMap), Message should have java.util.Map payload. Sample definition should be as follows :
|
||||
```
|
||||
<int:channel id="mapChannel"/>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="mapChannel" cache="distributedMap" />
|
||||
|
||||
<bean id="distributedMap" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="distributedMap"/>
|
||||
</bean>
|
||||
|
||||
<bean id="instance" class="com.hazelcast.core.Hazelcast"
|
||||
factory-method="newHazelcastInstance">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config" />
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
```
|
||||
**Case 2-** If incoming messages need to be written to distributed list(com.hazelcast.core.IList), Message should have java.util.List payload. Sample definition should be as follows :
|
||||
```
|
||||
<int:channel id="listChannel"/>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="listChannel" cache="distributedList" />
|
||||
|
||||
<bean id="distributedList" factory-bean="instance" factory-method="getList">
|
||||
<constructor-arg value="distributedList"/>
|
||||
</bean>
|
||||
```
|
||||
**Case 3-** If incoming messages need to be written to distributed set(com.hazelcast.core.ISet), Message should have java.util.Set payload. Sample definition should be as follows :
|
||||
```
|
||||
<int:channel id="setChannel"/>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="setChannel" cache="distributedSet" />
|
||||
|
||||
<bean id="distributedSet" factory-bean="instance" factory-method="getSet">
|
||||
<constructor-arg value="distributedSet"/>
|
||||
</bean>
|
||||
```
|
||||
**Case 4-** If incoming messages need to be written to distributed queue(com.hazelcast.core.IQueue), Message should have java.util.Queue payload. Sample definition should be as follows :
|
||||
```
|
||||
<int:channel id="queueChannel"/>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="queueChannel" cache="distributedQueue" />
|
||||
|
||||
<bean id="distributedQueue" factory-bean="instance" factory-method="getQueue">
|
||||
<constructor-arg value="distributedQueue"/>
|
||||
</bean>
|
||||
```
|
||||
226
spring-integration-hazelcast/build.gradle
Normal file
226
spring-integration-hazelcast/build.gradle
Normal file
@@ -0,0 +1,226 @@
|
||||
description = 'Spring Integration Hazelcast Support'
|
||||
|
||||
apply plugin: 'java'
|
||||
apply from: "${rootProject.projectDir}/publish-maven.gradle"
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'idea'
|
||||
|
||||
group = 'org.springframework.integration'
|
||||
|
||||
repositories {
|
||||
maven { url 'http://repo.spring.io/libs-milestone' }
|
||||
}
|
||||
|
||||
sourceCompatibility = targetCompatibility = 1.7
|
||||
|
||||
ext {
|
||||
hazelcastVersion = '3.4.2'
|
||||
jacocoVersion = '0.7.2.201409121644'
|
||||
slf4jVersion = '1.7.10'
|
||||
springIntegrationVersion = '4.1.2.RELEASE'
|
||||
|
||||
idPrefix = 'hazelcast'
|
||||
|
||||
linkHomepage = 'https://github.com/spring-projects/spring-integration-extensions'
|
||||
linkCi = 'https://build.spring.io/browse/INTEXT'
|
||||
linkIssue = 'https://jira.spring.io/browse/INTEXT'
|
||||
linkScmUrl = 'https://github.com/spring-projects/spring-integration-extensions'
|
||||
linkScmConnection = 'https://github.com/spring-projects/spring-integration-extensions.git'
|
||||
linkScmDevConnection = 'git@github.com:spring-projects/spring-integration-extensions.git'
|
||||
}
|
||||
|
||||
eclipse.project.natures += 'org.springframework.ide.eclipse.core.springnature'
|
||||
|
||||
sourceSets {
|
||||
test {
|
||||
resources {
|
||||
srcDirs = ['src/test/resources', 'src/test/java']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
jacoco //Configuration Group used by Sonar to provide Code Coverage using JaCoCo
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile "org.springframework.integration:spring-integration-core:$springIntegrationVersion"
|
||||
compile "com.hazelcast:hazelcast:$hazelcastVersion"
|
||||
|
||||
testCompile "org.springframework.integration:spring-integration-test:$springIntegrationVersion"
|
||||
|
||||
testRuntime "org.slf4j:slf4j-log4j12:$slf4jVersion"
|
||||
|
||||
jacoco "org.jacoco:org.jacoco.agent:$jacocoVersion:runtime"
|
||||
}
|
||||
|
||||
// enable all compiler warnings; individual projects may customize further
|
||||
[compileJava, compileTestJava]*.options*.compilerArgs = ['-Xlint:all,-options']
|
||||
|
||||
test {
|
||||
// suppress all console output during testing unless running `gradle -i`
|
||||
logging.captureStandardOutput(LogLevel.INFO)
|
||||
jvmArgs "-javaagent:${configurations.jacoco.asPath}=destfile=${buildDir}/jacoco.exec,includes=*",
|
||||
"-Dhazelcast.logging.type=slf4j"
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar) {
|
||||
classifier = 'sources'
|
||||
from sourceSets.main.allJava
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar) {
|
||||
classifier = 'javadoc'
|
||||
from javadoc
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives sourcesJar
|
||||
archives javadocJar
|
||||
}
|
||||
|
||||
apply plugin: 'sonar-runner'
|
||||
|
||||
sonarRunner {
|
||||
sonarProperties {
|
||||
property "sonar.jacoco.reportPath", "${buildDir.name}/jacoco.exec"
|
||||
property "sonar.links.homepage", linkHomepage
|
||||
property "sonar.links.ci", linkCi
|
||||
property "sonar.links.issue", linkIssue
|
||||
property "sonar.links.scm", linkScmUrl
|
||||
property "sonar.links.scm_dev", linkScmDevConnection
|
||||
property "sonar.java.coveragePlugin", "jacoco"
|
||||
}
|
||||
}
|
||||
|
||||
task api(type: Javadoc) {
|
||||
group = 'Documentation'
|
||||
description = 'Generates the Javadoc API documentation.'
|
||||
title = "${rootProject.description} ${version} API"
|
||||
options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED
|
||||
options.author = true
|
||||
options.header = rootProject.description
|
||||
options.overview = 'src/api/overview.html'
|
||||
options.stylesheetFile = file("src/api/stylesheet.css")
|
||||
|
||||
source = sourceSets.main.allJava
|
||||
classpath = project.sourceSets.main.compileClasspath
|
||||
destinationDir = new File(buildDir, "api")
|
||||
}
|
||||
|
||||
task schemaZip(type: Zip) {
|
||||
group = 'Distribution'
|
||||
classifier = 'schema'
|
||||
description = "Builds -${classifier} archive containing all " +
|
||||
"XSDs for deployment at static.springframework.org/schema."
|
||||
|
||||
duplicatesStrategy = 'exclude'
|
||||
|
||||
def Properties schemas = new Properties();
|
||||
def shortName = idPrefix.replaceFirst("${idPrefix}-", '')
|
||||
|
||||
project.sourceSets.main.resources.find {
|
||||
it.path.endsWith("META-INF${File.separator}spring.schemas")
|
||||
}?.withInputStream { schemas.load(it) }
|
||||
|
||||
for (def key : schemas.keySet()) {
|
||||
File xsdFile = project.sourceSets.main.resources.find {
|
||||
it.path.replaceAll('\\\\', '/').endsWith(schemas.get(key))
|
||||
}
|
||||
assert xsdFile != null
|
||||
into("integration/${shortName}") {
|
||||
from xsdFile.path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task docsZip(type: Zip) {
|
||||
group = 'Distribution'
|
||||
classifier = 'docs'
|
||||
description = "Builds -${classifier} archive containing api " +
|
||||
"for deployment at static.spring.io/spring-integration/docs."
|
||||
|
||||
from('src/dist') {
|
||||
include 'changelog.txt'
|
||||
}
|
||||
|
||||
from(api) {
|
||||
into 'api'
|
||||
}
|
||||
}
|
||||
|
||||
task distZip(type: Zip, dependsOn: [docsZip, schemaZip]) {
|
||||
group = 'Distribution'
|
||||
classifier = 'dist'
|
||||
description = "Builds -${classifier} archive, containing all jars and docs, " +
|
||||
"suitable for community download page."
|
||||
|
||||
ext.baseDir = "${project.name}-${project.version}";
|
||||
|
||||
from('src/dist') {
|
||||
include 'readme.txt'
|
||||
include 'license.txt'
|
||||
include 'notice.txt'
|
||||
into "${baseDir}"
|
||||
}
|
||||
|
||||
from(zipTree(docsZip.archivePath)) {
|
||||
into "${baseDir}/docs"
|
||||
}
|
||||
|
||||
from(zipTree(schemaZip.archivePath)) {
|
||||
into "${baseDir}/schema"
|
||||
}
|
||||
|
||||
into("${baseDir}/libs") {
|
||||
from project.jar
|
||||
from project.sourcesJar
|
||||
from project.javadocJar
|
||||
}
|
||||
}
|
||||
|
||||
// Create an optional "with dependencies" distribution.
|
||||
// Not published by default; only for use when building from source.
|
||||
task depsZip(type: Zip, dependsOn: distZip) { zipTask ->
|
||||
group = 'Distribution'
|
||||
classifier = 'dist-with-deps'
|
||||
description = "Builds -${classifier} archive, containing everything " +
|
||||
"in the -${distZip.classifier} archive plus all dependencies."
|
||||
|
||||
from zipTree(distZip.archivePath)
|
||||
|
||||
gradle.taskGraph.whenReady { taskGraph ->
|
||||
if (taskGraph.hasTask(":${zipTask.name}")) {
|
||||
def projectName = rootProject.name
|
||||
def artifacts = new HashSet()
|
||||
|
||||
rootProject.configurations.runtime.resolvedConfiguration.resolvedArtifacts.each { artifact ->
|
||||
def dependency = artifact.moduleVersion.id
|
||||
if (!projectName.equals(dependency.name)) {
|
||||
artifacts << artifact.file
|
||||
}
|
||||
}
|
||||
|
||||
zipTask.from(artifacts) {
|
||||
into "${distZip.baseDir}/deps"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives distZip
|
||||
archives docsZip
|
||||
archives schemaZip
|
||||
}
|
||||
|
||||
task dist(dependsOn: assemble) {
|
||||
group = 'Distribution'
|
||||
description = 'Builds -dist, -docs and -schema distribution archives.'
|
||||
}
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
description = 'Generates gradlew[.bat] scripts'
|
||||
gradleVersion = '2.3'
|
||||
distributionUrl = "http://services.gradle.org/distributions/gradle-${gradleVersion}-all.zip"
|
||||
}
|
||||
1
spring-integration-hazelcast/gradle.properties
Normal file
1
spring-integration-hazelcast/gradle.properties
Normal file
@@ -0,0 +1 @@
|
||||
version=1.0.0-BUILD-SNAPSHOT
|
||||
BIN
spring-integration-hazelcast/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
spring-integration-hazelcast/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
spring-integration-hazelcast/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
spring-integration-hazelcast/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Thu Mar 19 00:10:16 GMT 2015
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-2.3-all.zip
|
||||
164
spring-integration-hazelcast/gradlew
vendored
Executable file
164
spring-integration-hazelcast/gradlew
vendored
Executable file
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
90
spring-integration-hazelcast/gradlew.bat
vendored
Normal file
90
spring-integration-hazelcast/gradlew.bat
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
62
spring-integration-hazelcast/publish-maven.gradle
Normal file
62
spring-integration-hazelcast/publish-maven.gradle
Normal file
@@ -0,0 +1,62 @@
|
||||
apply plugin: 'maven'
|
||||
|
||||
ext.optionalDeps = []
|
||||
ext.providedDeps = []
|
||||
|
||||
ext.optional = { optionalDeps << it }
|
||||
ext.provided = { providedDeps << it }
|
||||
|
||||
install {
|
||||
repositories.mavenInstaller {
|
||||
customizePom(pom, project)
|
||||
}
|
||||
}
|
||||
|
||||
def customizePom(pom, gradleProject) {
|
||||
pom.whenConfigured { generatedPom ->
|
||||
// respect 'optional' and 'provided' dependencies
|
||||
gradleProject.optionalDeps.each { dep ->
|
||||
generatedPom.dependencies.find { it.artifactId == dep.name }?.optional = true
|
||||
}
|
||||
gradleProject.providedDeps.each { dep ->
|
||||
generatedPom.dependencies.find { it.artifactId == dep.name }?.scope = 'provided'
|
||||
}
|
||||
|
||||
// eliminate test-scoped dependencies (no need in maven central poms)
|
||||
generatedPom.dependencies.removeAll { dep ->
|
||||
dep.scope == 'test'
|
||||
}
|
||||
|
||||
// add all items necessary for maven central publication
|
||||
generatedPom.project {
|
||||
name = gradleProject.description
|
||||
description = gradleProject.description
|
||||
url = linkHomepage
|
||||
organization {
|
||||
name = 'SpringIO'
|
||||
url = 'http://spring.io'
|
||||
}
|
||||
licenses {
|
||||
license {
|
||||
name 'The Apache Software License, Version 2.0'
|
||||
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
||||
distribution 'repo'
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
url = linkScmUrl
|
||||
connection = 'scm:git:' + linkScmConnection
|
||||
developerConnection = 'scm:git:' + linkScmDevConnection
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id = 'erenavsarogullari'
|
||||
name = 'Eren Avsarogullari'
|
||||
email = 'erenavsarogullari@gmail.com'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1
spring-integration-hazelcast/settings.gradle
Normal file
1
spring-integration-hazelcast/settings.gradle
Normal file
@@ -0,0 +1 @@
|
||||
rootProject.name = 'spring-integration-hazelcast'
|
||||
22
spring-integration-hazelcast/src/api/overview.html
Normal file
22
spring-integration-hazelcast/src/api/overview.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<html>
|
||||
<body>
|
||||
This document is the API specification for Spring Integration Hazelcast Support project
|
||||
<hr/>
|
||||
<div id="overviewBody">
|
||||
<p>
|
||||
For further API reference and developer documentation, see the
|
||||
<a href="http://docs.spring.io/spring-integration/reference/"
|
||||
target="_top">Spring Integration Reference Documentation</a>.
|
||||
That documentation contains more detailed, developer-targeted
|
||||
descriptions, with conceptual overviews, definitions of terms,
|
||||
workarounds, and working code examples.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you are interested in commercial training, consultancy, and
|
||||
support for Spring Integration, please visit <a href="http://spring.io/" target="_top">
|
||||
http://spring.io</a>
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
598
spring-integration-hazelcast/src/api/stylesheet.css
Normal file
598
spring-integration-hazelcast/src/api/stylesheet.css
Normal file
@@ -0,0 +1,598 @@
|
||||
/* Javadoc style sheet */
|
||||
/*
|
||||
Overall document style
|
||||
*/
|
||||
|
||||
@import url('resources/fonts/dejavu.css');
|
||||
|
||||
body {
|
||||
background-color:#ffffff;
|
||||
color:#353833;
|
||||
font-family:'DejaVu Sans', Arial, Helvetica, sans-serif;
|
||||
font-size:14px;
|
||||
margin:0;
|
||||
}
|
||||
a:link, a:visited {
|
||||
text-decoration:none;
|
||||
color:#4A6782;
|
||||
}
|
||||
a:hover, a:focus {
|
||||
text-decoration:none;
|
||||
color:#bb7a2a;
|
||||
}
|
||||
a:active {
|
||||
text-decoration:none;
|
||||
color:#4A6782;
|
||||
}
|
||||
a[name] {
|
||||
color:#353833;
|
||||
}
|
||||
a[name]:hover {
|
||||
text-decoration:none;
|
||||
color:#353833;
|
||||
}
|
||||
pre {
|
||||
font-family:'DejaVu Sans Mono', monospace;
|
||||
font-size:14px;
|
||||
}
|
||||
h1 {
|
||||
font-size:20px;
|
||||
}
|
||||
h2 {
|
||||
font-size:18px;
|
||||
}
|
||||
h3 {
|
||||
font-size:16px;
|
||||
font-style:italic;
|
||||
}
|
||||
h4 {
|
||||
font-size:13px;
|
||||
}
|
||||
h5 {
|
||||
font-size:12px;
|
||||
}
|
||||
h6 {
|
||||
font-size:11px;
|
||||
}
|
||||
ul {
|
||||
list-style-type:disc;
|
||||
}
|
||||
code, tt {
|
||||
font-family:'DejaVu Sans Mono', monospace;
|
||||
font-size:14px;
|
||||
padding-top:4px;
|
||||
margin-top:8px;
|
||||
line-height:1.4em;
|
||||
}
|
||||
dt code {
|
||||
font-family:'DejaVu Sans Mono', monospace;
|
||||
font-size:14px;
|
||||
padding-top:4px;
|
||||
}
|
||||
table tr td dt code {
|
||||
font-family:'DejaVu Sans Mono', monospace;
|
||||
font-size:14px;
|
||||
vertical-align:top;
|
||||
padding-top:4px;
|
||||
}
|
||||
sup {
|
||||
font-size:8px;
|
||||
}
|
||||
/*
|
||||
Document title and Copyright styles
|
||||
*/
|
||||
.clear {
|
||||
clear:both;
|
||||
height:0px;
|
||||
overflow:hidden;
|
||||
}
|
||||
.aboutLanguage {
|
||||
float:right;
|
||||
padding:0px 21px;
|
||||
font-size:11px;
|
||||
z-index:200;
|
||||
margin-top:-9px;
|
||||
}
|
||||
.legalCopy {
|
||||
margin-left:.5em;
|
||||
}
|
||||
.bar a, .bar a:link, .bar a:visited, .bar a:active {
|
||||
color:#FFFFFF;
|
||||
text-decoration:none;
|
||||
}
|
||||
.bar a:hover, .bar a:focus {
|
||||
color:#bb7a2a;
|
||||
}
|
||||
.tab {
|
||||
background-color:#0066FF;
|
||||
color:#ffffff;
|
||||
padding:8px;
|
||||
width:5em;
|
||||
font-weight:bold;
|
||||
}
|
||||
/*
|
||||
Navigation bar styles
|
||||
*/
|
||||
.bar {
|
||||
background-color:#4D7A97;
|
||||
color:#FFFFFF;
|
||||
padding:.8em .5em .4em .8em;
|
||||
height:auto;/*height:1.8em;*/
|
||||
font-size:11px;
|
||||
margin:0;
|
||||
}
|
||||
.topNav {
|
||||
background-color:#4D7A97;
|
||||
color:#FFFFFF;
|
||||
float:left;
|
||||
padding:0;
|
||||
width:100%;
|
||||
clear:right;
|
||||
height:2.8em;
|
||||
padding-top:10px;
|
||||
overflow:hidden;
|
||||
font-size:12px;
|
||||
}
|
||||
.bottomNav {
|
||||
margin-top:10px;
|
||||
background-color:#4D7A97;
|
||||
color:#FFFFFF;
|
||||
float:left;
|
||||
padding:0;
|
||||
width:100%;
|
||||
clear:right;
|
||||
height:2.8em;
|
||||
padding-top:10px;
|
||||
overflow:hidden;
|
||||
font-size:12px;
|
||||
}
|
||||
.subNav {
|
||||
background-color:#dee3e9;
|
||||
float:left;
|
||||
width:100%;
|
||||
overflow:hidden;
|
||||
font-size:12px;
|
||||
}
|
||||
.subNav div {
|
||||
clear:left;
|
||||
float:left;
|
||||
padding:0 0 5px 6px;
|
||||
text-transform:uppercase;
|
||||
}
|
||||
ul.navList, ul.subNavList {
|
||||
float:left;
|
||||
margin:0 25px 0 0;
|
||||
padding:0;
|
||||
}
|
||||
ul.navList li{
|
||||
list-style:none;
|
||||
float:left;
|
||||
padding: 5px 6px;
|
||||
text-transform:uppercase;
|
||||
}
|
||||
ul.subNavList li{
|
||||
list-style:none;
|
||||
float:left;
|
||||
}
|
||||
.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited {
|
||||
color:#FFFFFF;
|
||||
text-decoration:none;
|
||||
text-transform:uppercase;
|
||||
}
|
||||
.topNav a:hover, .bottomNav a:hover {
|
||||
text-decoration:none;
|
||||
color:#bb7a2a;
|
||||
text-transform:uppercase;
|
||||
}
|
||||
.navBarCell1Rev {
|
||||
background-color:#F8981D;
|
||||
color:#253441;
|
||||
margin: auto 5px;
|
||||
}
|
||||
.skipNav {
|
||||
position:absolute;
|
||||
top:auto;
|
||||
left:-9999px;
|
||||
overflow:hidden;
|
||||
}
|
||||
/*
|
||||
Page header and footer styles
|
||||
*/
|
||||
.header, .footer {
|
||||
clear:both;
|
||||
margin:0 20px;
|
||||
padding:5px 0 0 0;
|
||||
}
|
||||
.indexHeader {
|
||||
margin:10px;
|
||||
position:relative;
|
||||
}
|
||||
.indexHeader span{
|
||||
margin-right:15px;
|
||||
}
|
||||
.indexHeader h1 {
|
||||
font-size:13px;
|
||||
}
|
||||
.title {
|
||||
color:#2c4557;
|
||||
margin:10px 0;
|
||||
}
|
||||
.subTitle {
|
||||
margin:5px 0 0 0;
|
||||
}
|
||||
.header ul {
|
||||
margin:0 0 15px 0;
|
||||
padding:0;
|
||||
}
|
||||
.footer ul {
|
||||
margin:20px 0 5px 0;
|
||||
}
|
||||
.header ul li, .footer ul li {
|
||||
list-style:none;
|
||||
font-size:13px;
|
||||
}
|
||||
/*
|
||||
Heading styles
|
||||
*/
|
||||
div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 {
|
||||
background-color:#dee3e9;
|
||||
border:1px solid #d0d9e0;
|
||||
margin:0 0 6px -8px;
|
||||
padding:7px 5px;
|
||||
}
|
||||
ul.blockList ul.blockList ul.blockList li.blockList h3 {
|
||||
background-color:#dee3e9;
|
||||
border:1px solid #d0d9e0;
|
||||
margin:0 0 6px -8px;
|
||||
padding:7px 5px;
|
||||
}
|
||||
ul.blockList ul.blockList li.blockList h3 {
|
||||
padding:0;
|
||||
margin:15px 0;
|
||||
}
|
||||
ul.blockList li.blockList h2 {
|
||||
padding:0px 0 20px 0;
|
||||
}
|
||||
/*
|
||||
Page layout container styles
|
||||
*/
|
||||
.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer {
|
||||
clear:both;
|
||||
padding:10px 20px;
|
||||
position:relative;
|
||||
}
|
||||
.indexContainer {
|
||||
margin:10px;
|
||||
position:relative;
|
||||
font-size:12px;
|
||||
}
|
||||
.indexContainer h2 {
|
||||
font-size:13px;
|
||||
padding:0 0 3px 0;
|
||||
}
|
||||
.indexContainer ul {
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
.indexContainer ul li {
|
||||
list-style:none;
|
||||
padding-top:2px;
|
||||
}
|
||||
.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt {
|
||||
font-size:12px;
|
||||
font-weight:bold;
|
||||
margin:10px 0 0 0;
|
||||
color:#4E4E4E;
|
||||
}
|
||||
.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd {
|
||||
margin:5px 0 10px 0px;
|
||||
font-size:14px;
|
||||
font-family:'DejaVu Sans Mono',monospace;
|
||||
}
|
||||
.serializedFormContainer dl.nameValue dt {
|
||||
margin-left:1px;
|
||||
font-size:1.1em;
|
||||
display:inline;
|
||||
font-weight:bold;
|
||||
}
|
||||
.serializedFormContainer dl.nameValue dd {
|
||||
margin:0 0 0 1px;
|
||||
font-size:1.1em;
|
||||
display:inline;
|
||||
}
|
||||
/*
|
||||
List styles
|
||||
*/
|
||||
ul.horizontal li {
|
||||
display:inline;
|
||||
font-size:0.9em;
|
||||
}
|
||||
ul.inheritance {
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
ul.inheritance li {
|
||||
display:inline;
|
||||
list-style:none;
|
||||
}
|
||||
ul.inheritance li ul.inheritance {
|
||||
margin-left:15px;
|
||||
padding-left:15px;
|
||||
padding-top:1px;
|
||||
}
|
||||
ul.blockList, ul.blockListLast {
|
||||
margin:10px 0 10px 0;
|
||||
padding:0;
|
||||
}
|
||||
ul.blockList li.blockList, ul.blockListLast li.blockList {
|
||||
list-style:none;
|
||||
margin-bottom:15px;
|
||||
line-height:1.4;
|
||||
}
|
||||
ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList {
|
||||
padding:0px 20px 5px 10px;
|
||||
border:1px solid #ededed;
|
||||
background-color:#f8f8f8;
|
||||
}
|
||||
ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList {
|
||||
padding:0 0 5px 8px;
|
||||
background-color:#ffffff;
|
||||
border:none;
|
||||
}
|
||||
ul.blockList ul.blockList ul.blockList ul.blockList li.blockList {
|
||||
margin-left:0;
|
||||
padding-left:0;
|
||||
padding-bottom:15px;
|
||||
border:none;
|
||||
}
|
||||
ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast {
|
||||
list-style:none;
|
||||
border-bottom:none;
|
||||
padding-bottom:0;
|
||||
}
|
||||
table tr td dl, table tr td dl dt, table tr td dl dd {
|
||||
margin-top:0;
|
||||
margin-bottom:1px;
|
||||
}
|
||||
/*
|
||||
Table styles
|
||||
*/
|
||||
.overviewSummary, .memberSummary, .typeSummary, .useSummary, .constantsSummary, .deprecatedSummary {
|
||||
width:100%;
|
||||
border-left:1px solid #EEE;
|
||||
border-right:1px solid #EEE;
|
||||
border-bottom:1px solid #EEE;
|
||||
}
|
||||
.overviewSummary, .memberSummary {
|
||||
padding:0px;
|
||||
}
|
||||
.overviewSummary caption, .memberSummary caption, .typeSummary caption,
|
||||
.useSummary caption, .constantsSummary caption, .deprecatedSummary caption {
|
||||
position:relative;
|
||||
text-align:left;
|
||||
background-repeat:no-repeat;
|
||||
color:#253441;
|
||||
font-weight:bold;
|
||||
clear:none;
|
||||
overflow:hidden;
|
||||
padding:0px;
|
||||
padding-top:10px;
|
||||
padding-left:1px;
|
||||
margin:0px;
|
||||
white-space:pre;
|
||||
}
|
||||
.overviewSummary caption a:link, .memberSummary caption a:link, .typeSummary caption a:link,
|
||||
.useSummary caption a:link, .constantsSummary caption a:link, .deprecatedSummary caption a:link,
|
||||
.overviewSummary caption a:hover, .memberSummary caption a:hover, .typeSummary caption a:hover,
|
||||
.useSummary caption a:hover, .constantsSummary caption a:hover, .deprecatedSummary caption a:hover,
|
||||
.overviewSummary caption a:active, .memberSummary caption a:active, .typeSummary caption a:active,
|
||||
.useSummary caption a:active, .constantsSummary caption a:active, .deprecatedSummary caption a:active,
|
||||
.overviewSummary caption a:visited, .memberSummary caption a:visited, .typeSummary caption a:visited,
|
||||
.useSummary caption a:visited, .constantsSummary caption a:visited, .deprecatedSummary caption a:visited {
|
||||
color:#FFFFFF;
|
||||
}
|
||||
.overviewSummary caption span, .memberSummary caption span, .typeSummary caption span,
|
||||
.useSummary caption span, .constantsSummary caption span, .deprecatedSummary caption span {
|
||||
white-space:nowrap;
|
||||
padding-top:5px;
|
||||
padding-left:12px;
|
||||
padding-right:12px;
|
||||
padding-bottom:7px;
|
||||
display:inline-block;
|
||||
float:left;
|
||||
background-color:#F8981D;
|
||||
border: none;
|
||||
height:16px;
|
||||
}
|
||||
.memberSummary caption span.activeTableTab span {
|
||||
white-space:nowrap;
|
||||
padding-top:5px;
|
||||
padding-left:12px;
|
||||
padding-right:12px;
|
||||
margin-right:3px;
|
||||
display:inline-block;
|
||||
float:left;
|
||||
background-color:#F8981D;
|
||||
height:16px;
|
||||
}
|
||||
.memberSummary caption span.tableTab span {
|
||||
white-space:nowrap;
|
||||
padding-top:5px;
|
||||
padding-left:12px;
|
||||
padding-right:12px;
|
||||
margin-right:3px;
|
||||
display:inline-block;
|
||||
float:left;
|
||||
background-color:#4D7A97;
|
||||
height:16px;
|
||||
}
|
||||
.memberSummary caption span.tableTab, .memberSummary caption span.activeTableTab {
|
||||
padding-top:0px;
|
||||
padding-left:0px;
|
||||
padding-right:0px;
|
||||
background-image:none;
|
||||
float:none;
|
||||
display:inline;
|
||||
}
|
||||
.overviewSummary .tabEnd, .memberSummary .tabEnd, .typeSummary .tabEnd,
|
||||
.useSummary .tabEnd, .constantsSummary .tabEnd, .deprecatedSummary .tabEnd {
|
||||
display:none;
|
||||
width:5px;
|
||||
position:relative;
|
||||
float:left;
|
||||
background-color:#F8981D;
|
||||
}
|
||||
.memberSummary .activeTableTab .tabEnd {
|
||||
display:none;
|
||||
width:5px;
|
||||
margin-right:3px;
|
||||
position:relative;
|
||||
float:left;
|
||||
background-color:#F8981D;
|
||||
}
|
||||
.memberSummary .tableTab .tabEnd {
|
||||
display:none;
|
||||
width:5px;
|
||||
margin-right:3px;
|
||||
position:relative;
|
||||
background-color:#4D7A97;
|
||||
float:left;
|
||||
|
||||
}
|
||||
.overviewSummary td, .memberSummary td, .typeSummary td,
|
||||
.useSummary td, .constantsSummary td, .deprecatedSummary td {
|
||||
text-align:left;
|
||||
padding:0px 0px 12px 10px;
|
||||
width:100%;
|
||||
}
|
||||
th.colOne, th.colFirst, th.colLast, .useSummary th, .constantsSummary th,
|
||||
td.colOne, td.colFirst, td.colLast, .useSummary td, .constantsSummary td{
|
||||
vertical-align:top;
|
||||
padding-right:0px;
|
||||
padding-top:8px;
|
||||
padding-bottom:3px;
|
||||
}
|
||||
th.colFirst, th.colLast, th.colOne, .constantsSummary th {
|
||||
background:#dee3e9;
|
||||
text-align:left;
|
||||
padding:8px 3px 3px 7px;
|
||||
}
|
||||
td.colFirst, th.colFirst {
|
||||
white-space:nowrap;
|
||||
font-size:13px;
|
||||
}
|
||||
td.colLast, th.colLast {
|
||||
font-size:13px;
|
||||
}
|
||||
td.colOne, th.colOne {
|
||||
font-size:13px;
|
||||
}
|
||||
.overviewSummary td.colFirst, .overviewSummary th.colFirst,
|
||||
.overviewSummary td.colOne, .overviewSummary th.colOne,
|
||||
.memberSummary td.colFirst, .memberSummary th.colFirst,
|
||||
.memberSummary td.colOne, .memberSummary th.colOne,
|
||||
.typeSummary td.colFirst{
|
||||
width:25%;
|
||||
vertical-align:top;
|
||||
}
|
||||
td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover {
|
||||
font-weight:bold;
|
||||
}
|
||||
.tableSubHeadingColor {
|
||||
background-color:#EEEEFF;
|
||||
}
|
||||
.altColor {
|
||||
background-color:#FFFFFF;
|
||||
}
|
||||
.rowColor {
|
||||
background-color:#EEEEEF;
|
||||
}
|
||||
/*
|
||||
Content styles
|
||||
*/
|
||||
.description pre {
|
||||
margin-top:0;
|
||||
}
|
||||
.deprecatedContent {
|
||||
margin:0;
|
||||
padding:10px 0;
|
||||
}
|
||||
.docSummary {
|
||||
padding:0;
|
||||
}
|
||||
|
||||
ul.blockList ul.blockList ul.blockList li.blockList h3 {
|
||||
font-style:normal;
|
||||
}
|
||||
|
||||
div.block {
|
||||
font-size:14px;
|
||||
font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif;
|
||||
}
|
||||
|
||||
td.colLast div {
|
||||
padding-top:0px;
|
||||
}
|
||||
|
||||
|
||||
td.colLast a {
|
||||
padding-bottom:3px;
|
||||
}
|
||||
/*
|
||||
Formatting effect styles
|
||||
*/
|
||||
.sourceLineNo {
|
||||
color:green;
|
||||
padding:0 30px 0 0;
|
||||
}
|
||||
h1.hidden {
|
||||
visibility:hidden;
|
||||
overflow:hidden;
|
||||
font-size:10px;
|
||||
}
|
||||
.block {
|
||||
display:block;
|
||||
margin:3px 10px 2px 0px;
|
||||
color:#474747;
|
||||
}
|
||||
.deprecatedLabel, .descfrmTypeLabel, .memberNameLabel, .memberNameLink,
|
||||
.overrideSpecifyLabel, .packageHierarchyLabel, .paramLabel, .returnLabel,
|
||||
.seeLabel, .simpleTagLabel, .throwsLabel, .typeNameLabel, .typeNameLink {
|
||||
font-weight:bold;
|
||||
}
|
||||
.deprecationComment, .emphasizedPhrase, .interfaceName {
|
||||
font-style:italic;
|
||||
}
|
||||
|
||||
div.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase,
|
||||
div.block div.block span.interfaceName {
|
||||
font-style:normal;
|
||||
}
|
||||
|
||||
div.contentContainer ul.blockList li.blockList h2{
|
||||
padding-bottom:0px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Spring
|
||||
*/
|
||||
|
||||
pre.code {
|
||||
background-color: #F8F8F8;
|
||||
border: 1px solid #CCCCCC;
|
||||
border-radius: 3px 3px 3px 3px;
|
||||
overflow: auto;
|
||||
padding: 10px;
|
||||
margin: 4px 20px 2px 0px;
|
||||
}
|
||||
|
||||
pre.code code, pre.code code * {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre.code code, pre.code code * {
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
201
spring-integration-hazelcast/src/dist/license.txt
vendored
Normal file
201
spring-integration-hazelcast/src/dist/license.txt
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
21
spring-integration-hazelcast/src/dist/notice.txt
vendored
Normal file
21
spring-integration-hazelcast/src/dist/notice.txt
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
========================================================================
|
||||
== NOTICE file corresponding to section 4 d of the Apache License, ==
|
||||
== Version 2.0, in this case for the Spring Integration distribution. ==
|
||||
========================================================================
|
||||
|
||||
This product includes software developed by
|
||||
the Apache Software Foundation (http://www.apache.org).
|
||||
|
||||
The end-user documentation included with a redistribution, if any,
|
||||
must include the following acknowledgement:
|
||||
|
||||
"This product includes software developed by the Spring Framework
|
||||
Project (http://www.spring.io)."
|
||||
|
||||
Alternatively, this acknowledgement may appear in the software itself,
|
||||
if and wherever such third-party acknowledgements normally appear.
|
||||
|
||||
The names "Spring", "Spring Framework", and "Spring Integration" must
|
||||
not be used to endorse or promote products derived from this software
|
||||
without prior written permission. For written permission, please contact
|
||||
enquiries@springsource.com.
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.common;
|
||||
|
||||
/**
|
||||
* Enumeration of Cache Event Types
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
* @see org.springframework.integration.hazelcast.inbound.AbstractHazelcastMessageProducer
|
||||
*/
|
||||
public enum CacheEventType {
|
||||
|
||||
ADDED, REMOVED, UPDATED, EVICTED, EVICT_ALL, CLEAR_ALL;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.common;
|
||||
|
||||
/**
|
||||
* Enumeration of Cache Listening Policy Type
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
* @see org.springframework.integration.hazelcast.inbound.AbstractHazelcastMessageProducer
|
||||
*/
|
||||
public enum CacheListeningPolicyType {
|
||||
|
||||
SINGLE, ALL;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.common;
|
||||
|
||||
/**
|
||||
* Enumeration of Distributed SQL Iteration Type
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
* @see org.springframework.integration.hazelcast.inbound.HazelcastDistributedSQLMessageSource
|
||||
*/
|
||||
public enum DistributedSQLIterationType {
|
||||
|
||||
ENTRY, KEY, LOCAL_KEY, VALUE
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.common;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.hazelcast.core.DistributedObject;
|
||||
import com.hazelcast.core.IList;
|
||||
import com.hazelcast.core.IMap;
|
||||
import com.hazelcast.core.IQueue;
|
||||
import com.hazelcast.core.ISet;
|
||||
import com.hazelcast.core.ITopic;
|
||||
import com.hazelcast.core.MultiMap;
|
||||
import com.hazelcast.core.ReplicatedMap;
|
||||
|
||||
import reactor.util.CollectionUtils;
|
||||
import reactor.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Common Validator for Hazelcast Integration. It validates cache types and events.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class HazelcastIntegrationDefinitionValidator {
|
||||
|
||||
public static <E extends Enum<E>> void validateEnumType(final Class<E> enumType, final String cacheEventTypes) {
|
||||
Set<String> eventTypeSet = StringUtils.commaDelimitedListToSet(cacheEventTypes);
|
||||
for (String eventType : eventTypeSet) {
|
||||
Enum.valueOf(enumType, eventType);
|
||||
}
|
||||
}
|
||||
|
||||
public static void validateCacheTypeForEventDrivenMessageProducer(final DistributedObject distributedObject) {
|
||||
if (!(distributedObject instanceof IMap
|
||||
|| distributedObject instanceof MultiMap
|
||||
|| distributedObject instanceof ReplicatedMap
|
||||
|| distributedObject instanceof IList
|
||||
|| distributedObject instanceof ISet
|
||||
|| distributedObject instanceof IQueue
|
||||
|| distributedObject instanceof ITopic)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid 'cache' type is set. IMap, MultiMap, ReplicatedMap, IList, ISet, IQueue and ITopic" +
|
||||
" cache object types are acceptable for Hazelcast Inbound Channel Adapter.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void validateCacheTypeForCacheWritingMessageHandler(final DistributedObject distributedObject) {
|
||||
if (!(distributedObject instanceof IMap
|
||||
|| distributedObject instanceof IList
|
||||
|| distributedObject instanceof ISet
|
||||
|| distributedObject instanceof IQueue)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid 'cache' type is set. IMap, IList, ISet and IQueue cache object types are acceptable "
|
||||
+ "for Hazelcast Outbound Channel Adapter.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void validateCacheEventsByDistributedObject(
|
||||
final DistributedObject distributedObject, final Set<String> cacheEventTypeSet) {
|
||||
List<String> supportedCacheEventTypes = getSupportedCacheEventTypes(distributedObject);
|
||||
if (!CollectionUtils.isEmpty(supportedCacheEventTypes)) {
|
||||
validateCacheEventsByDistributedObject(distributedObject, cacheEventTypeSet, supportedCacheEventTypes);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> getSupportedCacheEventTypes(final DistributedObject distributedObject) {
|
||||
if ((distributedObject instanceof IList)
|
||||
|| (distributedObject instanceof ISet)
|
||||
|| (distributedObject instanceof IQueue)) {
|
||||
return Arrays.asList(CacheEventType.ADDED.toString(), CacheEventType.REMOVED.toString());
|
||||
}
|
||||
else if (distributedObject instanceof MultiMap) {
|
||||
return Arrays.asList(CacheEventType.ADDED.toString(),
|
||||
CacheEventType.REMOVED.toString(),
|
||||
CacheEventType.CLEAR_ALL.toString());
|
||||
}
|
||||
else if (distributedObject instanceof ReplicatedMap) {
|
||||
return Arrays.asList(CacheEventType.ADDED.toString(),
|
||||
CacheEventType.REMOVED.toString(),
|
||||
CacheEventType.UPDATED.toString(),
|
||||
CacheEventType.EVICTED.toString());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void validateCacheEventsByDistributedObject(DistributedObject distributedObject,
|
||||
Set<String> cacheEventTypeSet, List<String> supportedCacheEventTypes) {
|
||||
if (!supportedCacheEventTypes.containsAll(cacheEventTypeSet)) {
|
||||
throw new IllegalArgumentException("'cache-events' attribute of "
|
||||
+ distributedObject.getName() + " can be set as " + supportedCacheEventTypes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.common;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.integration.hazelcast.listener.HazelcastMembershipListener;
|
||||
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.core.MultiMap;
|
||||
|
||||
/**
|
||||
* This class creates an internal configuration {@link MultiMap} to cache Hazelcast instances' socket
|
||||
* address information which used Hazelcast event-driven inbound channel adapter(s). It
|
||||
* also enables a Hazelcast {@link com.hazelcast.core.MembershipListener} to listen for
|
||||
* membership updates.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class HazelcastLocalInstanceRegistrar implements SmartInitializingSingleton {
|
||||
|
||||
public static final String SPRING_INTEGRATION_INTERNAL_CLUSTER_MULTIMAP =
|
||||
"SPRING_INTEGRATION_INTERNAL_CLUSTER_MULTIMAP";
|
||||
|
||||
public static final String SPRING_INTEGRATION_INTERNAL_CLUSTER_LOCK = "SPRING_INTEGRATION_INTERNAL_CLUSTER_LOCK";
|
||||
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
if (!Hazelcast.getAllHazelcastInstances().isEmpty()) {
|
||||
HazelcastInstance hazelcastInstance = Hazelcast.getAllHazelcastInstances().iterator().next();
|
||||
hazelcastInstance.getCluster().addMembershipListener(new HazelcastMembershipListener());
|
||||
syncConfigurationMultiMap(hazelcastInstance);
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("No Active Local Hazelcast Instance found.");
|
||||
}
|
||||
}
|
||||
|
||||
private void syncConfigurationMultiMap(HazelcastInstance hazelcastInstance) {
|
||||
Lock lock = hazelcastInstance.getLock(SPRING_INTEGRATION_INTERNAL_CLUSTER_LOCK);
|
||||
lock.lock();
|
||||
try {
|
||||
MultiMap<SocketAddress, SocketAddress> multiMap = hazelcastInstance
|
||||
.getMultiMap(SPRING_INTEGRATION_INTERNAL_CLUSTER_MULTIMAP);
|
||||
for (HazelcastInstance localInstance : Hazelcast.getAllHazelcastInstances()) {
|
||||
SocketAddress localInstanceSocketAddress = localInstance.getLocalEndpoint().getSocketAddress();
|
||||
if (multiMap.size() == 0) {
|
||||
multiMap.put(localInstanceSocketAddress, localInstanceSocketAddress);
|
||||
}
|
||||
else {
|
||||
multiMap.put(multiMap.keySet().iterator().next(), localInstanceSocketAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides common used types and classes.
|
||||
*/
|
||||
package org.springframework.integration.hazelcast.common;
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.config;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.integration.config.IntegrationConfigurationInitializer;
|
||||
import org.springframework.integration.hazelcast.common.HazelcastLocalInstanceRegistrar;
|
||||
|
||||
/**
|
||||
* The Hazelcast Integration infrastructure {@code beanFactory} initializer.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class HazelcastIntegrationConfigurationInitializer implements IntegrationConfigurationInitializer {
|
||||
|
||||
private static final String HAZELCAST_LOCAL_INSTANCE_REGISTRAR_BEAN_NAME =
|
||||
HazelcastLocalInstanceRegistrar.class.getName();
|
||||
|
||||
@Override
|
||||
public void initialize(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) beanFactory;
|
||||
if (!beanDefinitionRegistry.containsBeanDefinition(HAZELCAST_LOCAL_INSTANCE_REGISTRAR_BEAN_NAME)) {
|
||||
beanDefinitionRegistry.registerBeanDefinition(HAZELCAST_LOCAL_INSTANCE_REGISTRAR_BEAN_NAME,
|
||||
new RootBeanDefinition(HazelcastLocalInstanceRegistrar.class));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides classes for configuration.
|
||||
*/
|
||||
package org.springframework.integration.hazelcast.config;
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.config.xml;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.hazelcast.inbound.HazelcastContinuousQueryMessageProducer;
|
||||
|
||||
import reactor.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Hazelcast Continuous Query Inbound Channel Adapter Parser parses
|
||||
* {@code <int-hazelcast:cq-inbound-channel-adapter/>} configuration.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class HazelcastContinuousQueryInboundChannelAdapterParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
private static final String CHANNEL_ATTRIBUTE = "channel";
|
||||
|
||||
private static final String CACHE_ATTRIBUTE = "cache";
|
||||
|
||||
private static final String CACHE_EVENTS_ATTRIBUTE = "cache-events";
|
||||
|
||||
private static final String PREDICATE_ATTRIBUTE = "predicate";
|
||||
|
||||
private static final String INCLUDE_VALUE_ATTRIBUTE = "include-value";
|
||||
|
||||
private static final String CACHE_LISTENING_POLICY_ATTRIBUTE = "cache-listening-policy";
|
||||
|
||||
private static final String OUTPUT_CHANNEL = "outputChannel";
|
||||
|
||||
private static final String CACHE_EVENT_TYPES = "cacheEventTypes";
|
||||
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return HazelcastContinuousQueryMessageProducer.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
||||
throws BeanDefinitionStoreException {
|
||||
String id = super.resolveId(element, definition, parserContext);
|
||||
|
||||
if (!element.hasAttribute(CHANNEL_ATTRIBUTE)) {
|
||||
id = id + ".adapter";
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(id)) {
|
||||
id = BeanDefinitionReaderUtils.generateBeanName(definition, parserContext.getRegistry());
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
String channelName = element.getAttribute(CHANNEL_ATTRIBUTE);
|
||||
if (!StringUtils.hasText(channelName)) {
|
||||
channelName = IntegrationNamespaceUtils.createDirectChannel(element, parserContext);
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(element.getAttribute(CACHE_ATTRIBUTE))) {
|
||||
parserContext.getReaderContext().error("'" + CACHE_ATTRIBUTE + "' attribute is required.", element);
|
||||
}
|
||||
else if (!StringUtils.hasText(element.getAttribute(CACHE_EVENTS_ATTRIBUTE))) {
|
||||
parserContext.getReaderContext().error("'" + CACHE_EVENTS_ATTRIBUTE + "' attribute is required.", element);
|
||||
}
|
||||
else if (!StringUtils.hasText(element.getAttribute(PREDICATE_ATTRIBUTE))) {
|
||||
parserContext.getReaderContext().error("'" + PREDICATE_ATTRIBUTE + "' attribute is required.", element);
|
||||
}
|
||||
else if (!StringUtils.hasText(element.getAttribute(CACHE_LISTENING_POLICY_ATTRIBUTE))) {
|
||||
parserContext.getReaderContext().error("'" + CACHE_LISTENING_POLICY_ATTRIBUTE + "' attribute is required.",
|
||||
element);
|
||||
}
|
||||
|
||||
builder.addPropertyReference(OUTPUT_CHANNEL, channelName);
|
||||
builder.addConstructorArgReference(element.getAttribute(CACHE_ATTRIBUTE));
|
||||
builder.addConstructorArgValue(element.getAttribute(PREDICATE_ATTRIBUTE));
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, CACHE_EVENTS_ATTRIBUTE, CACHE_EVENT_TYPES);
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, INCLUDE_VALUE_ATTRIBUTE);
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, CACHE_LISTENING_POLICY_ATTRIBUTE);
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, IntegrationNamespaceUtils.AUTO_STARTUP);
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, IntegrationNamespaceUtils.PHASE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.config.xml;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.hazelcast.inbound.HazelcastDistributedSQLMessageSource;
|
||||
|
||||
import reactor.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Hazelcast Distributed SQL Inbound Channel Adapter Parser parses
|
||||
* {@code <int-hazelcast:cq-inbound-channel-adapter/>} configuration.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class HazelcastDistributedSQLInboundChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser {
|
||||
|
||||
private static final String CACHE_ATTRIBUTE = "cache";
|
||||
|
||||
private static final String DISTRIBUTED_SQL_ATTRIBUTE = "distributed-sql";
|
||||
|
||||
private static final String ITERATION_TYPE_ATTRIBUTE = "iteration-type";
|
||||
|
||||
@Override
|
||||
protected BeanMetadataElement parseSource(Element element, ParserContext parserContext) {
|
||||
if (!StringUtils.hasText(element.getAttribute(CACHE_ATTRIBUTE))) {
|
||||
parserContext.getReaderContext().error("'" + CACHE_ATTRIBUTE + "' attribute is required.", element);
|
||||
}
|
||||
else if (!StringUtils.hasText(element.getAttribute(DISTRIBUTED_SQL_ATTRIBUTE))) {
|
||||
parserContext.getReaderContext().error("'" + DISTRIBUTED_SQL_ATTRIBUTE + "' attribute is required.",
|
||||
element);
|
||||
}
|
||||
else if (!StringUtils.hasText(element.getAttribute(ITERATION_TYPE_ATTRIBUTE))) {
|
||||
parserContext.getReaderContext().error("'" + ITERATION_TYPE_ATTRIBUTE + "' attribute is required.",
|
||||
element);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(HazelcastDistributedSQLMessageSource.class.getName());
|
||||
|
||||
builder.addConstructorArgReference(element.getAttribute(CACHE_ATTRIBUTE));
|
||||
builder.addConstructorArgValue(element.getAttribute(DISTRIBUTED_SQL_ATTRIBUTE));
|
||||
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, ITERATION_TYPE_ATTRIBUTE);
|
||||
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.config.xml;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.hazelcast.inbound.HazelcastEventDrivenMessageProducer;
|
||||
|
||||
import reactor.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Hazelcast Event Driven Inbound Channel Adapter Parser parses
|
||||
* {@code <int-hazelcast:inbound-channel-adapter />} configuration.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class HazelcastEventDrivenInboundChannelAdapterParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
private static final String CHANNEL_ATTRIBUTE = "channel";
|
||||
|
||||
private static final String CACHE_ATTRIBUTE = "cache";
|
||||
|
||||
private static final String CACHE_EVENTS_ATTRIBUTE = "cache-events";
|
||||
|
||||
private static final String CACHE_LISTENING_POLICY_ATTRIBUTE = "cache-listening-policy";
|
||||
|
||||
private static final String OUTPUT_CHANNEL = "outputChannel";
|
||||
|
||||
private static final String CACHE_EVENT_TYPES = "cacheEventTypes";
|
||||
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return HazelcastEventDrivenMessageProducer.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
||||
throws BeanDefinitionStoreException {
|
||||
String id = super.resolveId(element, definition, parserContext);
|
||||
|
||||
if (!element.hasAttribute(CHANNEL_ATTRIBUTE)) {
|
||||
id = id + ".adapter";
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(id)) {
|
||||
id = BeanDefinitionReaderUtils.generateBeanName(definition, parserContext.getRegistry());
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
String channelName = element.getAttribute(CHANNEL_ATTRIBUTE);
|
||||
if (!StringUtils.hasText(channelName)) {
|
||||
channelName = IntegrationNamespaceUtils.createDirectChannel(element, parserContext);
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(element.getAttribute(CACHE_ATTRIBUTE))) {
|
||||
parserContext.getReaderContext().error("'" + CACHE_ATTRIBUTE + "' attribute is required.", element);
|
||||
}
|
||||
else if (!StringUtils.hasText(element.getAttribute(CACHE_EVENTS_ATTRIBUTE))) {
|
||||
parserContext.getReaderContext().error("'" + CACHE_EVENTS_ATTRIBUTE + "' attribute is required.", element);
|
||||
}
|
||||
else if (!StringUtils.hasText(element.getAttribute(CACHE_LISTENING_POLICY_ATTRIBUTE))) {
|
||||
parserContext.getReaderContext().error("'" + CACHE_LISTENING_POLICY_ATTRIBUTE + "' attribute is required.",
|
||||
element);
|
||||
}
|
||||
|
||||
builder.addPropertyReference(OUTPUT_CHANNEL, channelName);
|
||||
builder.addConstructorArgReference(element.getAttribute(CACHE_ATTRIBUTE));
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, CACHE_EVENTS_ATTRIBUTE, CACHE_EVENT_TYPES);
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, CACHE_LISTENING_POLICY_ATTRIBUTE);
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, IntegrationNamespaceUtils.AUTO_STARTUP);
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, IntegrationNamespaceUtils.PHASE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.config.xml;
|
||||
|
||||
import org.springframework.integration.config.xml.AbstractIntegrationNamespaceHandler;
|
||||
|
||||
/**
|
||||
* Namespace handler for the Hazelcast schema.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class HazelcastIntegrationNamespaceHandler extends AbstractIntegrationNamespaceHandler {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
registerBeanDefinitionParser("inbound-channel-adapter", new HazelcastEventDrivenInboundChannelAdapterParser());
|
||||
registerBeanDefinitionParser("outbound-channel-adapter", new HazelcastOutboundChannelAdapterParser());
|
||||
registerBeanDefinitionParser("cq-inbound-channel-adapter", new HazelcastContinuousQueryInboundChannelAdapterParser());
|
||||
registerBeanDefinitionParser("ds-inbound-channel-adapter", new HazelcastDistributedSQLInboundChannelAdapterParser());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.config.xml;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
|
||||
import org.springframework.integration.hazelcast.outbound.HazelcastCacheWritingMessageHandler;
|
||||
|
||||
import reactor.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Hazelcast Outbound Channel Adapter Parser for {@code <int-hazelcast:inbound-channel-adapter />}.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class HazelcastOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser {
|
||||
|
||||
private static final String CACHE_ATTRIBUTE = "cache";
|
||||
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(HazelcastCacheWritingMessageHandler.class);
|
||||
|
||||
if (!StringUtils.hasText(element.getAttribute(CACHE_ATTRIBUTE))) {
|
||||
parserContext.getReaderContext().error("'" + CACHE_ATTRIBUTE + "' attribute is required.", element);
|
||||
}
|
||||
|
||||
builder.addConstructorArgReference(element.getAttribute(CACHE_ATTRIBUTE));
|
||||
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides classes for parsers and namespace handlers.
|
||||
*/
|
||||
package org.springframework.integration.hazelcast.config.xml;
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.inbound;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Collections;
|
||||
import java.util.EventObject;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.integration.endpoint.MessageProducerSupport;
|
||||
import org.springframework.integration.hazelcast.common.CacheEventType;
|
||||
import org.springframework.integration.hazelcast.common.CacheListeningPolicyType;
|
||||
import org.springframework.integration.hazelcast.common.HazelcastIntegrationDefinitionValidator;
|
||||
import org.springframework.integration.hazelcast.common.HazelcastLocalInstanceRegistrar;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.hazelcast.core.AbstractIMapEvent;
|
||||
import com.hazelcast.core.DistributedObject;
|
||||
import com.hazelcast.core.EntryEvent;
|
||||
import com.hazelcast.core.EntryListener;
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.core.MapEvent;
|
||||
import com.hazelcast.core.MultiMap;
|
||||
|
||||
import reactor.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Hazelcast Base Event-Driven Message Producer.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public abstract class AbstractHazelcastMessageProducer extends MessageProducerSupport {
|
||||
|
||||
protected final DistributedObject distributedObject;
|
||||
|
||||
private CacheListeningPolicyType cacheListeningPolicy = CacheListeningPolicyType.SINGLE;
|
||||
|
||||
private String hazelcastRegisteredEventListenerId;
|
||||
|
||||
private Set<String> cacheEvents = Collections.singleton(CacheEventType.ADDED.name());
|
||||
|
||||
protected AbstractHazelcastMessageProducer(DistributedObject distributedObject) {
|
||||
Assert.notNull(distributedObject, "cache must not be null");
|
||||
this.distributedObject = distributedObject;
|
||||
}
|
||||
|
||||
protected Set<String> getCacheEvents() {
|
||||
return cacheEvents;
|
||||
}
|
||||
|
||||
public void setCacheEventTypes(String cacheEventTypes) {
|
||||
HazelcastIntegrationDefinitionValidator.validateEnumType(CacheEventType.class, cacheEventTypes);
|
||||
final Set<String> cacheEvents = StringUtils.commaDelimitedListToSet(cacheEventTypes);
|
||||
Assert.notEmpty(cacheEvents, "cacheEvents must have elements");
|
||||
HazelcastIntegrationDefinitionValidator.validateCacheEventsByDistributedObject(
|
||||
this.distributedObject, cacheEvents);
|
||||
this.cacheEvents = cacheEvents;
|
||||
}
|
||||
|
||||
protected CacheListeningPolicyType getCacheListeningPolicy() {
|
||||
return cacheListeningPolicy;
|
||||
}
|
||||
|
||||
public void setCacheListeningPolicy(CacheListeningPolicyType cacheListeningPolicy) {
|
||||
Assert.notNull(cacheListeningPolicy, "cacheListeningPolicy must not be null");
|
||||
this.cacheListeningPolicy = cacheListeningPolicy;
|
||||
}
|
||||
|
||||
protected String getHazelcastRegisteredEventListenerId() {
|
||||
return hazelcastRegisteredEventListenerId;
|
||||
}
|
||||
|
||||
protected void setHazelcastRegisteredEventListenerId(String hazelcastRegisteredEventListenerId) {
|
||||
this.hazelcastRegisteredEventListenerId = hazelcastRegisteredEventListenerId;
|
||||
}
|
||||
|
||||
protected abstract class AbstractHazelcastEventListener {
|
||||
|
||||
protected abstract void processEvent(EventObject event);
|
||||
|
||||
protected void sendMessage(final EventObject event, final InetSocketAddress socketAddress,
|
||||
final CacheListeningPolicyType cacheListeningPolicyType) {
|
||||
if (CacheListeningPolicyType.ALL == cacheListeningPolicyType || isEventAcceptable(socketAddress)) {
|
||||
AbstractHazelcastMessageProducer.this.sendMessage(getMessageBuilderFactory().withPayload(event).build());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEventAcceptable(final InetSocketAddress socketAddress) {
|
||||
final Set<HazelcastInstance> hazelcastInstanceSet = Hazelcast.getAllHazelcastInstances();
|
||||
final Set<SocketAddress> localSocketAddressesSet = getLocalSocketAddresses(hazelcastInstanceSet);
|
||||
if ((!localSocketAddressesSet.isEmpty())
|
||||
&& (localSocketAddressesSet.contains(socketAddress) ||
|
||||
isEventComingFromNonRegisteredHazelcastInstance(hazelcastInstanceSet.iterator().next(),
|
||||
localSocketAddressesSet, socketAddress))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private Set<SocketAddress> getLocalSocketAddresses(final Set<HazelcastInstance> hazelcastInstanceSet) {
|
||||
final Set<SocketAddress> localSocketAddressesSet = new HashSet<>();
|
||||
for (HazelcastInstance hazelcastInstance : hazelcastInstanceSet) {
|
||||
localSocketAddressesSet.add(hazelcastInstance.getLocalEndpoint().getSocketAddress());
|
||||
}
|
||||
|
||||
return localSocketAddressesSet;
|
||||
}
|
||||
|
||||
private boolean isEventComingFromNonRegisteredHazelcastInstance(
|
||||
final HazelcastInstance hazelcastInstance,
|
||||
final Set<SocketAddress> localSocketAddressesSet,
|
||||
final InetSocketAddress socketAddressOfEvent) {
|
||||
final MultiMap<SocketAddress, SocketAddress> configMultiMap = hazelcastInstance
|
||||
.getMultiMap(HazelcastLocalInstanceRegistrar.SPRING_INTEGRATION_INTERNAL_CLUSTER_MULTIMAP);
|
||||
return configMultiMap.size() > 0
|
||||
&& !configMultiMap.values().contains(socketAddressOfEvent)
|
||||
&& localSocketAddressesSet.contains(configMultiMap.keySet().iterator().next());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected final class HazelcastEntryListener<K, V> extends
|
||||
AbstractHazelcastEventListener implements EntryListener<K, V> {
|
||||
|
||||
@Override
|
||||
public void entryAdded(EntryEvent<K, V> event) {
|
||||
processEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void entryRemoved(EntryEvent<K, V> event) {
|
||||
processEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void entryUpdated(EntryEvent<K, V> event) {
|
||||
processEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void entryEvicted(EntryEvent<K, V> event) {
|
||||
processEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mapEvicted(MapEvent event) {
|
||||
processEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mapCleared(MapEvent event) {
|
||||
processEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processEvent(EventObject event) {
|
||||
Assert.notNull(event, "event must not be null");
|
||||
|
||||
if (getCacheEvents().contains(((AbstractIMapEvent) event).getEventType().toString())) {
|
||||
sendMessage(event, ((AbstractIMapEvent) event).getMember().getSocketAddress(),
|
||||
getCacheListeningPolicy());
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Received Event : " + event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.inbound;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.hazelcast.core.IMap;
|
||||
import com.hazelcast.query.SqlPredicate;
|
||||
|
||||
/**
|
||||
* Hazelcast Continuous Query Message Producer is a message producer which enables
|
||||
* {@link AbstractHazelcastMessageProducer.HazelcastEntryListener} with a
|
||||
* {@link SqlPredicate} in order to listen related distributed map events in the light of
|
||||
* defined predicate and sends events to related channel.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class HazelcastContinuousQueryMessageProducer extends AbstractHazelcastMessageProducer {
|
||||
|
||||
private final String predicate;
|
||||
|
||||
private boolean includeValue = true;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public HazelcastContinuousQueryMessageProducer(IMap distributedMap, String predicate) {
|
||||
super(distributedMap);
|
||||
Assert.hasText(predicate, "predicate must not be null");
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public void setIncludeValue(boolean includeValue) {
|
||||
this.includeValue = includeValue;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Override
|
||||
protected void doStart() {
|
||||
setHazelcastRegisteredEventListenerId(((IMap<?, ?>) this.distributedObject)
|
||||
.addEntryListener(new HazelcastEntryListener(), new SqlPredicate(this.predicate), this.includeValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() {
|
||||
((IMap<?, ?>) this.distributedObject).removeEntryListener(getHazelcastRegisteredEventListenerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComponentType() {
|
||||
return "hazelcast:cq-inbound-channel-adapter";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.inbound;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.integration.endpoint.AbstractMessageSource;
|
||||
import org.springframework.integration.hazelcast.common.DistributedSQLIterationType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import com.hazelcast.core.IMap;
|
||||
import com.hazelcast.query.SqlPredicate;
|
||||
|
||||
/**
|
||||
* Hazelcast Distributed SQL Message Source is a message source which runs defined
|
||||
* distributed query in the cluster and returns results in the light of iteration type.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class HazelcastDistributedSQLMessageSource extends AbstractMessageSource {
|
||||
|
||||
private final IMap<?, ?> distributedMap;
|
||||
|
||||
private final String distributedSQL;
|
||||
|
||||
private DistributedSQLIterationType iterationType = DistributedSQLIterationType.VALUE;
|
||||
|
||||
public HazelcastDistributedSQLMessageSource(IMap distributedMap, String distributedSQL) {
|
||||
Assert.notNull(distributedMap, "cache must not be null");
|
||||
Assert.hasText(distributedSQL, "distributed-sql must not be null");
|
||||
this.distributedMap = distributedMap;
|
||||
this.distributedSQL = distributedSQL;
|
||||
}
|
||||
|
||||
public void setIterationType(DistributedSQLIterationType iterationType) {
|
||||
Assert.notNull(this.iterationType, "iterationType must not be null");
|
||||
this.iterationType = iterationType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComponentType() {
|
||||
return "hazelcast:ds-inbound-channel-adapter";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<?> doReceive() {
|
||||
switch (this.iterationType) {
|
||||
case ENTRY:
|
||||
return getDistributedSQLResultSet(Collections
|
||||
.unmodifiableCollection(this.distributedMap.entrySet(new SqlPredicate(this.distributedSQL))));
|
||||
|
||||
case KEY:
|
||||
return getDistributedSQLResultSet(Collections
|
||||
.unmodifiableCollection(this.distributedMap.keySet(new SqlPredicate(this.distributedSQL))));
|
||||
|
||||
case LOCAL_KEY:
|
||||
return getDistributedSQLResultSet(Collections
|
||||
.unmodifiableCollection(this.distributedMap.localKeySet(new SqlPredicate(this.distributedSQL))));
|
||||
|
||||
default:
|
||||
return getDistributedSQLResultSet(this.distributedMap.values(new SqlPredicate(this.distributedSQL)));
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<?> getDistributedSQLResultSet(Collection<?> collection) {
|
||||
if (CollectionUtils.isEmpty(collection)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.inbound;
|
||||
|
||||
import java.util.EventObject;
|
||||
|
||||
import org.springframework.integration.hazelcast.common.HazelcastIntegrationDefinitionValidator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.hazelcast.core.DistributedObject;
|
||||
import com.hazelcast.core.IList;
|
||||
import com.hazelcast.core.IMap;
|
||||
import com.hazelcast.core.IQueue;
|
||||
import com.hazelcast.core.ISet;
|
||||
import com.hazelcast.core.ITopic;
|
||||
import com.hazelcast.core.ItemEvent;
|
||||
import com.hazelcast.core.ItemListener;
|
||||
import com.hazelcast.core.Message;
|
||||
import com.hazelcast.core.MessageListener;
|
||||
import com.hazelcast.core.MultiMap;
|
||||
import com.hazelcast.core.ReplicatedMap;
|
||||
|
||||
/**
|
||||
* Hazelcast Event Driven Message Producer is a message producer which enables
|
||||
* {@link AbstractHazelcastMessageProducer.HazelcastEntryListener},
|
||||
* {@link HazelcastEventDrivenMessageProducer.HazelcastItemListener} and
|
||||
* {@link HazelcastEventDrivenMessageProducer.HazelcastMessageListener} listeners in order
|
||||
* to listen related cache events and sends events to related channel.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public class HazelcastEventDrivenMessageProducer extends AbstractHazelcastMessageProducer {
|
||||
|
||||
public HazelcastEventDrivenMessageProducer(DistributedObject distributedObject) {
|
||||
super(distributedObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInit() {
|
||||
super.onInit();
|
||||
HazelcastIntegrationDefinitionValidator.validateCacheTypeForEventDrivenMessageProducer(this.distributedObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() {
|
||||
if(this.distributedObject instanceof IMap) {
|
||||
setHazelcastRegisteredEventListenerId(((IMap<?, ?>) this.distributedObject)
|
||||
.addEntryListener(new HazelcastEntryListener(), true));
|
||||
}
|
||||
else if(this.distributedObject instanceof MultiMap) {
|
||||
setHazelcastRegisteredEventListenerId(((MultiMap<?, ?>) this.distributedObject)
|
||||
.addEntryListener(new HazelcastEntryListener(), true));
|
||||
}
|
||||
else if(this.distributedObject instanceof ReplicatedMap) {
|
||||
setHazelcastRegisteredEventListenerId(((ReplicatedMap<?, ?>) this.distributedObject)
|
||||
.addEntryListener(new HazelcastEntryListener()));
|
||||
}
|
||||
else if(this.distributedObject instanceof IList) {
|
||||
setHazelcastRegisteredEventListenerId(((IList<?>) this.distributedObject)
|
||||
.addItemListener(new HazelcastItemListener(), true));
|
||||
}
|
||||
else if(this.distributedObject instanceof ISet) {
|
||||
setHazelcastRegisteredEventListenerId(((ISet<?>) this.distributedObject)
|
||||
.addItemListener(new HazelcastItemListener(), true));
|
||||
}
|
||||
else if(this.distributedObject instanceof IQueue) {
|
||||
setHazelcastRegisteredEventListenerId(((IQueue<?>) this.distributedObject)
|
||||
.addItemListener(new HazelcastItemListener(), true));
|
||||
}
|
||||
else if(this.distributedObject instanceof ITopic) {
|
||||
setHazelcastRegisteredEventListenerId(((ITopic<?>) this.distributedObject)
|
||||
.addMessageListener(new HazelcastMessageListener()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() {
|
||||
if(this.distributedObject instanceof IMap) {
|
||||
((IMap<?, ?>) this.distributedObject).removeEntryListener(getHazelcastRegisteredEventListenerId());
|
||||
}
|
||||
else if(this.distributedObject instanceof MultiMap) {
|
||||
((MultiMap<?, ?>) this.distributedObject).removeEntryListener(getHazelcastRegisteredEventListenerId());
|
||||
}
|
||||
else if(this.distributedObject instanceof ReplicatedMap) {
|
||||
((ReplicatedMap<?, ?>) this.distributedObject).removeEntryListener(getHazelcastRegisteredEventListenerId());
|
||||
}
|
||||
else if(this.distributedObject instanceof IList) {
|
||||
((IList<?>) this.distributedObject).removeItemListener(getHazelcastRegisteredEventListenerId());
|
||||
}
|
||||
else if(this.distributedObject instanceof ISet) {
|
||||
((ISet<?>) this.distributedObject).removeItemListener(getHazelcastRegisteredEventListenerId());
|
||||
}
|
||||
else if(this.distributedObject instanceof IQueue) {
|
||||
((IQueue<?>) this.distributedObject).removeItemListener(getHazelcastRegisteredEventListenerId());
|
||||
}
|
||||
else if(this.distributedObject instanceof ITopic) {
|
||||
((ITopic<?>) this.distributedObject).removeMessageListener(getHazelcastRegisteredEventListenerId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComponentType() {
|
||||
return "hazelcast:inbound-channel-adapter";
|
||||
}
|
||||
|
||||
private class HazelcastItemListener<E> extends AbstractHazelcastEventListener implements ItemListener<E> {
|
||||
|
||||
@Override
|
||||
public void itemAdded(ItemEvent<E> item) {
|
||||
processEvent(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void itemRemoved(ItemEvent<E> item) {
|
||||
processEvent(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processEvent(EventObject event) {
|
||||
Assert.notNull(event, "event must not be null");
|
||||
|
||||
if (getCacheEvents().contains(((ItemEvent<E>) event).getEventType().toString())) {
|
||||
sendMessage(event, ((ItemEvent<E>) event).getMember().getSocketAddress(), getCacheListeningPolicy());
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()){
|
||||
logger.debug("Received ItemEvent : " + event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class HazelcastMessageListener<E> extends AbstractHazelcastEventListener implements MessageListener<E> {
|
||||
|
||||
@Override
|
||||
public void onMessage(Message<E> message) {
|
||||
processEvent(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processEvent(EventObject event) {
|
||||
Assert.notNull(event, "event must not be null");
|
||||
sendMessage(event, ((Message<E>) event).getPublishingMember().getSocketAddress(), null);
|
||||
|
||||
if (logger.isDebugEnabled()){
|
||||
logger.debug("Received Message : " + event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides classes supporting inbound endpoints.
|
||||
*/
|
||||
package org.springframework.integration.hazelcast.inbound;
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.listener;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import org.springframework.integration.hazelcast.common.HazelcastLocalInstanceRegistrar;
|
||||
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.core.MembershipAdapter;
|
||||
import com.hazelcast.core.MembershipEvent;
|
||||
import com.hazelcast.core.MultiMap;
|
||||
|
||||
/**
|
||||
* Hazelcast {@link MembershipAdapter} in order to listen for membership updates in the cluster.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class HazelcastMembershipListener extends MembershipAdapter {
|
||||
|
||||
@Override
|
||||
public void memberRemoved(MembershipEvent membershipEvent) {
|
||||
SocketAddress removedMemberSocketAddress = membershipEvent.getMember().getSocketAddress();
|
||||
Set<HazelcastInstance> hazelcastLocalInstanceSet = Hazelcast.getAllHazelcastInstances();
|
||||
if (!hazelcastLocalInstanceSet.isEmpty()) {
|
||||
HazelcastInstance hazelcastInstance = hazelcastLocalInstanceSet.iterator().next();
|
||||
Lock lock = hazelcastInstance
|
||||
.getLock(HazelcastLocalInstanceRegistrar.SPRING_INTEGRATION_INTERNAL_CLUSTER_LOCK);
|
||||
lock.lock();
|
||||
try {
|
||||
MultiMap<SocketAddress, SocketAddress> configMultiMap = hazelcastInstance
|
||||
.getMultiMap(HazelcastLocalInstanceRegistrar.SPRING_INTEGRATION_INTERNAL_CLUSTER_MULTIMAP);
|
||||
|
||||
if (configMultiMap.containsKey(removedMemberSocketAddress)) {
|
||||
SocketAddress newAdminSocketAddress = getNewAdminInstanceSocketAddress(
|
||||
configMultiMap, removedMemberSocketAddress);
|
||||
for (SocketAddress socketAddress : configMultiMap.values()) {
|
||||
if (!socketAddress.equals(removedMemberSocketAddress)) {
|
||||
configMultiMap.put(newAdminSocketAddress, socketAddress);
|
||||
}
|
||||
}
|
||||
configMultiMap.remove(removedMemberSocketAddress);
|
||||
}
|
||||
else {
|
||||
configMultiMap.remove(configMultiMap.keySet().iterator().next(), removedMemberSocketAddress);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SocketAddress getNewAdminInstanceSocketAddress(
|
||||
MultiMap<SocketAddress, SocketAddress> configMultiMap, SocketAddress removedMemberSocketAddress) {
|
||||
for (SocketAddress socketAddress : configMultiMap.values()) {
|
||||
if (!socketAddress.equals(removedMemberSocketAddress)) {
|
||||
return socketAddress;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException("No Active Hazelcast Instance Found.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides classes for listeners.
|
||||
*/
|
||||
package org.springframework.integration.hazelcast.listener;
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.outbound;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.integration.handler.AbstractMessageHandler;
|
||||
import org.springframework.integration.hazelcast.common.HazelcastIntegrationDefinitionValidator;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.hazelcast.core.DistributedObject;
|
||||
import com.hazelcast.core.IList;
|
||||
import com.hazelcast.core.IMap;
|
||||
import com.hazelcast.core.IQueue;
|
||||
import com.hazelcast.core.ISet;
|
||||
|
||||
/**
|
||||
* MessageHandler implementation that writes {@link Message} payload to defined Hazelcast
|
||||
* distributed cache object. Currently, it supports {@link java.util.Map},
|
||||
* {@link java.util.List}, {@link java.util.Set} and {@link java.util.Queue} data
|
||||
* structures.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class HazelcastCacheWritingMessageHandler extends AbstractMessageHandler {
|
||||
|
||||
private final DistributedObject distributedObject;
|
||||
|
||||
public HazelcastCacheWritingMessageHandler(DistributedObject distributedObject) {
|
||||
Assert.notNull(distributedObject, "cache must not be null");
|
||||
this.distributedObject = distributedObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInit() throws Exception {
|
||||
super.onInit();
|
||||
HazelcastIntegrationDefinitionValidator.validateCacheTypeForCacheWritingMessageHandler(this.distributedObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleMessageInternal(Message<?> message) throws Exception {
|
||||
writeToCache(message);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private void writeToCache(Message<?> message) {
|
||||
if (this.distributedObject instanceof IMap) {
|
||||
((IMap<?, ?>) this.distributedObject).putAll((Map) message.getPayload());
|
||||
}
|
||||
else if (this.distributedObject instanceof IList) {
|
||||
((IList<?>) this.distributedObject).addAll((List) message.getPayload());
|
||||
}
|
||||
else if (this.distributedObject instanceof ISet) {
|
||||
((ISet<?>) this.distributedObject).addAll((Set) message.getPayload());
|
||||
}
|
||||
else if (this.distributedObject instanceof IQueue) {
|
||||
((IQueue<?>) this.distributedObject).addAll((Queue) message.getPayload());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides classes supporting outbound endpoints.
|
||||
*/
|
||||
package org.springframework.integration.hazelcast.outbound;
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.integration.config.IntegrationConfigurationInitializer=\
|
||||
org.springframework.integration.hazelcast.config.HazelcastIntegrationConfigurationInitializer
|
||||
@@ -0,0 +1 @@
|
||||
http\://www.springframework.org/schema/integration/hazelcast=org.springframework.integration.hazelcast.config.xml.HazelcastIntegrationNamespaceHandler
|
||||
@@ -0,0 +1,2 @@
|
||||
http\://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast-1.0.xsd=org/springframework/integration/hazelcast/config/xml/spring-integration-hazelcast-1.0.xsd
|
||||
http\://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd=org/springframework/integration/hazelcast/config/xml/spring-integration-hazelcast-1.0.xsd
|
||||
@@ -0,0 +1,235 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsd:schema xmlns="http://www.springframework.org/schema/integration/hazelcast"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
xmlns:integration="http://www.springframework.org/schema/integration"
|
||||
targetNamespace="http://www.springframework.org/schema/integration/hazelcast"
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
|
||||
<xsd:import namespace="http://www.springframework.org/schema/beans"
|
||||
schemaLocation="http://www.springframework.org/schema/beans/spring-beans.xsd"/>
|
||||
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
|
||||
<xsd:import namespace="http://www.springframework.org/schema/integration"
|
||||
schemaLocation="http://www.springframework.org/schema/integration/spring-integration.xsd"/>
|
||||
|
||||
<xsd:element name="inbound-channel-adapter">
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Configures Hazelcast Event-Driven Inbound Channel Adapter
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:complexType>
|
||||
<xsd:attributeGroup ref="integration:channelAdapterAttributes"/>
|
||||
|
||||
<xsd:attribute name="cache" use="required" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="com.hazelcast.core.DistributedObject" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Specifies cache reference to listen ]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
<xsd:attribute name="cache-events" type="xsd:string" use="optional" default="ADDED">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="value">
|
||||
<tool:expected-type
|
||||
type="org.springframework.integration.hazelcast.common.CacheEventType" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Specifies cache entry event types ]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
<xsd:attribute name="cache-listening-policy" default="SINGLE" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[ Specifies cache listening policy. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="SINGLE" />
|
||||
<xsd:enumeration value="ALL" />
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="outbound-channel-adapter">
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Configures Hazelcast Outbound Channel Adapter
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:complexType>
|
||||
<xsd:all>
|
||||
<xsd:element name="request-handler-advice-chain" type="integration:handlerAdviceChainType"
|
||||
minOccurs="0" maxOccurs="1" />
|
||||
</xsd:all>
|
||||
|
||||
<xsd:attributeGroup ref="integration:channelAdapterAttributes"/>
|
||||
|
||||
<xsd:attribute name="cache" use="required" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="com.hazelcast.core.DistributedObject" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Specifies cache reference to listen ]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
<xsd:attribute name="order" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Specifies the order for invocation when this endpoint is connected as a
|
||||
subscriber to a SubscribableChannel.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="cq-inbound-channel-adapter">
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Configures Hazelcast Continuous Query Inbound Channel Adapter
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:complexType>
|
||||
|
||||
<xsd:attributeGroup ref="integration:channelAdapterAttributes"/>
|
||||
|
||||
<xsd:attribute name="cache" use="required" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="com.hazelcast.core.IMap" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Specifies cache reference to listen ]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
<xsd:attribute name="cache-events" type="xsd:string" use="optional" default="ADDED">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="value">
|
||||
<tool:expected-type
|
||||
type="org.springframework.integration.hazelcast.common.CacheEventType" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Specifies cache entry event types ]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
<xsd:attribute name="predicate" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Specifies predicate for continuous query ]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
<xsd:attribute name="include-value" type="xsd:boolean" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Specifies including of value and oldValue in continuous query result ]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
<xsd:attribute name="cache-listening-policy" default="SINGLE" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[ Specifies cache listening policy. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="SINGLE" />
|
||||
<xsd:enumeration value="ALL" />
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="ds-inbound-channel-adapter">
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Configures Hazelcast Distributed SQL Inbound Channel Adapter
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:complexType>
|
||||
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
|
||||
<xsd:attributeGroup ref="integration:channelAdapterAttributes"/>
|
||||
|
||||
<xsd:attribute name="cache" use="required" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="com.hazelcast.core.IMap" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Specifies cache reference to listen ]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
<xsd:attribute name="iteration-type" default="VALUE" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[ Specifies Distributed-SQL Iteration Types. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="ENTRY" />
|
||||
<xsd:enumeration value="KEY" />
|
||||
<xsd:enumeration value="LOCAL_KEY" />
|
||||
<xsd:enumeration value="VALUE" />
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
|
||||
<xsd:attribute name="distributed-sql" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Specifies Distributed-SQL ]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
</xsd:complexType>
|
||||
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* User Bean for Hazelcast Integration Unit Tests
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class HazelcastIntegrationTestUser implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -5357485957528362705L;
|
||||
|
||||
private int id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String surname;
|
||||
|
||||
private int age;
|
||||
|
||||
public HazelcastIntegrationTestUser(int id, String name, String surname) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.surname = surname;
|
||||
}
|
||||
|
||||
public HazelcastIntegrationTestUser(int id, String name, String surname, int age) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.surname = surname;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getSurname() {
|
||||
return surname;
|
||||
}
|
||||
|
||||
public void setSurname(String surname) {
|
||||
this.surname = surname;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User [id=" + id + ", name=" + name + ", surname=" + surname + ", age="
|
||||
+ age + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + age;
|
||||
result = prime * result + id;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((surname == null) ? 0 : surname.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
HazelcastIntegrationTestUser other = (HazelcastIntegrationTestUser) obj;
|
||||
if (age != other.age)
|
||||
return false;
|
||||
if (id != other.id)
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
}
|
||||
else if (!name.equals(other.name))
|
||||
return false;
|
||||
if (surname == null) {
|
||||
if (other.surname != null)
|
||||
return false;
|
||||
}
|
||||
else if (!surname.equals(other.surname))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-hazelcast="http://www.springframework.org/schema/integration/hazelcast"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
http://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<int:channel id="cqMapChannel1">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="cqMapChannel2">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="cqMapChannel3">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="cqMapChannel4">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="cqMapChannel5">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int-hazelcast:cq-inbound-channel-adapter channel="cqMapChannel1" cache="cqDistributedMap1"
|
||||
predicate="name=TestName1"/>
|
||||
<int-hazelcast:cq-inbound-channel-adapter channel="cqMapChannel2" cache="cqDistributedMap2" cache-events="REMOVED"
|
||||
predicate="name=TestName2" include-value="true"/>
|
||||
<int-hazelcast:cq-inbound-channel-adapter channel="cqMapChannel3" cache="cqDistributedMap3"
|
||||
cache-events="ADDED,REMOVED,UPDATED,CLEAR_ALL"
|
||||
predicate="name=TestName1 OR name=TestName2"/>
|
||||
<int-hazelcast:cq-inbound-channel-adapter channel="cqMapChannel4" cache="cqDistributedMap4" cache-events="UPDATED"
|
||||
predicate="surname=TestSurname2" include-value="true"/>
|
||||
<int-hazelcast:cq-inbound-channel-adapter channel="cqMapChannel5" cache="cqDistributedMap5" cache-events="UPDATED"
|
||||
predicate="surname=TestSurname2" include-value="false"/>
|
||||
|
||||
<bean id="cqDistributedMap1" factory-bean="cqInstance" factory-method="getMap">
|
||||
<constructor-arg value="cqDistributedMap1"/>
|
||||
</bean>
|
||||
|
||||
<bean id="cqDistributedMap2" factory-bean="cqInstance" factory-method="getMap">
|
||||
<constructor-arg value="cqDistributedMap2"/>
|
||||
</bean>
|
||||
|
||||
<bean id="cqDistributedMap3" factory-bean="cqInstance" factory-method="getMap">
|
||||
<constructor-arg value="cqDistributedMap3"/>
|
||||
</bean>
|
||||
|
||||
<bean id="cqDistributedMap4" factory-bean="cqInstance" factory-method="getMap">
|
||||
<constructor-arg value="cqDistributedMap4"/>
|
||||
</bean>
|
||||
|
||||
<bean id="cqDistributedMap5" factory-bean="cqInstance" factory-method="getMap">
|
||||
<constructor-arg value="cqDistributedMap5"/>
|
||||
</bean>
|
||||
|
||||
<bean id="cqInstance" class="com.hazelcast.core.Hazelcast" factory-method="newHazelcastInstance"
|
||||
destroy-method="shutdown">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.inbound;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.hazelcast.core.AbstractIMapEvent;
|
||||
import com.hazelcast.core.EntryEvent;
|
||||
import com.hazelcast.core.EntryEventType;
|
||||
import com.hazelcast.core.IMap;
|
||||
|
||||
/**
|
||||
* Hazelcast Continuous Query Inbound Channel Adapter Unit Test Class
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
public class HazelcastCQDistributedMapInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cqMapChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cqMapChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cqMapChannel3;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cqMapChannel4;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cqMapChannel5;
|
||||
|
||||
@Resource
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> cqDistributedMap1;
|
||||
|
||||
@Resource
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> cqDistributedMap2;
|
||||
|
||||
@Resource
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> cqDistributedMap3;
|
||||
|
||||
@Resource
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> cqDistributedMap4;
|
||||
|
||||
@Resource
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> cqDistributedMap5;
|
||||
|
||||
@Test
|
||||
public void testContinuousQueryForOnlyADDEDEntryEvent() {
|
||||
cqDistributedMap1.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
cqDistributedMap1.remove(1);
|
||||
cqDistributedMap1.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
Message<?> msg = cqMapChannel1.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof EntryEvent);
|
||||
Assert.assertEquals(EntryEventType.ADDED,
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getEventType());
|
||||
Assert.assertEquals("cqDistributedMap1",
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getName());
|
||||
Assert.assertEquals(1, ((EntryEvent<?, ?>) msg.getPayload()).getKey());
|
||||
Assert.assertEquals(1,
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getId());
|
||||
Assert.assertEquals("TestName1",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getName());
|
||||
Assert.assertEquals("TestSurname1",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContinuousQueryForOnlyREMOVEDEntryEvent() {
|
||||
cqDistributedMap2.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
cqDistributedMap2.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
cqDistributedMap2.remove(2);
|
||||
Message<?> msg = cqMapChannel2.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof EntryEvent);
|
||||
Assert.assertEquals(EntryEventType.REMOVED,
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getEventType());
|
||||
Assert.assertEquals("cqDistributedMap2",
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getName());
|
||||
Assert.assertEquals(2, ((EntryEvent<?, ?>) msg.getPayload()).getKey());
|
||||
Assert.assertEquals(2,
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getId());
|
||||
Assert.assertEquals("TestName2",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getName());
|
||||
Assert.assertEquals("TestSurname2",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContinuousQueryForALLEntryEvent() {
|
||||
cqDistributedMap3.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg = cqMapChannel3.receive(2_000);
|
||||
verify(msg, "cqDistributedMap3", EntryEventType.ADDED);
|
||||
|
||||
cqDistributedMap3.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurnameUpdated"));
|
||||
msg = cqMapChannel3.receive(2_000);
|
||||
verify(msg, "cqDistributedMap3", EntryEventType.UPDATED);
|
||||
|
||||
cqDistributedMap3.remove(1);
|
||||
msg = cqMapChannel3.receive(2_000);
|
||||
verify(msg, "cqDistributedMap3", EntryEventType.REMOVED);
|
||||
|
||||
cqDistributedMap3.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
msg = cqMapChannel3.receive(2_000);
|
||||
verify(msg, "cqDistributedMap3", EntryEventType.ADDED);
|
||||
|
||||
cqDistributedMap3.clear();
|
||||
msg = cqMapChannel3.receive(2_000);
|
||||
verify(msg, "cqDistributedMap3", EntryEventType.CLEAR_ALL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContinuousQueryForOnlyUPDATEDEntryEvent() {
|
||||
cqDistributedMap4.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
cqDistributedMap4.put(1, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
Message<?> msg = cqMapChannel4.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof EntryEvent);
|
||||
Assert.assertEquals(EntryEventType.UPDATED,
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getEventType());
|
||||
Assert.assertEquals("cqDistributedMap4",
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getName());
|
||||
Assert.assertEquals(1, ((EntryEvent<?, ?>) msg.getPayload()).getKey());
|
||||
Assert.assertEquals(1,
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getId());
|
||||
Assert.assertEquals("TestName1",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getName());
|
||||
Assert.assertEquals("TestSurname1",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getSurname());
|
||||
Assert.assertEquals(2,
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getId());
|
||||
Assert.assertEquals("TestName2",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getName());
|
||||
Assert.assertEquals("TestSurname2",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContinuousQueryForOnlyUPDATEDEntryEventWhenIncludeValueIsFalse() {
|
||||
cqDistributedMap5.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
cqDistributedMap5.put(1, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
Message<?> msg = cqMapChannel5.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof EntryEvent);
|
||||
Assert.assertEquals(EntryEventType.UPDATED, ((EntryEvent<?, ?>) msg.getPayload()).getEventType());
|
||||
Assert.assertEquals("cqDistributedMap5", ((EntryEvent<?, ?>) msg.getPayload()).getName());
|
||||
Assert.assertEquals(1, ((EntryEvent<?, ?>) msg.getPayload()).getKey());
|
||||
Assert.assertNull(((EntryEvent<?, ?>) msg.getPayload()).getOldValue());
|
||||
Assert.assertNull(((EntryEvent<?, ?>) msg.getPayload()).getValue());
|
||||
}
|
||||
|
||||
private void verify(Message<?> msg, String cacheName, EntryEventType type) {
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof AbstractIMapEvent);
|
||||
Assert.assertEquals(cacheName, ((AbstractIMapEvent) msg.getPayload()).getName());
|
||||
Assert.assertEquals(type, ((AbstractIMapEvent) msg.getPayload()).getEventType());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-hazelcast="http://www.springframework.org/schema/integration/hazelcast"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
http://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<int:channel id="edListChannel1">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="edListChannel2">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="edListChannel3">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int-hazelcast:inbound-channel-adapter channel="edListChannel1" cache="edDistributedList1"/>
|
||||
<int-hazelcast:inbound-channel-adapter channel="edListChannel2" cache="edDistributedList2" cache-events="REMOVED"
|
||||
cache-listening-policy="SINGLE"/>
|
||||
<int-hazelcast:inbound-channel-adapter channel="edListChannel3" cache="edDistributedList3"
|
||||
cache-events="ADDED,REMOVED"/>
|
||||
|
||||
<bean id="edDistributedList1" factory-bean="edListInstance" factory-method="getList">
|
||||
<constructor-arg value="edDistributedList1"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedList2" factory-bean="edListInstance" factory-method="getList">
|
||||
<constructor-arg value="edDistributedList2"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedList3" factory-bean="edListInstance" factory-method="getList">
|
||||
<constructor-arg value="edDistributedList3"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edListInstance" class="com.hazelcast.core.Hazelcast" factory-method="newHazelcastInstance"
|
||||
destroy-method="shutdown">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.inbound;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.hazelcast.core.EntryEventType;
|
||||
import com.hazelcast.core.IList;
|
||||
import com.hazelcast.core.ItemEvent;
|
||||
|
||||
/**
|
||||
* Hazelcast Distributed List Event Driven Inbound Channel Adapter Test Class
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
public class HazelcastDistributedListEventDrivenInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edListChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edListChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edListChannel3;
|
||||
|
||||
@Resource
|
||||
private IList<HazelcastIntegrationTestUser> edDistributedList1;
|
||||
|
||||
@Resource
|
||||
private IList<HazelcastIntegrationTestUser> edDistributedList2;
|
||||
|
||||
@Resource
|
||||
private IList<HazelcastIntegrationTestUser> edDistributedList3;
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyADDEDEntryEvent() {
|
||||
edDistributedList1.add(new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg = edListChannel1.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof ItemEvent);
|
||||
Assert.assertEquals(EntryEventType.ADDED.toString(),
|
||||
((ItemEvent<?>) msg.getPayload()).getEventType().toString());
|
||||
Assert.assertEquals(1,
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getId());
|
||||
Assert.assertEquals("TestName1",
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getName());
|
||||
Assert.assertEquals("TestSurname1",
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyREMOVEDEntryEvent() {
|
||||
HazelcastIntegrationTestUser user = new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2");
|
||||
edDistributedList2.add(user);
|
||||
edDistributedList2.remove(user);
|
||||
Message<?> msg = edListChannel2.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof ItemEvent);
|
||||
Assert.assertEquals(EntryEventType.REMOVED.toString(),
|
||||
((ItemEvent<?>) msg.getPayload()).getEventType().toString());
|
||||
Assert.assertEquals(2,
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getId());
|
||||
Assert.assertEquals("TestName2",
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getName());
|
||||
Assert.assertEquals("TestSurname2",
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForALLEntryEvent() {
|
||||
HazelcastIntegrationTestUser user = new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1");
|
||||
edDistributedList3.add(user);
|
||||
Message<?> msg = edListChannel3.receive(2_000);
|
||||
verify(msg, EntryEventType.ADDED);
|
||||
|
||||
edDistributedList3.remove(user);
|
||||
msg = edListChannel3.receive(2_000);
|
||||
verify(msg, EntryEventType.REMOVED);
|
||||
|
||||
user = new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2");
|
||||
edDistributedList3.add(user);
|
||||
msg = edListChannel3.receive(2_000);
|
||||
verify(msg, EntryEventType.ADDED);
|
||||
}
|
||||
|
||||
private void verify(Message<?> msg, EntryEventType type) {
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof ItemEvent);
|
||||
Assert.assertEquals(type.toString(),
|
||||
((ItemEvent<?>) msg.getPayload()).getEventType().toString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-hazelcast="http://www.springframework.org/schema/integration/hazelcast"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
http://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<int:channel id="edMapChannel1">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="edMapChannel2">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="edMapChannel3">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="edMapChannel4">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int-hazelcast:inbound-channel-adapter channel="edMapChannel1" cache="edDistributedMap1"/>
|
||||
<int-hazelcast:inbound-channel-adapter channel="edMapChannel2" cache="edDistributedMap2" cache-events="UPDATED"/>
|
||||
<int-hazelcast:inbound-channel-adapter channel="edMapChannel3" cache="edDistributedMap3" cache-events="REMOVED"
|
||||
cache-listening-policy="SINGLE"/>
|
||||
<int-hazelcast:inbound-channel-adapter channel="edMapChannel4" cache="edDistributedMap4"
|
||||
cache-events="ADDED,REMOVED,UPDATED,CLEAR_ALL"/>
|
||||
|
||||
<bean id="edDistributedMap1" factory-bean="edMapInstance" factory-method="getMap">
|
||||
<constructor-arg value="edDistributedMap1"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedMap2" factory-bean="edMapInstance" factory-method="getMap">
|
||||
<constructor-arg value="edDistributedMap2"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedMap3" factory-bean="edMapInstance" factory-method="getMap">
|
||||
<constructor-arg value="edDistributedMap3"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedMap4" factory-bean="edMapInstance" factory-method="getMap">
|
||||
<constructor-arg value="edDistributedMap4"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edMapInstance" class="com.hazelcast.core.Hazelcast" factory-method="newHazelcastInstance"
|
||||
destroy-method="shutdown">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.inbound;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.hazelcast.core.AbstractIMapEvent;
|
||||
import com.hazelcast.core.EntryEvent;
|
||||
import com.hazelcast.core.EntryEventType;
|
||||
import com.hazelcast.core.IMap;
|
||||
|
||||
/**
|
||||
* Hazelcast Distributed Map Event Driven Inbound Channel Adapter Test
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
public class HazelcastDistributedMapEventDrivenInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edMapChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edMapChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edMapChannel3;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edMapChannel4;
|
||||
|
||||
@Resource
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> edDistributedMap1;
|
||||
|
||||
@Resource
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> edDistributedMap2;
|
||||
|
||||
@Resource
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> edDistributedMap3;
|
||||
|
||||
@Resource
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> edDistributedMap4;
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyADDEDEntryEvent() {
|
||||
edDistributedMap1.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg = edMapChannel1.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof EntryEvent);
|
||||
Assert.assertEquals(EntryEventType.ADDED,
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getEventType());
|
||||
Assert.assertEquals("edDistributedMap1",
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getName());
|
||||
Assert.assertEquals(1, ((EntryEvent<?, ?>) msg.getPayload()).getKey());
|
||||
Assert.assertEquals(1,
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getId());
|
||||
Assert.assertEquals("TestName1",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getName());
|
||||
Assert.assertEquals("TestSurname1",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyUPDATEDEntryEvent() {
|
||||
edDistributedMap2.put(2, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
edDistributedMap2.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
Message<?> msg = edMapChannel2.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof EntryEvent);
|
||||
Assert.assertEquals(EntryEventType.UPDATED,
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getEventType());
|
||||
Assert.assertEquals("edDistributedMap2",
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getName());
|
||||
Assert.assertEquals(2, ((EntryEvent<?, ?>) msg.getPayload()).getKey());
|
||||
Assert.assertEquals(1,
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getId());
|
||||
Assert.assertEquals("TestName1",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getName());
|
||||
Assert.assertEquals("TestSurname1",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getSurname());
|
||||
Assert.assertEquals(2,
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getId());
|
||||
Assert.assertEquals("TestName2",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getName());
|
||||
Assert.assertEquals("TestSurname2",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyREMOVEDEntryEvent() {
|
||||
edDistributedMap3.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
edDistributedMap3.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
edDistributedMap3.remove(2);
|
||||
Message<?> msg = edMapChannel3.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof EntryEvent);
|
||||
Assert.assertEquals(EntryEventType.REMOVED,
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getEventType());
|
||||
Assert.assertEquals("edDistributedMap3",
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getName());
|
||||
Assert.assertEquals(2, ((EntryEvent<?, ?>) msg.getPayload()).getKey());
|
||||
Assert.assertEquals(2,
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getId());
|
||||
Assert.assertEquals("TestName2",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getName());
|
||||
Assert.assertEquals("TestSurname2",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForALLEntryEvent() {
|
||||
edDistributedMap4.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg = edMapChannel4.receive(2_000);
|
||||
verify(msg, "edDistributedMap4", EntryEventType.ADDED);
|
||||
|
||||
edDistributedMap4.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurnameUpdated"));
|
||||
msg = edMapChannel4.receive(2_000);
|
||||
verify(msg, "edDistributedMap4", EntryEventType.UPDATED);
|
||||
|
||||
edDistributedMap4.remove(1);
|
||||
msg = edMapChannel4.receive(2_000);
|
||||
verify(msg, "edDistributedMap4", EntryEventType.REMOVED);
|
||||
|
||||
edDistributedMap4.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
msg = edMapChannel4.receive(2_000);
|
||||
verify(msg, "edDistributedMap4", EntryEventType.ADDED);
|
||||
|
||||
edDistributedMap4.clear();
|
||||
msg = edMapChannel4.receive(2_000);
|
||||
verify(msg, "edDistributedMap4", EntryEventType.CLEAR_ALL);
|
||||
}
|
||||
|
||||
private void verify(Message<?> msg, String cacheName, EntryEventType type) {
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof AbstractIMapEvent);
|
||||
Assert.assertEquals(cacheName, ((AbstractIMapEvent) msg.getPayload()).getName());
|
||||
Assert.assertEquals(type, ((AbstractIMapEvent) msg.getPayload()).getEventType());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-hazelcast="http://www.springframework.org/schema/integration/hazelcast"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
http://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<int:channel id="edQueueChannel1">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="edQueueChannel2">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="edQueueChannel3">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int-hazelcast:inbound-channel-adapter channel="edQueueChannel1" cache="edDistributedQueue1"
|
||||
cache-listening-policy="SINGLE"/>
|
||||
<int-hazelcast:inbound-channel-adapter channel="edQueueChannel2" cache="edDistributedQueue2"
|
||||
cache-events="REMOVED"/>
|
||||
<int-hazelcast:inbound-channel-adapter channel="edQueueChannel3" cache="edDistributedQueue3"
|
||||
cache-events="ADDED,REMOVED"/>
|
||||
|
||||
<bean id="edDistributedQueue1" factory-bean="edQueueInstance" factory-method="getQueue">
|
||||
<constructor-arg value="edDistributedQueue1"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedQueue2" factory-bean="edQueueInstance" factory-method="getQueue">
|
||||
<constructor-arg value="edDistributedQueue2"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedQueue3" factory-bean="edQueueInstance" factory-method="getQueue">
|
||||
<constructor-arg value="edDistributedQueue3"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edQueueInstance" class="com.hazelcast.core.Hazelcast" factory-method="newHazelcastInstance"
|
||||
destroy-method="shutdown">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.inbound;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.hazelcast.core.EntryEventType;
|
||||
import com.hazelcast.core.IQueue;
|
||||
import com.hazelcast.core.ItemEvent;
|
||||
|
||||
/**
|
||||
* Hazelcast Distributed Queue Event Driven Inbound Channel Adapter Test
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
public class HazelcastDistributedQueueEventDrivenInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edQueueChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edQueueChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edQueueChannel3;
|
||||
|
||||
@Resource
|
||||
private IQueue<HazelcastIntegrationTestUser> edDistributedQueue1;
|
||||
|
||||
@Resource
|
||||
private IQueue<HazelcastIntegrationTestUser> edDistributedQueue2;
|
||||
|
||||
@Resource
|
||||
private IQueue<HazelcastIntegrationTestUser> edDistributedQueue3;
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyADDEDEntryEvent() {
|
||||
edDistributedQueue1.add(new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg = edQueueChannel1.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof ItemEvent);
|
||||
Assert.assertEquals(EntryEventType.ADDED.toString(),
|
||||
((ItemEvent<?>) msg.getPayload()).getEventType().toString());
|
||||
Assert.assertEquals(1,
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getId());
|
||||
Assert.assertEquals("TestName1",
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getName());
|
||||
Assert.assertEquals("TestSurname1",
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyREMOVEDEntryEvent() {
|
||||
HazelcastIntegrationTestUser user = new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2");
|
||||
edDistributedQueue2.add(user);
|
||||
edDistributedQueue2.remove(user);
|
||||
Message<?> msg = edQueueChannel2.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof ItemEvent);
|
||||
Assert.assertEquals(EntryEventType.REMOVED.toString(),
|
||||
((ItemEvent<?>) msg.getPayload()).getEventType().toString());
|
||||
Assert.assertEquals(2,
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getId());
|
||||
Assert.assertEquals("TestName2",
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getName());
|
||||
Assert.assertEquals("TestSurname2",
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForALLEntryEvent() {
|
||||
HazelcastIntegrationTestUser user = new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1");
|
||||
edDistributedQueue3.add(user);
|
||||
Message<?> msg = edQueueChannel3.receive(2_000);
|
||||
verify(msg, EntryEventType.ADDED);
|
||||
|
||||
edDistributedQueue3.remove(user);
|
||||
msg = edQueueChannel3.receive(2_000);
|
||||
verify(msg, EntryEventType.REMOVED);
|
||||
|
||||
user = new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2");
|
||||
edDistributedQueue3.add(user);
|
||||
msg = edQueueChannel3.receive(2_000);
|
||||
verify(msg, EntryEventType.ADDED);
|
||||
}
|
||||
|
||||
private void verify(Message<?> msg, EntryEventType type) {
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof ItemEvent);
|
||||
Assert.assertEquals(type.toString(), ((ItemEvent<?>) msg.getPayload())
|
||||
.getEventType().toString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-hazelcast="http://www.springframework.org/schema/integration/hazelcast"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
http://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<int:channel id="dsMapChannel1">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="dsMapChannel2">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="dsMapChannel3">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="dsMapChannel4">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int-hazelcast:ds-inbound-channel-adapter channel="dsMapChannel1" cache="dsDistributedMap1" iteration-type="ENTRY"
|
||||
distributed-sql="age = 40">
|
||||
<int:poller fixed-delay="100"/>
|
||||
</int-hazelcast:ds-inbound-channel-adapter>
|
||||
|
||||
<int-hazelcast:ds-inbound-channel-adapter channel="dsMapChannel2" cache="dsDistributedMap2" iteration-type="KEY"
|
||||
distributed-sql="age > 0 AND age <= 10">
|
||||
<int:poller fixed-delay="100"/>
|
||||
</int-hazelcast:ds-inbound-channel-adapter>
|
||||
|
||||
<int-hazelcast:ds-inbound-channel-adapter channel="dsMapChannel3" cache="dsDistributedMap3"
|
||||
iteration-type="LOCAL_KEY" distributed-sql="age > 10 AND age <= 20">
|
||||
<int:poller fixed-delay="100"/>
|
||||
</int-hazelcast:ds-inbound-channel-adapter>
|
||||
|
||||
<int-hazelcast:ds-inbound-channel-adapter channel="dsMapChannel4" cache="dsDistributedMap4" iteration-type="VALUE"
|
||||
distributed-sql="age > 20 AND age <= 30">
|
||||
<int:poller fixed-delay="100"/>
|
||||
</int-hazelcast:ds-inbound-channel-adapter>
|
||||
|
||||
<bean id="dsDistributedMap1" factory-bean="dsInstance" factory-method="getMap">
|
||||
<constructor-arg value="dsDistributedMap1"/>
|
||||
</bean>
|
||||
|
||||
<bean id="dsDistributedMap2" factory-bean="dsInstance" factory-method="getMap">
|
||||
<constructor-arg value="dsDistributedMap2"/>
|
||||
</bean>
|
||||
|
||||
<bean id="dsDistributedMap3" factory-bean="dsInstance" factory-method="getMap">
|
||||
<constructor-arg value="dsDistributedMap3"/>
|
||||
</bean>
|
||||
|
||||
<bean id="dsDistributedMap4" factory-bean="dsInstance" factory-method="getMap">
|
||||
<constructor-arg value="dsDistributedMap4"/>
|
||||
</bean>
|
||||
|
||||
<bean id="dsInstance" class="com.hazelcast.core.Hazelcast" factory-method="newHazelcastInstance"
|
||||
destroy-method="shutdown">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.inbound;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.hazelcast.core.IMap;
|
||||
|
||||
/**
|
||||
* Hazelcast Distributed SQL Inbound Channel Adapter Test
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
public class HazelcastDistributedSQLInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel dsMapChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel dsMapChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel dsMapChannel3;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel dsMapChannel4;
|
||||
|
||||
@Resource
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> dsDistributedMap1;
|
||||
|
||||
@Resource
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> dsDistributedMap2;
|
||||
|
||||
@Resource
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> dsDistributedMap3;
|
||||
|
||||
@Resource
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> dsDistributedMap4;
|
||||
|
||||
@Test
|
||||
public void testDistributedSQLForOnlyENTRYIterationType() throws InterruptedException {
|
||||
dsDistributedMap1.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1", 10));
|
||||
dsDistributedMap1.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2", 20));
|
||||
dsDistributedMap1.put(3, new HazelcastIntegrationTestUser(3, "TestName3", "TestSurname3", 30));
|
||||
dsDistributedMap1.put(4, new HazelcastIntegrationTestUser(4, "TestName4", "TestSurname4", 40));
|
||||
dsDistributedMap1.put(5, new HazelcastIntegrationTestUser(5, "TestName5", "TestSurname5", 50));
|
||||
|
||||
Message<?> msg = dsMapChannel1.receive(2_000);
|
||||
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof Collection);
|
||||
Assert.assertEquals(4, (((Map.Entry<?, ?>) ((Collection<?>) msg.getPayload()).iterator()
|
||||
.next()).getKey()));
|
||||
Assert.assertEquals(4, ((HazelcastIntegrationTestUser) ((Map.Entry<?, ?>) ((Collection<?>) msg.getPayload())
|
||||
.iterator().next()).getValue()).getId());
|
||||
Assert.assertEquals("TestName4", ((HazelcastIntegrationTestUser) ((Map.Entry<?, ?>) ((Collection<?>) msg
|
||||
.getPayload()).iterator().next()).getValue()).getName());
|
||||
Assert.assertEquals("TestSurname4", ((HazelcastIntegrationTestUser) ((Map.Entry<?, ?>) ((Collection<?>) msg
|
||||
.getPayload()).iterator().next()).getValue()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDistributedSQLForOnlyKEYIterationType() throws InterruptedException {
|
||||
dsDistributedMap2.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1", 10));
|
||||
dsDistributedMap2.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2", 20));
|
||||
dsDistributedMap2.put(3, new HazelcastIntegrationTestUser(3, "TestName3", "TestSurname3", 30));
|
||||
|
||||
Message<?> msg = dsMapChannel2.receive(2_000);
|
||||
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof Collection);
|
||||
Assert.assertEquals(1, ((Collection<?>) msg.getPayload()).iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDistributedSQLForOnlyLOCAL_KEYIterationType()
|
||||
throws InterruptedException {
|
||||
dsDistributedMap3.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1", 10));
|
||||
dsDistributedMap3.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2", 20));
|
||||
dsDistributedMap3.put(3, new HazelcastIntegrationTestUser(3, "TestName3", "TestSurname3", 30));
|
||||
|
||||
Message<?> msg = dsMapChannel3.receive(2_000);
|
||||
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof Collection);
|
||||
Assert.assertEquals(2, ((Collection<?>) msg.getPayload()).iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDistributedSQLForOnlyVALUEIterationType() throws InterruptedException {
|
||||
dsDistributedMap4.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1", 10));
|
||||
dsDistributedMap4.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2", 20));
|
||||
dsDistributedMap4.put(3, new HazelcastIntegrationTestUser(3, "TestName3", "TestSurname3", 30));
|
||||
dsDistributedMap4.put(4, new HazelcastIntegrationTestUser(4, "TestName4", "TestSurname4", 40));
|
||||
dsDistributedMap4.put(5, new HazelcastIntegrationTestUser(5, "TestName5", "TestSurname5", 50));
|
||||
|
||||
Message<?> msg = dsMapChannel4.receive(2_000);
|
||||
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof Collection);
|
||||
Assert.assertEquals(3,
|
||||
((HazelcastIntegrationTestUser) (((Collection<?>) msg.getPayload()).iterator().next())).getId());
|
||||
Assert.assertEquals("TestName3",
|
||||
((HazelcastIntegrationTestUser) (((Collection<?>) msg.getPayload()).iterator().next())).getName());
|
||||
Assert.assertEquals("TestSurname3",
|
||||
((HazelcastIntegrationTestUser) (((Collection<?>) msg.getPayload()).iterator().next())).getSurname());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-hazelcast="http://www.springframework.org/schema/integration/hazelcast"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
http://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<int:channel id="edSetChannel1">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="edSetChannel2">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="edSetChannel3">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int-hazelcast:inbound-channel-adapter channel="edSetChannel1" cache="edDistributedSet1"/>
|
||||
<int-hazelcast:inbound-channel-adapter channel="edSetChannel2" cache="edDistributedSet2" cache-events="REMOVED"/>
|
||||
<int-hazelcast:inbound-channel-adapter channel="edSetChannel3" cache="edDistributedSet3"
|
||||
cache-events="ADDED,REMOVED" cache-listening-policy="SINGLE"/>
|
||||
|
||||
<bean id="edDistributedSet1" factory-bean="edSetInstance" factory-method="getSet">
|
||||
<constructor-arg value="edDistributedSet1"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedSet2" factory-bean="edSetInstance" factory-method="getSet">
|
||||
<constructor-arg value="edDistributedSet2"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedSet3" factory-bean="edSetInstance" factory-method="getSet">
|
||||
<constructor-arg value="edDistributedSet3"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edSetInstance" class="com.hazelcast.core.Hazelcast" factory-method="newHazelcastInstance"
|
||||
destroy-method="shutdown">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.inbound;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.hazelcast.core.EntryEventType;
|
||||
import com.hazelcast.core.ISet;
|
||||
import com.hazelcast.core.ItemEvent;
|
||||
|
||||
/**
|
||||
* Hazelcast Distributed Set Event Driven Inbound Channel Adapter Test
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
public class HazelcastDistributedSetEventDrivenInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edSetChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edSetChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edSetChannel3;
|
||||
|
||||
@Resource
|
||||
private ISet<HazelcastIntegrationTestUser> edDistributedSet1;
|
||||
|
||||
@Resource
|
||||
private ISet<HazelcastIntegrationTestUser> edDistributedSet2;
|
||||
|
||||
@Resource
|
||||
private ISet<HazelcastIntegrationTestUser> edDistributedSet3;
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyADDEDEntryEvent() {
|
||||
edDistributedSet1.add(new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg = edSetChannel1.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof ItemEvent);
|
||||
Assert.assertEquals(EntryEventType.ADDED.toString(),
|
||||
((ItemEvent<?>) msg.getPayload()).getEventType().toString());
|
||||
Assert.assertEquals(1,
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getId());
|
||||
Assert.assertEquals("TestName1",
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getName());
|
||||
Assert.assertEquals("TestSurname1",
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyREMOVEDEntryEvent() {
|
||||
HazelcastIntegrationTestUser user = new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2");
|
||||
edDistributedSet2.add(user);
|
||||
edDistributedSet2.remove(user);
|
||||
Message<?> msg = edSetChannel2.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof ItemEvent);
|
||||
Assert.assertEquals(EntryEventType.REMOVED.toString(),
|
||||
((ItemEvent<?>) msg.getPayload()).getEventType().toString());
|
||||
Assert.assertEquals(2,
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getId());
|
||||
Assert.assertEquals("TestName2",
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getName());
|
||||
Assert.assertEquals("TestSurname2",
|
||||
((HazelcastIntegrationTestUser) ((ItemEvent<?>) msg.getPayload()).getItem()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForALLEntryEvent() {
|
||||
HazelcastIntegrationTestUser user = new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1");
|
||||
edDistributedSet3.add(user);
|
||||
Message<?> msg = edSetChannel3.receive(2_000);
|
||||
verify(msg, EntryEventType.ADDED);
|
||||
|
||||
edDistributedSet3.remove(user);
|
||||
msg = edSetChannel3.receive(2_000);
|
||||
verify(msg, EntryEventType.REMOVED);
|
||||
|
||||
user = new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2");
|
||||
edDistributedSet3.add(user);
|
||||
msg = edSetChannel3.receive(2_000);
|
||||
verify(msg, EntryEventType.ADDED);
|
||||
}
|
||||
|
||||
private void verify(Message<?> msg, EntryEventType type) {
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof ItemEvent);
|
||||
Assert.assertEquals(type.toString(),
|
||||
((ItemEvent<?>) msg.getPayload()).getEventType().toString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-hazelcast="http://www.springframework.org/schema/integration/hazelcast"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
http://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<int:channel id="edTopicChannel1">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int-hazelcast:inbound-channel-adapter channel="edTopicChannel1" cache="edDistributedTopic1"/>
|
||||
|
||||
<bean id="edDistributedTopic1" factory-bean="edTopicInstance" factory-method="getTopic">
|
||||
<constructor-arg value="edDistributedTopic1"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edTopicInstance" class="com.hazelcast.core.Hazelcast" factory-method="newHazelcastInstance"
|
||||
destroy-method="shutdown">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.inbound;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.hazelcast.core.ITopic;
|
||||
|
||||
/**
|
||||
* Hazelcast Distributed Topic Event Driven Inbound Channel Adapter Test
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
public class HazelcastDistributedTopicEventDrivenInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edTopicChannel1;
|
||||
|
||||
@Resource
|
||||
private ITopic<HazelcastIntegrationTestUser> edDistributedTopic1;
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyADDEDEntryEvent() {
|
||||
edDistributedTopic1.publish(new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg = edTopicChannel1.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof com.hazelcast.core.Message);
|
||||
Assert.assertEquals(1, ((HazelcastIntegrationTestUser) ((com.hazelcast.core.Message<?>) msg.getPayload())
|
||||
.getMessageObject()).getId());
|
||||
Assert.assertEquals("TestName1", ((HazelcastIntegrationTestUser) ((com.hazelcast.core.Message<?>) msg
|
||||
.getPayload()).getMessageObject()).getName());
|
||||
Assert.assertEquals("TestSurname1", ((HazelcastIntegrationTestUser) ((com.hazelcast.core.Message<?>) msg
|
||||
.getPayload()).getMessageObject()).getSurname());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-hazelcast="http://www.springframework.org/schema/integration/hazelcast"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
http://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<int:channel id="edMultiMapChannel1">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="edMultiMapChannel2">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="edMultiMapChannel3">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int-hazelcast:inbound-channel-adapter channel="edMultiMapChannel1" cache="edMultiMap1"/>
|
||||
<int-hazelcast:inbound-channel-adapter channel="edMultiMapChannel2" cache="edMultiMap2" cache-events="REMOVED"
|
||||
cache-listening-policy="SINGLE"/>
|
||||
<int-hazelcast:inbound-channel-adapter channel="edMultiMapChannel3" cache="edMultiMap3"
|
||||
cache-events="ADDED,REMOVED,CLEAR_ALL"/>
|
||||
|
||||
<bean id="edMultiMap1" factory-bean="edMultiMapInstance" factory-method="getMultiMap">
|
||||
<constructor-arg value="edMultiMap1"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edMultiMap2" factory-bean="edMultiMapInstance" factory-method="getMultiMap">
|
||||
<constructor-arg value="edMultiMap2"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edMultiMap3" factory-bean="edMultiMapInstance" factory-method="getMultiMap">
|
||||
<constructor-arg value="edMultiMap3"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edMultiMapInstance" class="com.hazelcast.core.Hazelcast" factory-method="newHazelcastInstance"
|
||||
destroy-method="shutdown">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.inbound;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.hazelcast.core.AbstractIMapEvent;
|
||||
import com.hazelcast.core.EntryEvent;
|
||||
import com.hazelcast.core.EntryEventType;
|
||||
import com.hazelcast.core.MultiMap;
|
||||
|
||||
/**
|
||||
* Hazelcast MultiMap Event Driven Inbound Channel Adapter Test
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
public class HazelcastMultiMapEventDrivenInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edMultiMapChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edMultiMapChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edMultiMapChannel3;
|
||||
|
||||
@Resource
|
||||
private MultiMap<Integer, HazelcastIntegrationTestUser> edMultiMap1;
|
||||
|
||||
@Resource
|
||||
private MultiMap<Integer, HazelcastIntegrationTestUser> edMultiMap2;
|
||||
|
||||
@Resource
|
||||
private MultiMap<Integer, HazelcastIntegrationTestUser> edMultiMap3;
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyADDEDEntryEvent() {
|
||||
edMultiMap1.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg = edMultiMapChannel1.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof EntryEvent);
|
||||
Assert.assertEquals(EntryEventType.ADDED,
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getEventType());
|
||||
Assert.assertEquals("edMultiMap1",
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getName());
|
||||
Assert.assertEquals(1, ((EntryEvent<?, ?>) msg.getPayload()).getKey());
|
||||
Assert.assertEquals(1,
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getId());
|
||||
Assert.assertEquals("TestName1",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getName());
|
||||
Assert.assertEquals("TestSurname1",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyREMOVEDEntryEvent() {
|
||||
edMultiMap2.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
edMultiMap2.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
edMultiMap2.remove(2);
|
||||
Message<?> msg = edMultiMapChannel2.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof EntryEvent);
|
||||
Assert.assertEquals(EntryEventType.REMOVED,
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getEventType());
|
||||
Assert.assertEquals("edMultiMap2",
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getName());
|
||||
Assert.assertEquals(2, ((EntryEvent<?, ?>) msg.getPayload()).getKey());
|
||||
Assert.assertEquals(2,
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getId());
|
||||
Assert.assertEquals("TestName2",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getName());
|
||||
Assert.assertEquals("TestSurname2",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForALLEntryEvent() {
|
||||
edMultiMap3.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg = edMultiMapChannel3.receive(2_000);
|
||||
verify(msg, "edMultiMap3", EntryEventType.ADDED);
|
||||
|
||||
edMultiMap3.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurnameUpdated"));
|
||||
msg = edMultiMapChannel3.receive(2_000);
|
||||
verify(msg, "edMultiMap3", EntryEventType.ADDED);
|
||||
|
||||
edMultiMap3.remove(1);
|
||||
msg = edMultiMapChannel3.receive(2_000);
|
||||
verify(msg, "edMultiMap3", EntryEventType.REMOVED);
|
||||
msg = edMultiMapChannel3.receive(2_000);
|
||||
verify(msg, "edMultiMap3", EntryEventType.REMOVED);
|
||||
|
||||
edMultiMap3.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
msg = edMultiMapChannel3.receive(2_000);
|
||||
verify(msg, "edMultiMap3", EntryEventType.ADDED);
|
||||
|
||||
edMultiMap3.clear();
|
||||
msg = edMultiMapChannel3.receive(2_000);
|
||||
verify(msg, "edMultiMap3", EntryEventType.CLEAR_ALL);
|
||||
}
|
||||
|
||||
private void verify(Message<?> msg, String cacheName, EntryEventType type) {
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof AbstractIMapEvent);
|
||||
Assert.assertEquals(cacheName, ((AbstractIMapEvent) msg.getPayload()).getName());
|
||||
Assert.assertEquals(type, ((AbstractIMapEvent) msg.getPayload()).getEventType());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-hazelcast="http://www.springframework.org/schema/integration/hazelcast"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
http://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<int:channel id="edReplicatedMapChannel1">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="edReplicatedMapChannel2">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="edReplicatedMapChannel3">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="edReplicatedMapChannel4">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int-hazelcast:inbound-channel-adapter channel="edReplicatedMapChannel1" cache="edReplicatedMap1"/>
|
||||
<int-hazelcast:inbound-channel-adapter channel="edReplicatedMapChannel2" cache="edReplicatedMap2"
|
||||
cache-events="UPDATED"/>
|
||||
<int-hazelcast:inbound-channel-adapter channel="edReplicatedMapChannel3" cache="edReplicatedMap3"
|
||||
cache-events="REMOVED"/>
|
||||
<int-hazelcast:inbound-channel-adapter channel="edReplicatedMapChannel4" cache="edReplicatedMap4"
|
||||
cache-events="ADDED,REMOVED,UPDATED"/>
|
||||
|
||||
<bean id="edReplicatedMap1" factory-bean="edReplicatedMapInstance" factory-method="getReplicatedMap">
|
||||
<constructor-arg value="edReplicatedMap1"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edReplicatedMap2" factory-bean="edReplicatedMapInstance" factory-method="getReplicatedMap">
|
||||
<constructor-arg value="edReplicatedMap2"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edReplicatedMap3" factory-bean="edReplicatedMapInstance" factory-method="getReplicatedMap">
|
||||
<constructor-arg value="edReplicatedMap3"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edReplicatedMap4" factory-bean="edReplicatedMapInstance" factory-method="getReplicatedMap">
|
||||
<constructor-arg value="edReplicatedMap4"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edReplicatedMapInstance" class="com.hazelcast.core.Hazelcast" factory-method="newHazelcastInstance"
|
||||
destroy-method="shutdown">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.inbound;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.hazelcast.core.AbstractIMapEvent;
|
||||
import com.hazelcast.core.EntryEvent;
|
||||
import com.hazelcast.core.EntryEventType;
|
||||
import com.hazelcast.core.ReplicatedMap;
|
||||
|
||||
/**
|
||||
* Hazelcast Replicated Map Event Driven Inbound Channel Adapter Test
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
public class HazelcastReplicatedMapEventDrivenInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edReplicatedMapChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edReplicatedMapChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edReplicatedMapChannel3;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edReplicatedMapChannel4;
|
||||
|
||||
@Resource
|
||||
private ReplicatedMap<Integer, HazelcastIntegrationTestUser> edReplicatedMap1;
|
||||
|
||||
@Resource
|
||||
private ReplicatedMap<Integer, HazelcastIntegrationTestUser> edReplicatedMap2;
|
||||
|
||||
@Resource
|
||||
private ReplicatedMap<Integer, HazelcastIntegrationTestUser> edReplicatedMap3;
|
||||
|
||||
@Resource
|
||||
private ReplicatedMap<Integer, HazelcastIntegrationTestUser> edReplicatedMap4;
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyADDEDEntryEvent() {
|
||||
edReplicatedMap1.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg = edReplicatedMapChannel1.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof EntryEvent);
|
||||
Assert.assertEquals(EntryEventType.ADDED,
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getEventType());
|
||||
Assert.assertEquals("edReplicatedMap1",
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getName());
|
||||
Assert.assertEquals(1, ((EntryEvent<?, ?>) msg.getPayload()).getKey());
|
||||
Assert.assertEquals(1,
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getId());
|
||||
Assert.assertEquals("TestName1",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getName());
|
||||
Assert.assertEquals("TestSurname1",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyUPDATEDEntryEvent() {
|
||||
edReplicatedMap2.put(2, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
edReplicatedMap2.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
Message<?> msg = edReplicatedMapChannel2.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof EntryEvent);
|
||||
Assert.assertEquals(EntryEventType.UPDATED,
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getEventType());
|
||||
Assert.assertEquals("edReplicatedMap2",
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getName());
|
||||
Assert.assertEquals(2, ((EntryEvent<?, ?>) msg.getPayload()).getKey());
|
||||
Assert.assertEquals(1,
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getId());
|
||||
Assert.assertEquals("TestName1",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getName());
|
||||
Assert.assertEquals("TestSurname1",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getSurname());
|
||||
Assert.assertEquals(2,
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getId());
|
||||
Assert.assertEquals("TestName2",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getName());
|
||||
Assert.assertEquals("TestSurname2",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getValue()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyREMOVEDEntryEvent() {
|
||||
edReplicatedMap3.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
edReplicatedMap3.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
edReplicatedMap3.remove(2);
|
||||
Message<?> msg = edReplicatedMapChannel3.receive(2_000);
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof EntryEvent);
|
||||
Assert.assertEquals(EntryEventType.REMOVED,
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getEventType());
|
||||
Assert.assertEquals("edReplicatedMap3",
|
||||
((EntryEvent<?, ?>) msg.getPayload()).getName());
|
||||
Assert.assertEquals(2, ((EntryEvent<?, ?>) msg.getPayload()).getKey());
|
||||
Assert.assertEquals(2,
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getId());
|
||||
Assert.assertEquals("TestName2",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getName());
|
||||
Assert.assertEquals("TestSurname2",
|
||||
((HazelcastIntegrationTestUser) ((EntryEvent<?, ?>) msg.getPayload()).getOldValue()).getSurname());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForALLEntryEvent() {
|
||||
edReplicatedMap4.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg = edReplicatedMapChannel4.receive(2_000);
|
||||
verify(msg, "edReplicatedMap4", EntryEventType.ADDED);
|
||||
|
||||
edReplicatedMap4.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurnameUpdated"));
|
||||
msg = edReplicatedMapChannel4.receive(2_000);
|
||||
verify(msg, "edReplicatedMap4", EntryEventType.UPDATED);
|
||||
|
||||
edReplicatedMap4.remove(1);
|
||||
msg = edReplicatedMapChannel4.receive(2_000);
|
||||
verify(msg, "edReplicatedMap4", EntryEventType.REMOVED);
|
||||
|
||||
edReplicatedMap4.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
msg = edReplicatedMapChannel4.receive(2_000);
|
||||
verify(msg, "edReplicatedMap4", EntryEventType.ADDED);
|
||||
|
||||
}
|
||||
|
||||
private void verify(Message<?> msg, String cacheName, EntryEventType type) {
|
||||
Assert.assertNotNull(msg);
|
||||
Assert.assertNotNull(msg.getPayload());
|
||||
Assert.assertTrue(msg.getPayload() instanceof AbstractIMapEvent);
|
||||
Assert.assertEquals(cacheName, ((AbstractIMapEvent) msg.getPayload()).getName());
|
||||
Assert.assertEquals(type, ((AbstractIMapEvent) msg.getPayload()).getEventType());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-hazelcast="http://www.springframework.org/schema/integration/hazelcast"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
http://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<int:channel id="mapChannel"/>
|
||||
<int:channel id="listChannel"/>
|
||||
<int:channel id="setChannel"/>
|
||||
<int:channel id="queueChannel"/>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="mapChannel" cache="distributedMap"/>
|
||||
<int-hazelcast:outbound-channel-adapter channel="listChannel" cache="distributedList"/>
|
||||
<int-hazelcast:outbound-channel-adapter channel="setChannel" cache="distributedSet"/>
|
||||
<int-hazelcast:outbound-channel-adapter channel="queueChannel" cache="distributedQueue"/>
|
||||
|
||||
<bean id="distributedMap" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="distributedMap"/>
|
||||
</bean>
|
||||
|
||||
<bean id="distributedList" factory-bean="instance" factory-method="getList">
|
||||
<constructor-arg value="distributedList"/>
|
||||
</bean>
|
||||
|
||||
<bean id="distributedSet" factory-bean="instance" factory-method="getSet">
|
||||
<constructor-arg value="distributedSet"/>
|
||||
</bean>
|
||||
|
||||
<bean id="distributedQueue" factory-bean="instance" factory-method="getQueue">
|
||||
<constructor-arg value="distributedQueue"/>
|
||||
</bean>
|
||||
|
||||
<bean id="instance" class="com.hazelcast.core.Hazelcast" factory-method="newHazelcastInstance"
|
||||
destroy-method="shutdown">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.hazelcast.outbound;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageHandlingException;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* Hazelcast Outbound Channel Adapter Test Class
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
public class HazelcastOutboundChannelAdapterTests {
|
||||
|
||||
private static final int DATA_COUNT = 100;
|
||||
|
||||
@Autowired
|
||||
private MessageChannel mapChannel;
|
||||
|
||||
@Autowired
|
||||
private MessageChannel listChannel;
|
||||
|
||||
@Autowired
|
||||
private MessageChannel setChannel;
|
||||
|
||||
@Autowired
|
||||
private MessageChannel queueChannel;
|
||||
|
||||
@Resource
|
||||
private Map<?, ?> distributedMap;
|
||||
|
||||
@Resource
|
||||
private List<?> distributedList;
|
||||
|
||||
@Resource
|
||||
private Set<?> distributedSet;
|
||||
|
||||
@Resource
|
||||
private Queue<?> distributedQueue;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
distributedMap.clear();
|
||||
distributedList.clear();
|
||||
distributedSet.clear();
|
||||
distributedQueue.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteDistributedMap() {
|
||||
Map<Integer, String> map = createMapByEntryCount();
|
||||
mapChannel.send(new GenericMessage<>(map));
|
||||
verifyDistributedMap();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteDistributedList() {
|
||||
List<Integer> list = (List<Integer>) fillCollectionByEntryCount(new ArrayList<Integer>());
|
||||
listChannel.send(new GenericMessage<>(list));
|
||||
verifyDistributedList();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteDistributedSet() {
|
||||
Set<Integer> set = (Set<Integer>) fillCollectionByEntryCount(new HashSet<Integer>());
|
||||
setChannel.send(new GenericMessage<>(set));
|
||||
verifyDistributedSet();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteDistributedQueue() {
|
||||
Queue<Integer> queue = (Queue<Integer>) fillCollectionByEntryCount(
|
||||
new LinkedBlockingQueue<Integer>(DATA_COUNT));
|
||||
queueChannel.send(new GenericMessage<>(queue));
|
||||
verifyDistributedQueue();
|
||||
}
|
||||
|
||||
@Test(expected = MessageHandlingException.class)
|
||||
public void testMapChannelWithIncorrectDataType() {
|
||||
Set<Integer> set = new HashSet<>();
|
||||
set.add(1);
|
||||
mapChannel.send(new GenericMessage<>(set));
|
||||
}
|
||||
|
||||
@Test(expected = MessageHandlingException.class)
|
||||
public void testListChannelWithIncorrectDataType() {
|
||||
Set<Integer> set = new HashSet<>();
|
||||
set.add(1);
|
||||
listChannel.send(new GenericMessage<>(set));
|
||||
}
|
||||
|
||||
@Test(expected = MessageHandlingException.class)
|
||||
public void testSetChannelWithIncorrectDataType() {
|
||||
List<Integer> list = new ArrayList<>();
|
||||
list.add(1);
|
||||
setChannel.send(new GenericMessage<>(list));
|
||||
}
|
||||
|
||||
@Test(expected = MessageHandlingException.class)
|
||||
public void testQueueChannelWithIncorrectDataType() {
|
||||
Set<Integer> set = new HashSet<>();
|
||||
set.add(1);
|
||||
queueChannel.send(new GenericMessage<>(set));
|
||||
}
|
||||
|
||||
private Map<Integer, String> createMapByEntryCount() {
|
||||
Map<Integer, String> map = new HashMap<>();
|
||||
StringBuilder strBuilder = new StringBuilder();
|
||||
for (int index = 0; index < DATA_COUNT; index++) {
|
||||
String value = strBuilder.append("Value_").append(index).toString();
|
||||
map.put(index, value);
|
||||
strBuilder.delete(0, strBuilder.length());
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private void verifyDistributedMap() {
|
||||
Assert.assertEquals(true, distributedMap.size() == DATA_COUNT);
|
||||
|
||||
StringBuilder strBuilder = new StringBuilder();
|
||||
for (int index = 0; index < DATA_COUNT; index++) {
|
||||
String value = strBuilder.append("Value_").append(index).toString();
|
||||
Assert.assertEquals(value, distributedMap.get(index));
|
||||
strBuilder.delete(0, strBuilder.length());
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<Integer> fillCollectionByEntryCount(Collection<Integer> coll) {
|
||||
for (int index = 0; index < DATA_COUNT; index++) {
|
||||
coll.add(index);
|
||||
}
|
||||
|
||||
return coll;
|
||||
}
|
||||
|
||||
private void verifyDistributedList() {
|
||||
Assert.assertEquals(true, distributedList.size() == DATA_COUNT);
|
||||
for (int index = 0; index < DATA_COUNT; index++) {
|
||||
Assert.assertEquals(index, distributedList.get(index));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private void verifyDistributedSet() {
|
||||
Assert.assertEquals(true, distributedSet.size() == DATA_COUNT);
|
||||
List list = new ArrayList(distributedSet);
|
||||
Collections.sort(list);
|
||||
for (int index = 0; index < DATA_COUNT; index++) {
|
||||
Assert.assertEquals(index, list.get(index));
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyDistributedQueue() {
|
||||
Assert.assertEquals(true, distributedQueue.size() == DATA_COUNT);
|
||||
int index = 0;
|
||||
for (Object o : distributedQueue) {
|
||||
Assert.assertEquals(index++, o);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
log4j.rootCategory=WARN, stdout
|
||||
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d %p %c{1} [%t] : %m%n
|
||||
|
||||
log4j.category.org.springframework.integration=WARN
|
||||
log4j.category.org.springframework.integration.hazelcast=INFO
|
||||
Reference in New Issue
Block a user