-
Notifications
You must be signed in to change notification settings - Fork 14
/
CacheableAnnotationDynamicRegionCreationBeanPostProcessor.java
172 lines (138 loc) · 5.73 KB
/
CacheableAnnotationDynamicRegionCreationBeanPostProcessor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*
* Copyright 2014-present 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.spring.data.gemfire.config;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.execute.FunctionService;
import org.apache.geode.internal.concurrent.ConcurrentHashSet;
import org.spring.data.gemfire.cache.execute.OnMembersCreateRegionFunctionExecution;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.gemfire.function.execution.GemfireOnMembersFunctionTemplate;
/**
* The CacheableAnnotationDynamicRegionCreationBeanPostProcessor class is a Spring BeanPostProcessor processing Spring beans
* and application components on startup that are annotated with @Cacheable in order to dynamically create
* GemFire Regions corresponding for the target "cache" identified in @Cacheable.
*
* @author John Blum
* @see org.spring.data.gemfire.cache.execute.OnMembersCreateRegionFunctionExecution
* @see org.springframework.beans.factory.config.BeanPostProcessor
* @see org.springframework.cache.annotation.Cacheable
* @see org.springframework.data.gemfire.function.execution.GemfireOnMembersFunctionTemplate
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.execute.FunctionService
* @since 1.7.0
*/
@SuppressWarnings("unused")
public class CacheableAnnotationDynamicRegionCreationBeanPostProcessor implements BeanPostProcessor {
public static final String CREATE_REGION_FUNCTION_ID = "createRegion";
protected static final Set<String> IGNORED_PACKAGE_NAMES;
static {
Set<String> ignoredPackageNames = new HashSet<>(2);
ignoredPackageNames.add("org.apache.geode");
ignoredPackageNames.add("org.springframework");
IGNORED_PACKAGE_NAMES = Collections.unmodifiableSet(ignoredPackageNames);
}
private volatile Cache gemfireCache;
private Set<String> storedCacheNames = new ConcurrentHashSet<>();
//@Autowired
private OnMembersCreateRegionFunctionExecution createRegionFunctionExecution;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (isProcessableBean(bean)) {
processCacheableAnnotation(bean.getClass().getAnnotation(Cacheable.class));
for (Method method : bean.getClass().getMethods()) {
processCacheableAnnotation(method.getAnnotation(Cacheable.class));
}
}
return bean;
}
protected boolean isProcessableBean(Object bean) {
for (String packageName : IGNORED_PACKAGE_NAMES) {
if (bean.getClass().getPackage().getName().startsWith(packageName)) {
return false;
}
}
return true;
}
protected boolean processCacheableAnnotation(Cacheable cacheableAnnotation) {
boolean result = false;
if (cacheableAnnotation != null) {
result = true;
for (String cacheName : cacheableAnnotation.value()) {
result &= (isRegionCreationPossible() ? createRegion(cacheName) : store(cacheName));
}
}
return result;
}
protected boolean isRegionCreationPossible() {
return (isCachePresent() && FunctionService.isRegistered(CREATE_REGION_FUNCTION_ID));
}
protected boolean isCachePresent() {
return (gemfireCache != null);
}
protected boolean createRegion(String regionName) {
return createRegion(regionName, DataPolicy.PARTITION);
}
protected boolean createRegion(String regionName, DataPolicy dataPolicy) {
return getCreateRegionFunctionExecution().createRegion(regionName, dataPolicy);
}
protected OnMembersCreateRegionFunctionExecution getCreateRegionFunctionExecution() {
createRegionFunctionExecution = (createRegionFunctionExecution != null ? createRegionFunctionExecution
: newRegionCreationFunctionExecution());
return createRegionFunctionExecution;
}
protected OnMembersCreateRegionFunctionExecution newRegionCreationFunctionExecution() {
return new OnMembersCreateRegionFunctionExecution() {
private GemfireOnMembersFunctionTemplate functionTemplate = new GemfireOnMembersFunctionTemplate();
@Override
public boolean createRegion(String regionName, DataPolicy dataPolicy) {
return Boolean.valueOf(String.valueOf(functionTemplate.execute(CREATE_REGION_FUNCTION_ID, regionName,
dataPolicy)));
}
};
}
protected boolean store(String cacheName) {
return storedCacheNames.add(cacheName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
gemfireCache = (bean instanceof Cache ? (Cache) bean : gemfireCache);
processStoredCacheNames();
return bean;
}
protected boolean processStoredCacheNames() {
boolean result = isRegionCreationPossible();
if (result) {
for (String cacheName : storedCacheNames) {
if (createRegion(cacheName)) {
storedCacheNames.remove(cacheName);
result &= true;
}
else {
result = false;
}
}
}
return result;
}
}