Skip to content

Commit e062adb

Browse files
author
Udo Kohlmeyer
committed
DATAGEODE-236 - Adding AsCacheListener, AsCacheWriter and
AsRegionEventHandler annotation. Using these annotation on a method, will enable methods to be added as CacheListener or CacheWriter to the specified Region(s)
1 parent c9cb4fb commit e062adb

28 files changed

+3295
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2016-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package org.springframework.data.gemfire.config.annotation;
19+
20+
import java.lang.annotation.ElementType;
21+
import java.lang.annotation.Retention;
22+
import java.lang.annotation.RetentionPolicy;
23+
import java.lang.annotation.Target;
24+
25+
import org.springframework.data.gemfire.eventing.config.CacheListenerEventType;
26+
import org.springframework.data.gemfire.eventing.config.RegionCacheListenerEventType;
27+
28+
/**
29+
* Used to declare a concrete method as a {@link org.apache.geode.cache.CacheListener} event handler
30+
*
31+
* @author Udo Kohlmeyer
32+
* @see org.apache.geode.cache.CacheListener
33+
* @see CacheListenerEventType
34+
* @see org.apache.geode.cache.Region
35+
* @see org.apache.geode.cache.RegionEvent
36+
* @see org.apache.geode.cache.EntryEvent
37+
* @since 2.4.0
38+
*/
39+
@Retention(RetentionPolicy.RUNTIME)
40+
@Target({ ElementType.METHOD })
41+
public @interface AsCacheListener {
42+
43+
/**
44+
* An array of {@link CacheListenerEventType} that control what region CRUD events need to be observed
45+
* {@link CacheListenerEventType} and {@link RegionCacheListenerEventType} cannot be set on the same method. As they
46+
* are mutually exclusive and require that the implementing method uses {@link org.apache.geode.cache.RegionEvent} or
47+
* {@link org.apache.geode.cache.EntryEvent}
48+
*/
49+
CacheListenerEventType[] eventTypes() default {};
50+
51+
/**
52+
* An array for {@link org.apache.geode.cache.Region} names which this {@link org.apache.geode.cache.CacheListener}
53+
* will be link to. Not declaring any regions will result in the CacheListener to be configured against all defined
54+
* regions.
55+
*/
56+
String[] regions() default {};
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2016-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package org.springframework.data.gemfire.config.annotation;
19+
20+
import java.lang.annotation.ElementType;
21+
import java.lang.annotation.Retention;
22+
import java.lang.annotation.RetentionPolicy;
23+
import java.lang.annotation.Target;
24+
25+
import org.springframework.data.gemfire.eventing.config.CacheWriterEventType;
26+
import org.springframework.data.gemfire.eventing.config.RegionCacheWriterEventType;
27+
28+
/**
29+
* Used to declare a concrete method as a {@link org.apache.geode.cache.CacheWriter} event handler
30+
*
31+
* @author Udo Kohlmeyer
32+
* @see org.apache.geode.cache.CacheWriter
33+
* @see CacheWriterEventType
34+
* @see org.apache.geode.cache.Region
35+
* @see org.apache.geode.cache.RegionEvent
36+
* @see org.apache.geode.cache.EntryEvent
37+
* @since 2.4.0
38+
*/
39+
@Retention(RetentionPolicy.RUNTIME)
40+
@Target({ ElementType.METHOD })
41+
public @interface AsCacheWriter {
42+
43+
/**
44+
* An array of {@link CacheWriterEventType} that control what region CRUD events need to be observed
45+
* {@link CacheWriterEventType} and {@link RegionCacheWriterEventType} cannot be set on the same method. As they
46+
* are mutually exclusive and require that the implementing method uses {@link org.apache.geode.cache.RegionEvent} or
47+
* {@link org.apache.geode.cache.EntryEvent}
48+
*/
49+
CacheWriterEventType[] eventTypes() default {};
50+
51+
/**
52+
* An array for {@link org.apache.geode.cache.Region} names which this {@link org.apache.geode.cache.CacheWriter}
53+
* will be link to. Not declaring any regions will result in the CacheWriter to be configured against all defined
54+
* regions.
55+
*/
56+
String[] regions() default {};
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2016-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package org.springframework.data.gemfire.config.annotation;
19+
20+
import java.lang.annotation.ElementType;
21+
import java.lang.annotation.Retention;
22+
import java.lang.annotation.RetentionPolicy;
23+
import java.lang.annotation.Target;
24+
25+
import org.springframework.data.gemfire.eventing.config.CacheListenerEventType;
26+
import org.springframework.data.gemfire.eventing.config.CacheWriterEventType;
27+
import org.springframework.data.gemfire.eventing.config.RegionCacheListenerEventType;
28+
import org.springframework.data.gemfire.eventing.config.RegionCacheWriterEventType;
29+
30+
/**
31+
* Used to declare a concrete method as a {@link AsRegionEventHandler} event handler,
32+
* which handles {@link org.apache.geode.cache.Region}
33+
*
34+
* @author Udo Kohlmeyer
35+
* @see org.apache.geode.cache.CacheWriter
36+
* @see org.apache.geode.cache.CacheListener
37+
* @see org.apache.geode.cache.Region
38+
* @see RegionCacheListenerEventType
39+
* @see RegionCacheWriterEventType
40+
* @see org.apache.geode.cache.RegionEvent
41+
* @see org.apache.geode.cache.EntryEvent
42+
* @since 2.4.0
43+
*/
44+
@Retention(RetentionPolicy.RUNTIME)
45+
@Target({ ElementType.METHOD })
46+
public @interface AsRegionEventHandler {
47+
48+
/**
49+
* An array of {@link RegionCacheListenerEventType} that control what region events need to be observed
50+
* {@link CacheListenerEventType} and {@link RegionCacheListenerEventType} cannot be set on the same method. As they
51+
* are mutually exclusive and require that the implementing method uses {@link org.apache.geode.cache.RegionEvent} or
52+
* {@link org.apache.geode.cache.EntryEvent}
53+
*/
54+
RegionCacheListenerEventType[] regionListenerEventTypes() default {};
55+
56+
/**
57+
* An array of {@link RegionCacheWriterEventType} that control what region events need to be observed.
58+
* {@link CacheWriterEventType} and {@link RegionCacheWriterEventType} cannot be set on the same method. As they
59+
* are mutually exclusive and require that the implementing method uses {@link org.apache.geode.cache.RegionEvent} or
60+
* {@link org.apache.geode.cache.EntryEvent}
61+
*/
62+
RegionCacheWriterEventType[] regionWriterEventTypes() default {};
63+
64+
/**
65+
* An array for {@link org.apache.geode.cache.Region} names which this {@link org.apache.geode.cache.CacheWriter}
66+
* will be link to. Not declaring any regions will result in the CacheListener to be configured against all defined
67+
* regions.
68+
*/
69+
String[] regions() default {};
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2016-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package org.springframework.data.gemfire.config.annotation;
19+
20+
import java.lang.annotation.Documented;
21+
import java.lang.annotation.ElementType;
22+
import java.lang.annotation.Inherited;
23+
import java.lang.annotation.Retention;
24+
import java.lang.annotation.RetentionPolicy;
25+
import java.lang.annotation.Target;
26+
27+
import org.springframework.context.annotation.Import;
28+
import org.springframework.data.gemfire.eventing.config.AsCacheListenerBeanPostProcessorRegistrar;
29+
import org.springframework.data.gemfire.eventing.config.AsCacheWriterBeanPostProcessorRegistrar;
30+
import org.springframework.data.gemfire.eventing.config.PojoCacheListenerWrapper;
31+
32+
/**
33+
* Enables GemFire annotated EventHandler implementations. These implementation will include {@link org.apache.geode.cache.CacheListener},
34+
* {@link org.apache.geode.cache.CacheWriter}, {@link org.apache.geode.cache.TransactionListener} and {@link org.apache.geode.cache.CacheLoader}
35+
*
36+
* This annotation results in the container discovering any beans that are annotated with:
37+
* <ul><
38+
* <li> {code}@AsCacheListener{code},wraps them in a {@link PojoCacheListenerWrapper}</li>
39+
* <li> {code}@AsCacheWriter{code},wraps them in a {@link ComposableCacheWriterWrapper}</li>
40+
* <li></li>and register them with the corresponding {@link org.apache.geode.cache.Region}.
41+
* </ul>
42+
*
43+
* @author Udo Kohlmeyer
44+
* @since 2.3.0
45+
*/
46+
@Target(ElementType.TYPE)
47+
@Retention(RetentionPolicy.RUNTIME)
48+
@Inherited
49+
@Documented
50+
@Import({ AsCacheListenerBeanPostProcessorRegistrar.class,
51+
AsCacheWriterBeanPostProcessorRegistrar.class})
52+
@SuppressWarnings("unused")
53+
public @interface EnableEventProcessing {
54+
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Copyright 2016-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package org.springframework.data.gemfire.config.support;
19+
20+
import java.lang.annotation.Annotation;
21+
import java.lang.reflect.Method;
22+
import java.util.List;
23+
24+
import org.apache.geode.cache.CacheEvent;
25+
import org.apache.geode.cache.CacheListener;
26+
import org.apache.geode.cache.EntryEvent;
27+
import org.apache.geode.cache.Region;
28+
import org.apache.geode.cache.RegionEvent;
29+
import org.springframework.beans.factory.config.BeanPostProcessor;
30+
import org.springframework.context.annotation.Configuration;
31+
import org.springframework.core.annotation.AnnotationAttributes;
32+
import org.springframework.data.gemfire.config.annotation.AsCacheListener;
33+
import org.springframework.data.gemfire.config.annotation.AsRegionEventHandler;
34+
import org.springframework.data.gemfire.eventing.EventProcessorUtils;
35+
import org.springframework.data.gemfire.eventing.config.CacheListenerEventType;
36+
import org.springframework.data.gemfire.eventing.config.PojoCacheListenerWrapper;
37+
import org.springframework.data.gemfire.eventing.config.PojoRegionEventCacheListenerWrapper;
38+
import org.springframework.data.gemfire.eventing.config.RegionCacheListenerEventType;
39+
40+
/**
41+
* A {@link BeanPostProcessor} to create and register {@link CacheListener}, annotated with {@link AsCacheListener}
42+
* and {@link AsRegionEventHandler} onto the configured {@link Region}s
43+
*
44+
* @author Udo Kohlmeyer
45+
* @see BeanPostProcessor
46+
* @see CacheListener
47+
* @see Region
48+
* @see AsCacheListener
49+
* @see AsRegionEventHandler
50+
* @see CallbackPostProcessor
51+
* @since 2.4.0
52+
*/
53+
@Configuration
54+
public class CacheListenerPostProcessor extends CallbackPostProcessor {
55+
56+
@Override
57+
protected Class getRegionEventHandlerClass() {
58+
return AsRegionEventHandler.class;
59+
}
60+
61+
@Override
62+
protected Class getEventHandlerClass() {
63+
return AsCacheListener.class;
64+
}
65+
66+
@Override
67+
protected <T extends Annotation> void registerEventHandlers(Object bean, Class<T> listenerAnnotationClazz,
68+
Method method, AnnotationAttributes cacheListenerAttributes) {
69+
if (listenerAnnotationClazz.isAssignableFrom(getEventHandlerClass())) {
70+
registerCacheListenerEventHandler(bean, method, cacheListenerAttributes);
71+
}
72+
else if (listenerAnnotationClazz.isAssignableFrom(getRegionEventHandlerClass())) {
73+
registerRegionEventHandler(bean, method, cacheListenerAttributes);
74+
}
75+
}
76+
77+
/**
78+
* Lookup {@link CacheListenerEventType} from the {@link AsCacheListener} annotation and create a {@link PojoCacheListenerWrapper}
79+
* of type {@link CacheListener} that would register itself onto a {@link Region} for the configured events
80+
*/
81+
private void registerCacheListenerEventHandler(Object bean, Method method,
82+
AnnotationAttributes cacheListenerAttributes) {
83+
CacheListenerEventType[] eventTypes = (CacheListenerEventType[]) cacheListenerAttributes
84+
.get("eventTypes");
85+
registerEventHandlerToRegion(method, cacheListenerAttributes,
86+
new PojoCacheListenerWrapper(method, bean, eventTypes), EntryEvent.class);
87+
}
88+
89+
/**
90+
* Lookup {@link RegionCacheListenerEventType} from the {@link AsRegionEventHandler} annotation and
91+
* create a {@link PojoRegionEventCacheListenerWrapper}
92+
* of type {@link CacheListener} that would register itself onto a {@link Region} for the configured
93+
* {@link Region} specific events
94+
*/
95+
private void registerRegionEventHandler(Object bean, Method method,
96+
AnnotationAttributes cacheListenerAttributes) {
97+
RegionCacheListenerEventType[] eventTypes = (RegionCacheListenerEventType[]) cacheListenerAttributes
98+
.get("regionListenerEventTypes");
99+
registerEventHandlerToRegion(method, cacheListenerAttributes,
100+
new PojoRegionEventCacheListenerWrapper(method, bean, eventTypes), RegionEvent.class);
101+
}
102+
103+
/**
104+
* Validates the method parameters to be of the correct type dependent on the eventing Annotation. It then registers
105+
* the defined {@link CacheListener} onto the defined set of {@link Region}.
106+
*
107+
* @param method - The event handler callback method for event handling type
108+
* @param cacheListenerAttributes - A set of {@link Annotation} attributes used to get the region names configured
109+
* on the annotation
110+
* @param cacheListener - The {@link CacheListener} to be registered onto the {@link Region}
111+
* @param eventClass - The expected method parameter type. Can be either {@link EntryEvent} or {@link RegionEvent}
112+
*/
113+
private <T extends CacheEvent> void registerEventHandlerToRegion(Method method,
114+
AnnotationAttributes cacheListenerAttributes, CacheListener cacheListener, Class<T> eventClass) {
115+
List<String> regions = getRegionsForEventRegistration(cacheListenerAttributes.getStringArray("regions"),
116+
getBeanFactory());
117+
118+
EventProcessorUtils.validateEventHandlerMethodParameters(method, eventClass);
119+
EventProcessorUtils.registerCacheListenerToRegions(regions, beanFactory, cacheListener);
120+
}
121+
122+
}

0 commit comments

Comments
 (0)