/* * Copyright 2002-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 * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.integration.gemfire.inbound; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.geode.cache.CacheClosedException; import org.apache.geode.cache.CacheListener; import org.apache.geode.cache.EntryEvent; import org.apache.geode.cache.Region; import org.apache.geode.cache.util.CacheListenerAdapter; import org.springframework.integration.endpoint.ExpressionMessageProducerSupport; import org.springframework.messaging.Message; import org.springframework.util.Assert; /** * An inbound endpoint that listens to a GemFire region for events and then publishes Messages to * a channel. The default supported event types are CREATED and UPDATED. See the {@link EventType} * enum for all options. A SpEL expression may be provided to generate a Message payload by * evaluating that expression against the {@link EntryEvent} instance as the root object. If no * payloadExpression is provided, the {@link EntryEvent} itself will be the payload. * * @author Mark Fisher * @author David Turanski * @author Artem Bilan * @since 2.1 */ @SuppressWarnings({ "rawtypes", "unchecked" }) public class CacheListeningMessageProducer extends ExpressionMessageProducerSupport { private final Log logger = LogFactory.getLog(this.getClass()); private final Region region; private final CacheListener<?, ?> listener; private volatile Set<EventType> supportedEventTypes = new HashSet<EventType>(Arrays.asList(EventType.CREATED, EventType.UPDATED)); public CacheListeningMessageProducer(Region<?, ?> region) { Assert.notNull(region, "region must not be null"); this.region = region; this.listener = new MessageProducingCacheListener(); } public void setSupportedEventTypes(EventType... eventTypes) { Assert.notEmpty(eventTypes, "eventTypes must not be empty"); this.supportedEventTypes = new HashSet<EventType>(Arrays.asList(eventTypes)); } @Override public String getComponentType() { return "gemfire:inbound-channel-adapter"; } @Override protected void doStart() { if (this.logger.isInfoEnabled()) { this.logger.info("adding MessageProducingCacheListener to GemFire Region '" + this.region.getName() + "'"); } this.region.getAttributesMutator().addCacheListener(this.listener); } @Override protected void doStop() { if (this.logger.isInfoEnabled()) { this.logger.info("removing MessageProducingCacheListener from GemFire Region '" + this.region.getName() + "'"); } try { this.region.getAttributesMutator().removeCacheListener(this.listener); } catch (CacheClosedException e) { if (this.logger.isDebugEnabled()) { this.logger.debug(e.getMessage(), e); } } } private class MessageProducingCacheListener extends CacheListenerAdapter { @Override public void afterCreate(EntryEvent event) { if (CacheListeningMessageProducer.this.supportedEventTypes.contains(EventType.CREATED)) { processEvent(event); } } @Override public void afterUpdate(EntryEvent event) { if (CacheListeningMessageProducer.this.supportedEventTypes.contains(EventType.UPDATED)) { processEvent(event); } } @Override public void afterInvalidate(EntryEvent event) { if (CacheListeningMessageProducer.this.supportedEventTypes.contains(EventType.INVALIDATED)) { processEvent(event); } } @Override public void afterDestroy(EntryEvent event) { if (CacheListeningMessageProducer.this.supportedEventTypes.contains(EventType.DESTROYED)) { processEvent(event); } } private void processEvent(EntryEvent event) { publish(evaluatePayloadExpression(event)); } private void publish(Object object) { Message<?> message = null; if (object instanceof Message) { message = (Message<?>) object; } else { message = getMessageBuilderFactory().withPayload(object).build(); } sendMessage(message); } } }