Move spring-integration-hazelcast from extensions
* Update javadocs * Upgrade from log4j to log4j2 * Remove unnecessary test deps. * Change from implmementation to api * Remove unneeded test deps. * Fix HZ XSD to be "versionless" * Use `com.google.code.findbugs:annotations` dep to avoid warning from HZ code base
This commit is contained in:
committed by
Artem Bilan
parent
040438f5e9
commit
a322f5c35d
15
build.gradle
15
build.gradle
@@ -59,8 +59,8 @@ ext {
|
||||
commonsNetVersion = '3.8.0'
|
||||
curatorVersion = '4.3.0'
|
||||
derbyVersion = '10.14.2.0'
|
||||
findbugsVersion = '3.0.1'
|
||||
ftpServerVersion = '1.2.0'
|
||||
googleJsr305Version = '3.0.2'
|
||||
greenmailVersion = '2.0.0-alpha-2'
|
||||
groovyVersion = '3.0.10'
|
||||
hamcrestVersion = '2.2'
|
||||
@@ -251,8 +251,8 @@ configure(javaProjects) { subproject ->
|
||||
}
|
||||
|
||||
// JSR-305 only used for non-required meta-annotations
|
||||
compileOnly "com.google.code.findbugs:jsr305:$googleJsr305Version"
|
||||
testImplementation "com.google.code.findbugs:jsr305:$googleJsr305Version"
|
||||
compileOnly "com.google.code.findbugs:annotations:$findbugsVersion"
|
||||
testImplementation "com.google.code.findbugs:annotations:$findbugsVersion"
|
||||
testImplementation("org.awaitility:awaitility:$awaitilityVersion") {
|
||||
exclude group: 'org.hamcrest'
|
||||
}
|
||||
@@ -1080,6 +1080,15 @@ project('spring-integration-bom') {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
project('spring-integration-hazelcast') {
|
||||
description = 'Spring Integration Hazelcast Support'
|
||||
dependencies {
|
||||
api "com.hazelcast:hazelcast:$hazelcastVersion"
|
||||
api project(':spring-integration-core')
|
||||
}
|
||||
}
|
||||
|
||||
sonarqube {
|
||||
properties {
|
||||
property 'sonar.links.homepage', linkHomepage
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
/**
|
||||
* Enumeration of Cache Event Types.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @see org.springframework.integration.hazelcast.inbound.AbstractHazelcastMessageProducer
|
||||
*/
|
||||
public enum CacheEventType {
|
||||
|
||||
/**
|
||||
* The Hazelcast ADDED event.
|
||||
*/
|
||||
ADDED,
|
||||
|
||||
/**
|
||||
* The Hazelcast REMOVED event.
|
||||
*/
|
||||
REMOVED,
|
||||
|
||||
/**
|
||||
* The Hazelcast UPDATED event.
|
||||
*/
|
||||
UPDATED,
|
||||
|
||||
/**
|
||||
* The Hazelcast EVICTED event.
|
||||
*/
|
||||
EVICTED,
|
||||
|
||||
/**
|
||||
* The Hazelcast EXPIRED event.
|
||||
*/
|
||||
EXPIRED,
|
||||
|
||||
/**
|
||||
* The Hazelcast EVICT_ALL event.
|
||||
*/
|
||||
EVICT_ALL,
|
||||
|
||||
/**
|
||||
* The Hazelcast CLEAR_ALL event.
|
||||
*/
|
||||
CLEAR_ALL
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
/**
|
||||
* Enumeration of Cache Listening Policy Type.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @see org.springframework.integration.hazelcast.inbound.AbstractHazelcastMessageProducer
|
||||
*/
|
||||
public enum CacheListeningPolicyType {
|
||||
|
||||
/**
|
||||
* Only the local Hazelcast node can accept event.
|
||||
*/
|
||||
SINGLE,
|
||||
|
||||
/**
|
||||
* All subscribed members can accept event.
|
||||
*/
|
||||
ALL
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
/**
|
||||
* Enumeration of Hazelcast Cluster Monitor Types.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @see org.springframework.integration.hazelcast.inbound.HazelcastClusterMonitorMessageProducer
|
||||
* @see com.hazelcast.core.DistributedObjectListener
|
||||
* @see com.hazelcast.core.LifecycleListener
|
||||
*/
|
||||
public enum ClusterMonitorType {
|
||||
|
||||
/**
|
||||
* The membership listener mode.
|
||||
*/
|
||||
MEMBERSHIP,
|
||||
|
||||
/**
|
||||
* The distributed object listener mode.
|
||||
*/
|
||||
DISTRIBUTED_OBJECT,
|
||||
|
||||
/**
|
||||
* The migration listener mode.
|
||||
*/
|
||||
MIGRATION,
|
||||
|
||||
/**
|
||||
* The listener listener mode.
|
||||
*/
|
||||
LIFECYCLE,
|
||||
|
||||
/**
|
||||
* The client listener mode.
|
||||
*/
|
||||
CLIENT
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
/**
|
||||
* Enumeration of Distributed SQL Iteration Type.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @see org.springframework.integration.hazelcast.inbound.HazelcastDistributedSQLMessageSource
|
||||
* @see com.hazelcast.map.IMap
|
||||
*/
|
||||
public enum DistributedSQLIterationType {
|
||||
|
||||
/**
|
||||
* The {@link com.hazelcast.map.IMap#entrySet()} to iterate.
|
||||
*/
|
||||
ENTRY,
|
||||
|
||||
/**
|
||||
* The {@link com.hazelcast.map.IMap#keySet()} to iterate.
|
||||
*/
|
||||
KEY,
|
||||
|
||||
/**
|
||||
* The {@link com.hazelcast.map.IMap#localKeySet()} to iterate.
|
||||
*/
|
||||
LOCAL_KEY,
|
||||
|
||||
/**
|
||||
* The {@link com.hazelcast.map.IMap#values()} to iterate.
|
||||
*/
|
||||
VALUE
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
/**
|
||||
* Hazelcast Message Headers.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public abstract class HazelcastHeaders {
|
||||
|
||||
private static final String PREFIX = "hazelcast_";
|
||||
|
||||
/**
|
||||
* The event type header name.
|
||||
*/
|
||||
public static final String EVENT_TYPE = PREFIX + "eventType";
|
||||
|
||||
/**
|
||||
* The member header name.
|
||||
*/
|
||||
public static final String MEMBER = PREFIX + "member";
|
||||
|
||||
/**
|
||||
* The cache name header name.
|
||||
*/
|
||||
public static final String CACHE_NAME = PREFIX + "cacheName";
|
||||
|
||||
/**
|
||||
* The publishing time header name.
|
||||
*/
|
||||
public static final String PUBLISHING_TIME = PREFIX + "publishingTime";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.hazelcast.collection.IList;
|
||||
import com.hazelcast.collection.IQueue;
|
||||
import com.hazelcast.collection.ISet;
|
||||
import com.hazelcast.core.DistributedObject;
|
||||
import com.hazelcast.map.IMap;
|
||||
import com.hazelcast.multimap.MultiMap;
|
||||
import com.hazelcast.replicatedmap.ReplicatedMap;
|
||||
import com.hazelcast.topic.ITopic;
|
||||
|
||||
/**
|
||||
* Common Validator for Hazelcast Integration. It validates cache types and events.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public final class HazelcastIntegrationDefinitionValidator {
|
||||
|
||||
public static <E extends Enum<E>> Set<String> validateEnumType(final Class<E> enumType, final String types) {
|
||||
Set<String> typeSet = StringUtils.commaDelimitedListToSet(StringUtils.trimAllWhitespace(types));
|
||||
for (String type : typeSet) {
|
||||
Enum.valueOf(enumType, type);
|
||||
}
|
||||
|
||||
return typeSet;
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
private HazelcastIntegrationDefinitionValidator() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2015-2019 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
|
||||
*
|
||||
* https://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.net.SocketAddress;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.integration.hazelcast.listener.HazelcastMembershipListener;
|
||||
|
||||
import com.hazelcast.cluster.MembershipListener;
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.multimap.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 MembershipListener} to listen for
|
||||
* membership updates.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public class HazelcastLocalInstanceRegistrar implements SmartInitializingSingleton {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(HazelcastLocalInstanceRegistrar.class);
|
||||
|
||||
/**
|
||||
* The bean name for the {@link HazelcastLocalInstanceRegistrar} instance.
|
||||
*/
|
||||
public static final String BEAN_NAME = "hazelcastLocalInstanceRegistrar";
|
||||
|
||||
/**
|
||||
* The name for the Hazelcast MultiMap used for membership registration.
|
||||
*/
|
||||
public static final String SPRING_INTEGRATION_INTERNAL_CLUSTER_MULTIMAP =
|
||||
"SPRING_INTEGRATION_INTERNAL_CLUSTER_MULTIMAP";
|
||||
|
||||
/**
|
||||
* The name for the Hazelcast Lock used for membership registration.
|
||||
*/
|
||||
public static final String SPRING_INTEGRATION_INTERNAL_CLUSTER_LOCK = "SPRING_INTEGRATION_INTERNAL_CLUSTER_LOCK";
|
||||
|
||||
private final HazelcastInstance hazelcastInstance;
|
||||
|
||||
/**
|
||||
* Construct {@link HazelcastLocalInstanceRegistrar} based on the local JVM {@link HazelcastInstance}s if any.
|
||||
*/
|
||||
public HazelcastLocalInstanceRegistrar() {
|
||||
this.hazelcastInstance = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct {@link HazelcastLocalInstanceRegistrar} based on the provided {@link HazelcastInstance}.
|
||||
* @param hazelcastInstance the {@link HazelcastInstance} to use.
|
||||
*/
|
||||
public HazelcastLocalInstanceRegistrar(HazelcastInstance hazelcastInstance) {
|
||||
this.hazelcastInstance = hazelcastInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
if (this.hazelcastInstance == null) {
|
||||
if (!Hazelcast.getAllHazelcastInstances().isEmpty()) {
|
||||
HazelcastInstance hazelcastInstance = Hazelcast.getAllHazelcastInstances().iterator().next();
|
||||
hazelcastInstance.getCluster().addMembershipListener(new HazelcastMembershipListener());
|
||||
syncConfigurationMultiMap(hazelcastInstance);
|
||||
}
|
||||
else {
|
||||
logger.warn("No HazelcastInstances for MembershipListener registration");
|
||||
}
|
||||
}
|
||||
else {
|
||||
syncConfigurationMultiMap(this.hazelcastInstance);
|
||||
this.hazelcastInstance.getCluster().addMembershipListener(new HazelcastMembershipListener());
|
||||
}
|
||||
}
|
||||
|
||||
private void syncConfigurationMultiMap(HazelcastInstance hazelcastInstance) {
|
||||
Lock lock = hazelcastInstance.getCPSubsystem().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,45 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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.HazelcastLocalInstanceRegistrar;
|
||||
|
||||
/**
|
||||
* The Hazelcast Integration infrastructure {@code beanFactory} initializer.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public class HazelcastIntegrationConfigurationInitializer implements IntegrationConfigurationInitializer {
|
||||
|
||||
@Override
|
||||
public void initialize(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) beanFactory;
|
||||
if (!beanDefinitionRegistry.containsBeanDefinition(HazelcastLocalInstanceRegistrar.BEAN_NAME)) {
|
||||
beanDefinitionRegistry.registerBeanDefinition(HazelcastLocalInstanceRegistrar.BEAN_NAME,
|
||||
new RootBeanDefinition(HazelcastLocalInstanceRegistrar.class));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides classes for configuration.
|
||||
*/
|
||||
package org.springframework.integration.hazelcast.config;
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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.HazelcastClusterMonitorMessageProducer;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Parser for the {@code <int-hazelcast:cm-inbound-channel-adapter />} component.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.0
|
||||
*/
|
||||
public class HazelcastClusterMonitorInboundChannelAdapterParser extends
|
||||
AbstractSingleBeanDefinitionParser {
|
||||
|
||||
private static final String CHANNEL_ATTRIBUTE = "channel";
|
||||
|
||||
private static final String HAZELCAST_INSTANCE_ATTRIBUTE = "hazelcast-instance";
|
||||
|
||||
private static final String MONITOR_TYPES_ATTRIBUTE = "monitor-types";
|
||||
|
||||
private static final String OUTPUT_CHANNEL = "outputChannel";
|
||||
|
||||
private static final String MONITOR_EVENT_TYPES = "monitorEventTypes";
|
||||
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return HazelcastClusterMonitorMessageProducer.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(HAZELCAST_INSTANCE_ATTRIBUTE))) {
|
||||
parserContext.getReaderContext().error(
|
||||
"'" + HAZELCAST_INSTANCE_ATTRIBUTE + "' attribute is required.",
|
||||
element);
|
||||
}
|
||||
|
||||
builder.addPropertyReference(OUTPUT_CHANNEL, channelName);
|
||||
builder.addConstructorArgReference(element
|
||||
.getAttribute(HAZELCAST_INSTANCE_ATTRIBUTE));
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element,
|
||||
MONITOR_TYPES_ATTRIBUTE, MONITOR_EVENT_TYPES);
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element,
|
||||
IntegrationNamespaceUtils.AUTO_STARTUP);
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element,
|
||||
IntegrationNamespaceUtils.PHASE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Hazelcast Continuous Query Inbound Channel Adapter Parser parses
|
||||
* {@code <int-hazelcast:cq-inbound-channel-adapter/>} configuration.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.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,68 @@
|
||||
/*
|
||||
* Copyright 2015-2016 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
|
||||
*
|
||||
* https://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 org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Hazelcast Distributed SQL Inbound Channel Adapter Parser parses
|
||||
* {@code <int-hazelcast:ds-inbound-channel-adapter/>} configuration.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.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,99 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Hazelcast Event Driven Inbound Channel Adapter Parser parses
|
||||
* {@code <int-hazelcast:inbound-channel-adapter />} configuration.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.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,38 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* https://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 6.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());
|
||||
registerBeanDefinitionParser("cm-inbound-channel-adapter", new HazelcastClusterMonitorInboundChannelAdapterParser());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* https://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.config.BeanDefinition;
|
||||
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.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.hazelcast.outbound.HazelcastCacheWritingMessageHandler;
|
||||
|
||||
/**
|
||||
* Hazelcast Outbound Channel Adapter Parser for
|
||||
* {@code <int-hazelcast:inbound-channel-adapter />}.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.0
|
||||
*/
|
||||
public class HazelcastOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser {
|
||||
|
||||
private static final String CACHE_ATTRIBUTE = "cache";
|
||||
|
||||
private static final String CACHE_EXPRESSION_ATTRIBUTE = "cache-expression";
|
||||
|
||||
private static final String KEY_EXPRESSION_ATTRIBUTE = "key-expression";
|
||||
|
||||
private static final String EXTRACT_PAYLOAD_ATTRIBUTE = "extract-payload";
|
||||
|
||||
private static final String DISTRIBUTED_OBJECT = "distributedObject";
|
||||
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(HazelcastCacheWritingMessageHandler.class);
|
||||
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, CACHE_ATTRIBUTE, DISTRIBUTED_OBJECT);
|
||||
BeanDefinition cacheExpressionDef =
|
||||
IntegrationNamespaceUtils.createExpressionDefIfAttributeDefined(CACHE_EXPRESSION_ATTRIBUTE, element);
|
||||
if (cacheExpressionDef != null) {
|
||||
builder.addPropertyValue("cacheExpression", cacheExpressionDef);
|
||||
}
|
||||
|
||||
BeanDefinition keyExpressionDef =
|
||||
IntegrationNamespaceUtils.createExpressionDefIfAttributeDefined(KEY_EXPRESSION_ATTRIBUTE, element);
|
||||
if (keyExpressionDef != null) {
|
||||
builder.addPropertyValue("keyExpression", keyExpressionDef);
|
||||
}
|
||||
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, EXTRACT_PAYLOAD_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,232 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.integration.endpoint.MessageProducerSupport;
|
||||
import org.springframework.integration.hazelcast.CacheEventType;
|
||||
import org.springframework.integration.hazelcast.CacheListeningPolicyType;
|
||||
import org.springframework.integration.hazelcast.HazelcastHeaders;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationDefinitionValidator;
|
||||
import org.springframework.integration.hazelcast.HazelcastLocalInstanceRegistrar;
|
||||
import org.springframework.integration.hazelcast.message.EntryEventMessagePayload;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
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.instance.EndpointQualifier;
|
||||
import com.hazelcast.map.AbstractIMapEvent;
|
||||
import com.hazelcast.map.MapEvent;
|
||||
import com.hazelcast.multimap.MultiMap;
|
||||
|
||||
/**
|
||||
* Hazelcast Base Event-Driven Message Producer.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public abstract class AbstractHazelcastMessageProducer extends MessageProducerSupport {
|
||||
|
||||
protected final DistributedObject distributedObject;
|
||||
|
||||
private volatile CacheListeningPolicyType cacheListeningPolicy = CacheListeningPolicyType.SINGLE;
|
||||
|
||||
private volatile UUID hazelcastRegisteredEventListenerId;
|
||||
|
||||
private Set<String> cacheEvents = Collections.singleton(CacheEventType.ADDED.name());
|
||||
|
||||
public AbstractHazelcastMessageProducer(DistributedObject distributedObject) {
|
||||
Assert.notNull(distributedObject, "'distributedObject' must not be null");
|
||||
this.distributedObject = distributedObject;
|
||||
}
|
||||
|
||||
protected Set<String> getCacheEvents() {
|
||||
return this.cacheEvents;
|
||||
}
|
||||
|
||||
public void setCacheEventTypes(String cacheEventTypes) {
|
||||
Set<String> cacheEvents =
|
||||
HazelcastIntegrationDefinitionValidator.validateEnumType(CacheEventType.class, cacheEventTypes);
|
||||
Assert.notEmpty(cacheEvents, "'cacheEvents' must have elements");
|
||||
HazelcastIntegrationDefinitionValidator.validateCacheEventsByDistributedObject(this.distributedObject,
|
||||
cacheEvents);
|
||||
this.cacheEvents = cacheEvents;
|
||||
}
|
||||
|
||||
protected CacheListeningPolicyType getCacheListeningPolicy() {
|
||||
return this.cacheListeningPolicy;
|
||||
}
|
||||
|
||||
public void setCacheListeningPolicy(CacheListeningPolicyType cacheListeningPolicy) {
|
||||
Assert.notNull(cacheListeningPolicy, "'cacheListeningPolicy' must not be null");
|
||||
this.cacheListeningPolicy = cacheListeningPolicy;
|
||||
}
|
||||
|
||||
protected UUID getHazelcastRegisteredEventListenerId() {
|
||||
return this.hazelcastRegisteredEventListenerId;
|
||||
}
|
||||
|
||||
protected void setHazelcastRegisteredEventListenerId(UUID hazelcastRegisteredEventListenerId) {
|
||||
this.hazelcastRegisteredEventListenerId = hazelcastRegisteredEventListenerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* A base event listener abstraction.
|
||||
*
|
||||
* @param <E> the event type
|
||||
*/
|
||||
protected abstract class AbstractHazelcastEventListener<E> {
|
||||
|
||||
protected abstract void processEvent(E event);
|
||||
|
||||
protected abstract Message<?> toMessage(E event);
|
||||
|
||||
protected void sendMessage(E event, InetSocketAddress socketAddress,
|
||||
CacheListeningPolicyType cacheListeningPolicyType) {
|
||||
if (CacheListeningPolicyType.ALL == cacheListeningPolicyType || isEventAcceptable(socketAddress)) {
|
||||
AbstractHazelcastMessageProducer.this.sendMessage(toMessage(event));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEventAcceptable(final InetSocketAddress socketAddress) {
|
||||
final Set<HazelcastInstance> hazelcastInstanceSet = Hazelcast.getAllHazelcastInstances();
|
||||
final Set<SocketAddress> localSocketAddressesSet = getLocalSocketAddresses(hazelcastInstanceSet);
|
||||
return localSocketAddressesSet.isEmpty() ||
|
||||
localSocketAddressesSet.contains(socketAddress)
|
||||
|| isEventComingFromNonRegisteredHazelcastInstance(hazelcastInstanceSet.iterator().next(),
|
||||
localSocketAddressesSet, socketAddress);
|
||||
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link AbstractHazelcastEventListener} implementation for the {@link AbstractIMapEvent}s.
|
||||
*
|
||||
* @param <K> the entry key type
|
||||
* @param <V> the entry value type
|
||||
*/
|
||||
protected final class HazelcastEntryListener<K, V> extends
|
||||
AbstractHazelcastEventListener<AbstractIMapEvent> 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 entryExpired(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(AbstractIMapEvent event) {
|
||||
if (getCacheEvents().contains(event.getEventType().toString())) {
|
||||
if (AbstractHazelcastMessageProducer.this.logger.isDebugEnabled()) {
|
||||
AbstractHazelcastMessageProducer.this.logger.debug("Received Event : " + event);
|
||||
}
|
||||
sendMessage(event,
|
||||
event.getMember().getSocketAddress(EndpointQualifier.MEMBER), getCacheListeningPolicy());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Message<?> toMessage(AbstractIMapEvent event) {
|
||||
final Map<String, Object> headers = new HashMap<>();
|
||||
headers.put(HazelcastHeaders.EVENT_TYPE, event.getEventType().name());
|
||||
headers.put(HazelcastHeaders.MEMBER, event.getMember().getSocketAddress(EndpointQualifier.MEMBER));
|
||||
headers.put(HazelcastHeaders.CACHE_NAME, event.getName());
|
||||
|
||||
if (event instanceof EntryEvent) {
|
||||
@SuppressWarnings("unchecked")
|
||||
EntryEvent<K, V> entryEvent = (EntryEvent<K, V>) event;
|
||||
EntryEventMessagePayload<K, V> messagePayload = new EntryEventMessagePayload<>(entryEvent.getKey(),
|
||||
entryEvent.getValue(), entryEvent.getOldValue());
|
||||
return getMessageBuilderFactory().withPayload(messagePayload).copyHeaders(headers).build();
|
||||
}
|
||||
else if (event instanceof MapEvent) {
|
||||
return getMessageBuilderFactory()
|
||||
.withPayload(((MapEvent) event).getNumberOfEntriesAffected()).copyHeaders(headers).build();
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Invalid event is received. Event : " + event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* https://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.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.integration.endpoint.MessageProducerSupport;
|
||||
import org.springframework.integration.hazelcast.ClusterMonitorType;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationDefinitionValidator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.hazelcast.client.Client;
|
||||
import com.hazelcast.client.ClientListener;
|
||||
import com.hazelcast.cluster.MembershipEvent;
|
||||
import com.hazelcast.cluster.MembershipListener;
|
||||
import com.hazelcast.core.DistributedObjectEvent;
|
||||
import com.hazelcast.core.DistributedObjectListener;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.core.LifecycleEvent;
|
||||
import com.hazelcast.core.LifecycleListener;
|
||||
import com.hazelcast.partition.MigrationListener;
|
||||
import com.hazelcast.partition.MigrationState;
|
||||
import com.hazelcast.partition.ReplicaMigrationEvent;
|
||||
|
||||
/**
|
||||
* Hazelcast Cluster Monitor Event Driven Message Producer is a message producer which
|
||||
* enables {@link HazelcastClusterMonitorMessageProducer.HazelcastClusterMonitorListener}
|
||||
* listener in order to listen cluster related events and sends events to related channel.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public class HazelcastClusterMonitorMessageProducer extends MessageProducerSupport {
|
||||
|
||||
private final HazelcastInstance hazelcastInstance;
|
||||
|
||||
private Set<String> monitorTypes = Collections.singleton(ClusterMonitorType.MEMBERSHIP.name());
|
||||
|
||||
private final Map<ClusterMonitorType, UUID> hazelcastRegisteredListenerIdMap = new ConcurrentHashMap<>(5);
|
||||
|
||||
public HazelcastClusterMonitorMessageProducer(HazelcastInstance hazelcastInstance) {
|
||||
Assert.notNull(hazelcastInstance, "'hazelcastInstance' must not be null");
|
||||
this.hazelcastInstance = hazelcastInstance;
|
||||
}
|
||||
|
||||
public void setMonitorEventTypes(String monitorEventTypes) {
|
||||
final Set<String> monitorTypes =
|
||||
HazelcastIntegrationDefinitionValidator.validateEnumType(ClusterMonitorType.class, monitorEventTypes);
|
||||
Assert.notEmpty(monitorTypes, "'monitorTypes' must have elements");
|
||||
this.monitorTypes = monitorTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() {
|
||||
final HazelcastClusterMonitorListener clusterMonitorListener = new HazelcastClusterMonitorListener();
|
||||
|
||||
if (this.monitorTypes.contains(ClusterMonitorType.MEMBERSHIP.name())) {
|
||||
final UUID registrationId = this.hazelcastInstance.getCluster()
|
||||
.addMembershipListener(clusterMonitorListener);
|
||||
this.hazelcastRegisteredListenerIdMap.put(ClusterMonitorType.MEMBERSHIP, registrationId);
|
||||
}
|
||||
|
||||
if (this.monitorTypes.contains(ClusterMonitorType.DISTRIBUTED_OBJECT.name())) {
|
||||
final UUID registrationId = this.hazelcastInstance
|
||||
.addDistributedObjectListener(clusterMonitorListener);
|
||||
this.hazelcastRegisteredListenerIdMap.put(ClusterMonitorType.DISTRIBUTED_OBJECT, registrationId);
|
||||
}
|
||||
|
||||
if (this.monitorTypes.contains(ClusterMonitorType.MIGRATION.name())) {
|
||||
final UUID registrationId = this.hazelcastInstance.getPartitionService()
|
||||
.addMigrationListener(clusterMonitorListener);
|
||||
this.hazelcastRegisteredListenerIdMap.put(ClusterMonitorType.MIGRATION, registrationId);
|
||||
}
|
||||
|
||||
if (this.monitorTypes.contains(ClusterMonitorType.LIFECYCLE.name())) {
|
||||
final UUID registrationId = this.hazelcastInstance.getLifecycleService()
|
||||
.addLifecycleListener(clusterMonitorListener);
|
||||
this.hazelcastRegisteredListenerIdMap.put(ClusterMonitorType.LIFECYCLE, registrationId);
|
||||
}
|
||||
|
||||
if (this.monitorTypes.contains(ClusterMonitorType.CLIENT.name())) {
|
||||
final UUID registrationId = this.hazelcastInstance.getClientService()
|
||||
.addClientListener(clusterMonitorListener);
|
||||
this.hazelcastRegisteredListenerIdMap.put(ClusterMonitorType.CLIENT, registrationId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() {
|
||||
if (this.hazelcastInstance.getLifecycleService().isRunning()) {
|
||||
UUID id = this.hazelcastRegisteredListenerIdMap.remove(ClusterMonitorType.MEMBERSHIP);
|
||||
if (id != null) {
|
||||
this.hazelcastInstance.getCluster().removeMembershipListener(id);
|
||||
}
|
||||
|
||||
id = this.hazelcastRegisteredListenerIdMap.remove(ClusterMonitorType.DISTRIBUTED_OBJECT);
|
||||
if (id != null) {
|
||||
this.hazelcastInstance.removeDistributedObjectListener(id);
|
||||
}
|
||||
|
||||
id = this.hazelcastRegisteredListenerIdMap.remove(ClusterMonitorType.MIGRATION);
|
||||
if (id != null) {
|
||||
this.hazelcastInstance.getPartitionService().removeMigrationListener(id);
|
||||
}
|
||||
|
||||
id = this.hazelcastRegisteredListenerIdMap.remove(ClusterMonitorType.LIFECYCLE);
|
||||
if (id != null) {
|
||||
this.hazelcastInstance.getLifecycleService().removeLifecycleListener(id);
|
||||
}
|
||||
|
||||
id = this.hazelcastRegisteredListenerIdMap.remove(ClusterMonitorType.CLIENT);
|
||||
if (id != null) {
|
||||
this.hazelcastInstance.getClientService().removeClientListener(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComponentType() {
|
||||
return "hazelcast:cm-inbound-channel-adapter";
|
||||
}
|
||||
|
||||
private void processEvent(Object event) {
|
||||
Assert.notNull(event, "'hazelcast event' must not be null");
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Received Cluster Monitor Event : " + event);
|
||||
}
|
||||
this.sendMessage(getMessageBuilderFactory().withPayload(event).build());
|
||||
|
||||
}
|
||||
|
||||
private final class HazelcastClusterMonitorListener implements MembershipListener,
|
||||
DistributedObjectListener, MigrationListener, LifecycleListener,
|
||||
ClientListener {
|
||||
|
||||
@Override
|
||||
public void memberAdded(MembershipEvent membershipEvent) {
|
||||
processEvent(membershipEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void memberRemoved(MembershipEvent membershipEvent) {
|
||||
processEvent(membershipEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void distributedObjectCreated(DistributedObjectEvent event) {
|
||||
processEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void distributedObjectDestroyed(DistributedObjectEvent event) {
|
||||
processEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrationStarted(MigrationState migrationEvent) {
|
||||
processEvent(migrationEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrationFinished(MigrationState migrationEvent) {
|
||||
processEvent(migrationEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replicaMigrationCompleted(ReplicaMigrationEvent event) {
|
||||
processEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replicaMigrationFailed(ReplicaMigrationEvent event) {
|
||||
processEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateChanged(LifecycleEvent event) {
|
||||
processEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clientConnected(Client client) {
|
||||
processEvent(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clientDisconnected(Client client) {
|
||||
processEvent(client);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* https://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.map.IMap;
|
||||
import com.hazelcast.query.impl.predicates.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 6.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,92 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* https://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.DistributedSQLIterationType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import com.hazelcast.map.IMap;
|
||||
import com.hazelcast.query.impl.predicates.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 6.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, "'distributedMap' must not be null");
|
||||
Assert.hasText(distributedSql, "'distributedSql' must not be empty");
|
||||
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
|
||||
@SuppressWarnings("unchecked")
|
||||
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,197 @@
|
||||
/*
|
||||
* Copyright 2015-2019 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
|
||||
*
|
||||
* https://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.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.integration.hazelcast.HazelcastHeaders;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationDefinitionValidator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.hazelcast.collection.IList;
|
||||
import com.hazelcast.collection.IQueue;
|
||||
import com.hazelcast.collection.ISet;
|
||||
import com.hazelcast.collection.ItemEvent;
|
||||
import com.hazelcast.collection.ItemListener;
|
||||
import com.hazelcast.core.DistributedObject;
|
||||
import com.hazelcast.instance.EndpointQualifier;
|
||||
import com.hazelcast.map.IMap;
|
||||
import com.hazelcast.map.listener.MapListener;
|
||||
import com.hazelcast.multimap.MultiMap;
|
||||
import com.hazelcast.replicatedmap.ReplicatedMap;
|
||||
import com.hazelcast.topic.ITopic;
|
||||
import com.hazelcast.topic.Message;
|
||||
import com.hazelcast.topic.MessageListener;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public class HazelcastEventDrivenMessageProducer extends AbstractHazelcastMessageProducer {
|
||||
|
||||
public HazelcastEventDrivenMessageProducer(DistributedObject distributedObject) {
|
||||
super(distributedObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInit() {
|
||||
super.onInit();
|
||||
HazelcastIntegrationDefinitionValidator.validateCacheTypeForEventDrivenMessageProducer(this.distributedObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
protected void doStart() {
|
||||
if (this.distributedObject instanceof IMap) {
|
||||
setHazelcastRegisteredEventListenerId(((IMap<?, ?>) this.distributedObject)
|
||||
.addEntryListener((MapListener) 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<ItemEvent<E>>
|
||||
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(ItemEvent<E> event) {
|
||||
if (getCacheEvents().contains(event.getEventType().toString())) {
|
||||
sendMessage(event,
|
||||
event.getMember().getSocketAddress(EndpointQualifier.MEMBER), getCacheListeningPolicy());
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Received ItemEvent : " + event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected org.springframework.messaging.Message<?> toMessage(ItemEvent<E> event) {
|
||||
final Map<String, Object> headers = new HashMap<>();
|
||||
headers.put(HazelcastHeaders.EVENT_TYPE, event.getEventType().name());
|
||||
headers.put(HazelcastHeaders.MEMBER, event.getMember().getSocketAddress(EndpointQualifier.MEMBER));
|
||||
|
||||
return getMessageBuilderFactory().withPayload(event.getItem()).copyHeaders(headers).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class HazelcastMessageListener<E> extends AbstractHazelcastEventListener<Message<E>>
|
||||
implements MessageListener<E> {
|
||||
|
||||
@Override
|
||||
public void onMessage(Message<E> message) {
|
||||
processEvent(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processEvent(Message<E> event) {
|
||||
sendMessage(event,
|
||||
event.getPublishingMember().getSocketAddress(EndpointQualifier.MEMBER), getCacheListeningPolicy());
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Received Message : " + event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected org.springframework.messaging.Message<?> toMessage(Message<E> event) {
|
||||
Assert.notNull(event.getMessageObject(), "message must not be null");
|
||||
|
||||
final Map<String, Object> headers = new HashMap<>();
|
||||
headers.put(HazelcastHeaders.MEMBER,
|
||||
event.getPublishingMember().getSocketAddress(EndpointQualifier.MEMBER));
|
||||
headers.put(HazelcastHeaders.CACHE_NAME, event.getSource());
|
||||
headers.put(HazelcastHeaders.PUBLISHING_TIME, event.getPublishTime());
|
||||
|
||||
return getMessageBuilderFactory().withPayload(event.getMessageObject()).copyHeaders(headers).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides classes supporting inbound endpoints.
|
||||
*/
|
||||
package org.springframework.integration.hazelcast.inbound;
|
||||
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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.leader;
|
||||
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.integration.leader.Candidate;
|
||||
import org.springframework.integration.leader.Context;
|
||||
import org.springframework.integration.leader.DefaultCandidate;
|
||||
import org.springframework.integration.leader.event.DefaultLeaderEventPublisher;
|
||||
import org.springframework.integration.leader.event.LeaderEventPublisher;
|
||||
import org.springframework.integration.support.leader.LockRegistryLeaderInitiator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.cp.CPSubsystem;
|
||||
import com.hazelcast.cp.lock.FencedLock;
|
||||
|
||||
/**
|
||||
* Bootstrap leadership {@link org.springframework.integration.leader.Candidate candidates}
|
||||
* with Hazelcast. Upon construction, {@link #start} must be invoked to
|
||||
* register the candidate for leadership election.
|
||||
*
|
||||
* @author Patrick Peralta
|
||||
* @author Gary Russell
|
||||
* @author Dave Syer
|
||||
* @author Artem Bilan
|
||||
* @author Mael Le Guével
|
||||
* @author Alexey Tsoy
|
||||
* @author Robert Höglund
|
||||
*/
|
||||
public class LeaderInitiator implements SmartLifecycle, DisposableBean, ApplicationEventPublisherAware {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(LeaderInitiator.class);
|
||||
|
||||
private static int threadNameCount = 0;
|
||||
|
||||
private static final Context NULL_CONTEXT = new NullContext();
|
||||
|
||||
/*** Hazelcast client.
|
||||
*/
|
||||
private final HazelcastInstance client;
|
||||
|
||||
/**
|
||||
* Candidate for leader election.
|
||||
*/
|
||||
private final Candidate candidate;
|
||||
|
||||
/**
|
||||
* Executor service for running leadership daemon.
|
||||
*/
|
||||
private final ExecutorService executorService =
|
||||
Executors.newSingleThreadExecutor(r -> {
|
||||
Thread thread = new Thread(r, "Hazelcast-leadership-" + (threadNameCount++));
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
});
|
||||
|
||||
private long heartBeatMillis = LockRegistryLeaderInitiator.DEFAULT_HEART_BEAT_TIME;
|
||||
|
||||
private long busyWaitMillis = LockRegistryLeaderInitiator.DEFAULT_BUSY_WAIT_TIME;
|
||||
|
||||
private LeaderSelector leaderSelector;
|
||||
|
||||
/**
|
||||
* Leader event publisher.
|
||||
*/
|
||||
private LeaderEventPublisher leaderEventPublisher = new DefaultLeaderEventPublisher();
|
||||
|
||||
private boolean autoStartup = true;
|
||||
|
||||
private int phase;
|
||||
|
||||
/**
|
||||
* Future returned by submitting an {@link LeaderSelector} to {@link #executorService}.
|
||||
* This is used to cancel leadership.
|
||||
*/
|
||||
private volatile Future<Void> future;
|
||||
|
||||
private boolean customPublisher = false;
|
||||
|
||||
private volatile boolean running;
|
||||
|
||||
private final Semaphore yieldSign = new Semaphore(0);
|
||||
|
||||
/**
|
||||
* Construct a {@link LeaderInitiator} with a default candidate.
|
||||
* @param client Hazelcast client
|
||||
*/
|
||||
public LeaderInitiator(HazelcastInstance client) {
|
||||
this(client, new DefaultCandidate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link LeaderInitiator}.
|
||||
* @param client Hazelcast client
|
||||
* @param candidate leadership election candidate
|
||||
*/
|
||||
public LeaderInitiator(HazelcastInstance client, Candidate candidate) {
|
||||
Assert.notNull(client, "'client' must not be null");
|
||||
Assert.notNull(candidate, "'candidate' must not be null");
|
||||
this.client = client;
|
||||
this.candidate = candidate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link LeaderEventPublisher}.
|
||||
* @param leaderEventPublisher the event publisher
|
||||
*/
|
||||
public void setLeaderEventPublisher(LeaderEventPublisher leaderEventPublisher) {
|
||||
Assert.notNull(leaderEventPublisher, "'leaderEventPublisher' must not be null");
|
||||
this.leaderEventPublisher = leaderEventPublisher;
|
||||
this.customPublisher = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time in milliseconds to wait in between attempts to re-acquire the lock, once it is
|
||||
* held. The heartbeat time has to be less than the remote lock expiry period, if
|
||||
* there is one, otherwise other nodes can steal the lock while we are sleeping here.
|
||||
* @param heartBeatMillis the heart-beat timeout in milliseconds.
|
||||
* Defaults to {@link LockRegistryLeaderInitiator#DEFAULT_HEART_BEAT_TIME}
|
||||
* @since 1.0.1
|
||||
*/
|
||||
public void setHeartBeatMillis(long heartBeatMillis) {
|
||||
this.heartBeatMillis = heartBeatMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time in milliseconds to wait in between attempts to acquire the lock, if it is not
|
||||
* held. The longer this is, the longer the system can be leaderless, if the leader
|
||||
* dies. If a leader dies without releasing its lock, the system might still have to
|
||||
* wait for the old lock to expire, but after that it should not have to wait longer
|
||||
* than the busy wait time to get a new leader.
|
||||
* @param busyWaitMillis the busy-wait timeout in milliseconds
|
||||
* Defaults to {@link LockRegistryLeaderInitiator#DEFAULT_BUSY_WAIT_TIME}
|
||||
* @since 1.0.1
|
||||
*/
|
||||
public void setBusyWaitMillis(long busyWaitMillis) {
|
||||
this.busyWaitMillis = busyWaitMillis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
|
||||
if (!this.customPublisher) {
|
||||
this.leaderEventPublisher = new DefaultLeaderEventPublisher(applicationEventPublisher);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAutoStartup(boolean autoStartup) {
|
||||
this.autoStartup = autoStartup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoStartup() {
|
||||
return this.autoStartup;
|
||||
}
|
||||
|
||||
public void setPhase(int phase) {
|
||||
this.phase = phase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPhase() {
|
||||
return this.phase;
|
||||
}
|
||||
|
||||
/**
|
||||
* The context of the initiator or null if not running.
|
||||
* @return the context (or null if not running)
|
||||
*/
|
||||
public Context getContext() {
|
||||
if (this.leaderSelector == null) {
|
||||
return NULL_CONTEXT;
|
||||
}
|
||||
return this.leaderSelector.context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the registration of the {@link #candidate} for leader election.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void start() {
|
||||
if (!this.running) {
|
||||
this.leaderSelector = new LeaderSelector();
|
||||
this.running = true;
|
||||
this.future = this.executorService.submit(this.leaderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(Runnable callback) {
|
||||
stop();
|
||||
callback.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the registration of the {@link #candidate} for leader election.
|
||||
* If the candidate is currently leader, its leadership will be revoked.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void stop() {
|
||||
if (this.running) {
|
||||
this.running = false;
|
||||
if (this.future != null) {
|
||||
this.future.cancel(true);
|
||||
}
|
||||
this.future = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code true} if leadership election for this {@link #candidate} is running.
|
||||
* @return true if leadership election for this {@link #candidate} is running
|
||||
*/
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return this.running;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
stop();
|
||||
this.executorService.shutdown();
|
||||
}
|
||||
|
||||
|
||||
FencedLock getLock() {
|
||||
CPSubsystem cpSubSystem = this.client.getCPSubsystem();
|
||||
FencedLock lock = cpSubSystem.getLock(this.candidate.getRole());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(
|
||||
String.format("Use lock groupId '%s', lock count '%s'", lock.getGroupId(), lock.getLockCount()));
|
||||
}
|
||||
return lock;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callable that manages the acquisition of Hazelcast locks
|
||||
* for leadership election.
|
||||
*/
|
||||
protected class LeaderSelector implements Callable<Void> {
|
||||
|
||||
protected final HazelcastContext context = new HazelcastContext();
|
||||
|
||||
protected final String role = LeaderInitiator.this.candidate.getRole();
|
||||
|
||||
private volatile boolean leader = false;
|
||||
|
||||
@Override
|
||||
public Void call() {
|
||||
try {
|
||||
while (isRunning()) {
|
||||
try {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Am I the leader (" + LeaderInitiator.this.candidate.getRole() + ") ? "
|
||||
+ this.leader);
|
||||
}
|
||||
if (getLock().isLockedByCurrentThread()) {
|
||||
if (!this.leader) {
|
||||
// Since we have the lock we need to ensure that the leader flag is set
|
||||
this.leader = true;
|
||||
}
|
||||
// Give it a chance to expire.
|
||||
if (LeaderInitiator.this.yieldSign.tryAcquire(LeaderInitiator.this.heartBeatMillis, TimeUnit.MILLISECONDS)) {
|
||||
revokeLeadership();
|
||||
// Give it a chance to elect some other leader.
|
||||
Thread.sleep(LeaderInitiator.this.busyWaitMillis);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We try to acquire the lock
|
||||
boolean acquired = getLock()
|
||||
.tryLock(LeaderInitiator.this.heartBeatMillis, TimeUnit.MILLISECONDS);
|
||||
if (acquired && !this.leader) {
|
||||
// Success: we are now leader
|
||||
this.leader = true;
|
||||
handleGranted();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
// The lock was broken and we are no longer leader
|
||||
revokeLeadership();
|
||||
|
||||
|
||||
if (isRunning()) {
|
||||
// Give it a chance to elect some other leader.
|
||||
try {
|
||||
Thread.sleep(LeaderInitiator.this.busyWaitMillis);
|
||||
}
|
||||
catch (InterruptedException e1) {
|
||||
// Ignore interruption and let it to be caught on the next cycle.
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Error acquiring the lock for " + this.context +
|
||||
". " + (isRunning() ? "Retrying..." : ""), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
revokeLeadership();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void revokeLeadership() {
|
||||
if (this.leader) {
|
||||
this.leader = false;
|
||||
try {
|
||||
// Try to unlock
|
||||
getLock().unlock();
|
||||
}
|
||||
catch (Exception e1) {
|
||||
logger.warn("Could not unlock - treat as broken " + this.context + ". Revoking "
|
||||
+ (isRunning() ? " and retrying..." : "..."), e1);
|
||||
|
||||
}
|
||||
|
||||
handleRevoked();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void handleGranted() throws InterruptedException {
|
||||
LeaderInitiator.this.candidate.onGranted(this.context);
|
||||
if (LeaderInitiator.this.leaderEventPublisher != null) {
|
||||
try {
|
||||
LeaderInitiator.this.leaderEventPublisher.publishOnGranted(
|
||||
LeaderInitiator.this, this.context, this.role);
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.warn("Error publishing OnGranted event.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleRevoked() {
|
||||
LeaderInitiator.this.candidate.onRevoked(this.context);
|
||||
if (LeaderInitiator.this.leaderEventPublisher != null) {
|
||||
try {
|
||||
LeaderInitiator.this.leaderEventPublisher.publishOnRevoked(
|
||||
LeaderInitiator.this, this.context, this.role);
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.warn("Error publishing OnRevoked event.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of leadership context backed by Hazelcast.
|
||||
*/
|
||||
protected class HazelcastContext implements Context {
|
||||
|
||||
@Override
|
||||
public boolean isLeader() {
|
||||
return LeaderInitiator.this.leaderSelector.leader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void yield() {
|
||||
if (isLeader()) {
|
||||
LeaderInitiator.this.yieldSign.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRole() {
|
||||
return LeaderInitiator.this.candidate.getRole();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HazelcastContext{role=" + LeaderInitiator.this.candidate.getRole() +
|
||||
", id=" + LeaderInitiator.this.candidate.getId() +
|
||||
", isLeader=" + isLeader() + "}";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class NullContext implements Context {
|
||||
|
||||
@Override
|
||||
public boolean isLeader() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void yield() {
|
||||
// No-op
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides the Leader Initiator support classes.
|
||||
*/
|
||||
package org.springframework.integration.hazelcast.leader;
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2015-2019 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
|
||||
*
|
||||
* https://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.HazelcastLocalInstanceRegistrar;
|
||||
|
||||
import com.hazelcast.cluster.MembershipAdapter;
|
||||
import com.hazelcast.cluster.MembershipEvent;
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.instance.EndpointQualifier;
|
||||
import com.hazelcast.multimap.MultiMap;
|
||||
|
||||
/**
|
||||
* Hazelcast {@link MembershipAdapter} in order to listen for membership updates in the cluster.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public class HazelcastMembershipListener extends MembershipAdapter {
|
||||
|
||||
@Override
|
||||
public void memberRemoved(MembershipEvent membershipEvent) {
|
||||
SocketAddress removedMemberSocketAddress =
|
||||
membershipEvent.getMember().getSocketAddress(EndpointQualifier.MEMBER);
|
||||
Set<HazelcastInstance> hazelcastLocalInstanceSet = Hazelcast.getAllHazelcastInstances();
|
||||
if (!hazelcastLocalInstanceSet.isEmpty()) {
|
||||
HazelcastInstance hazelcastInstance = hazelcastLocalInstanceSet.iterator().next();
|
||||
Lock lock =
|
||||
hazelcastInstance.getCPSubsystem()
|
||||
.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,46 @@
|
||||
/*
|
||||
* Copyright 2017-2019 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
|
||||
*
|
||||
* https://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.lock;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import org.springframework.integration.support.locks.LockRegistry;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
|
||||
/**
|
||||
* A {@link LockRegistry} implementation Hazelcast distributed locks.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public class HazelcastLockRegistry implements LockRegistry {
|
||||
|
||||
private final HazelcastInstance client;
|
||||
|
||||
public HazelcastLockRegistry(HazelcastInstance hazelcastInstance) {
|
||||
Assert.notNull(hazelcastInstance, "'hazelcastInstance' must not be null");
|
||||
this.client = hazelcastInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lock obtain(Object lockKey) {
|
||||
Assert.isInstanceOf(String.class, lockKey);
|
||||
return this.client.getCPSubsystem().getLock((String) lockKey);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides the distributed Locks support classes.
|
||||
*/
|
||||
package org.springframework.integration.hazelcast.lock;
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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.message;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Hazelcast Message Payload for Entry Events.
|
||||
*
|
||||
* @param <K> the entry key type
|
||||
* @param <V> the entry value type
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public class EntryEventMessagePayload<K, V> {
|
||||
|
||||
/**
|
||||
* The entry key.
|
||||
*/
|
||||
public final K key;
|
||||
|
||||
/**
|
||||
* The entry value.
|
||||
*/
|
||||
public final V value;
|
||||
|
||||
/**
|
||||
* The entry old value if any.
|
||||
*/
|
||||
public final V oldValue;
|
||||
|
||||
public EntryEventMessagePayload(final K key, final V value, final V oldValue) {
|
||||
Assert.notNull(key, "'key' must not be null");
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.oldValue = oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EntryEventMessagePayload [key=" + this.key + ", value=" + this.value + ", oldValue=" + this.oldValue + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EntryEventMessagePayload<?, ?> that = (EntryEventMessagePayload<?, ?>) o;
|
||||
|
||||
return this.key.equals(that.key) && !(this.value != null ? !this.value.equals(that.value)
|
||||
: that.value != null) && !(this.oldValue != null
|
||||
? !this.oldValue.equals(that.oldValue) : that.oldValue != null);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = this.key.hashCode();
|
||||
result = 31 * result + (this.value != null ? this.value.hashCode() : 0);
|
||||
result = 31 * result + (this.oldValue != null ? this.oldValue.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides classes supporting Hazelcast message headers and payload.
|
||||
*/
|
||||
package org.springframework.integration.hazelcast.message;
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2017 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
|
||||
*
|
||||
* https://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.metadata;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.integration.metadata.ListenableMetadataStore;
|
||||
import org.springframework.integration.metadata.MetadataStoreListener;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.hazelcast.core.EntryEvent;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.map.IMap;
|
||||
import com.hazelcast.map.listener.EntryAddedListener;
|
||||
import com.hazelcast.map.listener.EntryRemovedListener;
|
||||
import com.hazelcast.map.listener.EntryUpdatedListener;
|
||||
|
||||
/**
|
||||
* The Hazelcast {@link IMap}-based {@link ListenableMetadataStore} implementation.
|
||||
*
|
||||
* @author Vinicius Carvalho
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public class HazelcastMetadataStore implements ListenableMetadataStore, InitializingBean {
|
||||
|
||||
private static final String METADATA_STORE_MAP_NAME = "SPRING_INTEGRATION_METADATA_STORE";
|
||||
|
||||
private final IMap<String, String> map;
|
||||
|
||||
private final List<MetadataStoreListener> listeners = new CopyOnWriteArrayList<MetadataStoreListener>();
|
||||
|
||||
public HazelcastMetadataStore(HazelcastInstance hazelcastInstance) {
|
||||
Assert.notNull(hazelcastInstance, "Hazelcast instance can't be null");
|
||||
this.map = hazelcastInstance.getMap(METADATA_STORE_MAP_NAME);
|
||||
}
|
||||
|
||||
public HazelcastMetadataStore(IMap<String, String> map) {
|
||||
Assert.notNull(map, "IMap reference can not be null");
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String putIfAbsent(String key, String value) {
|
||||
Assert.notNull(key, "'key' must not be null.");
|
||||
Assert.notNull(value, "'value' must not be null.");
|
||||
return this.map.putIfAbsent(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replace(String key, String oldValue, String newValue) {
|
||||
Assert.notNull(key, "'key' must not be null.");
|
||||
Assert.notNull(oldValue, "'oldValue' must not be null.");
|
||||
Assert.notNull(newValue, "'newValue' must not be null.");
|
||||
return this.map.replace(key, oldValue, newValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String key, String value) {
|
||||
Assert.notNull(key, "'key' must not be null.");
|
||||
Assert.notNull(value, "'value' must not be null.");
|
||||
this.map.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String key) {
|
||||
Assert.notNull(key, "'key' must not be null.");
|
||||
return this.map.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String remove(String key) {
|
||||
Assert.notNull(key, "'key' must not be null.");
|
||||
return this.map.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(MetadataStoreListener callback) {
|
||||
Assert.notNull(callback, "callback object can not be null");
|
||||
this.listeners.add(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(MetadataStoreListener callback) {
|
||||
this.listeners.remove(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
this.map.addEntryListener(new MapListener(this.listeners), true);
|
||||
}
|
||||
|
||||
private static class MapListener implements EntryAddedListener<String, String>,
|
||||
EntryRemovedListener<String, String>, EntryUpdatedListener<String, String> {
|
||||
|
||||
private final List<MetadataStoreListener> listeners;
|
||||
|
||||
MapListener(List<MetadataStoreListener> listeners) {
|
||||
this.listeners = listeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void entryAdded(EntryEvent<String, String> event) {
|
||||
for (MetadataStoreListener listener : this.listeners) {
|
||||
listener.onAdd(event.getKey(), event.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void entryRemoved(EntryEvent<String, String> event) {
|
||||
for (MetadataStoreListener listener : this.listeners) {
|
||||
listener.onRemove(event.getKey(), event.getOldValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void entryUpdated(EntryEvent<String, String> event) {
|
||||
for (MetadataStoreListener listener : this.listeners) {
|
||||
listener.onUpdate(event.getKey(), event.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides the Metadata Store support classes.
|
||||
*/
|
||||
package org.springframework.integration.hazelcast.metadata;
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2015-2019 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
|
||||
*
|
||||
* https://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.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.integration.expression.ExpressionUtils;
|
||||
import org.springframework.integration.handler.AbstractMessageHandler;
|
||||
import org.springframework.integration.hazelcast.HazelcastHeaders;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.hazelcast.core.DistributedObject;
|
||||
import com.hazelcast.multimap.MultiMap;
|
||||
import com.hazelcast.topic.ITopic;
|
||||
|
||||
/**
|
||||
* MessageHandler implementation that writes {@link Message} or payload to defined
|
||||
* Hazelcast distributed cache object.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public class HazelcastCacheWritingMessageHandler extends AbstractMessageHandler {
|
||||
|
||||
private DistributedObject distributedObject;
|
||||
|
||||
private Expression cacheExpression;
|
||||
|
||||
private Expression keyExpression;
|
||||
|
||||
private boolean extractPayload = true;
|
||||
|
||||
private EvaluationContext evaluationContext;
|
||||
|
||||
public void setDistributedObject(DistributedObject distributedObject) {
|
||||
Assert.notNull(distributedObject, "'distributedObject' must not be null");
|
||||
this.distributedObject = distributedObject;
|
||||
}
|
||||
|
||||
public void setCacheExpression(Expression cacheExpression) {
|
||||
Assert.notNull(cacheExpression, "'cacheExpression' must not be null");
|
||||
this.cacheExpression = cacheExpression;
|
||||
}
|
||||
|
||||
public void setKeyExpression(Expression keyExpression) {
|
||||
Assert.notNull(keyExpression, "'keyExpression' must not be null");
|
||||
this.keyExpression = keyExpression;
|
||||
}
|
||||
|
||||
public void setExtractPayload(boolean extractPayload) {
|
||||
this.extractPayload = extractPayload;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInit() {
|
||||
super.onInit();
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(getBeanFactory());
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
protected void handleMessageInternal(final Message<?> message) {
|
||||
Object objectToStore = message;
|
||||
if (this.extractPayload) {
|
||||
objectToStore = message.getPayload();
|
||||
}
|
||||
|
||||
DistributedObject distributedObject = getDistributedObject(message);
|
||||
|
||||
if (distributedObject instanceof Map) {
|
||||
Map map = (Map) distributedObject;
|
||||
if (objectToStore instanceof Map) {
|
||||
map.putAll((Map) objectToStore);
|
||||
}
|
||||
else if (objectToStore instanceof Map.Entry) {
|
||||
Map.Entry entry = (Map.Entry) objectToStore;
|
||||
map.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
else {
|
||||
map.put(getKey(message), objectToStore);
|
||||
}
|
||||
}
|
||||
else if (distributedObject instanceof MultiMap) {
|
||||
MultiMap map = (MultiMap) distributedObject;
|
||||
if (objectToStore instanceof Map) {
|
||||
Map<?, ?> mapToStore = (Map) objectToStore;
|
||||
for (Map.Entry entry : mapToStore.entrySet()) {
|
||||
map.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
else if (objectToStore instanceof Map.Entry) {
|
||||
Map.Entry entry = (Map.Entry) objectToStore;
|
||||
map.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
else {
|
||||
map.put(getKey(message), objectToStore);
|
||||
}
|
||||
}
|
||||
else if (distributedObject instanceof ITopic) {
|
||||
((ITopic) distributedObject).publish(objectToStore);
|
||||
}
|
||||
else if (distributedObject instanceof Collection) {
|
||||
if (objectToStore instanceof Collection) {
|
||||
((Collection) distributedObject).addAll((Collection) objectToStore);
|
||||
}
|
||||
else {
|
||||
((Collection) distributedObject).add(objectToStore);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("The 'distributedObject' for 'HazelcastCacheWritingMessageHandler' " +
|
||||
"must be of 'IMap', 'MultiMap', 'ITopic', 'ISet' or 'IList' type, " +
|
||||
"but gotten: [" + distributedObject + "].");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private DistributedObject getDistributedObject(final Message<?> message) {
|
||||
if (this.distributedObject != null) {
|
||||
return this.distributedObject;
|
||||
}
|
||||
else if (this.cacheExpression != null) {
|
||||
return this.cacheExpression.getValue(this.evaluationContext, message, DistributedObject.class);
|
||||
}
|
||||
else if (message.getHeaders().containsKey(HazelcastHeaders.CACHE_NAME)) {
|
||||
return getBeanFactory()
|
||||
.getBean(message.getHeaders().get(HazelcastHeaders.CACHE_NAME, String.class),
|
||||
DistributedObject.class);
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("One of 'cache', 'cache-expression' and "
|
||||
+ HazelcastHeaders.CACHE_NAME
|
||||
+ " must be set for cache object definition.");
|
||||
}
|
||||
}
|
||||
|
||||
private Object getKey(Message<?> message) {
|
||||
if (this.keyExpression != null) {
|
||||
return this.keyExpression.getValue(this.evaluationContext, message);
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(
|
||||
"'key-expression' must be set to place the raw 'payload' to the IMap, MultiMap and ReplicatedMap");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides classes supporting outbound endpoints.
|
||||
*/
|
||||
package org.springframework.integration.hazelcast.outbound;
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides common used types and classes.
|
||||
*/
|
||||
package org.springframework.integration.hazelcast;
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2017-2021 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
|
||||
*
|
||||
* https://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.store;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.integration.store.AbstractKeyValueMessageStore;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.map.IMap;
|
||||
import com.hazelcast.query.Predicates;
|
||||
import com.hazelcast.query.QueryConstants;
|
||||
|
||||
/**
|
||||
* The Hazelcast {@link IMap}-based {@link AbstractKeyValueMessageStore} implementation.
|
||||
*
|
||||
* @author Vinicius Carvalho
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public class HazelcastMessageStore extends AbstractKeyValueMessageStore {
|
||||
|
||||
private static final String MESSAGE_STORE_MAP_NAME = "SPRING_INTEGRATION_MESSAGE_STORE";
|
||||
|
||||
private final IMap<Object, Object> map;
|
||||
|
||||
public HazelcastMessageStore(HazelcastInstance hazelcastInstance) {
|
||||
Assert.notNull(hazelcastInstance, "Hazelcast instance can't be null");
|
||||
this.map = hazelcastInstance.getMap(MESSAGE_STORE_MAP_NAME);
|
||||
}
|
||||
|
||||
public HazelcastMessageStore(IMap<Object, Object> map) {
|
||||
Assert.notNull(map, "IMap reference can not be null");
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doRetrieve(Object id) {
|
||||
return this.map.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStore(Object id, Object objectToStore) {
|
||||
this.map.put(id, objectToStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStoreIfAbsent(Object id, Object objectToStore) {
|
||||
this.map.putIfAbsent(id, objectToStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRemoveAll(Collection<Object> ids) {
|
||||
this.map.removeAll((mapEntry) -> ids.contains(mapEntry.getKey()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doRemove(Object id) {
|
||||
return this.map.remove(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<?> doListKeys(String keyPattern) {
|
||||
Assert.hasText(keyPattern, "'keyPattern' must not be empty");
|
||||
keyPattern = keyPattern.replaceAll("\\*", "%");
|
||||
return this.map.keySet(Predicates.like(QueryConstants.KEY_ATTRIBUTE_NAME.value(), keyPattern));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides the Message Store support classes.
|
||||
*/
|
||||
package org.springframework.integration.hazelcast.store;
|
||||
@@ -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,4 @@
|
||||
http\://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast-1.0.xsd=org/springframework/integration/hazelcast/config/xml/spring-integration-hazelcast.xsd
|
||||
http\://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd=org/springframework/integration/hazelcast/config/xml/spring-integration-hazelcast.xsd
|
||||
https\://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast-1.0.xsd=org/springframework/integration/hazelcast/config/xml/spring-integration-hazelcast.xsd
|
||||
https\://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd=org/springframework/integration/hazelcast/config/xml/spring-integration-hazelcast.xsd
|
||||
@@ -0,0 +1,303 @@
|
||||
<?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="https://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="https://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:choice minOccurs="0" maxOccurs="2">
|
||||
<xsd:element name="request-handler-advice-chain" type="integration:handlerAdviceChainType"
|
||||
minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:choice>
|
||||
|
||||
<xsd:attributeGroup ref="integration:channelAdapterAttributes"/>
|
||||
|
||||
<xsd:attribute name="cache" type="xsd:string" use="optional">
|
||||
<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-expression" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Specifies cache name to listen ]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
<xsd:attribute name="key-expression" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Specifies entry key ]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
<xsd:attribute name="extract-payload" type="xsd:boolean" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Specifies whole message or just payload to send ]]>
|
||||
</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:element name="cm-inbound-channel-adapter">
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Configures Hazelcast Cluster Monitor Inbound Channel Adapter
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:complexType>
|
||||
|
||||
<xsd:attributeGroup ref="integration:channelAdapterAttributes"/>
|
||||
|
||||
<xsd:attribute name="hazelcast-instance" use="required" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="com.hazelcast.core.HazelcastInstance" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Specifies hazelcast instance reference to listen ]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
<xsd:attribute name="monitor-types" type="xsd:string" use="optional" default="MEMBERSHIP">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="value">
|
||||
<tool:expected-type
|
||||
type="org.springframework.integration.hazelcast.ClusterMonitorType" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Specifies cluster monitor types ]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
</xsd:element>
|
||||
|
||||
</xsd:schema>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<bean id="distList" factory-bean="hzInstance" factory-method="getList">
|
||||
<constructor-arg value="distList"/>
|
||||
</bean>
|
||||
|
||||
<bean id="hzInstance" class="com.hazelcast.core.Hazelcast" factory-method="newHazelcastInstance">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config">
|
||||
<property name="instanceName" value="Test_Hazelcast_Instance"/>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.hazelcast.collection.IList;
|
||||
import com.hazelcast.core.DistributedObject;
|
||||
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
|
||||
|
||||
/**
|
||||
* Hazelcast Integration Definition Validator Test Class
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
@SuppressWarnings({ "rawtypes" })
|
||||
public class HazelcastIntegrationDefinitionValidatorTests {
|
||||
|
||||
@Autowired
|
||||
private IList distList;
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() {
|
||||
HazelcastInstanceFactory.terminateAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateEnumType() {
|
||||
final String cacheEventTypes =
|
||||
" ADDED, REMOVED, UPDATED, EVICTED, EVICT_ALL, CLEAR_ALL ";
|
||||
final Set<String> typeSet = HazelcastIntegrationDefinitionValidator
|
||||
.validateEnumType(CacheEventType.class, cacheEventTypes);
|
||||
assertThat(typeSet.size()).isEqualTo(6);
|
||||
for (String type : typeSet) {
|
||||
Enum.valueOf(CacheEventType.class, type);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testValidateEnumTypeWithInvalidValue() {
|
||||
final String cacheEventTypes = "Invalid_Enum_Type";
|
||||
HazelcastIntegrationDefinitionValidator
|
||||
.validateEnumType(CacheEventType.class, cacheEventTypes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCacheEventsByDistributedObject() {
|
||||
Set<String> cacheEventTypeSet = new HashSet<>(2);
|
||||
cacheEventTypeSet.add(CacheEventType.ADDED.toString());
|
||||
cacheEventTypeSet.add(CacheEventType.REMOVED.toString());
|
||||
HazelcastIntegrationDefinitionValidator
|
||||
.validateCacheEventsByDistributedObject(this.distList, cacheEventTypeSet);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testValidateCacheEventsByDistributedObjectWithInvalidValue() {
|
||||
Set<String> cacheEventTypeSet = new HashSet<>(1);
|
||||
cacheEventTypeSet.add("Invalid_Cache_Event_Type");
|
||||
HazelcastIntegrationDefinitionValidator
|
||||
.validateCacheEventsByDistributedObject(this.distList, cacheEventTypeSet);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCacheTypeForEventDrivenMessageProducer() {
|
||||
HazelcastIntegrationDefinitionValidator
|
||||
.validateCacheTypeForEventDrivenMessageProducer(this.distList);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testValidateCacheTypeForEventDrivenMessageProducerWithUnexpectedDistObject() {
|
||||
HazelcastIntegrationDefinitionValidator
|
||||
.validateCacheTypeForEventDrivenMessageProducer(new DistributedObject() {
|
||||
|
||||
@Override
|
||||
public String getPartitionKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServiceName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* User Bean for Hazelcast Integration Unit Tests
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.0
|
||||
*/
|
||||
public class HazelcastIntegrationTestUser implements Comparable<HazelcastIntegrationTestUser>, 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 compareTo(HazelcastIntegrationTestUser user) {
|
||||
return (this.id < user.getId()) ? -1 : (this.id > user.getId()) ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
HazelcastIntegrationTestUser that = (HazelcastIntegrationTestUser) o;
|
||||
return id == that.id &&
|
||||
age == that.age &&
|
||||
Objects.equals(name, that.name) &&
|
||||
Objects.equals(surname, that.surname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, name, surname, age);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2015-2019 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
|
||||
*
|
||||
* https://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.util.concurrent.CountDownLatch;
|
||||
|
||||
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
|
||||
import org.springframework.messaging.Message;
|
||||
|
||||
/**
|
||||
* {@link AbstractRequestHandlerAdvice} advice class for Hazelcast Integration Unit Tests.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public class HazelcastTestRequestHandlerAdvice extends AbstractRequestHandlerAdvice {
|
||||
|
||||
public CountDownLatch executeLatch = null;
|
||||
|
||||
public HazelcastTestRequestHandlerAdvice(int count) {
|
||||
this.executeLatch = new CountDownLatch(count);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) {
|
||||
try {
|
||||
return callback.execute();
|
||||
}
|
||||
finally {
|
||||
this.executeLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<bean id="instance" class="com.hazelcast.core.Hazelcast" factory-method="newHazelcastInstance">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config">
|
||||
<property name="CPSubsystemConfig">
|
||||
<bean class="com.hazelcast.config.cp.CPSubsystemConfig">
|
||||
<property name="CPMemberCount" value="0"/>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,71 @@
|
||||
<?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
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
https://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
https://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<import resource="classpath:org/springframework/integration/hazelcast/common-config.xml"/>
|
||||
|
||||
<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"/>
|
||||
|
||||
<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"/>
|
||||
|
||||
<int-hazelcast:cq-inbound-channel-adapter channel="cqMapChannel5" cache="cqDistributedMap5" cache-events="UPDATED"
|
||||
predicate="surname=TestSurname2" include-value="false"/>
|
||||
|
||||
<bean id="cqDistributedMap1" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="cqDistributedMap1"/>
|
||||
</bean>
|
||||
|
||||
<bean id="cqDistributedMap2" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="cqDistributedMap2"/>
|
||||
</bean>
|
||||
|
||||
<bean id="cqDistributedMap3" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="cqDistributedMap3"/>
|
||||
</bean>
|
||||
|
||||
<bean id="cqDistributedMap4" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="cqDistributedMap4"/>
|
||||
</bean>
|
||||
|
||||
<bean id="cqDistributedMap5" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="cqDistributedMap5"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.HazelcastHeaders;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.integration.hazelcast.inbound.util.HazelcastInboundChannelAdapterTestUtils;
|
||||
import org.springframework.integration.hazelcast.message.EntryEventMessagePayload;
|
||||
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.SpringRunner;
|
||||
|
||||
import com.hazelcast.core.EntryEventType;
|
||||
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
|
||||
import com.hazelcast.map.IMap;
|
||||
|
||||
/**
|
||||
* Hazelcast Continuous Query Inbound Channel Adapter Unit Test Class
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public class HazelcastCQDistributedMapInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cqMapChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cqMapChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cqMapChannel3;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cqMapChannel4;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cqMapChannel5;
|
||||
|
||||
@Autowired
|
||||
private IMap cqDistributedMap1;
|
||||
|
||||
@Autowired
|
||||
private IMap cqDistributedMap2;
|
||||
|
||||
@Autowired
|
||||
private IMap cqDistributedMap3;
|
||||
|
||||
@Autowired
|
||||
private IMap cqDistributedMap4;
|
||||
|
||||
@Autowired
|
||||
private IMap cqDistributedMap5;
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() {
|
||||
HazelcastInstanceFactory.terminateAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContinuousQueryForOnlyADDEDEntryEvent() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForADDEDDistributedMapEntryEvent(cqDistributedMap1,
|
||||
cqMapChannel1, "cqDistributedMap1");
|
||||
}
|
||||
|
||||
@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(HazelcastInboundChannelAdapterTestUtils.TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getPayload() instanceof EntryEventMessagePayload).isTrue();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE)).isEqualTo(EntryEventType.REMOVED.name());
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.CACHE_NAME)).isEqualTo("cqDistributedMap2");
|
||||
|
||||
assertThat(((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).key).isEqualTo(Integer.valueOf(2));
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getId()).isEqualTo(2);
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getName()).isEqualTo("TestName2");
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getSurname()).isEqualTo("TestSurname2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContinuousQueryForALLEntryEvent() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForDistributedMapEntryEvents(cqDistributedMap3,
|
||||
cqMapChannel3, "cqDistributedMap3");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContinuousQueryForOnlyUPDATEDEntryEvent() {
|
||||
cqDistributedMap4
|
||||
.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
cqDistributedMap4
|
||||
.put(1, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
Message<?> msg =
|
||||
cqMapChannel4.receive(HazelcastInboundChannelAdapterTestUtils.TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getPayload() instanceof EntryEventMessagePayload).isTrue();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE)).isEqualTo(EntryEventType.UPDATED.name());
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.CACHE_NAME)).isEqualTo("cqDistributedMap4");
|
||||
|
||||
assertThat(((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).key).isEqualTo(Integer.valueOf(1));
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getId()).isEqualTo(1);
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getName()).isEqualTo("TestName1");
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getSurname()).isEqualTo("TestSurname1");
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getId()).isEqualTo(2);
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getName()).isEqualTo("TestName2");
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getSurname()).isEqualTo("TestSurname2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContinuousQueryForOnlyUPDATEDEntryEventWhenIncludeValueIsFalse() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testContinuousQueryForUPDATEDEntryEventWhenIncludeValueIsFalse(
|
||||
cqDistributedMap5, cqMapChannel5, "cqDistributedMap5");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
<?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
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
https://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
https://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<int:channel id="cmChannel1">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="cmChannel2">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="cmChannel3">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="cmChannel4">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="cmChannel5">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="cmChannel6">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int-hazelcast:cm-inbound-channel-adapter
|
||||
channel="cmChannel1"
|
||||
hazelcast-instance="hazelcastInstance"
|
||||
monitor-types="MEMBERSHIP" />
|
||||
|
||||
<int-hazelcast:cm-inbound-channel-adapter
|
||||
channel="cmChannel2"
|
||||
hazelcast-instance="hazelcastInstance"
|
||||
monitor-types="DISTRIBUTED_OBJECT" />
|
||||
|
||||
<int-hazelcast:cm-inbound-channel-adapter
|
||||
channel="cmChannel3"
|
||||
hazelcast-instance="hazelcastInstance"
|
||||
monitor-types="MIGRATION" />
|
||||
|
||||
<int-hazelcast:cm-inbound-channel-adapter
|
||||
channel="cmChannel4"
|
||||
hazelcast-instance="hazelcastInstance2"
|
||||
monitor-types="LIFECYCLE" />
|
||||
|
||||
<int-hazelcast:cm-inbound-channel-adapter
|
||||
channel="cmChannel5"
|
||||
hazelcast-instance="hazelcastInstance"
|
||||
monitor-types="CLIENT" />
|
||||
|
||||
<int-hazelcast:cm-inbound-channel-adapter
|
||||
channel="cmChannel6"
|
||||
hazelcast-instance="hazelcastInstance"
|
||||
monitor-types="MEMBERSHIP,DISTRIBUTED_OBJECT" />
|
||||
|
||||
<bean id="hazelcastInstance" class="com.hazelcast.core.Hazelcast" factory-method="newHazelcastInstance"
|
||||
destroy-method="shutdown">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config">
|
||||
<property name="groupConfig">
|
||||
<bean class="com.hazelcast.config.GroupConfig">
|
||||
<property name="name" value="Test_Group_Name1"/>
|
||||
<property name="password" value="dev-pass"/>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="networkConfig">
|
||||
<bean class="com.hazelcast.config.NetworkConfig">
|
||||
<property name="port" value="5701"/>
|
||||
<property name="portAutoIncrement" value="false"/>
|
||||
<property name="join">
|
||||
<bean class="com.hazelcast.config.JoinConfig">
|
||||
<property name="multicastConfig">
|
||||
<bean class="com.hazelcast.config.MulticastConfig">
|
||||
<property name="enabled" value="false" />
|
||||
</bean>
|
||||
</property>
|
||||
<property name="tcpIpConfig">
|
||||
<bean class="com.hazelcast.config.TcpIpConfig">
|
||||
<property name="members" value="127.0.0.1:5701,127.0.0.1:5703" />
|
||||
<property name="enabled" value="true" />
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="hazelcastInstance2" class="com.hazelcast.core.Hazelcast" factory-method="newHazelcastInstance"
|
||||
destroy-method="shutdown">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config">
|
||||
<property name="groupConfig">
|
||||
<bean class="com.hazelcast.config.GroupConfig">
|
||||
<property name="name" value="Test_Group_Name2"/>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="networkConfig">
|
||||
<bean class="com.hazelcast.config.NetworkConfig">
|
||||
<property name="port" value="5702"/>
|
||||
<property name="portAutoIncrement" value="false"/>
|
||||
<property name="join">
|
||||
<bean class="com.hazelcast.config.JoinConfig">
|
||||
<property name="multicastConfig">
|
||||
<bean class="com.hazelcast.config.MulticastConfig">
|
||||
<property name="enabled" value="false" />
|
||||
</bean>
|
||||
</property>
|
||||
<property name="tcpIpConfig">
|
||||
<bean class="com.hazelcast.config.TcpIpConfig">
|
||||
<property name="members" value="127.0.0.1:5702" />
|
||||
<property name="enabled" value="true" />
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="hazelcastInstance3" class="com.hazelcast.core.Hazelcast" factory-method="newHazelcastInstance"
|
||||
destroy-method="shutdown">
|
||||
<constructor-arg>
|
||||
<bean class="com.hazelcast.config.Config">
|
||||
<property name="groupConfig">
|
||||
<bean class="com.hazelcast.config.GroupConfig">
|
||||
<property name="name" value="Test_Group_Name1"/>
|
||||
<property name="password" value="dev-pass"/>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="networkConfig">
|
||||
<bean class="com.hazelcast.config.NetworkConfig">
|
||||
<property name="port" value="5703"/>
|
||||
<property name="portAutoIncrement" value="false"/>
|
||||
<property name="join">
|
||||
<bean class="com.hazelcast.config.JoinConfig">
|
||||
<property name="multicastConfig">
|
||||
<bean class="com.hazelcast.config.MulticastConfig">
|
||||
<property name="enabled" value="false" />
|
||||
</bean>
|
||||
</property>
|
||||
<property name="tcpIpConfig">
|
||||
<bean class="com.hazelcast.config.TcpIpConfig">
|
||||
<property name="members" value="127.0.0.1:5701,127.0.0.1:5703" />
|
||||
<property name="enabled" value="true" />
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</beans>
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.inbound.util.HazelcastInboundChannelAdapterTestUtils;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.core.LifecycleEvent;
|
||||
import com.hazelcast.core.LifecycleEvent.LifecycleState;
|
||||
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
|
||||
|
||||
/**
|
||||
* Hazelcast Cluster Monitor Inbound Channel Adapter Unit Test Class
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringJUnitConfig
|
||||
@DirtiesContext
|
||||
@Ignore("Hard to reach CP consensus with limited number of members in two clusters")
|
||||
public class HazelcastClusterMonitorInboundChannelAdapterTests {
|
||||
|
||||
private static final String TEST_GROUP_NAME1 = "Test_Group_Name1";
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cmChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cmChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cmChannel3;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cmChannel4;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cmChannel5;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cmChannel6;
|
||||
|
||||
@Autowired
|
||||
private HazelcastInstance hazelcastInstance;
|
||||
|
||||
@Autowired
|
||||
private HazelcastInstance hazelcastInstance2;
|
||||
|
||||
@Autowired
|
||||
private HazelcastInstance hazelcastInstance3;
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() {
|
||||
HazelcastInstanceFactory.terminateAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDistributedObjectEvent() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testDistributedObjectEventByChannelAndHazelcastInstance(cmChannel2,
|
||||
hazelcastInstance, "Test_Distributed_Map4");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycleEvent() {
|
||||
hazelcastInstance2.getLifecycleService().terminate();
|
||||
|
||||
Message<?> msg =
|
||||
cmChannel4.receive(HazelcastInboundChannelAdapterTestUtils.TIMEOUT);
|
||||
verifyLifecycleEvent(msg, LifecycleState.SHUTTING_DOWN);
|
||||
|
||||
msg = cmChannel4.receive(HazelcastInboundChannelAdapterTestUtils.TIMEOUT);
|
||||
verifyLifecycleEvent(msg, LifecycleState.SHUTDOWN);
|
||||
}
|
||||
|
||||
private void verifyLifecycleEvent(final Message<?> msg,
|
||||
final LifecycleState lifecycleState) {
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getPayload() instanceof LifecycleEvent).isTrue();
|
||||
assertThat(((LifecycleEvent) msg.getPayload()).getState()).isEqualTo(lifecycleState);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
https://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
https://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<import resource="classpath:org/springframework/integration/hazelcast/common-config.xml"/>
|
||||
|
||||
<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"/>
|
||||
|
||||
<int-hazelcast:inbound-channel-adapter channel="edListChannel3" cache="edDistributedList3"
|
||||
cache-events="ADDED,REMOVED"/>
|
||||
|
||||
<bean id="edDistributedList1" factory-bean="instance" factory-method="getList">
|
||||
<constructor-arg value="edDistributedList1"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedList2" factory-bean="instance" factory-method="getList">
|
||||
<constructor-arg value="edDistributedList2"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedList3" factory-bean="instance" factory-method="getList">
|
||||
<constructor-arg value="edDistributedList3"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.HazelcastHeaders;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.integration.hazelcast.inbound.util.HazelcastInboundChannelAdapterTestUtils;
|
||||
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.SpringRunner;
|
||||
|
||||
import com.hazelcast.collection.IList;
|
||||
import com.hazelcast.core.EntryEventType;
|
||||
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
|
||||
|
||||
/**
|
||||
* Hazelcast Distributed List Event Driven Inbound Channel Adapter Test Class
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public class HazelcastDistributedListEventDrivenInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edListChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edListChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edListChannel3;
|
||||
|
||||
@Autowired
|
||||
private IList edDistributedList1;
|
||||
|
||||
@Autowired
|
||||
private IList edDistributedList2;
|
||||
|
||||
@Autowired
|
||||
private IList edDistributedList3;
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() {
|
||||
HazelcastInstanceFactory.terminateAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyADDEDEntryEvent() {
|
||||
edDistributedList1.add(new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg = edListChannel1.receive(HazelcastInboundChannelAdapterTestUtils.TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE).toString()).isEqualTo(EntryEventType.ADDED.toString());
|
||||
assertThat(((HazelcastIntegrationTestUser) msg.getPayload()).getId()).isEqualTo(1);
|
||||
assertThat(((HazelcastIntegrationTestUser) msg.getPayload()).getName()).isEqualTo("TestName1");
|
||||
assertThat(((HazelcastIntegrationTestUser) msg.getPayload()).getSurname()).isEqualTo("TestSurname1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyREMOVEDEntryEvent() {
|
||||
HazelcastIntegrationTestUser user = new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2");
|
||||
edDistributedList2.add(user);
|
||||
edDistributedList2.remove(user);
|
||||
Message<?> msg = edListChannel2.receive(HazelcastInboundChannelAdapterTestUtils.TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE).toString()).isEqualTo(EntryEventType.REMOVED.toString());
|
||||
assertThat(((HazelcastIntegrationTestUser) msg.getPayload()).getId()).isEqualTo(2);
|
||||
assertThat(((HazelcastIntegrationTestUser) msg.getPayload()).getName()).isEqualTo("TestName2");
|
||||
assertThat(((HazelcastIntegrationTestUser) msg.getPayload()).getSurname()).isEqualTo("TestSurname2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForALLEntryEvent() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForDistributedCollectionItemEvents(edDistributedList3, edListChannel3);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?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
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
https://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
https://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<import resource="classpath:org/springframework/integration/hazelcast/common-config.xml"/>
|
||||
|
||||
<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"/>
|
||||
|
||||
<int-hazelcast:inbound-channel-adapter channel="edMapChannel4" cache="edDistributedMap4"
|
||||
cache-events="ADDED,REMOVED,UPDATED,CLEAR_ALL"/>
|
||||
|
||||
<bean id="edDistributedMap1" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="edDistributedMap1"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedMap2" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="edDistributedMap2"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedMap3" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="edDistributedMap3"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedMap4" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="edDistributedMap4"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.HazelcastHeaders;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.integration.hazelcast.inbound.util.HazelcastInboundChannelAdapterTestUtils;
|
||||
import org.springframework.integration.hazelcast.message.EntryEventMessagePayload;
|
||||
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.SpringRunner;
|
||||
|
||||
import com.hazelcast.core.EntryEventType;
|
||||
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
|
||||
import com.hazelcast.map.IMap;
|
||||
|
||||
/**
|
||||
* Hazelcast Distributed Map Event Driven Inbound Channel Adapter Test
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public class HazelcastDistributedMapEventDrivenInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edMapChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edMapChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edMapChannel3;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edMapChannel4;
|
||||
|
||||
@Autowired
|
||||
private IMap edDistributedMap1;
|
||||
|
||||
@Autowired
|
||||
private IMap edDistributedMap2;
|
||||
|
||||
@Autowired
|
||||
private IMap edDistributedMap3;
|
||||
|
||||
@Autowired
|
||||
private IMap edDistributedMap4;
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() {
|
||||
HazelcastInstanceFactory.terminateAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyADDEDEntryEvent() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForADDEDDistributedMapEntryEvent(edDistributedMap1,
|
||||
edMapChannel1, "edDistributedMap1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyUPDATEDEntryEvent() {
|
||||
edDistributedMap2
|
||||
.put(2, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
edDistributedMap2
|
||||
.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
Message<?> msg =
|
||||
edMapChannel2.receive(HazelcastInboundChannelAdapterTestUtils.TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getPayload() instanceof EntryEventMessagePayload).isTrue();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE)).isEqualTo(EntryEventType.UPDATED.name());
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.CACHE_NAME)).isEqualTo("edDistributedMap2");
|
||||
|
||||
assertThat(((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).key).isEqualTo(Integer.valueOf(2));
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getId()).isEqualTo(1);
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getName()).isEqualTo("TestName1");
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getSurname()).isEqualTo("TestSurname1");
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getId()).isEqualTo(2);
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getName()).isEqualTo("TestName2");
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getSurname()).isEqualTo("TestSurname2");
|
||||
}
|
||||
|
||||
@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(HazelcastInboundChannelAdapterTestUtils.TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getPayload() instanceof EntryEventMessagePayload).isTrue();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE)).isEqualTo(EntryEventType.REMOVED.name());
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.CACHE_NAME)).isEqualTo("edDistributedMap3");
|
||||
|
||||
assertThat(((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).key).isEqualTo(Integer.valueOf(2));
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getId()).isEqualTo(2);
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getName()).isEqualTo("TestName2");
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getSurname()).isEqualTo("TestSurname2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForALLEntryEvent() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForDistributedMapEntryEvents(edDistributedMap4, edMapChannel4,
|
||||
"edDistributedMap4");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?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
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
https://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
https://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<import resource="classpath:org/springframework/integration/hazelcast/common-config.xml"/>
|
||||
|
||||
<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"/>
|
||||
|
||||
<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="instance" factory-method="getQueue">
|
||||
<constructor-arg value="edDistributedQueue1"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedQueue2" factory-bean="instance" factory-method="getQueue">
|
||||
<constructor-arg value="edDistributedQueue2"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedQueue3" factory-bean="instance" factory-method="getQueue">
|
||||
<constructor-arg value="edDistributedQueue3"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.HazelcastHeaders;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.integration.hazelcast.inbound.util.HazelcastInboundChannelAdapterTestUtils;
|
||||
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.SpringRunner;
|
||||
|
||||
import com.hazelcast.collection.IQueue;
|
||||
import com.hazelcast.core.EntryEventType;
|
||||
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
|
||||
|
||||
/**
|
||||
* Hazelcast Distributed Queue Event Driven Inbound Channel Adapter Test
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public class HazelcastDistributedQueueEventDrivenInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edQueueChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edQueueChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edQueueChannel3;
|
||||
|
||||
@Autowired
|
||||
private IQueue edDistributedQueue1;
|
||||
|
||||
@Autowired
|
||||
private IQueue edDistributedQueue2;
|
||||
|
||||
@Autowired
|
||||
private IQueue edDistributedQueue3;
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() {
|
||||
HazelcastInstanceFactory.terminateAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyADDEDEntryEvent() {
|
||||
edDistributedQueue1
|
||||
.add(new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg =
|
||||
edQueueChannel1.receive(HazelcastInboundChannelAdapterTestUtils.TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE).toString()).isEqualTo(EntryEventType.ADDED.toString());
|
||||
assertThat((((HazelcastIntegrationTestUser) msg.getPayload()).getId())).isEqualTo(1);
|
||||
assertThat((((HazelcastIntegrationTestUser) msg.getPayload()).getName())).isEqualTo("TestName1");
|
||||
assertThat((((HazelcastIntegrationTestUser) msg.getPayload()).getSurname())).isEqualTo("TestSurname1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyREMOVEDEntryEvent() {
|
||||
HazelcastIntegrationTestUser user =
|
||||
new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2");
|
||||
edDistributedQueue2.add(user);
|
||||
edDistributedQueue2.remove(user);
|
||||
Message<?> msg =
|
||||
edQueueChannel2.receive(HazelcastInboundChannelAdapterTestUtils.TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE).toString()).isEqualTo(EntryEventType.REMOVED.toString());
|
||||
assertThat((((HazelcastIntegrationTestUser) msg.getPayload()).getId())).isEqualTo(2);
|
||||
assertThat((((HazelcastIntegrationTestUser) msg.getPayload()).getName())).isEqualTo("TestName2");
|
||||
assertThat((((HazelcastIntegrationTestUser) msg.getPayload()).getSurname())).isEqualTo("TestSurname2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForALLEntryEvent() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForDistributedCollectionItemEvents(edDistributedQueue3,
|
||||
edQueueChannel3);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?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
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
https://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
https://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<import resource="classpath:org/springframework/integration/hazelcast/common-config.xml"/>
|
||||
|
||||
<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="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"
|
||||
distributed-sql="age > 20 AND age <= 30">
|
||||
<int:poller fixed-delay="100"/>
|
||||
</int-hazelcast:ds-inbound-channel-adapter>
|
||||
|
||||
<bean id="dsDistributedMap1" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="dsDistributedMap1"/>
|
||||
</bean>
|
||||
|
||||
<bean id="dsDistributedMap2" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="dsDistributedMap2"/>
|
||||
</bean>
|
||||
|
||||
<bean id="dsDistributedMap3" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="dsDistributedMap3"/>
|
||||
</bean>
|
||||
|
||||
<bean id="dsDistributedMap4" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="dsDistributedMap4"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.inbound.util.HazelcastInboundChannelAdapterTestUtils;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
|
||||
import com.hazelcast.map.IMap;
|
||||
|
||||
/**
|
||||
* Hazelcast Distributed SQL Inbound Channel Adapter Test
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public class HazelcastDistributedSQLInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel dsMapChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel dsMapChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel dsMapChannel3;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel dsMapChannel4;
|
||||
|
||||
@Autowired
|
||||
private IMap dsDistributedMap1;
|
||||
|
||||
@Autowired
|
||||
private IMap dsDistributedMap2;
|
||||
|
||||
@Autowired
|
||||
private IMap dsDistributedMap3;
|
||||
|
||||
@Autowired
|
||||
private IMap dsDistributedMap4;
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() {
|
||||
HazelcastInstanceFactory.terminateAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDistributedSQLForOnlyENTRYIterationType() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testDistributedSQLForENTRYIterationType(dsDistributedMap1, dsMapChannel1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDistributedSQLForOnlyKEYIterationType() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testDistributedSQLForKEYIterationType(dsDistributedMap2, dsMapChannel2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDistributedSQLForOnlyLOCAL_KEYIterationType() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testDistributedSQLForLOCAL_KEYIterationType(dsDistributedMap3, dsMapChannel3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDistributedSQLForOnlyVALUEIterationType() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testDistributedSQLForVALUEIterationType(dsDistributedMap4, dsMapChannel4);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?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
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
https://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
https://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<import resource="classpath:org/springframework/integration/hazelcast/common-config.xml"/>
|
||||
|
||||
<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"/>
|
||||
|
||||
<bean id="edDistributedSet1" factory-bean="instance" factory-method="getSet">
|
||||
<constructor-arg value="edDistributedSet1"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedSet2" factory-bean="instance" factory-method="getSet">
|
||||
<constructor-arg value="edDistributedSet2"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edDistributedSet3" factory-bean="instance" factory-method="getSet">
|
||||
<constructor-arg value="edDistributedSet3"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.HazelcastHeaders;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.integration.hazelcast.inbound.util.HazelcastInboundChannelAdapterTestUtils;
|
||||
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.SpringRunner;
|
||||
|
||||
import com.hazelcast.collection.ISet;
|
||||
import com.hazelcast.core.EntryEventType;
|
||||
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
|
||||
|
||||
/**
|
||||
* Hazelcast Distributed Set Event Driven Inbound Channel Adapter Test
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public class HazelcastDistributedSetEventDrivenInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edSetChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edSetChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edSetChannel3;
|
||||
|
||||
@Autowired
|
||||
private ISet edDistributedSet1;
|
||||
|
||||
@Autowired
|
||||
private ISet edDistributedSet2;
|
||||
|
||||
@Autowired
|
||||
private ISet edDistributedSet3;
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() {
|
||||
HazelcastInstanceFactory.terminateAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyADDEDEntryEvent() {
|
||||
edDistributedSet1
|
||||
.add(new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg =
|
||||
edSetChannel1.receive(HazelcastInboundChannelAdapterTestUtils.TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE).toString()).isEqualTo(EntryEventType.ADDED.toString());
|
||||
assertThat((((HazelcastIntegrationTestUser) msg.getPayload()).getId())).isEqualTo(1);
|
||||
assertThat((((HazelcastIntegrationTestUser) msg.getPayload()).getName())).isEqualTo("TestName1");
|
||||
assertThat((((HazelcastIntegrationTestUser) msg.getPayload()).getSurname())).isEqualTo("TestSurname1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyREMOVEDEntryEvent() {
|
||||
HazelcastIntegrationTestUser user =
|
||||
new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2");
|
||||
edDistributedSet2.add(user);
|
||||
edDistributedSet2.remove(user);
|
||||
Message<?> msg =
|
||||
edSetChannel2.receive(HazelcastInboundChannelAdapterTestUtils.TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE).toString()).isEqualTo(EntryEventType.REMOVED.toString());
|
||||
assertThat((((HazelcastIntegrationTestUser) msg.getPayload()).getId())).isEqualTo(2);
|
||||
assertThat((((HazelcastIntegrationTestUser) msg.getPayload()).getName())).isEqualTo("TestName2");
|
||||
assertThat((((HazelcastIntegrationTestUser) msg.getPayload()).getSurname())).isEqualTo("TestSurname2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForALLEntryEvent() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForDistributedCollectionItemEvents(edDistributedSet3,
|
||||
edSetChannel3);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?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
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
https://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
https://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<import resource="classpath:org/springframework/integration/hazelcast/common-config.xml"/>
|
||||
|
||||
<int:channel id="edTopicChannel1">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int-hazelcast:inbound-channel-adapter channel="edTopicChannel1" cache="edDistributedTopic1"/>
|
||||
|
||||
<bean id="edDistributedTopic1" factory-bean="instance" factory-method="getTopic">
|
||||
<constructor-arg value="edDistributedTopic1"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.inbound.util.HazelcastInboundChannelAdapterTestUtils;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
|
||||
import com.hazelcast.topic.ITopic;
|
||||
|
||||
/**
|
||||
* Hazelcast Distributed Topic Event Driven Inbound Channel Adapter Test
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public class HazelcastDistributedTopicEventDrivenInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edTopicChannel1;
|
||||
|
||||
@Autowired
|
||||
private ITopic edDistributedTopic1;
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() {
|
||||
HazelcastInstanceFactory.terminateAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyADDEDEntryEvent() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForTopicMessageEvent(edDistributedTopic1, edTopicChannel1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?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
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
https://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
https://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<import resource="classpath:org/springframework/integration/hazelcast/common-config.xml"/>
|
||||
|
||||
<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"/>
|
||||
<int-hazelcast:inbound-channel-adapter channel="edMultiMapChannel3" cache="edMultiMap3"
|
||||
cache-events="ADDED,REMOVED,CLEAR_ALL"/>
|
||||
|
||||
<bean id="edMultiMap1" factory-bean="instance" factory-method="getMultiMap">
|
||||
<constructor-arg value="edMultiMap1"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edMultiMap2" factory-bean="instance" factory-method="getMultiMap">
|
||||
<constructor-arg value="edMultiMap2"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edMultiMap3" factory-bean="instance" factory-method="getMultiMap">
|
||||
<constructor-arg value="edMultiMap3"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.HazelcastHeaders;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.integration.hazelcast.inbound.util.HazelcastInboundChannelAdapterTestUtils;
|
||||
import org.springframework.integration.hazelcast.message.EntryEventMessagePayload;
|
||||
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.SpringRunner;
|
||||
|
||||
import com.hazelcast.core.EntryEventType;
|
||||
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
|
||||
import com.hazelcast.multimap.MultiMap;
|
||||
|
||||
/**
|
||||
* Hazelcast MultiMap Event Driven Inbound Channel Adapter Test
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
* @since 6.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public class HazelcastMultiMapEventDrivenInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edMultiMapChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edMultiMapChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edMultiMapChannel3;
|
||||
|
||||
@Autowired
|
||||
private MultiMap edMultiMap1;
|
||||
|
||||
@Autowired
|
||||
private MultiMap edMultiMap2;
|
||||
|
||||
@Autowired
|
||||
private MultiMap edMultiMap3;
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() {
|
||||
HazelcastInstanceFactory.terminateAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyADDEDEntryEvent() {
|
||||
edMultiMap1
|
||||
.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg =
|
||||
edMultiMapChannel1.receive(HazelcastInboundChannelAdapterTestUtils.TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getPayload() instanceof EntryEventMessagePayload).isTrue();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE)).isEqualTo(EntryEventType.ADDED.name());
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.CACHE_NAME)).isEqualTo("edMultiMap1");
|
||||
|
||||
assertThat(((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).key).isEqualTo(Integer.valueOf(1));
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getId()).isEqualTo(1);
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getName()).isEqualTo("TestName1");
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getSurname()).isEqualTo("TestSurname1");
|
||||
}
|
||||
|
||||
@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(HazelcastInboundChannelAdapterTestUtils.TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getPayload() instanceof EntryEventMessagePayload).isTrue();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE)).isEqualTo(EntryEventType.REMOVED.name());
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.CACHE_NAME)).isEqualTo("edMultiMap2");
|
||||
|
||||
assertThat(((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).key).isEqualTo(Integer.valueOf(2));
|
||||
assertThat(((EntryEventMessagePayload<?, ?>) msg.getPayload()).value).isNull();
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getId()).isEqualTo(2);
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getName()).isEqualTo("TestName2");
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getSurname()).isEqualTo("TestSurname2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForALLEntryEvent() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForMultiMapEntryEvents(edMultiMap3, edMultiMapChannel3,
|
||||
"edMultiMap3");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?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
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
https://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
https://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<import resource="classpath:org/springframework/integration/hazelcast/common-config.xml"/>
|
||||
|
||||
<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="instance" factory-method="getReplicatedMap">
|
||||
<constructor-arg value="edReplicatedMap1"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edReplicatedMap2" factory-bean="instance" factory-method="getReplicatedMap">
|
||||
<constructor-arg value="edReplicatedMap2"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edReplicatedMap3" factory-bean="instance" factory-method="getReplicatedMap">
|
||||
<constructor-arg value="edReplicatedMap3"/>
|
||||
</bean>
|
||||
|
||||
<bean id="edReplicatedMap4" factory-bean="instance" factory-method="getReplicatedMap">
|
||||
<constructor-arg value="edReplicatedMap4"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.HazelcastHeaders;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.integration.hazelcast.inbound.util.HazelcastInboundChannelAdapterTestUtils;
|
||||
import org.springframework.integration.hazelcast.message.EntryEventMessagePayload;
|
||||
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.SpringRunner;
|
||||
|
||||
import com.hazelcast.core.EntryEventType;
|
||||
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
|
||||
import com.hazelcast.replicatedmap.ReplicatedMap;
|
||||
|
||||
/**
|
||||
* Hazelcast Replicated Map Event Driven Inbound Channel Adapter Test
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public class HazelcastReplicatedMapEventDrivenInboundChannelAdapterTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edReplicatedMapChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edReplicatedMapChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edReplicatedMapChannel3;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel edReplicatedMapChannel4;
|
||||
|
||||
@Autowired
|
||||
private ReplicatedMap edReplicatedMap1;
|
||||
|
||||
@Autowired
|
||||
private ReplicatedMap edReplicatedMap2;
|
||||
|
||||
@Autowired
|
||||
private ReplicatedMap edReplicatedMap3;
|
||||
|
||||
@Autowired
|
||||
private ReplicatedMap edReplicatedMap4;
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() {
|
||||
HazelcastInstanceFactory.terminateAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyADDEDEntryEvent() {
|
||||
edReplicatedMap1
|
||||
.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg = edReplicatedMapChannel1
|
||||
.receive(HazelcastInboundChannelAdapterTestUtils.TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getPayload() instanceof EntryEventMessagePayload).isTrue();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE)).isEqualTo(EntryEventType.ADDED.name());
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.CACHE_NAME)).isEqualTo("edReplicatedMap1");
|
||||
|
||||
assertThat(((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).key).isEqualTo(Integer.valueOf(1));
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getId()).isEqualTo(1);
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getName()).isEqualTo("TestName1");
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getSurname()).isEqualTo("TestSurname1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForOnlyUPDATEDEntryEvent() {
|
||||
edReplicatedMap2
|
||||
.put(2, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
edReplicatedMap2
|
||||
.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
Message<?> msg = edReplicatedMapChannel2
|
||||
.receive(HazelcastInboundChannelAdapterTestUtils.TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
|
||||
assertThat(msg.getPayload() instanceof EntryEventMessagePayload).isTrue();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE)).isEqualTo(EntryEventType.UPDATED.name());
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.CACHE_NAME)).isEqualTo("edReplicatedMap2");
|
||||
|
||||
assertThat(((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).key).isEqualTo(Integer.valueOf(2));
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getId()).isEqualTo(1);
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getName()).isEqualTo("TestName1");
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getSurname()).isEqualTo("TestSurname1");
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getId()).isEqualTo(2);
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getName()).isEqualTo("TestName2");
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getSurname()).isEqualTo("TestSurname2");
|
||||
}
|
||||
|
||||
@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(HazelcastInboundChannelAdapterTestUtils.TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getPayload() instanceof EntryEventMessagePayload).isTrue();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE)).isEqualTo(EntryEventType.REMOVED.name());
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.CACHE_NAME)).isEqualTo("edReplicatedMap3");
|
||||
|
||||
assertThat(((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).key).isEqualTo(Integer.valueOf(2));
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getId()).isEqualTo(2);
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getName()).isEqualTo("TestName2");
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).getSurname()).isEqualTo("TestSurname2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForALLEntryEvent() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForReplicatedMapEntryEvents(edReplicatedMap4,
|
||||
edReplicatedMapChannel4, "edReplicatedMap4");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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.config;
|
||||
|
||||
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.integration.hazelcast.inbound.util.HazelcastInboundChannelAdapterTestUtils;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.context.support.AnnotationConfigContextLoader;
|
||||
|
||||
import com.hazelcast.map.IMap;
|
||||
|
||||
/**
|
||||
* Hazelcast Continuous Query Inbound Channel Adapter JavaConfig driven Unit Test Class
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration(classes = HazelcastIntegrationInboundTestConfiguration.class,
|
||||
loader = AnnotationConfigContextLoader.class)
|
||||
@DirtiesContext
|
||||
public class HazelcastCQDistributedMapInboundChannelAdapterConfigTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cqDistributedMapChannel1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cqDistributedMapChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cqDistributedMapChannel3;
|
||||
|
||||
@Autowired
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> testCQDistributedMap1;
|
||||
|
||||
@Autowired
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> testCQDistributedMap2;
|
||||
|
||||
@Autowired
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> testCQDistributedMap3;
|
||||
|
||||
@Test
|
||||
public void testContinuousQueryForADDEDEntryEvent() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForADDEDDistributedMapEntryEvent(testCQDistributedMap1,
|
||||
cqDistributedMapChannel1, "Test_CQ_Distributed_Map1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContinuousQueryForALLEntryEvent() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForDistributedMapEntryEvents(testCQDistributedMap2,
|
||||
cqDistributedMapChannel2, "Test_CQ_Distributed_Map2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContinuousQueryForUPDATEDEntryEventWhenIncludeValueIsFalse() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testContinuousQueryForUPDATEDEntryEventWhenIncludeValueIsFalse(
|
||||
testCQDistributedMap3, cqDistributedMapChannel3,
|
||||
"Test_CQ_Distributed_Map3");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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.config;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.hazelcast.inbound.util.HazelcastInboundChannelAdapterTestUtils;
|
||||
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.HazelcastInstance;
|
||||
|
||||
/**
|
||||
* Hazelcast Cluster Monitor Inbound Channel Adapter JavaConfig driven Unit Test Class
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.0
|
||||
*/
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = HazelcastIntegrationInboundTestConfiguration.class)
|
||||
@DirtiesContext
|
||||
public class HazelcastClusterMonitorInboundChannelAdapterConfigTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cmonChannel;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel cmonChannel2;
|
||||
|
||||
@Autowired
|
||||
private HazelcastInstance testHazelcastInstance;
|
||||
|
||||
@Test
|
||||
public void testConfigDrivenDistributedObjectEvent() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testDistributedObjectEventByChannelAndHazelcastInstance(cmonChannel2,
|
||||
testHazelcastInstance, "Test_Distributed_Map3");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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.config;
|
||||
|
||||
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.integration.hazelcast.inbound.util.HazelcastInboundChannelAdapterTestUtils;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.context.support.AnnotationConfigContextLoader;
|
||||
|
||||
import com.hazelcast.map.IMap;
|
||||
|
||||
/**
|
||||
* Hazelcast Distributed SQL Inbound Channel Adapter JavaConfig driven Unit Test Class
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration(classes = HazelcastIntegrationInboundTestConfiguration.class,
|
||||
loader = AnnotationConfigContextLoader.class)
|
||||
@DirtiesContext
|
||||
public class HazelcastDistributedSQLInboundChannelAdapterConfigTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel dsDistributedMapChannel;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel dsDistributedMapChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel dsDistributedMapChannel3;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel dsDistributedMapChannel4;
|
||||
|
||||
@Autowired
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> testDSDistributedMap;
|
||||
|
||||
@Autowired
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> testDSDistributedMap2;
|
||||
|
||||
@Autowired
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> testDSDistributedMap3;
|
||||
|
||||
@Autowired
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> testDSDistributedMap4;
|
||||
|
||||
@Test
|
||||
public void testDistributedSQLForENTRYIterationType() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testDistributedSQLForENTRYIterationType(testDSDistributedMap,
|
||||
dsDistributedMapChannel);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDistributedSQLForKEYIterationType() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testDistributedSQLForKEYIterationType(testDSDistributedMap2,
|
||||
dsDistributedMapChannel2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDistributedSQLForLOCAL_KEYIterationType() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testDistributedSQLForLOCAL_KEYIterationType(testDSDistributedMap3,
|
||||
dsDistributedMapChannel3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDistributedSQLForVALUEIterationType() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testDistributedSQLForVALUEIterationType(testDSDistributedMap4,
|
||||
dsDistributedMapChannel4);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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.config;
|
||||
|
||||
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.integration.hazelcast.inbound.util.HazelcastInboundChannelAdapterTestUtils;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.context.support.AnnotationConfigContextLoader;
|
||||
|
||||
import com.hazelcast.collection.IList;
|
||||
import com.hazelcast.collection.IQueue;
|
||||
import com.hazelcast.collection.ISet;
|
||||
import com.hazelcast.map.IMap;
|
||||
import com.hazelcast.multimap.MultiMap;
|
||||
import com.hazelcast.replicatedmap.ReplicatedMap;
|
||||
import com.hazelcast.topic.ITopic;
|
||||
|
||||
/**
|
||||
* Hazelcast Event Driven Inbound Channel Adapter JavaConfig driven Unit Test Class
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration(classes = HazelcastIntegrationInboundTestConfiguration.class,
|
||||
loader = AnnotationConfigContextLoader.class)
|
||||
@DirtiesContext
|
||||
public class HazelcastEventDrivenInboundChannelAdapterConfigTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel distributedMapChannel;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel distributedMapChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel distributedListChannel;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel distributedSetChannel;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel distributedQueueChannel;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel topicChannel;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel replicatedMapChannel;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel multiMapChannel;
|
||||
|
||||
@Autowired
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> testDistributedMap;
|
||||
|
||||
@Autowired
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> testDistributedMap2;
|
||||
|
||||
@Autowired
|
||||
private IList<HazelcastIntegrationTestUser> testDistributedList;
|
||||
|
||||
@Autowired
|
||||
private ISet<HazelcastIntegrationTestUser> testDistributedSet;
|
||||
|
||||
@Autowired
|
||||
private IQueue<HazelcastIntegrationTestUser> testDistributedQueue;
|
||||
|
||||
@Autowired
|
||||
private ITopic<HazelcastIntegrationTestUser> testTopic;
|
||||
|
||||
@Autowired
|
||||
private ReplicatedMap<Integer, HazelcastIntegrationTestUser> testReplicatedMap;
|
||||
|
||||
@Autowired
|
||||
private MultiMap<Integer, HazelcastIntegrationTestUser> testMultiMap;
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForADDEDEntryEvent() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForADDEDDistributedMapEntryEvent(testDistributedMap,
|
||||
distributedMapChannel, "Test_Distributed_Map");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForEntryEvents() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForDistributedMapEntryEvents(testDistributedMap2,
|
||||
distributedMapChannel2, "Test_Distributed_Map2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForDistributedListItemEvents() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForDistributedCollectionItemEvents(testDistributedList,
|
||||
distributedListChannel);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForDistributedSetItemEvents() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForDistributedCollectionItemEvents(testDistributedSet,
|
||||
distributedSetChannel);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForDistributedQueueItemEvents() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForDistributedCollectionItemEvents(testDistributedQueue,
|
||||
distributedQueueChannel);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForADDEDMessageEvent() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForTopicMessageEvent(testTopic, topicChannel);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForReplicatedMapEntryEvents() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForReplicatedMapEntryEvents(testReplicatedMap,
|
||||
replicatedMapChannel, "Test_Replicated_Map");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDrivenForMultiMapEntryEvents() {
|
||||
HazelcastInboundChannelAdapterTestUtils
|
||||
.testEventDrivenForMultiMapEntryEvents(testMultiMap, multiMapChannel,
|
||||
"Test_Multi_Map");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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.config;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.annotation.InboundChannelAdapter;
|
||||
import org.springframework.integration.annotation.Poller;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.config.EnableIntegration;
|
||||
import org.springframework.integration.hazelcast.DistributedSQLIterationType;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.integration.hazelcast.HazelcastLocalInstanceRegistrar;
|
||||
import org.springframework.integration.hazelcast.inbound.HazelcastClusterMonitorMessageProducer;
|
||||
import org.springframework.integration.hazelcast.inbound.HazelcastContinuousQueryMessageProducer;
|
||||
import org.springframework.integration.hazelcast.inbound.HazelcastDistributedSQLMessageSource;
|
||||
import org.springframework.integration.hazelcast.inbound.HazelcastEventDrivenMessageProducer;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
|
||||
import com.hazelcast.collection.IList;
|
||||
import com.hazelcast.collection.IQueue;
|
||||
import com.hazelcast.collection.ISet;
|
||||
import com.hazelcast.config.Config;
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
|
||||
import com.hazelcast.map.IMap;
|
||||
import com.hazelcast.multimap.MultiMap;
|
||||
import com.hazelcast.replicatedmap.ReplicatedMap;
|
||||
import com.hazelcast.topic.ITopic;
|
||||
|
||||
/**
|
||||
* Configuration Class for Hazelcast Integration Inbound Test
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
@Configuration
|
||||
@EnableIntegration
|
||||
public class HazelcastIntegrationInboundTestConfiguration {
|
||||
|
||||
@AfterClass
|
||||
public void shutdown() {
|
||||
HazelcastInstanceFactory.terminateAll();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel distributedMapChannel() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel distributedMapChannel2() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel distributedListChannel() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel distributedSetChannel() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel distributedQueueChannel() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel topicChannel() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel multiMapChannel() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel replicatedMapChannel() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel cqDistributedMapChannel1() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel cqDistributedMapChannel2() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel cqDistributedMapChannel3() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel dsDistributedMapChannel() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel dsDistributedMapChannel2() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel dsDistributedMapChannel3() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel dsDistributedMapChannel4() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel cmonChannel() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel cmonChannel2() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IMap<Integer, HazelcastIntegrationTestUser> testDistributedMap() {
|
||||
return testHazelcastInstance().getMap("Test_Distributed_Map");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IMap<Integer, HazelcastIntegrationTestUser> testDistributedMap2() {
|
||||
return testHazelcastInstance().getMap("Test_Distributed_Map2");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IList<HazelcastIntegrationTestUser> testDistributedList() {
|
||||
return testHazelcastInstance().getList("Test_Distributed_List");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ISet<HazelcastIntegrationTestUser> testDistributedSet() {
|
||||
return testHazelcastInstance().getSet("Test_Distributed_Set");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IQueue<HazelcastIntegrationTestUser> testDistributedQueue() {
|
||||
return testHazelcastInstance().getQueue("Test_Distributed_Queue");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ITopic<HazelcastIntegrationTestUser> testTopic() {
|
||||
return testHazelcastInstance().getTopic("Test_Topic");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MultiMap<Integer, HazelcastIntegrationTestUser> testMultiMap() {
|
||||
return testHazelcastInstance().getMultiMap("Test_Multi_Map");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ReplicatedMap<Integer, HazelcastIntegrationTestUser> testReplicatedMap() {
|
||||
return testHazelcastInstance().getReplicatedMap("Test_Replicated_Map");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IMap<Integer, HazelcastIntegrationTestUser> testCQDistributedMap1() {
|
||||
return testHazelcastInstance().getMap("Test_CQ_Distributed_Map1");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IMap<Integer, HazelcastIntegrationTestUser> testCQDistributedMap2() {
|
||||
return testHazelcastInstance().getMap("Test_CQ_Distributed_Map2");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IMap<Integer, HazelcastIntegrationTestUser> testCQDistributedMap3() {
|
||||
return testHazelcastInstance().getMap("Test_CQ_Distributed_Map3");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IMap<Integer, HazelcastIntegrationTestUser> testDSDistributedMap() {
|
||||
return testHazelcastInstance().getMap("Test_DS_Distributed_Map");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IMap<Integer, HazelcastIntegrationTestUser> testDSDistributedMap2() {
|
||||
return testHazelcastInstance().getMap("Test_DS_Distributed_Map2");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IMap<Integer, HazelcastIntegrationTestUser> testDSDistributedMap3() {
|
||||
return testHazelcastInstance().getMap("Test_DS_Distributed_Map3");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IMap<Integer, HazelcastIntegrationTestUser> testDSDistributedMap4() {
|
||||
return testHazelcastInstance().getMap("Test_DS_Distributed_Map4");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Config hazelcastConfig() {
|
||||
Config config = new Config();
|
||||
config.getCPSubsystemConfig().setCPMemberCount(0)
|
||||
.setSessionHeartbeatIntervalSeconds(1);
|
||||
return config;
|
||||
}
|
||||
|
||||
@Bean(destroyMethod = "")
|
||||
public HazelcastInstance testHazelcastInstance() {
|
||||
return Hazelcast.newHazelcastInstance(hazelcastConfig());
|
||||
}
|
||||
|
||||
@Bean(HazelcastLocalInstanceRegistrar.BEAN_NAME)
|
||||
public HazelcastLocalInstanceRegistrar hazelcastLocalInstanceRegistrar() {
|
||||
return new HazelcastLocalInstanceRegistrar(testHazelcastInstance());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastEventDrivenMessageProducer hazelcastEventDrivenMessageProducer() {
|
||||
final HazelcastEventDrivenMessageProducer producer =
|
||||
new HazelcastEventDrivenMessageProducer(testDistributedMap());
|
||||
producer.setOutputChannel(distributedMapChannel());
|
||||
return producer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastEventDrivenMessageProducer hazelcastEventDrivenMessageProducer2() {
|
||||
final HazelcastEventDrivenMessageProducer producer =
|
||||
new HazelcastEventDrivenMessageProducer(testDistributedMap2());
|
||||
producer.setOutputChannel(distributedMapChannel2());
|
||||
producer.setCacheEventTypes("ADDED,REMOVED,UPDATED,CLEAR_ALL");
|
||||
return producer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastEventDrivenMessageProducer hazelcastEventDrivenMessageProducer3() {
|
||||
final HazelcastEventDrivenMessageProducer producer =
|
||||
new HazelcastEventDrivenMessageProducer(testDistributedList());
|
||||
producer.setOutputChannel(distributedListChannel());
|
||||
producer.setCacheEventTypes("ADDED,REMOVED");
|
||||
return producer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastEventDrivenMessageProducer hazelcastEventDrivenMessageProducer4() {
|
||||
final HazelcastEventDrivenMessageProducer producer =
|
||||
new HazelcastEventDrivenMessageProducer(testDistributedSet());
|
||||
producer.setOutputChannel(distributedSetChannel());
|
||||
producer.setCacheEventTypes("ADDED,REMOVED");
|
||||
return producer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastEventDrivenMessageProducer hazelcastEventDrivenMessageProducer5() {
|
||||
final HazelcastEventDrivenMessageProducer producer =
|
||||
new HazelcastEventDrivenMessageProducer(testDistributedQueue());
|
||||
producer.setOutputChannel(distributedQueueChannel());
|
||||
producer.setCacheEventTypes("ADDED,REMOVED");
|
||||
return producer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastEventDrivenMessageProducer hazelcastEventDrivenMessageProducer6() {
|
||||
final HazelcastEventDrivenMessageProducer producer =
|
||||
new HazelcastEventDrivenMessageProducer(testTopic());
|
||||
producer.setOutputChannel(topicChannel());
|
||||
return producer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastEventDrivenMessageProducer hazelcastEventDrivenMessageProducer7() {
|
||||
final HazelcastEventDrivenMessageProducer producer =
|
||||
new HazelcastEventDrivenMessageProducer(testReplicatedMap());
|
||||
producer.setOutputChannel(replicatedMapChannel());
|
||||
producer.setCacheEventTypes("ADDED,REMOVED,UPDATED");
|
||||
return producer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastEventDrivenMessageProducer hazelcastEventDrivenMessageProducer8() {
|
||||
final HazelcastEventDrivenMessageProducer producer =
|
||||
new HazelcastEventDrivenMessageProducer(testMultiMap());
|
||||
producer.setOutputChannel(multiMapChannel());
|
||||
producer.setCacheEventTypes("ADDED,REMOVED,CLEAR_ALL");
|
||||
return producer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastContinuousQueryMessageProducer hazelcastContinuousQueryMessageProducer() {
|
||||
final HazelcastContinuousQueryMessageProducer producer =
|
||||
new HazelcastContinuousQueryMessageProducer(testCQDistributedMap1(),
|
||||
"name=TestName1");
|
||||
producer.setOutputChannel(cqDistributedMapChannel1());
|
||||
return producer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastContinuousQueryMessageProducer hazelcastContinuousQueryMessageProducer2() {
|
||||
final HazelcastContinuousQueryMessageProducer producer =
|
||||
new HazelcastContinuousQueryMessageProducer(testCQDistributedMap2(),
|
||||
"name=TestName1 OR name=TestName2");
|
||||
producer.setOutputChannel(cqDistributedMapChannel2());
|
||||
producer.setCacheEventTypes("ADDED,REMOVED,UPDATED,CLEAR_ALL");
|
||||
return producer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastContinuousQueryMessageProducer hazelcastContinuousQueryMessageProducer3() {
|
||||
final HazelcastContinuousQueryMessageProducer producer =
|
||||
new HazelcastContinuousQueryMessageProducer(testCQDistributedMap3(),
|
||||
"surname=TestSurname2");
|
||||
producer.setOutputChannel(cqDistributedMapChannel3());
|
||||
producer.setCacheEventTypes("UPDATED");
|
||||
producer.setIncludeValue(false);
|
||||
return producer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastClusterMonitorMessageProducer hazelcastClusterMonitorMessageProducer() {
|
||||
final HazelcastClusterMonitorMessageProducer producer =
|
||||
new HazelcastClusterMonitorMessageProducer(testHazelcastInstance());
|
||||
producer.setOutputChannel(cmonChannel());
|
||||
return producer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastClusterMonitorMessageProducer hazelcastClusterMonitorMessageProducer2() {
|
||||
final HazelcastClusterMonitorMessageProducer producer =
|
||||
new HazelcastClusterMonitorMessageProducer(testHazelcastInstance());
|
||||
producer.setOutputChannel(cmonChannel2());
|
||||
producer.setMonitorEventTypes("DISTRIBUTED_OBJECT");
|
||||
return producer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@InboundChannelAdapter(value = "dsDistributedMapChannel",
|
||||
poller = @Poller(maxMessagesPerPoll = "1"))
|
||||
public HazelcastDistributedSQLMessageSource hazelcastDistributedSQLMessageSource() {
|
||||
final HazelcastDistributedSQLMessageSource messageSource =
|
||||
new HazelcastDistributedSQLMessageSource(testDSDistributedMap(),
|
||||
"name='TestName4' AND surname='TestSurname4'");
|
||||
messageSource.setIterationType(DistributedSQLIterationType.ENTRY);
|
||||
return messageSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@InboundChannelAdapter(value = "dsDistributedMapChannel2",
|
||||
poller = @Poller(maxMessagesPerPoll = "1"))
|
||||
public HazelcastDistributedSQLMessageSource hazelcastDistributedSQLMessageSource2() {
|
||||
final HazelcastDistributedSQLMessageSource messageSource =
|
||||
new HazelcastDistributedSQLMessageSource(testDSDistributedMap2(),
|
||||
"name='TestName1' AND surname='TestSurname1'");
|
||||
messageSource.setIterationType(DistributedSQLIterationType.KEY);
|
||||
return messageSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@InboundChannelAdapter(value = "dsDistributedMapChannel3",
|
||||
poller = @Poller(maxMessagesPerPoll = "1"))
|
||||
public HazelcastDistributedSQLMessageSource hazelcastDistributedSQLMessageSource3() {
|
||||
final HazelcastDistributedSQLMessageSource messageSource =
|
||||
new HazelcastDistributedSQLMessageSource(testDSDistributedMap3(),
|
||||
"age > 5");
|
||||
messageSource.setIterationType(DistributedSQLIterationType.KEY);
|
||||
return messageSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@InboundChannelAdapter(value = "dsDistributedMapChannel4",
|
||||
poller = @Poller(maxMessagesPerPoll = "1"))
|
||||
public HazelcastDistributedSQLMessageSource hazelcastDistributedSQLMessageSource4() {
|
||||
final HazelcastDistributedSQLMessageSource messageSource =
|
||||
new HazelcastDistributedSQLMessageSource(testDSDistributedMap4(),
|
||||
"name='TestName3' AND surname='TestSurname3'");
|
||||
messageSource.setIterationType(DistributedSQLIterationType.VALUE);
|
||||
return messageSource;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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.util;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.integration.hazelcast.HazelcastHeaders;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.integration.hazelcast.message.EntryEventMessagePayload;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
|
||||
import com.hazelcast.cluster.MembershipEvent;
|
||||
import com.hazelcast.collection.ICollection;
|
||||
import com.hazelcast.core.DistributedObjectEvent;
|
||||
import com.hazelcast.core.EntryEventType;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.map.IMap;
|
||||
import com.hazelcast.multimap.MultiMap;
|
||||
import com.hazelcast.replicatedmap.ReplicatedMap;
|
||||
import com.hazelcast.spi.exception.DistributedObjectDestroyedException;
|
||||
import com.hazelcast.topic.ITopic;
|
||||
|
||||
/**
|
||||
* Util Class for Hazelcast Inbound Channel Adapters Test Support.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.0
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public final class HazelcastInboundChannelAdapterTestUtils {
|
||||
|
||||
public static final int TIMEOUT = 30_000;
|
||||
|
||||
public static void verifyEntryEvent(Message<?> msg, String cacheName,
|
||||
EntryEventType event) {
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
if (event == EntryEventType.CLEAR_ALL || event == EntryEventType.EVICT_ALL) {
|
||||
assertThat(msg.getPayload() instanceof Integer).isTrue();
|
||||
}
|
||||
else {
|
||||
assertThat(msg.getPayload() instanceof EntryEventMessagePayload).isTrue();
|
||||
}
|
||||
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.CACHE_NAME)).isEqualTo(cacheName);
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE)).isEqualTo(event.name());
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
}
|
||||
|
||||
public static void verifyItemEvent(Message<?> msg, EntryEventType event) {
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE).toString()).isEqualTo(event.toString());
|
||||
}
|
||||
|
||||
public static void testEventDrivenForADDEDDistributedMapEntryEvent(
|
||||
final IMap<Integer, HazelcastIntegrationTestUser> distributedMap,
|
||||
final PollableChannel channel, final String cacheName) {
|
||||
HazelcastIntegrationTestUser hazelcastIntegrationTestUser =
|
||||
new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1");
|
||||
distributedMap.put(1, hazelcastIntegrationTestUser);
|
||||
Message<?> msg = channel.receive(TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getPayload() instanceof EntryEventMessagePayload).isTrue();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE)).isEqualTo(EntryEventType.ADDED.name());
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.CACHE_NAME)).isEqualTo(cacheName);
|
||||
|
||||
assertThat(((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).key).isEqualTo(Integer.valueOf(1));
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getId()).isEqualTo(1);
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getName()).isEqualTo("TestName1");
|
||||
assertThat((((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).getSurname()).isEqualTo("TestSurname1");
|
||||
}
|
||||
|
||||
public static void testEventDrivenForDistributedMapEntryEvents(
|
||||
final IMap<Integer, HazelcastIntegrationTestUser> distributedMap,
|
||||
final PollableChannel channel, final String cacheName) {
|
||||
distributedMap
|
||||
.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg = channel.receive(TIMEOUT);
|
||||
verifyEntryEvent(msg, cacheName, EntryEventType.ADDED);
|
||||
|
||||
distributedMap.put(1,
|
||||
new HazelcastIntegrationTestUser(1, "TestName1", "TestSurnameUpdated"));
|
||||
msg = channel.receive(TIMEOUT);
|
||||
verifyEntryEvent(msg, cacheName, EntryEventType.UPDATED);
|
||||
|
||||
distributedMap.remove(1);
|
||||
msg = channel.receive(TIMEOUT);
|
||||
verifyEntryEvent(msg, cacheName, EntryEventType.REMOVED);
|
||||
|
||||
distributedMap
|
||||
.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
msg = channel.receive(TIMEOUT);
|
||||
verifyEntryEvent(msg, cacheName, EntryEventType.ADDED);
|
||||
|
||||
distributedMap.clear();
|
||||
msg = channel.receive(TIMEOUT);
|
||||
verifyEntryEvent(msg, cacheName, EntryEventType.CLEAR_ALL);
|
||||
}
|
||||
|
||||
public static void testEventDrivenForDistributedCollectionItemEvents(
|
||||
final ICollection<HazelcastIntegrationTestUser> distributedObject,
|
||||
final PollableChannel channel) {
|
||||
HazelcastIntegrationTestUser user =
|
||||
new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1");
|
||||
distributedObject.add(user);
|
||||
Message<?> msg = channel.receive(TIMEOUT);
|
||||
verifyItemEvent(msg, EntryEventType.ADDED);
|
||||
|
||||
distributedObject.remove(user);
|
||||
msg = channel.receive(TIMEOUT);
|
||||
verifyItemEvent(msg, EntryEventType.REMOVED);
|
||||
|
||||
user = new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2");
|
||||
distributedObject.add(user);
|
||||
msg = channel.receive(TIMEOUT);
|
||||
verifyItemEvent(msg, EntryEventType.ADDED);
|
||||
}
|
||||
|
||||
public static void testEventDrivenForReplicatedMapEntryEvents(
|
||||
final ReplicatedMap<Integer, HazelcastIntegrationTestUser> replicatedMap,
|
||||
final PollableChannel channel, final String cacheName) {
|
||||
replicatedMap
|
||||
.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg = channel.receive(TIMEOUT);
|
||||
verifyEntryEvent(msg, cacheName, EntryEventType.ADDED);
|
||||
|
||||
replicatedMap.put(1,
|
||||
new HazelcastIntegrationTestUser(1, "TestName1", "TestSurnameUpdated"));
|
||||
msg = channel.receive(TIMEOUT);
|
||||
verifyEntryEvent(msg, cacheName, EntryEventType.UPDATED);
|
||||
|
||||
replicatedMap.remove(1);
|
||||
msg = channel.receive(TIMEOUT);
|
||||
verifyEntryEvent(msg, cacheName, EntryEventType.REMOVED);
|
||||
|
||||
replicatedMap
|
||||
.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
msg = channel.receive(TIMEOUT);
|
||||
verifyEntryEvent(msg, cacheName, EntryEventType.ADDED);
|
||||
}
|
||||
|
||||
public static void testEventDrivenForTopicMessageEvent(
|
||||
final ITopic<HazelcastIntegrationTestUser> topic, final PollableChannel channel) {
|
||||
topic.publish(new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg = channel.receive(TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.PUBLISHING_TIME)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.CACHE_NAME)).isEqualTo(topic.getName());
|
||||
assertThat(((HazelcastIntegrationTestUser) msg.getPayload()).getId()).isEqualTo(1);
|
||||
assertThat(((HazelcastIntegrationTestUser) msg.getPayload()).getName()).isEqualTo("TestName1");
|
||||
assertThat(((HazelcastIntegrationTestUser) msg.getPayload()).getSurname()).isEqualTo("TestSurname1");
|
||||
}
|
||||
|
||||
public static void testEventDrivenForMultiMapEntryEvents(
|
||||
final MultiMap<Integer, HazelcastIntegrationTestUser> multiMap,
|
||||
final PollableChannel channel, final String cacheName) {
|
||||
multiMap.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
Message<?> msg = channel.receive(TIMEOUT);
|
||||
verifyEntryEvent(msg, cacheName, EntryEventType.ADDED);
|
||||
|
||||
multiMap.put(1,
|
||||
new HazelcastIntegrationTestUser(1, "TestName1", "TestSurnameUpdated"));
|
||||
msg = channel.receive(TIMEOUT);
|
||||
verifyEntryEvent(msg, cacheName, EntryEventType.ADDED);
|
||||
|
||||
multiMap.remove(1);
|
||||
msg = channel.receive(TIMEOUT);
|
||||
verifyEntryEvent(msg, cacheName, EntryEventType.REMOVED);
|
||||
msg = channel.receive(TIMEOUT);
|
||||
verifyEntryEvent(msg, cacheName, EntryEventType.REMOVED);
|
||||
|
||||
multiMap.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
msg = channel.receive(TIMEOUT);
|
||||
verifyEntryEvent(msg, cacheName, EntryEventType.ADDED);
|
||||
|
||||
multiMap.clear();
|
||||
msg = channel.receive(TIMEOUT);
|
||||
verifyEntryEvent(msg, cacheName, EntryEventType.CLEAR_ALL);
|
||||
}
|
||||
|
||||
public static void testContinuousQueryForUPDATEDEntryEventWhenIncludeValueIsFalse(
|
||||
final IMap<Integer, HazelcastIntegrationTestUser> cqDistributedMap,
|
||||
final PollableChannel channel, final String cacheName) {
|
||||
cqDistributedMap
|
||||
.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1"));
|
||||
cqDistributedMap
|
||||
.put(1, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2"));
|
||||
Message<?> msg = channel.receive(TIMEOUT);
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getPayload() instanceof EntryEventMessagePayload).isTrue();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.MEMBER)).isNotNull();
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.EVENT_TYPE)).isEqualTo(EntryEventType.UPDATED.name());
|
||||
assertThat(msg.getHeaders().get(HazelcastHeaders.CACHE_NAME)).isEqualTo(cacheName);
|
||||
|
||||
assertThat(((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).key).isEqualTo(Integer.valueOf(1));
|
||||
assertThat(((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).oldValue).isNull();
|
||||
assertThat(((EntryEventMessagePayload<Integer, HazelcastIntegrationTestUser>) msg
|
||||
.getPayload()).value).isNull();
|
||||
}
|
||||
|
||||
public static void testDistributedSQLForENTRYIterationType(
|
||||
final IMap<Integer, HazelcastIntegrationTestUser> dsDistributedMap,
|
||||
final PollableChannel channel) {
|
||||
dsDistributedMap
|
||||
.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1", 10));
|
||||
dsDistributedMap
|
||||
.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2", 20));
|
||||
dsDistributedMap
|
||||
.put(3, new HazelcastIntegrationTestUser(3, "TestName3", "TestSurname3", 30));
|
||||
dsDistributedMap
|
||||
.put(4, new HazelcastIntegrationTestUser(4, "TestName4", "TestSurname4", 40));
|
||||
dsDistributedMap
|
||||
.put(5, new HazelcastIntegrationTestUser(5, "TestName5", "TestSurname5", 50));
|
||||
|
||||
Message<?> msg = channel.receive(TIMEOUT);
|
||||
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getPayload() instanceof Collection).isTrue();
|
||||
assertThat((((Map.Entry<?, ?>) ((Collection<?>) msg.getPayload()).iterator().next())
|
||||
.getKey())).isEqualTo(4);
|
||||
assertThat(((HazelcastIntegrationTestUser) ((Map.Entry<?, ?>) ((Collection<?>) msg
|
||||
.getPayload()).iterator().next()).getValue()).getId()).isEqualTo(4);
|
||||
assertThat(((HazelcastIntegrationTestUser) ((Map.Entry<?, ?>) ((Collection<?>) msg
|
||||
.getPayload()).iterator().next()).getValue()).getName()).isEqualTo("TestName4");
|
||||
assertThat(((HazelcastIntegrationTestUser) ((Map.Entry<?, ?>) ((Collection<?>) msg
|
||||
.getPayload()).iterator().next()).getValue()).getSurname()).isEqualTo("TestSurname4");
|
||||
}
|
||||
|
||||
public static void testDistributedSQLForKEYIterationType(
|
||||
final IMap<Integer, HazelcastIntegrationTestUser> dsDistributedMap,
|
||||
final PollableChannel channel) {
|
||||
dsDistributedMap
|
||||
.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1", 10));
|
||||
dsDistributedMap
|
||||
.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2", 20));
|
||||
dsDistributedMap
|
||||
.put(3, new HazelcastIntegrationTestUser(3, "TestName3", "TestSurname3", 30));
|
||||
|
||||
Message<?> msg = channel.receive(TIMEOUT);
|
||||
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getPayload() instanceof Collection).isTrue();
|
||||
assertThat(((Collection<?>) msg.getPayload()).iterator().next()).isEqualTo(1);
|
||||
}
|
||||
|
||||
public static void testDistributedSQLForLOCAL_KEYIterationType(
|
||||
final IMap<Integer, HazelcastIntegrationTestUser> dsDistributedMap,
|
||||
final PollableChannel channel) {
|
||||
dsDistributedMap
|
||||
.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1", 10));
|
||||
dsDistributedMap
|
||||
.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2", 20));
|
||||
dsDistributedMap
|
||||
.put(3, new HazelcastIntegrationTestUser(3, "TestName3", "TestSurname3", 30));
|
||||
|
||||
Message<?> msg = channel.receive(TIMEOUT);
|
||||
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getPayload() instanceof Collection).isTrue();
|
||||
}
|
||||
|
||||
public static void testDistributedSQLForVALUEIterationType(
|
||||
final IMap<Integer, HazelcastIntegrationTestUser> dsDistributedMap,
|
||||
final PollableChannel channel) {
|
||||
dsDistributedMap
|
||||
.put(1, new HazelcastIntegrationTestUser(1, "TestName1", "TestSurname1", 10));
|
||||
dsDistributedMap
|
||||
.put(2, new HazelcastIntegrationTestUser(2, "TestName2", "TestSurname2", 20));
|
||||
dsDistributedMap
|
||||
.put(3, new HazelcastIntegrationTestUser(3, "TestName3", "TestSurname3", 30));
|
||||
dsDistributedMap
|
||||
.put(4, new HazelcastIntegrationTestUser(4, "TestName4", "TestSurname4", 40));
|
||||
dsDistributedMap
|
||||
.put(5, new HazelcastIntegrationTestUser(5, "TestName5", "TestSurname5", 50));
|
||||
|
||||
Message<?> msg = channel.receive(TIMEOUT);
|
||||
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getPayload() instanceof Collection).isTrue();
|
||||
assertThat(((HazelcastIntegrationTestUser) (((Collection<?>) msg.getPayload()).iterator()
|
||||
.next())).getId()).isEqualTo(3);
|
||||
assertThat(((HazelcastIntegrationTestUser) (((Collection<?>) msg.getPayload()).iterator()
|
||||
.next())).getName()).isEqualTo("TestName3");
|
||||
assertThat(((HazelcastIntegrationTestUser) (((Collection<?>) msg.getPayload()).iterator()
|
||||
.next())).getSurname()).isEqualTo("TestSurname3");
|
||||
}
|
||||
|
||||
public static void testDistributedObjectEventByChannelAndHazelcastInstance(
|
||||
final PollableChannel channel, final HazelcastInstance hazelcastInstance,
|
||||
final String distributedObjectName) {
|
||||
final IMap<Integer, String> distributedMap =
|
||||
hazelcastInstance.getMap(distributedObjectName);
|
||||
|
||||
Message<?> msg = channel.receive(TIMEOUT);
|
||||
verifyDistributedObjectEvent(msg, DistributedObjectEvent.EventType.CREATED,
|
||||
distributedObjectName);
|
||||
|
||||
distributedMap.destroy();
|
||||
|
||||
msg = channel.receive(TIMEOUT);
|
||||
try {
|
||||
// Since Hazelcast 3.6 we can use DistributedObjectEvent.getDistributedObject() for DESTROYED objects.
|
||||
verifyDistributedObjectEvent(msg, DistributedObjectEvent.EventType.DESTROYED, distributedObjectName);
|
||||
fail("DistributedObjectDestroyedException expected");
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertThat(e).isInstanceOf(DistributedObjectDestroyedException.class);
|
||||
}
|
||||
}
|
||||
|
||||
private static void verifyMembershipEvent(final Message<?> msg,
|
||||
final int membershipEvent) {
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getPayload() instanceof MembershipEvent).isTrue();
|
||||
assertThat(((MembershipEvent) msg.getPayload()).getEventType()).isEqualTo(membershipEvent);
|
||||
assertThat(((MembershipEvent) msg.getPayload()).getMember()).isNotNull();
|
||||
}
|
||||
|
||||
private static void verifyDistributedObjectEvent(final Message<?> msg,
|
||||
final DistributedObjectEvent.EventType eventType,
|
||||
final String distributedObjectName) {
|
||||
assertThat(msg).isNotNull();
|
||||
assertThat(msg.getPayload()).isNotNull();
|
||||
assertThat(msg.getPayload() instanceof DistributedObjectEvent).isTrue();
|
||||
assertThat(((DistributedObjectEvent) msg.getPayload()).getEventType()).isEqualTo(eventType);
|
||||
assertThat(distributedObjectName).as((((DistributedObjectEvent) msg.getPayload()).getDistributedObject())
|
||||
.getName()).isNotNull();
|
||||
}
|
||||
|
||||
private HazelcastInboundChannelAdapterTestUtils() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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.leader;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.willAnswer;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.leader.Context;
|
||||
import org.springframework.integration.leader.DefaultCandidate;
|
||||
import org.springframework.integration.leader.event.AbstractLeaderEvent;
|
||||
import org.springframework.integration.leader.event.DefaultLeaderEventPublisher;
|
||||
import org.springframework.integration.leader.event.LeaderEventPublisher;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.hazelcast.config.Config;
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
|
||||
|
||||
/**
|
||||
* Tests for hazelcast leader election.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
* @author Patrick Peralta
|
||||
* @author Dave Syer
|
||||
* @author Artem Bilan
|
||||
* @author Mael Le Guével
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
public class LeaderInitiatorTests {
|
||||
|
||||
@Autowired
|
||||
private HazelcastInstance hazelcastInstance;
|
||||
|
||||
@Autowired
|
||||
private TestCandidate candidate;
|
||||
|
||||
@Autowired
|
||||
private TestEventListener listener;
|
||||
|
||||
@Autowired
|
||||
private LeaderInitiator initiator;
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() {
|
||||
HazelcastInstanceFactory.terminateAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeaderElections() throws Exception {
|
||||
assertThat(this.candidate.onGrantedLatch.await(5, TimeUnit.SECONDS)).isTrue();
|
||||
assertThat(this.listener.onEventLatch.await(5, TimeUnit.SECONDS)).isTrue();
|
||||
assertThat(this.listener.events.size()).isEqualTo(1);
|
||||
|
||||
this.initiator.destroy();
|
||||
|
||||
CountDownLatch granted = new CountDownLatch(1);
|
||||
CountingPublisher countingPublisher = new CountingPublisher(granted);
|
||||
List<LeaderInitiator> initiators = new ArrayList<>();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
LeaderInitiator initiator = new LeaderInitiator(this.hazelcastInstance, new DefaultCandidate());
|
||||
initiator.setLeaderEventPublisher(countingPublisher);
|
||||
initiators.add(initiator);
|
||||
}
|
||||
|
||||
for (LeaderInitiator initiator : initiators) {
|
||||
initiator.start();
|
||||
}
|
||||
|
||||
assertThat(granted.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
|
||||
LeaderInitiator initiator1 = countingPublisher.initiator;
|
||||
|
||||
LeaderInitiator initiator2 = null;
|
||||
|
||||
for (LeaderInitiator initiator : initiators) {
|
||||
if (initiator != initiator1) {
|
||||
initiator2 = initiator;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assertThat(initiator2).isNotNull();
|
||||
|
||||
assertThat(initiator1.getContext().isLeader()).isTrue();
|
||||
assertThat(initiator2.getContext().isLeader()).isFalse();
|
||||
|
||||
final CountDownLatch granted1 = new CountDownLatch(1);
|
||||
final CountDownLatch granted2 = new CountDownLatch(1);
|
||||
CountDownLatch revoked1 = new CountDownLatch(1);
|
||||
CountDownLatch revoked2 = new CountDownLatch(1);
|
||||
initiator1.setLeaderEventPublisher(new CountingPublisher(granted1, revoked1) {
|
||||
|
||||
@Override
|
||||
public void publishOnRevoked(Object source, Context context, String role) {
|
||||
try {
|
||||
// It's difficult to see round-robin election, so block one initiator until the second is elected.
|
||||
assertThat(granted2.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
// No op
|
||||
}
|
||||
super.publishOnRevoked(source, context, role);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
initiator2.setLeaderEventPublisher(new CountingPublisher(granted2, revoked2) {
|
||||
|
||||
@Override
|
||||
public void publishOnRevoked(Object source, Context context, String role) {
|
||||
try {
|
||||
// It's difficult to see round-robin election, so block one initiator until the second is elected.
|
||||
assertThat(granted1.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
// No op
|
||||
}
|
||||
super.publishOnRevoked(source, context, role);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
initiator1.getContext().yield();
|
||||
|
||||
assertThat(revoked1.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
|
||||
assertThat(initiator2.getContext().isLeader()).isTrue();
|
||||
assertThat(initiator1.getContext().isLeader()).isFalse();
|
||||
|
||||
initiator2.getContext().yield();
|
||||
|
||||
assertThat(revoked2.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
|
||||
assertThat(initiator1.getContext().isLeader()).isTrue();
|
||||
assertThat(initiator2.getContext().isLeader()).isFalse();
|
||||
|
||||
initiator2.destroy();
|
||||
|
||||
CountDownLatch revoked11 = new CountDownLatch(1);
|
||||
initiator1.setLeaderEventPublisher(new CountingPublisher(new CountDownLatch(1), revoked11));
|
||||
|
||||
initiator1.getContext().yield();
|
||||
|
||||
assertThat(revoked11.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
|
||||
initiator1.destroy();
|
||||
|
||||
|
||||
CountDownLatch onGranted = new CountDownLatch(1);
|
||||
|
||||
DefaultCandidate candidate = spy(new DefaultCandidate());
|
||||
willAnswer(invocation -> {
|
||||
try {
|
||||
return invocation.callRealMethod();
|
||||
}
|
||||
finally {
|
||||
onGranted.countDown();
|
||||
}
|
||||
})
|
||||
.given(candidate).onGranted(any(Context.class));
|
||||
|
||||
LeaderInitiator initiator = new LeaderInitiator(this.hazelcastInstance, candidate);
|
||||
|
||||
initiator.setLeaderEventPublisher(new DefaultLeaderEventPublisher() {
|
||||
|
||||
@Override
|
||||
public void publishOnGranted(Object source, Context context, String role) {
|
||||
throw new RuntimeException("intentional");
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
initiator.start();
|
||||
|
||||
assertThat(onGranted.await(5, TimeUnit.SECONDS)).isTrue();
|
||||
|
||||
assertThat(initiator.getContext().isLeader()).isTrue();
|
||||
|
||||
initiator.destroy();
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
public static class TestConfig {
|
||||
|
||||
@Bean
|
||||
public TestCandidate candidate() {
|
||||
return new TestCandidate();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Config hazelcastConfig() {
|
||||
Config config = new Config();
|
||||
config.getCPSubsystemConfig()
|
||||
.setSessionHeartbeatIntervalSeconds(1);
|
||||
return config;
|
||||
}
|
||||
|
||||
@Bean(destroyMethod = "")
|
||||
public HazelcastInstance hazelcastInstance() {
|
||||
return Hazelcast.newHazelcastInstance(hazelcastConfig());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LeaderInitiator initiator() {
|
||||
return new LeaderInitiator(hazelcastInstance(), candidate());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestEventListener testEventListener() {
|
||||
return new TestEventListener();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestCandidate extends DefaultCandidate {
|
||||
|
||||
CountDownLatch onGrantedLatch = new CountDownLatch(1);
|
||||
|
||||
@Override
|
||||
public void onGranted(Context ctx) {
|
||||
this.onGrantedLatch.countDown();
|
||||
super.onGranted(ctx);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestEventListener implements ApplicationListener<AbstractLeaderEvent> {
|
||||
|
||||
CountDownLatch onEventLatch = new CountDownLatch(1);
|
||||
|
||||
ArrayList<AbstractLeaderEvent> events = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(AbstractLeaderEvent event) {
|
||||
this.events.add(event);
|
||||
this.onEventLatch.countDown();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class CountingPublisher implements LeaderEventPublisher {
|
||||
|
||||
private CountDownLatch granted;
|
||||
|
||||
private CountDownLatch revoked;
|
||||
|
||||
private volatile LeaderInitiator initiator;
|
||||
|
||||
CountingPublisher(CountDownLatch granted, CountDownLatch revoked) {
|
||||
this.granted = granted;
|
||||
this.revoked = revoked;
|
||||
}
|
||||
|
||||
CountingPublisher(CountDownLatch granted) {
|
||||
this(granted, new CountDownLatch(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishOnRevoked(Object source, Context context, String role) {
|
||||
this.revoked.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishOnFailedToAcquire(Object source, Context context, String role) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishOnGranted(Object source, Context context, String role) {
|
||||
this.initiator = (LeaderInitiator) source;
|
||||
this.granted.countDown();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* Copyright 2017-2020 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
|
||||
*
|
||||
* https://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.lock;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.hazelcast.config.Config;
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.cp.lock.FencedLock;
|
||||
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
|
||||
|
||||
/**
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public class HazelcastLockRegistryTests {
|
||||
|
||||
private static final Config CONFIG = new Config();
|
||||
|
||||
static {
|
||||
CONFIG.getCPSubsystemConfig().setCPMemberCount(0);
|
||||
}
|
||||
|
||||
private static final HazelcastInstance instance = Hazelcast.newHazelcastInstance(CONFIG);
|
||||
|
||||
@AfterClass
|
||||
public static void destroy() {
|
||||
HazelcastInstanceFactory.terminateAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLock() {
|
||||
HazelcastLockRegistry registry = new HazelcastLockRegistry(instance);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Lock lock = registry.obtain("foo");
|
||||
lock.lock();
|
||||
try {
|
||||
assertThat(((FencedLock) lock).isLocked()).isTrue();
|
||||
assertThat(((FencedLock) lock).isLockedByCurrentThread()).isTrue();
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockInterruptibly() throws Exception {
|
||||
HazelcastLockRegistry registry = new HazelcastLockRegistry(instance);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Lock lock = registry.obtain("foo");
|
||||
lock.lockInterruptibly();
|
||||
try {
|
||||
assertThat(((FencedLock) lock).isLocked()).isTrue();
|
||||
assertThat(((FencedLock) lock).isLockedByCurrentThread()).isTrue();
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReentrantLock() {
|
||||
HazelcastLockRegistry registry = new HazelcastLockRegistry(instance);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Lock lock1 = registry.obtain("foo");
|
||||
lock1.lock();
|
||||
try {
|
||||
Lock lock2 = registry.obtain("foo");
|
||||
assertThat(lock2).isSameAs(lock1);
|
||||
lock2.lock();
|
||||
lock2.unlock();
|
||||
}
|
||||
finally {
|
||||
lock1.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReentrantLockInterruptibly() throws Exception {
|
||||
HazelcastLockRegistry registry = new HazelcastLockRegistry(instance);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Lock lock1 = registry.obtain("foo");
|
||||
lock1.lockInterruptibly();
|
||||
try {
|
||||
Lock lock2 = registry.obtain("foo");
|
||||
assertThat(lock2).isSameAs(lock1);
|
||||
lock2.lockInterruptibly();
|
||||
lock2.unlock();
|
||||
}
|
||||
finally {
|
||||
lock1.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoLocks() throws Exception {
|
||||
HazelcastLockRegistry registry = new HazelcastLockRegistry(instance);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Lock lock1 = registry.obtain("foo");
|
||||
lock1.lockInterruptibly();
|
||||
try {
|
||||
Lock lock2 = registry.obtain("bar");
|
||||
assertThat(lock2).isNotSameAs(lock1);
|
||||
lock2.lockInterruptibly();
|
||||
lock2.unlock();
|
||||
}
|
||||
finally {
|
||||
lock1.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoThreadsSecondFailsToGetLock() throws Exception {
|
||||
HazelcastLockRegistry registry = new HazelcastLockRegistry(instance);
|
||||
Lock lock1 = registry.obtain("foo");
|
||||
lock1.lockInterruptibly();
|
||||
AtomicBoolean locked = new AtomicBoolean();
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
Future<Object> result = Executors.newSingleThreadExecutor().submit(() -> {
|
||||
Lock lock2 = registry.obtain("foo");
|
||||
locked.set(lock2.tryLock(200, TimeUnit.MILLISECONDS));
|
||||
latch.countDown();
|
||||
try {
|
||||
lock2.unlock();
|
||||
}
|
||||
catch (Exception e) {
|
||||
return e;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
assertThat(locked.get()).isFalse();
|
||||
lock1.unlock();
|
||||
Object ise = result.get(10, TimeUnit.SECONDS);
|
||||
assertThat(ise).isInstanceOf(IllegalMonitorStateException.class);
|
||||
assertThat(((Exception) ise).getMessage()).contains("Current thread is not owner of the lock!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoThreads() throws Exception {
|
||||
HazelcastLockRegistry registry = new HazelcastLockRegistry(instance);
|
||||
Lock lock1 = registry.obtain("foo");
|
||||
AtomicBoolean locked = new AtomicBoolean();
|
||||
CountDownLatch latch1 = new CountDownLatch(1);
|
||||
CountDownLatch latch2 = new CountDownLatch(1);
|
||||
CountDownLatch latch3 = new CountDownLatch(1);
|
||||
lock1.lockInterruptibly();
|
||||
Executors.newSingleThreadExecutor().execute(() -> {
|
||||
Lock lock2 = registry.obtain("foo");
|
||||
try {
|
||||
latch1.countDown();
|
||||
lock2.lockInterruptibly();
|
||||
latch2.await(10, TimeUnit.SECONDS);
|
||||
locked.set(true);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
finally {
|
||||
lock2.unlock();
|
||||
latch3.countDown();
|
||||
}
|
||||
});
|
||||
assertThat(latch1.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
assertThat(locked.get()).isFalse();
|
||||
lock1.unlock();
|
||||
latch2.countDown();
|
||||
assertThat(latch3.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
assertThat(locked.get()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoThreadsDifferentRegistries() throws Exception {
|
||||
HazelcastLockRegistry registry1 = new HazelcastLockRegistry(instance);
|
||||
HazelcastLockRegistry registry2 = new HazelcastLockRegistry(instance);
|
||||
Lock lock1 = registry1.obtain("foo");
|
||||
AtomicBoolean locked = new AtomicBoolean();
|
||||
CountDownLatch latch1 = new CountDownLatch(1);
|
||||
CountDownLatch latch2 = new CountDownLatch(1);
|
||||
CountDownLatch latch3 = new CountDownLatch(1);
|
||||
lock1.lockInterruptibly();
|
||||
Executors.newSingleThreadExecutor().execute(() -> {
|
||||
Lock lock2 = registry2.obtain("foo");
|
||||
try {
|
||||
latch1.countDown();
|
||||
lock2.lockInterruptibly();
|
||||
latch2.await(10, TimeUnit.SECONDS);
|
||||
locked.set(true);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
finally {
|
||||
lock2.unlock();
|
||||
latch3.countDown();
|
||||
}
|
||||
});
|
||||
assertThat(latch1.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
assertThat(locked.get()).isFalse();
|
||||
lock1.unlock();
|
||||
latch2.countDown();
|
||||
assertThat(latch3.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
assertThat(locked.get()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoThreadsWrongOneUnlocks() throws Exception {
|
||||
HazelcastLockRegistry registry = new HazelcastLockRegistry(instance);
|
||||
final Lock lock = registry.obtain("foo");
|
||||
lock.lockInterruptibly();
|
||||
final AtomicBoolean locked = new AtomicBoolean();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
Future<Object> result = Executors.newSingleThreadExecutor().submit(() -> {
|
||||
try {
|
||||
lock.unlock();
|
||||
}
|
||||
catch (Exception e) {
|
||||
latch.countDown();
|
||||
return e;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
assertThat(locked.get()).isFalse();
|
||||
lock.unlock();
|
||||
Object imse = result.get(10, TimeUnit.SECONDS);
|
||||
assertThat(imse).isInstanceOf(IllegalMonitorStateException.class);
|
||||
assertThat(((Exception) imse).getMessage()).contains("Current thread is not owner of the lock!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTryLock() throws Exception {
|
||||
HazelcastLockRegistry registry = new HazelcastLockRegistry(instance);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Lock lock = registry.obtain("foo");
|
||||
|
||||
int n = 0;
|
||||
while (!lock.tryLock() && n++ < 100) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
assertThat(n).isLessThan(100);
|
||||
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright 2017-2020 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
|
||||
*
|
||||
* https://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.metadata;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.integration.metadata.MetadataStoreListener;
|
||||
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.map.IMap;
|
||||
|
||||
/**
|
||||
* @author Vinicius Carvalho
|
||||
*/
|
||||
public class HazelcastMetadataStoreTests {
|
||||
|
||||
private static HazelcastInstance instance;
|
||||
|
||||
private static IMap<String, String> map;
|
||||
|
||||
HazelcastMetadataStore metadataStore;
|
||||
|
||||
@BeforeClass
|
||||
public static void init() {
|
||||
instance = Hazelcast.newHazelcastInstance();
|
||||
map = instance.getMap("customTestsMetadataStore");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void destroy() {
|
||||
instance.getLifecycleService().terminate();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
this.metadataStore = new HazelcastMetadataStore(map);
|
||||
this.metadataStore.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@After
|
||||
public void clean() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNonExistingKeyValue() {
|
||||
String retrievedValue = this.metadataStore.get("does-not-exist");
|
||||
assertThat(retrievedValue).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersistKeyValue() {
|
||||
this.metadataStore.put("HazelcastMetadataStoreTests-Spring", "Integration");
|
||||
assertThat(map.get("HazelcastMetadataStoreTests-Spring")).isEqualTo("Integration");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValueFromMetadataStore() {
|
||||
this.metadataStore.put("HazelcastMetadataStoreTests-GetValue", "Hello Hazelcast");
|
||||
String retrievedValue = this.metadataStore
|
||||
.get("HazelcastMetadataStoreTests-GetValue");
|
||||
assertThat(retrievedValue).isEqualTo("Hello Hazelcast");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersistEmptyStringToMetadataStore() {
|
||||
this.metadataStore.put("HazelcastMetadataStoreTests-PersistEmpty", "");
|
||||
|
||||
String retrievedValue = this.metadataStore
|
||||
.get("HazelcastMetadataStoreTests-PersistEmpty");
|
||||
assertThat(retrievedValue).isEqualTo("");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersistNullStringToMetadataStore() {
|
||||
try {
|
||||
this.metadataStore.put("HazelcastMetadataStoreTests-PersistEmpty", null);
|
||||
fail("Expected an IllegalArgumentException to be thrown.");
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage()).isEqualTo("'value' must not be null.");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersistWithEmptyKeyToMetadataStore() {
|
||||
this.metadataStore.put("", "PersistWithEmptyKey");
|
||||
|
||||
String retrievedValue = this.metadataStore.get("");
|
||||
assertThat(retrievedValue).isEqualTo("PersistWithEmptyKey");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersistWithNullKeyToMetadataStore() {
|
||||
try {
|
||||
this.metadataStore.put(null, "something");
|
||||
fail("Expected an IllegalArgumentException to be thrown.");
|
||||
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage()).isEqualTo("'key' must not be null.");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValueWithNullKeyFromMetadataStore() {
|
||||
try {
|
||||
this.metadataStore.get(null);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage()).isEqualTo("'key' must not be null.");
|
||||
return;
|
||||
}
|
||||
|
||||
fail("Expected an IllegalArgumentException to be thrown.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveFromMetadataStore() {
|
||||
String testKey = "HazelcastMetadataStoreTests-Remove";
|
||||
String testValue = "Integration";
|
||||
|
||||
this.metadataStore.put(testKey, testValue);
|
||||
|
||||
assertThat(this.metadataStore.remove(testKey)).isEqualTo(testValue);
|
||||
assertThat(this.metadataStore.remove(testKey)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersistKeyValueIfAbsent() {
|
||||
this.metadataStore.putIfAbsent("HazelcastMetadataStoreTests-Spring",
|
||||
"Integration");
|
||||
assertThat(map.get("HazelcastMetadataStoreTests-Spring")).isEqualTo("Integration");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceValue() {
|
||||
this.metadataStore.put("key", "old");
|
||||
assertThat(map.get("key")).isEqualTo("old");
|
||||
this.metadataStore.replace("key", "old", "new");
|
||||
assertThat(map.get("key")).isEqualTo("new");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListener() {
|
||||
MetadataStoreListener listener = mock(MetadataStoreListener.class);
|
||||
this.metadataStore.addListener(listener);
|
||||
|
||||
this.metadataStore.put("foo", "bar");
|
||||
this.metadataStore.replace("foo", "bar", "baz");
|
||||
this.metadataStore.remove("foo");
|
||||
verify(listener).onAdd("foo", "bar");
|
||||
verify(listener).onUpdate("foo", "baz");
|
||||
verify(listener).onRemove("foo", "baz");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
<?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
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
https://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/hazelcast
|
||||
https://www.springframework.org/schema/integration/hazelcast/spring-integration-hazelcast.xsd">
|
||||
|
||||
<import resource="classpath:org/springframework/integration/hazelcast/common-config.xml"/>
|
||||
|
||||
<int:channel id="firstMapChannel"/>
|
||||
|
||||
<int:channel id="secondMapChannel"/>
|
||||
|
||||
<int:channel id="thirdMapChannel"/>
|
||||
|
||||
<int:channel id="fourthMapChannel"/>
|
||||
|
||||
<int:channel id="fifthMapChannel"/>
|
||||
|
||||
<int:channel id="sixthMapChannel"/>
|
||||
|
||||
<int:channel id="bulkMapChannel"/>
|
||||
|
||||
<int:channel id="multiMapChannel"/>
|
||||
|
||||
<int:channel id="replicatedMapChannel"/>
|
||||
|
||||
<int:channel id="bulkReplicatedMapChannel"/>
|
||||
|
||||
<int:channel id="listChannel"/>
|
||||
|
||||
<int:channel id="bulkListChannel"/>
|
||||
|
||||
<int:channel id="setChannel"/>
|
||||
|
||||
<int:channel id="bulkSetChannel"/>
|
||||
|
||||
<int:channel id="queueChannel">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="bulkQueueChannel">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="topicChannel"/>
|
||||
|
||||
<bean id="testFirstMapRequestHandlerAdvice"
|
||||
class="org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice">
|
||||
<constructor-arg type="int" value="100"/>
|
||||
</bean>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="firstMapChannel" cache="distributedMap" key-expression="payload.id">
|
||||
<int-hazelcast:request-handler-advice-chain>
|
||||
<ref bean="testFirstMapRequestHandlerAdvice"/>
|
||||
</int-hazelcast:request-handler-advice-chain>
|
||||
</int-hazelcast:outbound-channel-adapter>
|
||||
|
||||
<bean id="testSecondMapRequestHandlerAdvice"
|
||||
class="org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice">
|
||||
<constructor-arg type="int" value="100"/>
|
||||
</bean>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="secondMapChannel" cache-expression="@distributedMap" key-expression="payload.id">
|
||||
<int-hazelcast:request-handler-advice-chain>
|
||||
<ref bean="testSecondMapRequestHandlerAdvice"/>
|
||||
</int-hazelcast:request-handler-advice-chain>
|
||||
</int-hazelcast:outbound-channel-adapter>
|
||||
|
||||
<bean id="testThirdMapRequestHandlerAdvice"
|
||||
class="org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice">
|
||||
<constructor-arg type="int" value="100"/>
|
||||
</bean>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="thirdMapChannel" key-expression="payload.id">
|
||||
<int-hazelcast:request-handler-advice-chain>
|
||||
<ref bean="testThirdMapRequestHandlerAdvice"/>
|
||||
</int-hazelcast:request-handler-advice-chain>
|
||||
</int-hazelcast:outbound-channel-adapter>
|
||||
|
||||
<bean id="testFourthMapRequestHandlerAdvice"
|
||||
class="org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice">
|
||||
<constructor-arg type="int" value="100"/>
|
||||
</bean>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="fourthMapChannel" key-expression="payload.id" extract-payload="false">
|
||||
<int-hazelcast:request-handler-advice-chain>
|
||||
<ref bean="testFourthMapRequestHandlerAdvice"/>
|
||||
</int-hazelcast:request-handler-advice-chain>
|
||||
</int-hazelcast:outbound-channel-adapter>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="fifthMapChannel" key-expression="payload.id" />
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="sixthMapChannel" />
|
||||
|
||||
<bean id="testBulkMapRequestHandlerAdvice"
|
||||
class="org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice">
|
||||
<constructor-arg type="int" value="1"/>
|
||||
</bean>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="bulkMapChannel" cache="distributedBulkMap" key-expression="payload.id">
|
||||
<int-hazelcast:request-handler-advice-chain>
|
||||
<ref bean="testBulkMapRequestHandlerAdvice"/>
|
||||
</int-hazelcast:request-handler-advice-chain>
|
||||
</int-hazelcast:outbound-channel-adapter>
|
||||
|
||||
<bean id="testMultiMapRequestHandlerAdvice"
|
||||
class="org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice">
|
||||
<constructor-arg type="int" value="100"/>
|
||||
</bean>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="multiMapChannel" cache="multiMap" key-expression="payload.id">
|
||||
<int-hazelcast:request-handler-advice-chain>
|
||||
<ref bean="testMultiMapRequestHandlerAdvice"/>
|
||||
</int-hazelcast:request-handler-advice-chain>
|
||||
</int-hazelcast:outbound-channel-adapter>
|
||||
|
||||
<bean id="testReplicatedMapRequestHandlerAdvice"
|
||||
class="org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice">
|
||||
<constructor-arg type="int" value="100"/>
|
||||
</bean>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="replicatedMapChannel" cache="replicatedMap" key-expression="payload.id">
|
||||
<int-hazelcast:request-handler-advice-chain>
|
||||
<ref bean="testReplicatedMapRequestHandlerAdvice"/>
|
||||
</int-hazelcast:request-handler-advice-chain>
|
||||
</int-hazelcast:outbound-channel-adapter>
|
||||
|
||||
<bean id="testBulkReplicatedMapRequestHandlerAdvice"
|
||||
class="org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice">
|
||||
<constructor-arg type="int" value="1"/>
|
||||
</bean>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="bulkReplicatedMapChannel" cache="bulkReplicatedMap" key-expression="payload.id">
|
||||
<int-hazelcast:request-handler-advice-chain>
|
||||
<ref bean="testBulkReplicatedMapRequestHandlerAdvice"/>
|
||||
</int-hazelcast:request-handler-advice-chain>
|
||||
</int-hazelcast:outbound-channel-adapter>
|
||||
|
||||
<bean id="testListRequestHandlerAdvice"
|
||||
class="org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice">
|
||||
<constructor-arg type="int" value="100"/>
|
||||
</bean>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="listChannel" cache="distributedList">
|
||||
<int-hazelcast:request-handler-advice-chain>
|
||||
<ref bean="testListRequestHandlerAdvice"/>
|
||||
</int-hazelcast:request-handler-advice-chain>
|
||||
</int-hazelcast:outbound-channel-adapter>
|
||||
|
||||
<bean id="testBulkListRequestHandlerAdvice"
|
||||
class="org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice">
|
||||
<constructor-arg type="int" value="1"/>
|
||||
</bean>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="bulkListChannel" cache="distributedBulkList">
|
||||
<int-hazelcast:request-handler-advice-chain>
|
||||
<ref bean="testBulkListRequestHandlerAdvice"/>
|
||||
</int-hazelcast:request-handler-advice-chain>
|
||||
</int-hazelcast:outbound-channel-adapter>
|
||||
|
||||
<bean id="testSetRequestHandlerAdvice"
|
||||
class="org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice">
|
||||
<constructor-arg type="int" value="100"/>
|
||||
</bean>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="setChannel" cache="distributedSet" >
|
||||
<int-hazelcast:request-handler-advice-chain>
|
||||
<ref bean="testSetRequestHandlerAdvice"/>
|
||||
</int-hazelcast:request-handler-advice-chain>
|
||||
</int-hazelcast:outbound-channel-adapter>
|
||||
|
||||
<bean id="testBulkSetRequestHandlerAdvice"
|
||||
class="org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice">
|
||||
<constructor-arg type="int" value="1"/>
|
||||
</bean>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="bulkSetChannel" cache="distributedBulkSet" >
|
||||
<int-hazelcast:request-handler-advice-chain>
|
||||
<ref bean="testBulkSetRequestHandlerAdvice"/>
|
||||
</int-hazelcast:request-handler-advice-chain>
|
||||
</int-hazelcast:outbound-channel-adapter>
|
||||
|
||||
<bean id="testQueueRequestHandlerAdvice"
|
||||
class="org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice">
|
||||
<constructor-arg type="int" value="100"/>
|
||||
</bean>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="queueChannel" cache="distributedQueue">
|
||||
<int:poller fixed-delay="100"/>
|
||||
<int-hazelcast:request-handler-advice-chain>
|
||||
<ref bean="testQueueRequestHandlerAdvice"/>
|
||||
</int-hazelcast:request-handler-advice-chain>
|
||||
</int-hazelcast:outbound-channel-adapter>
|
||||
|
||||
<bean id="testBulkQueueRequestHandlerAdvice"
|
||||
class="org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice">
|
||||
<constructor-arg type="int" value="1"/>
|
||||
</bean>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="bulkQueueChannel" cache="distributedBulkQueue">
|
||||
<int:poller fixed-delay="100"/>
|
||||
<int-hazelcast:request-handler-advice-chain>
|
||||
<ref bean="testBulkQueueRequestHandlerAdvice"/>
|
||||
</int-hazelcast:request-handler-advice-chain>
|
||||
</int-hazelcast:outbound-channel-adapter>
|
||||
|
||||
<bean id="testTopicRequestHandlerAdvice"
|
||||
class="org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice">
|
||||
<constructor-arg type="int" value="100" />
|
||||
</bean>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter channel="topicChannel" cache="topic" >
|
||||
<int-hazelcast:request-handler-advice-chain>
|
||||
<ref bean="testTopicRequestHandlerAdvice"/>
|
||||
</int-hazelcast:request-handler-advice-chain>
|
||||
</int-hazelcast:outbound-channel-adapter>
|
||||
|
||||
<int-hazelcast:outbound-channel-adapter id="lockChannel" cache="myLock" />
|
||||
|
||||
<bean id="distributedMap" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="distributedMap"/>
|
||||
</bean>
|
||||
|
||||
<bean id="distributedBulkMap" factory-bean="instance" factory-method="getMap">
|
||||
<constructor-arg value="distributedBulkMap"/>
|
||||
</bean>
|
||||
|
||||
<bean id="distributedList" factory-bean="instance" factory-method="getList">
|
||||
<constructor-arg value="distributedList"/>
|
||||
</bean>
|
||||
|
||||
<bean id="distributedBulkList" factory-bean="instance" factory-method="getList">
|
||||
<constructor-arg value="distributedBulkList"/>
|
||||
</bean>
|
||||
|
||||
<bean id="distributedSet" factory-bean="instance" factory-method="getSet">
|
||||
<constructor-arg value="distributedSet"/>
|
||||
</bean>
|
||||
|
||||
<bean id="distributedBulkSet" factory-bean="instance" factory-method="getSet">
|
||||
<constructor-arg value="distributedBulkSet"/>
|
||||
</bean>
|
||||
|
||||
<bean id="distributedQueue" factory-bean="instance" factory-method="getQueue">
|
||||
<constructor-arg value="distributedQueue"/>
|
||||
</bean>
|
||||
|
||||
<bean id="distributedBulkQueue" factory-bean="instance" factory-method="getQueue">
|
||||
<constructor-arg value="distributedBulkQueue"/>
|
||||
</bean>
|
||||
|
||||
<bean id="multiMap" factory-bean="instance" factory-method="getMultiMap">
|
||||
<constructor-arg value="multiMap"/>
|
||||
</bean>
|
||||
|
||||
<bean id="replicatedMap" factory-bean="instance" factory-method="getReplicatedMap">
|
||||
<constructor-arg value="replicatedMap"/>
|
||||
</bean>
|
||||
|
||||
<bean id="bulkReplicatedMap" factory-bean="instance" factory-method="getReplicatedMap">
|
||||
<constructor-arg value="bulkReplicatedMap"/>
|
||||
</bean>
|
||||
|
||||
<bean id="topic" factory-bean="instance" factory-method="getTopic">
|
||||
<constructor-arg value="topic"/>
|
||||
</bean>
|
||||
|
||||
<bean id="cpSubsystem" factory-bean="instance" factory-method="getCPSubsystem"/>
|
||||
|
||||
<bean id="myLock" factory-bean="cpSubsystem" factory-method="getLock">
|
||||
<constructor-arg value="myLock"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.integration.hazelcast.HazelcastHeaders;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice;
|
||||
import org.springframework.integration.hazelcast.outbound.util.HazelcastOutboundChannelAdapterTestUtils;
|
||||
import org.springframework.integration.support.DefaultMessageBuilderFactory;
|
||||
import org.springframework.integration.support.MessageBuilderFactory;
|
||||
import org.springframework.messaging.Message;
|
||||
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.SpringRunner;
|
||||
|
||||
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
|
||||
import com.hazelcast.multimap.MultiMap;
|
||||
import com.hazelcast.replicatedmap.ReplicatedMap;
|
||||
import com.hazelcast.topic.ITopic;
|
||||
|
||||
/**
|
||||
* Hazelcast Outbound Channel Adapter Test Class.
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public class HazelcastOutboundChannelAdapterTests {
|
||||
|
||||
private static final String DISTRIBUTED_MAP = "distributedMap";
|
||||
|
||||
private static final String CACHE_HEADER = "CACHE_HEADER";
|
||||
|
||||
private final MessageBuilderFactory messageBuilderFactory =
|
||||
new DefaultMessageBuilderFactory();
|
||||
|
||||
@Autowired
|
||||
@Qualifier("firstMapChannel")
|
||||
private MessageChannel firstMapChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("secondMapChannel")
|
||||
private MessageChannel secondMapChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("thirdMapChannel")
|
||||
private MessageChannel thirdMapChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("fourthMapChannel")
|
||||
private MessageChannel fourthMapChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("fifthMapChannel")
|
||||
private MessageChannel fifthMapChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("sixthMapChannel")
|
||||
private MessageChannel sixthMapChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("bulkMapChannel")
|
||||
private MessageChannel bulkMapChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("multiMapChannel")
|
||||
private MessageChannel multiMapChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("replicatedMapChannel")
|
||||
private MessageChannel replicatedMapChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("bulkReplicatedMapChannel")
|
||||
private MessageChannel bulkReplicatedMapChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("listChannel")
|
||||
private MessageChannel listChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("bulkListChannel")
|
||||
private MessageChannel bulkListChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("setChannel")
|
||||
private MessageChannel setChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("bulkSetChannel")
|
||||
private MessageChannel bulkSetChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("queueChannel")
|
||||
private MessageChannel queueChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("bulkQueueChannel")
|
||||
private MessageChannel bulkQueueChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("topicChannel")
|
||||
private MessageChannel topicChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("lockChannel")
|
||||
private MessageChannel lockChannel;
|
||||
|
||||
@Autowired
|
||||
private Map<?, ?> distributedMap;
|
||||
|
||||
@Autowired
|
||||
private Map<?, ?> distributedBulkMap;
|
||||
|
||||
@Autowired
|
||||
private MultiMap multiMap;
|
||||
|
||||
@Autowired
|
||||
private ReplicatedMap replicatedMap;
|
||||
|
||||
@Autowired
|
||||
private ReplicatedMap bulkReplicatedMap;
|
||||
|
||||
@Autowired
|
||||
private List distributedList;
|
||||
|
||||
@Autowired
|
||||
private List distributedBulkList;
|
||||
|
||||
@Autowired
|
||||
private Set distributedSet;
|
||||
|
||||
@Autowired
|
||||
private Set distributedBulkSet;
|
||||
|
||||
@Autowired
|
||||
private Queue distributedQueue;
|
||||
|
||||
@Autowired
|
||||
private Queue distributedBulkQueue;
|
||||
|
||||
@Autowired
|
||||
private ITopic topic;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("testFirstMapRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice testFirstMapRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("testSecondMapRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice testSecondMapRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("testThirdMapRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice testThirdMapRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("testFourthMapRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice testFourthMapRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("testBulkMapRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice testBulkMapRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("testMultiMapRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice testMultiMapRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("testReplicatedMapRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice testReplicatedMapRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("testBulkReplicatedMapRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice testBulkReplicatedMapRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("testListRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice testListRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("testBulkListRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice testBulkListRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("testSetRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice testSetRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("testBulkSetRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice testBulkSetRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("testQueueRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice testQueueRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("testBulkQueueRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice testBulkQueueRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("testTopicRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice testTopicRequestHandlerAdvice;
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() {
|
||||
HazelcastInstanceFactory.terminateAll();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.distributedMap.clear();
|
||||
this.distributedBulkMap.clear();
|
||||
this.distributedList.clear();
|
||||
this.distributedBulkList.clear();
|
||||
this.distributedSet.clear();
|
||||
this.distributedBulkSet.clear();
|
||||
this.distributedQueue.clear();
|
||||
this.distributedBulkQueue.clear();
|
||||
this.multiMap.clear();
|
||||
this.replicatedMap.clear();
|
||||
this.bulkReplicatedMap.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteToDistributedMap() {
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.testWriteToDistributedMap(this.firstMapChannel, this.distributedMap,
|
||||
this.testFirstMapRequestHandlerAdvice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBulkWriteToDistributedMap() {
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.testBulkWriteToDistributedMap(this.bulkMapChannel, this.distributedBulkMap,
|
||||
this.testBulkMapRequestHandlerAdvice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteToDistributedMapWhenCacheExpressionIsSet()
|
||||
throws InterruptedException {
|
||||
sendMessageWithCacheHeaderToChannel(this.secondMapChannel, CACHE_HEADER,
|
||||
DISTRIBUTED_MAP);
|
||||
assertThat(this.testSecondMapRequestHandlerAdvice.executeLatch
|
||||
.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.verifyMapForPayload(new TreeMap(this.distributedMap));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteToDistributedMapWhenHazelcastHeaderIsSet()
|
||||
throws InterruptedException {
|
||||
sendMessageWithCacheHeaderToChannel(this.thirdMapChannel,
|
||||
HazelcastHeaders.CACHE_NAME, DISTRIBUTED_MAP);
|
||||
assertThat(this.testThirdMapRequestHandlerAdvice.executeLatch
|
||||
.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.verifyMapForPayload(new TreeMap(this.distributedMap));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteToDistributedMapWhenExtractPayloadIsFalse()
|
||||
throws InterruptedException {
|
||||
sendMessageWithCacheHeaderToChannel(this.fourthMapChannel,
|
||||
HazelcastHeaders.CACHE_NAME, DISTRIBUTED_MAP);
|
||||
assertThat(this.testFourthMapRequestHandlerAdvice.executeLatch
|
||||
.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
verifyMapForMessage(new TreeMap(this.distributedMap));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteToMultiMap() {
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.testWriteToMultiMap(this.multiMapChannel, this.multiMap,
|
||||
this.testMultiMapRequestHandlerAdvice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteToReplicatedMap() {
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.testWriteToReplicatedMap(this.replicatedMapChannel, this.replicatedMap,
|
||||
this.testReplicatedMapRequestHandlerAdvice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBulkWriteToReplicatedMap() throws InterruptedException {
|
||||
Map<Integer, HazelcastIntegrationTestUser> userMap =
|
||||
new HashMap<>(HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT);
|
||||
for (int index = 1;
|
||||
index <= HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT; index++) {
|
||||
userMap
|
||||
.put(index, HazelcastOutboundChannelAdapterTestUtils.getTestUser(index));
|
||||
}
|
||||
|
||||
this.bulkReplicatedMapChannel.send(new GenericMessage<>(userMap));
|
||||
|
||||
assertThat(this.testBulkReplicatedMapRequestHandlerAdvice.executeLatch
|
||||
.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.verifyMapForPayload(new TreeMap(this.bulkReplicatedMap));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testWriteToDistributedList() {
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.testWriteToDistributedList(this.listChannel, this.distributedList,
|
||||
this.testListRequestHandlerAdvice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBulkWriteToDistributedList() throws InterruptedException {
|
||||
List<HazelcastIntegrationTestUser> userList =
|
||||
new ArrayList<>(HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT);
|
||||
for (int index = 1;
|
||||
index <= HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT; index++) {
|
||||
userList.add(HazelcastOutboundChannelAdapterTestUtils.getTestUser(index));
|
||||
}
|
||||
|
||||
this.bulkListChannel.send(new GenericMessage<>(userList));
|
||||
|
||||
assertThat(this.testBulkListRequestHandlerAdvice.executeLatch
|
||||
.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.verifyCollection(this.distributedBulkList,
|
||||
HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteToDistributedSet() {
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.testWriteToDistributedSet(this.setChannel, this.distributedSet,
|
||||
this.testSetRequestHandlerAdvice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBulkWriteToDistributedSet() throws InterruptedException {
|
||||
Set<HazelcastIntegrationTestUser> userSet =
|
||||
new HashSet<>(HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT);
|
||||
for (int index = 1;
|
||||
index <= HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT; index++) {
|
||||
userSet.add(HazelcastOutboundChannelAdapterTestUtils.getTestUser(index));
|
||||
}
|
||||
|
||||
this.bulkSetChannel.send(new GenericMessage<>(userSet));
|
||||
|
||||
assertThat(this.testBulkSetRequestHandlerAdvice.executeLatch
|
||||
.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
final List<HazelcastIntegrationTestUser> list =
|
||||
new ArrayList(this.distributedBulkSet);
|
||||
Collections.sort(list);
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.verifyCollection(list, HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteToDistributedQueue() {
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.testWriteToDistributedQueue(this.queueChannel, this.distributedQueue,
|
||||
this.testQueueRequestHandlerAdvice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBulkWriteToDistributedQueue() throws InterruptedException {
|
||||
Queue<HazelcastIntegrationTestUser> userQueue =
|
||||
new ArrayBlockingQueue(HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT);
|
||||
for (int index = 1;
|
||||
index <= HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT; index++) {
|
||||
userQueue.add(HazelcastOutboundChannelAdapterTestUtils.getTestUser(index));
|
||||
}
|
||||
|
||||
this.bulkQueueChannel.send(new GenericMessage<>(userQueue));
|
||||
|
||||
assertThat(this.testBulkQueueRequestHandlerAdvice.executeLatch
|
||||
.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.verifyCollection(this.distributedBulkQueue,
|
||||
HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteToTopic() {
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.testWriteToTopic(this.topicChannel, this.topic,
|
||||
this.testTopicRequestHandlerAdvice);
|
||||
}
|
||||
|
||||
@Test(expected = MessageHandlingException.class)
|
||||
public void testWriteToDistributedMapWhenCacheIsNotSet() {
|
||||
this.fifthMapChannel.send(new GenericMessage<>(
|
||||
HazelcastOutboundChannelAdapterTestUtils.getTestUser(1)));
|
||||
}
|
||||
|
||||
@Test(expected = MessageHandlingException.class)
|
||||
public void testWriteToDistributedMapWhenKeyExpressionIsNotSet() {
|
||||
Message<HazelcastIntegrationTestUser> message = this.messageBuilderFactory
|
||||
.withPayload(HazelcastOutboundChannelAdapterTestUtils.getTestUser(1))
|
||||
.setHeader(HazelcastHeaders.CACHE_NAME, DISTRIBUTED_MAP).build();
|
||||
this.sixthMapChannel.send(message);
|
||||
}
|
||||
|
||||
@Test(expected = MessageHandlingException.class)
|
||||
public void testWriteToLock() {
|
||||
this.lockChannel.send(new GenericMessage<>("foo"));
|
||||
}
|
||||
|
||||
private void sendMessageWithCacheHeaderToChannel(final MessageChannel channel,
|
||||
final String headerName, final String distributedObjectName) {
|
||||
for (int index = 1;
|
||||
index <= HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT; index++) {
|
||||
Message<HazelcastIntegrationTestUser> message = this.messageBuilderFactory
|
||||
.withPayload(HazelcastOutboundChannelAdapterTestUtils.getTestUser(index))
|
||||
.setHeader(headerName, distributedObjectName).build();
|
||||
channel.send(message);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyMapForMessage(
|
||||
final Map<Integer, Message<HazelcastIntegrationTestUser>> map) {
|
||||
int index = 1;
|
||||
assertThat(map).isNotNull();
|
||||
assertThat(map.size()).isEqualTo(HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT);
|
||||
for (Entry<Integer, Message<HazelcastIntegrationTestUser>> entry : map.entrySet()) {
|
||||
assertThat(entry).isNotNull();
|
||||
assertThat(entry.getKey().intValue()).isEqualTo(index);
|
||||
assertThat(entry.getValue().getHeaders().size() > 0).isTrue();
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.verifyHazelcastIntegrationTestUser(entry.getValue().getPayload(), index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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.config;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.integration.annotation.IntegrationComponentScan;
|
||||
import org.springframework.integration.annotation.ServiceActivator;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.config.EnableIntegration;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice;
|
||||
import org.springframework.integration.hazelcast.outbound.HazelcastCacheWritingMessageHandler;
|
||||
import org.springframework.integration.hazelcast.outbound.util.HazelcastOutboundChannelAdapterTestUtils;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
|
||||
import com.hazelcast.core.DistributedObject;
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
|
||||
import com.hazelcast.map.IMap;
|
||||
import com.hazelcast.multimap.MultiMap;
|
||||
import com.hazelcast.replicatedmap.ReplicatedMap;
|
||||
import com.hazelcast.topic.ITopic;
|
||||
|
||||
/**
|
||||
* Configuration Class for Hazelcast Integration Outbound Test
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@Configuration
|
||||
@ComponentScan(basePackages = { "org.springframework.integration.hazelcast.*" })
|
||||
@EnableIntegration
|
||||
@IntegrationComponentScan("org.springframework.integration.hazelcast.outbound")
|
||||
public class HazelcastIntegrationOutboundTestConfiguration {
|
||||
|
||||
@AfterClass
|
||||
public void terminate() {
|
||||
HazelcastInstanceFactory.terminateAll();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageChannel distMapChannel() {
|
||||
return new DirectChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageChannel distMapBulkChannel() {
|
||||
return new DirectChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageChannel distListChannel() {
|
||||
return new DirectChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageChannel distSetChannel() {
|
||||
return new DirectChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageChannel distQueueChannel() {
|
||||
return new DirectChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageChannel topicChannel2() {
|
||||
return new DirectChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageChannel multiMapChannel2() {
|
||||
return new DirectChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageChannel replicatedMapChannel2() {
|
||||
return new DirectChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IMap<Integer, HazelcastIntegrationTestUser> distMap() {
|
||||
return testHzInstance().getMap("Distributed_Map1");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IMap<Integer, HazelcastIntegrationTestUser> distBulkMap() {
|
||||
return testHzInstance().getMap("Distributed_Bulk_Map1");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public List<HazelcastIntegrationTestUser> distList() {
|
||||
return testHzInstance().getList("Distributed_List1");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Set<HazelcastIntegrationTestUser> distSet() {
|
||||
return testHzInstance().getSet("Distributed_Set1");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Queue<HazelcastIntegrationTestUser> distQueue() {
|
||||
return testHzInstance().getQueue("Distributed_Queue1");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ITopic<HazelcastIntegrationTestUser> topic() {
|
||||
return testHzInstance().getTopic("Topic1");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MultiMap<Integer, HazelcastIntegrationTestUser> multiMap() {
|
||||
return testHzInstance().getMultiMap("Multi_Map1");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ReplicatedMap<Integer, HazelcastIntegrationTestUser> replicatedMap() {
|
||||
return testHzInstance().getReplicatedMap("Replicated_Map1");
|
||||
}
|
||||
|
||||
@Bean(destroyMethod = "")
|
||||
public HazelcastInstance testHzInstance() {
|
||||
return Hazelcast.newHazelcastInstance();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastTestRequestHandlerAdvice distMapRequestHandlerAdvice() {
|
||||
return new HazelcastTestRequestHandlerAdvice(
|
||||
HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastTestRequestHandlerAdvice distBulkMapRequestHandlerAdvice() {
|
||||
return new HazelcastTestRequestHandlerAdvice(1);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastTestRequestHandlerAdvice distListRequestHandlerAdvice() {
|
||||
return new HazelcastTestRequestHandlerAdvice(
|
||||
HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastTestRequestHandlerAdvice distSetRequestHandlerAdvice() {
|
||||
return new HazelcastTestRequestHandlerAdvice(
|
||||
HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastTestRequestHandlerAdvice distQueueRequestHandlerAdvice() {
|
||||
return new HazelcastTestRequestHandlerAdvice(
|
||||
HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastTestRequestHandlerAdvice topicRequestHandlerAdvice() {
|
||||
return new HazelcastTestRequestHandlerAdvice(
|
||||
HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastTestRequestHandlerAdvice multiMapRequestHandlerAdvice() {
|
||||
return new HazelcastTestRequestHandlerAdvice(
|
||||
HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HazelcastTestRequestHandlerAdvice replicatedMapRequestHandlerAdvice() {
|
||||
return new HazelcastTestRequestHandlerAdvice(
|
||||
HazelcastOutboundChannelAdapterTestUtils.DATA_COUNT);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "distMapChannel", adviceChain = "distMapRequestHandlerAdvice")
|
||||
public HazelcastCacheWritingMessageHandler hazelcastCacheWritingMessageHandler() {
|
||||
final HazelcastCacheWritingMessageHandler handler =
|
||||
new HazelcastCacheWritingMessageHandler();
|
||||
handler.setDistributedObject(distMap());
|
||||
handler
|
||||
.setKeyExpression(new SpelExpressionParser().parseExpression("payload.id"));
|
||||
handler.setExtractPayload(true);
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "distMapBulkChannel",
|
||||
adviceChain = "distBulkMapRequestHandlerAdvice")
|
||||
public HazelcastCacheWritingMessageHandler hazelcastCacheWritingMessageHandler2() {
|
||||
final HazelcastCacheWritingMessageHandler handler =
|
||||
new HazelcastCacheWritingMessageHandler();
|
||||
handler.setDistributedObject(distBulkMap());
|
||||
handler
|
||||
.setKeyExpression(new SpelExpressionParser().parseExpression("payload.id"));
|
||||
handler.setExtractPayload(true);
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "distListChannel",
|
||||
adviceChain = "distListRequestHandlerAdvice")
|
||||
public HazelcastCacheWritingMessageHandler hazelcastCacheWritingMessageHandler3() {
|
||||
final HazelcastCacheWritingMessageHandler handler =
|
||||
new HazelcastCacheWritingMessageHandler();
|
||||
handler.setDistributedObject((DistributedObject) distList());
|
||||
handler
|
||||
.setKeyExpression(new SpelExpressionParser().parseExpression("payload.id"));
|
||||
handler.setExtractPayload(true);
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "distSetChannel",
|
||||
adviceChain = "distSetRequestHandlerAdvice")
|
||||
public HazelcastCacheWritingMessageHandler hazelcastCacheWritingMessageHandler4() {
|
||||
final HazelcastCacheWritingMessageHandler handler =
|
||||
new HazelcastCacheWritingMessageHandler();
|
||||
handler.setDistributedObject((DistributedObject) distSet());
|
||||
handler
|
||||
.setKeyExpression(new SpelExpressionParser().parseExpression("payload.id"));
|
||||
handler.setExtractPayload(true);
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "distQueueChannel",
|
||||
adviceChain = "distQueueRequestHandlerAdvice")
|
||||
public HazelcastCacheWritingMessageHandler hazelcastCacheWritingMessageHandler5() {
|
||||
final HazelcastCacheWritingMessageHandler handler =
|
||||
new HazelcastCacheWritingMessageHandler();
|
||||
handler.setDistributedObject((DistributedObject) distQueue());
|
||||
handler
|
||||
.setKeyExpression(new SpelExpressionParser().parseExpression("payload.id"));
|
||||
handler.setExtractPayload(true);
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "topicChannel2",
|
||||
adviceChain = "topicRequestHandlerAdvice")
|
||||
public HazelcastCacheWritingMessageHandler hazelcastCacheWritingMessageHandler6() {
|
||||
final HazelcastCacheWritingMessageHandler handler =
|
||||
new HazelcastCacheWritingMessageHandler();
|
||||
handler.setDistributedObject(topic());
|
||||
handler
|
||||
.setKeyExpression(new SpelExpressionParser().parseExpression("payload.id"));
|
||||
handler.setExtractPayload(true);
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "multiMapChannel2",
|
||||
adviceChain = "multiMapRequestHandlerAdvice")
|
||||
public HazelcastCacheWritingMessageHandler hazelcastCacheWritingMessageHandler7() {
|
||||
final HazelcastCacheWritingMessageHandler handler =
|
||||
new HazelcastCacheWritingMessageHandler();
|
||||
handler.setDistributedObject(multiMap());
|
||||
handler
|
||||
.setKeyExpression(new SpelExpressionParser().parseExpression("payload.id"));
|
||||
handler.setExtractPayload(true);
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "replicatedMapChannel2",
|
||||
adviceChain = "replicatedMapRequestHandlerAdvice")
|
||||
public HazelcastCacheWritingMessageHandler hazelcastCacheWritingMessageHandler8() {
|
||||
final HazelcastCacheWritingMessageHandler handler =
|
||||
new HazelcastCacheWritingMessageHandler();
|
||||
handler.setDistributedObject(replicatedMap());
|
||||
handler
|
||||
.setKeyExpression(new SpelExpressionParser().parseExpression("payload.id"));
|
||||
handler.setExtractPayload(true);
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright 2015-2022 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
|
||||
*
|
||||
* https://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.config;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice;
|
||||
import org.springframework.integration.hazelcast.outbound.util.HazelcastOutboundChannelAdapterTestUtils;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.context.support.AnnotationConfigContextLoader;
|
||||
|
||||
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
|
||||
import com.hazelcast.map.IMap;
|
||||
import com.hazelcast.multimap.MultiMap;
|
||||
import com.hazelcast.replicatedmap.ReplicatedMap;
|
||||
import com.hazelcast.topic.ITopic;
|
||||
|
||||
/**
|
||||
* Hazelcast Outbound Channel Adapter JavaConfig driven Unit Test Class
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
* @since 6.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration(classes = HazelcastIntegrationOutboundTestConfiguration.class,
|
||||
loader = AnnotationConfigContextLoader.class)
|
||||
@DirtiesContext
|
||||
public class HazelcastOutboundChannelAdapterConfigTests {
|
||||
|
||||
@Autowired
|
||||
@Qualifier("distMapChannel")
|
||||
private MessageChannel distMapChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("distMapBulkChannel")
|
||||
private MessageChannel distMapBulkChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("distListChannel")
|
||||
private MessageChannel distListChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("distSetChannel")
|
||||
private MessageChannel distSetChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("distQueueChannel")
|
||||
private MessageChannel distQueueChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("topicChannel2")
|
||||
private MessageChannel topicChannel2;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("multiMapChannel2")
|
||||
private MessageChannel multiMapChannel2;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("replicatedMapChannel2")
|
||||
private MessageChannel replicatedMapChannel2;
|
||||
|
||||
@Autowired
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> distMap;
|
||||
|
||||
@Autowired
|
||||
private IMap<Integer, HazelcastIntegrationTestUser> distBulkMap;
|
||||
|
||||
@Autowired
|
||||
private List<HazelcastIntegrationTestUser> distList;
|
||||
|
||||
@Autowired
|
||||
private Set<HazelcastIntegrationTestUser> distSet;
|
||||
|
||||
@Autowired
|
||||
private Queue<HazelcastIntegrationTestUser> distQueue;
|
||||
|
||||
@Autowired
|
||||
private ITopic<HazelcastIntegrationTestUser> topic;
|
||||
|
||||
@Autowired
|
||||
private MultiMap<Integer, HazelcastIntegrationTestUser> multiMap;
|
||||
|
||||
@Autowired
|
||||
private ReplicatedMap<Integer, HazelcastIntegrationTestUser> replicatedMap;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("distMapRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice distMapRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("distBulkMapRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice distBulkMapRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("distListRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice distListRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("distSetRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice distSetRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("distQueueRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice distQueueRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("topicRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice topicRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("multiMapRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice multiMapRequestHandlerAdvice;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("replicatedMapRequestHandlerAdvice")
|
||||
private HazelcastTestRequestHandlerAdvice replicatedMapRequestHandlerAdvice;
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() {
|
||||
HazelcastInstanceFactory.terminateAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteToDistributedMap() {
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.testWriteToDistributedMap(this.distMapChannel, this.distMap,
|
||||
this.distMapRequestHandlerAdvice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBulkWriteToDistributedMap() {
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.testBulkWriteToDistributedMap(this.distMapBulkChannel, this.distBulkMap,
|
||||
this.distBulkMapRequestHandlerAdvice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteToDistributedList() {
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.testWriteToDistributedList(this.distListChannel, this.distList,
|
||||
this.distListRequestHandlerAdvice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteToDistributedSet() {
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.testWriteToDistributedSet(this.distSetChannel, this.distSet,
|
||||
this.distSetRequestHandlerAdvice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteToDistributedQueue() {
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.testWriteToDistributedQueue(this.distQueueChannel, this.distQueue,
|
||||
this.distQueueRequestHandlerAdvice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteToTopic() {
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.testWriteToTopic(this.topicChannel2, this.topic, this.topicRequestHandlerAdvice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteToMultiMap() {
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.testWriteToMultiMap(this.multiMapChannel2, this.multiMap,
|
||||
this.multiMapRequestHandlerAdvice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteToReplicatedMap() {
|
||||
HazelcastOutboundChannelAdapterTestUtils
|
||||
.testWriteToReplicatedMap(this.replicatedMapChannel2, this.replicatedMap,
|
||||
this.replicatedMapRequestHandlerAdvice);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright 2016-2020 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
|
||||
*
|
||||
* https://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.util;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.integration.hazelcast.HazelcastIntegrationTestUser;
|
||||
import org.springframework.integration.hazelcast.HazelcastTestRequestHandlerAdvice;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
|
||||
import com.hazelcast.multimap.MultiMap;
|
||||
import com.hazelcast.replicatedmap.ReplicatedMap;
|
||||
import com.hazelcast.topic.ITopic;
|
||||
import com.hazelcast.topic.MessageListener;
|
||||
|
||||
/**
|
||||
* Util Class for Hazelcast Outbound Channel Adapter Test Support
|
||||
*
|
||||
* @author Eren Avsarogullari
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public final class HazelcastOutboundChannelAdapterTestUtils {
|
||||
|
||||
public static final int DATA_COUNT = 100;
|
||||
|
||||
public static final int DEFAULT_AGE = 5;
|
||||
|
||||
public static final String TEST_NAME = "Test_Name";
|
||||
|
||||
public static final String TEST_SURNAME = "Test_Surname";
|
||||
|
||||
public static void testWriteToDistributedMap(MessageChannel channel,
|
||||
Map<?, ?> distributedMap,
|
||||
HazelcastTestRequestHandlerAdvice requestHandlerAdvice) {
|
||||
testWriteToMap(channel, distributedMap, requestHandlerAdvice);
|
||||
}
|
||||
|
||||
private static void testWriteToMap(MessageChannel channel,
|
||||
Map<?, ?> distributedMap,
|
||||
HazelcastTestRequestHandlerAdvice requestHandlerAdvice) {
|
||||
try {
|
||||
sendMessageToChannel(channel);
|
||||
assertThat(requestHandlerAdvice.executeLatch.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
verifyMapForPayload(new TreeMap(distributedMap));
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
fail("Test has been failed due to " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static void testBulkWriteToDistributedMap(MessageChannel channel,
|
||||
Map<?, ?> distributedMap,
|
||||
HazelcastTestRequestHandlerAdvice requestHandlerAdvice) {
|
||||
try {
|
||||
Map<Integer, HazelcastIntegrationTestUser> userMap =
|
||||
new HashMap<>(DATA_COUNT);
|
||||
for (int index = 1; index <= DATA_COUNT; index++) {
|
||||
userMap.put(index, getTestUser(index));
|
||||
}
|
||||
|
||||
channel.send(new GenericMessage<>(userMap));
|
||||
|
||||
assertThat(requestHandlerAdvice.executeLatch.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
verifyMapForPayload(new TreeMap(distributedMap));
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
fail("Test has been failed due to " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static void testWriteToMultiMap(MessageChannel channel,
|
||||
MultiMap<Integer, HazelcastIntegrationTestUser> multiMap,
|
||||
HazelcastTestRequestHandlerAdvice requestHandlerAdvice) {
|
||||
try {
|
||||
sendMessageToChannel(channel);
|
||||
assertThat(requestHandlerAdvice.executeLatch.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
verifyMultiMapForPayload(multiMap);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
fail("Test has been failed due to " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static void testWriteToReplicatedMap(MessageChannel channel,
|
||||
ReplicatedMap<Integer, HazelcastIntegrationTestUser> replicatedMap,
|
||||
HazelcastTestRequestHandlerAdvice requestHandlerAdvice) {
|
||||
testWriteToMap(channel, replicatedMap, requestHandlerAdvice);
|
||||
}
|
||||
|
||||
public static void testWriteToDistributedList(MessageChannel channel,
|
||||
List<HazelcastIntegrationTestUser> distributedList,
|
||||
HazelcastTestRequestHandlerAdvice requestHandlerAdvice) {
|
||||
testWriteToDistributedCollection(channel, distributedList, requestHandlerAdvice);
|
||||
}
|
||||
|
||||
private static void testWriteToDistributedCollection(MessageChannel channel,
|
||||
Collection<HazelcastIntegrationTestUser> distributedList,
|
||||
HazelcastTestRequestHandlerAdvice requestHandlerAdvice) {
|
||||
try {
|
||||
sendMessageToChannel(channel);
|
||||
assertThat(requestHandlerAdvice.executeLatch.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
verifyCollection(distributedList, DATA_COUNT);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
fail("Test has been failed due to " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static void testWriteToDistributedSet(MessageChannel channel,
|
||||
Set<HazelcastIntegrationTestUser> distributedSet,
|
||||
HazelcastTestRequestHandlerAdvice requestHandlerAdvice) {
|
||||
try {
|
||||
sendMessageToChannel(channel);
|
||||
assertThat(requestHandlerAdvice.executeLatch.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
final List<HazelcastIntegrationTestUser> list = new ArrayList(distributedSet);
|
||||
Collections.sort(list);
|
||||
verifyCollection(list, DATA_COUNT);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
fail("Test has been failed due to " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static void testWriteToDistributedQueue(MessageChannel channel,
|
||||
Queue<HazelcastIntegrationTestUser> distributedQueue,
|
||||
HazelcastTestRequestHandlerAdvice requestHandlerAdvice) {
|
||||
testWriteToDistributedCollection(channel, distributedQueue, requestHandlerAdvice);
|
||||
}
|
||||
|
||||
public static void testWriteToTopic(MessageChannel channel,
|
||||
ITopic<HazelcastIntegrationTestUser> topic,
|
||||
HazelcastTestRequestHandlerAdvice requestHandlerAdvice) {
|
||||
try {
|
||||
topic.addMessageListener(new MessageListener() {
|
||||
|
||||
private int index = 1;
|
||||
|
||||
@Override
|
||||
public void onMessage(com.hazelcast.topic.Message message) {
|
||||
HazelcastIntegrationTestUser user =
|
||||
(HazelcastIntegrationTestUser) message.getMessageObject();
|
||||
verifyHazelcastIntegrationTestUser(user, index);
|
||||
index++;
|
||||
}
|
||||
});
|
||||
sendMessageToChannel(channel);
|
||||
assertThat(requestHandlerAdvice.executeLatch.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
fail("Test has been failed due to " + e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static HazelcastIntegrationTestUser getTestUser(int index) {
|
||||
return new HazelcastIntegrationTestUser(index, TEST_NAME, TEST_SURNAME,
|
||||
index + DEFAULT_AGE);
|
||||
}
|
||||
|
||||
public static void verifyMapForPayload(
|
||||
final Map<Integer, HazelcastIntegrationTestUser> map) {
|
||||
int index = 1;
|
||||
assertThat(map).isNotNull();
|
||||
assertThat(map.size() == DATA_COUNT).isEqualTo(true);
|
||||
for (Map.Entry<Integer, HazelcastIntegrationTestUser> entry : map.entrySet()) {
|
||||
assertThat(entry).isNotNull();
|
||||
assertThat(entry.getKey().intValue()).isEqualTo(index);
|
||||
verifyHazelcastIntegrationTestUser(entry.getValue(), index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
public static void verifyCollection(
|
||||
final Collection<HazelcastIntegrationTestUser> coll, final int dataCount) {
|
||||
int index = 1;
|
||||
assertThat(coll).isNotNull();
|
||||
assertThat(coll.size() == dataCount).isEqualTo(true);
|
||||
for (HazelcastIntegrationTestUser user : coll) {
|
||||
verifyHazelcastIntegrationTestUser(user, index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
public static void verifyHazelcastIntegrationTestUser(
|
||||
HazelcastIntegrationTestUser user, int index) {
|
||||
assertThat(user).isNotNull();
|
||||
assertThat(user.getId()).isEqualTo(index);
|
||||
assertThat(user.getName()).isEqualTo(TEST_NAME);
|
||||
assertThat(user.getSurname()).isEqualTo(TEST_SURNAME);
|
||||
assertThat(user.getAge()).isEqualTo(index + DEFAULT_AGE);
|
||||
}
|
||||
|
||||
private static void sendMessageToChannel(final MessageChannel channel) {
|
||||
for (int index = 1; index <= DATA_COUNT; index++) {
|
||||
channel.send(new GenericMessage<>(getTestUser(index)));
|
||||
}
|
||||
}
|
||||
|
||||
private static void verifyMultiMapForPayload(
|
||||
final MultiMap<Integer, HazelcastIntegrationTestUser> multiMap) {
|
||||
int index = 1;
|
||||
assertThat(multiMap).isNotNull();
|
||||
assertThat(multiMap.size() == DATA_COUNT).isEqualTo(true);
|
||||
SortedSet<Integer> keys = new TreeSet<>(multiMap.keySet());
|
||||
for (Integer key : keys) {
|
||||
assertThat(key).isNotNull();
|
||||
assertThat(key.intValue()).isEqualTo(index);
|
||||
HazelcastIntegrationTestUser user = multiMap.get(key).iterator().next();
|
||||
verifyHazelcastIntegrationTestUser(user, index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
private HazelcastOutboundChannelAdapterTestUtils() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2017-2021 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
|
||||
*
|
||||
* https://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.store;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.history.MessageHistory;
|
||||
import org.springframework.integration.store.MessageGroup;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.map.IMap;
|
||||
|
||||
/**
|
||||
* @author Vinicius Carvalho
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public class HazelcastMessageStoreTests {
|
||||
|
||||
private static HazelcastMessageStore store;
|
||||
|
||||
private static HazelcastInstance instance;
|
||||
|
||||
private static IMap<Object, Object> map;
|
||||
|
||||
@BeforeClass
|
||||
public static void init() {
|
||||
instance = Hazelcast.newHazelcastInstance();
|
||||
map = instance.getMap("customTestsMessageStore");
|
||||
store = new HazelcastMessageStore(map);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void destroy() {
|
||||
instance.getLifecycleService().terminate();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void clean() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithMessageHistory() {
|
||||
|
||||
Message<?> message = new GenericMessage<>("Hello");
|
||||
DirectChannel fooChannel = new DirectChannel();
|
||||
fooChannel.setBeanName("fooChannel");
|
||||
DirectChannel barChannel = new DirectChannel();
|
||||
barChannel.setBeanName("barChannel");
|
||||
|
||||
message = MessageHistory.write(message, fooChannel);
|
||||
message = MessageHistory.write(message, barChannel);
|
||||
store.addMessage(message);
|
||||
message = store.getMessage(message.getHeaders().getId());
|
||||
MessageHistory messageHistory = MessageHistory.read(message);
|
||||
assertThat(messageHistory).isNotNull();
|
||||
assertThat(messageHistory.size()).isEqualTo(2);
|
||||
Properties fooChannelHistory = messageHistory.get(0);
|
||||
assertThat(fooChannelHistory.get("name")).isEqualTo("fooChannel");
|
||||
assertThat(fooChannelHistory.get("type")).isEqualTo("channel");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAndRemoveMessagesFromMessageGroup() {
|
||||
String groupId = "X";
|
||||
List<Message<?>> messages = new ArrayList<>();
|
||||
for (int i = 0; i < 25; i++) {
|
||||
Message<String> message = MessageBuilder.withPayload("foo").setCorrelationId(groupId).build();
|
||||
store.addMessagesToGroup(groupId, message);
|
||||
messages.add(message);
|
||||
}
|
||||
MessageGroup group = store.getMessageGroup(groupId);
|
||||
assertThat(group.size()).isEqualTo(25);
|
||||
store.removeMessagesFromGroup(groupId, messages);
|
||||
group = store.getMessageGroup(groupId);
|
||||
assertThat(group.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addAndGetMessage() {
|
||||
|
||||
Message<?> message = MessageBuilder.withPayload("test").build();
|
||||
store.addMessage(message);
|
||||
Message<?> retrieved = store.getMessage(message.getHeaders().getId());
|
||||
assertThat(retrieved).isEqualTo(message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customMap() {
|
||||
assertThat(TestUtils.getPropertyValue(store, "map")).isSameAs(map);
|
||||
HazelcastMessageStore store2 = new HazelcastMessageStore(instance);
|
||||
assertThat(TestUtils.getPropertyValue(store2, "map")).isNotSameAs(map);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void messageStoreSize() {
|
||||
Message<?> message1 = MessageBuilder.withPayload("test").build();
|
||||
Message<?> message2 = MessageBuilder.withPayload("test").build();
|
||||
store.addMessage(message1);
|
||||
store.addMessage(message2);
|
||||
long size = store.getMessageCount();
|
||||
assertThat(size).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void messageStoreIterator() {
|
||||
Message<?> message1 = MessageBuilder.withPayload("test").build();
|
||||
Message<?> message2 = MessageBuilder.withPayload("test").build();
|
||||
store.addMessageToGroup("test", message1);
|
||||
store.addMessageToGroup("test", message2);
|
||||
int groupCount = 0;
|
||||
for (MessageGroup messageGroup : store) {
|
||||
assertThat(messageGroup.size()).isEqualTo(2);
|
||||
groupCount++;
|
||||
}
|
||||
assertThat(groupCount).isEqualTo(1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="WARN">
|
||||
<Appenders>
|
||||
<Console name="STDOUT" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%d %p [%t] [%c] - %m%n" />
|
||||
</Console>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Logger name="org.springframework" level="warn"/>
|
||||
<Logger name="org.springframework.integration" level="warn"/>
|
||||
<Logger name="org.springframework.integration.hazelcast" level="info"/>
|
||||
<Root level="warn">
|
||||
<AppenderRef ref="STDOUT" />
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
Reference in New Issue
Block a user