Skip to content
This repository was archived by the owner on Oct 22, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2016-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.data.gemfire.config.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.data.gemfire.eventing.config.CacheListenerEventType;
import org.springframework.data.gemfire.eventing.config.RegionCacheListenerEventType;

/**
* Used to declare a concrete method as a {@link org.apache.geode.cache.CacheListener} event handler
*
* @author Udo Kohlmeyer
* @see org.apache.geode.cache.CacheListener
* @see CacheListenerEventType
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.RegionEvent
* @see org.apache.geode.cache.EntryEvent
* @since 2.4.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface AsCacheListener {

/**
* An array of {@link CacheListenerEventType} that control what region CRUD events need to be observed
* {@link CacheListenerEventType} and {@link RegionCacheListenerEventType} cannot be set on the same method. As they
* are mutually exclusive and require that the implementing method uses {@link org.apache.geode.cache.RegionEvent} or
* {@link org.apache.geode.cache.EntryEvent}
*/
CacheListenerEventType[] eventTypes() default {};

/**
* An array for {@link org.apache.geode.cache.Region} names which this {@link org.apache.geode.cache.CacheListener}
* will be link to. Not declaring any regions will result in the CacheListener to be configured against all defined
* regions.
*/
String[] regions() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2016-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.data.gemfire.config.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.data.gemfire.eventing.config.CacheWriterEventType;
import org.springframework.data.gemfire.eventing.config.RegionCacheWriterEventType;

/**
* Used to declare a concrete method as a {@link org.apache.geode.cache.CacheWriter} event handler
*
* @author Udo Kohlmeyer
* @see org.apache.geode.cache.CacheWriter
* @see CacheWriterEventType
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.RegionEvent
* @see org.apache.geode.cache.EntryEvent
* @since 2.4.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface AsCacheWriter {

/**
* An array of {@link CacheWriterEventType} that control what region CRUD events need to be observed
* {@link CacheWriterEventType} and {@link RegionCacheWriterEventType} cannot be set on the same method. As they
* are mutually exclusive and require that the implementing method uses {@link org.apache.geode.cache.RegionEvent} or
* {@link org.apache.geode.cache.EntryEvent}
*/
CacheWriterEventType[] eventTypes() default {};

/**
* An array for {@link org.apache.geode.cache.Region} names which this {@link org.apache.geode.cache.CacheWriter}
* will be link to. Not declaring any regions will result in the CacheWriter to be configured against all defined
* regions.
*/
String[] regions() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2016-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.data.gemfire.config.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.data.gemfire.eventing.config.CacheListenerEventType;
import org.springframework.data.gemfire.eventing.config.CacheWriterEventType;
import org.springframework.data.gemfire.eventing.config.RegionCacheListenerEventType;
import org.springframework.data.gemfire.eventing.config.RegionCacheWriterEventType;

/**
* Used to declare a concrete method as a {@link AsRegionEventHandler} event handler,
* which handles {@link org.apache.geode.cache.Region}
*
* @author Udo Kohlmeyer
* @see org.apache.geode.cache.CacheWriter
* @see org.apache.geode.cache.CacheListener
* @see org.apache.geode.cache.Region
* @see RegionCacheListenerEventType
* @see RegionCacheWriterEventType
* @see org.apache.geode.cache.RegionEvent
* @see org.apache.geode.cache.EntryEvent
* @since 2.4.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface AsRegionEventHandler {

/**
* An array of {@link RegionCacheListenerEventType} that control what region events need to be observed
* {@link CacheListenerEventType} and {@link RegionCacheListenerEventType} cannot be set on the same method. As they
* are mutually exclusive and require that the implementing method uses {@link org.apache.geode.cache.RegionEvent} or
* {@link org.apache.geode.cache.EntryEvent}
*/
RegionCacheListenerEventType[] regionListenerEventTypes() default {};

/**
* An array of {@link RegionCacheWriterEventType} that control what region events need to be observed.
* {@link CacheWriterEventType} and {@link RegionCacheWriterEventType} cannot be set on the same method. As they
* are mutually exclusive and require that the implementing method uses {@link org.apache.geode.cache.RegionEvent} or
* {@link org.apache.geode.cache.EntryEvent}
*/
RegionCacheWriterEventType[] regionWriterEventTypes() default {};

/**
* An array for {@link org.apache.geode.cache.Region} names which this {@link org.apache.geode.cache.CacheWriter}
* will be link to. Not declaring any regions will result in the CacheListener to be configured against all defined
* regions.
*/
String[] regions() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2016-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.data.gemfire.config.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.context.annotation.Import;
import org.springframework.data.gemfire.eventing.config.AsCacheListenerBeanPostProcessorRegistrar;
import org.springframework.data.gemfire.eventing.config.AsCacheWriterBeanPostProcessorRegistrar;
import org.springframework.data.gemfire.eventing.config.PojoCacheListenerWrapper;

/**
* Enables GemFire annotated EventHandler implementations. These implementation will include {@link org.apache.geode.cache.CacheListener},
* {@link org.apache.geode.cache.CacheWriter}, {@link org.apache.geode.cache.TransactionListener} and {@link org.apache.geode.cache.CacheLoader}
*
* This annotation results in the container discovering any beans that are annotated with:
* <ul><
* <li> {code}@AsCacheListener{code},wraps them in a {@link PojoCacheListenerWrapper}</li>
* <li> {code}@AsCacheWriter{code},wraps them in a {@link ComposableCacheWriterWrapper}</li>
* <li></li>and register them with the corresponding {@link org.apache.geode.cache.Region}.
* </ul>
*
* @author Udo Kohlmeyer
* @since 2.3.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import({ AsCacheListenerBeanPostProcessorRegistrar.class,
AsCacheWriterBeanPostProcessorRegistrar.class})
@SuppressWarnings("unused")
public @interface EnableEventProcessing {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright 2016-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.data.gemfire.config.support;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.List;

import org.apache.geode.cache.CacheEvent;
import org.apache.geode.cache.CacheListener;
import org.apache.geode.cache.EntryEvent;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionEvent;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.data.gemfire.config.annotation.AsCacheListener;
import org.springframework.data.gemfire.config.annotation.AsRegionEventHandler;
import org.springframework.data.gemfire.eventing.EventProcessorUtils;
import org.springframework.data.gemfire.eventing.config.CacheListenerEventType;
import org.springframework.data.gemfire.eventing.config.PojoCacheListenerWrapper;
import org.springframework.data.gemfire.eventing.config.PojoRegionEventCacheListenerWrapper;
import org.springframework.data.gemfire.eventing.config.RegionCacheListenerEventType;

/**
* A {@link BeanPostProcessor} to create and register {@link CacheListener}, annotated with {@link AsCacheListener}
* and {@link AsRegionEventHandler} onto the configured {@link Region}s
*
* @author Udo Kohlmeyer
* @see BeanPostProcessor
* @see CacheListener
* @see Region
* @see AsCacheListener
* @see AsRegionEventHandler
* @see CallbackPostProcessor
* @since 2.4.0
*/
@Configuration
public class CacheListenerPostProcessor extends CallbackPostProcessor {

@Override
protected Class getRegionEventHandlerClass() {
return AsRegionEventHandler.class;
}

@Override
protected Class getEventHandlerClass() {
return AsCacheListener.class;
}

@Override
protected <T extends Annotation> void registerEventHandlers(Object bean, Class<T> listenerAnnotationClazz,
Method method, AnnotationAttributes cacheListenerAttributes) {
if (listenerAnnotationClazz.isAssignableFrom(getEventHandlerClass())) {
registerCacheListenerEventHandler(bean, method, cacheListenerAttributes);
}
else if (listenerAnnotationClazz.isAssignableFrom(getRegionEventHandlerClass())) {
registerRegionEventHandler(bean, method, cacheListenerAttributes);
}
}

/**
* Lookup {@link CacheListenerEventType} from the {@link AsCacheListener} annotation and create a {@link PojoCacheListenerWrapper}
* of type {@link CacheListener} that would register itself onto a {@link Region} for the configured events
*/
private void registerCacheListenerEventHandler(Object bean, Method method,
AnnotationAttributes cacheListenerAttributes) {
CacheListenerEventType[] eventTypes = (CacheListenerEventType[]) cacheListenerAttributes
.get("eventTypes");
registerEventHandlerToRegion(method, cacheListenerAttributes,
new PojoCacheListenerWrapper(method, bean, eventTypes), EntryEvent.class);
}

/**
* Lookup {@link RegionCacheListenerEventType} from the {@link AsRegionEventHandler} annotation and
* create a {@link PojoRegionEventCacheListenerWrapper}
* of type {@link CacheListener} that would register itself onto a {@link Region} for the configured
* {@link Region} specific events
*/
private void registerRegionEventHandler(Object bean, Method method,
AnnotationAttributes cacheListenerAttributes) {
RegionCacheListenerEventType[] eventTypes = (RegionCacheListenerEventType[]) cacheListenerAttributes
.get("regionListenerEventTypes");
registerEventHandlerToRegion(method, cacheListenerAttributes,
new PojoRegionEventCacheListenerWrapper(method, bean, eventTypes), RegionEvent.class);
}

/**
* Validates the method parameters to be of the correct type dependent on the eventing Annotation. It then registers
* the defined {@link CacheListener} onto the defined set of {@link Region}.
*
* @param method - The event handler callback method for event handling type
* @param cacheListenerAttributes - A set of {@link Annotation} attributes used to get the region names configured
* on the annotation
* @param cacheListener - The {@link CacheListener} to be registered onto the {@link Region}
* @param eventClass - The expected method parameter type. Can be either {@link EntryEvent} or {@link RegionEvent}
*/
private <T extends CacheEvent> void registerEventHandlerToRegion(Method method,
AnnotationAttributes cacheListenerAttributes, CacheListener cacheListener, Class<T> eventClass) {
List<String> regions = getRegionsForEventRegistration(cacheListenerAttributes.getStringArray("regions"),
getBeanFactory());

EventProcessorUtils.validateEventHandlerMethodParameters(method, eventClass);
EventProcessorUtils.registerCacheListenerToRegions(regions, beanFactory, cacheListener);
}

}
Loading